天天看點

stm32控制舵機旋轉到不同角度

最近學習了stm32,就想用它來控制舵機,然後寫下這篇文章分享給大家,如果有了解不到位的地方歡迎大家指正。(我使用的是stm32f103ve型号的開發闆,即使和你的型号不同,也有參考價值)

想要控制舵機的轉動,首先你得知道舵的工作原理。

舵機的主要組成部分為伺服電機,所謂伺服就是服從信号的要求而動作。在信号來之前,轉子停止不動;信号來到之後,轉子立即運動。是以我們就可以給舵機輸入不同的信号,來控制其旋轉到不同的角度。

舵機接收的是PWM信号,當信号進入内部電路産生一個偏置電壓,觸發電機通過減速齒輪帶動電位器移動,使電壓差為零時,電機停轉,進而達到伺服的效果。簡單來說就是給舵機一個特定的PWM信号,舵機就可以旋轉到指定的位置。

舵機上有三根線,分别是GND、VCC和SIG,也就是地線、電源線和信号線,其中的PWM波就是從信号線輸入給舵機的。

一般來說,舵機接收的PWM信号頻率為50HZ,即周期為20ms。當高電平的脈寬在0.5ms-2.5ms之間時舵機就可以對應旋轉到不同的角度。如下圖。

stm32控制舵機旋轉到不同角度
stm32控制舵機旋轉到不同角度

那麼我們如何使用stm32給舵機輸入信号,讓它聽從我們的指揮呢?

想要輸出PWM信号自然就得用上TIM定時器,而基本定時器沒有PWM信号的輸出功能,是以隻能選用通用定時器和進階定時器。對于初始化這些外設無非也就是那些套路,我總結為如下幾點:1、開啟該外設的時鐘2、配置初始化結構體(如果有對應的GPIO還需要初始化該GPIO)3、調用結構體初始化函數4、該使能的使能

對于TIM來說初始化結構體有兩個,分别是時基結構體和輸出比較結構體,除此之外還需要做的是先選擇具體開啟哪條輸出通道,我選擇的是TIM1(進階定時器)的CH1(通道一),對應的GPIO是PA8。我還初始化了通道一的互補通道PB13,為了更加友善測試。下面是初始化部分的代碼。

static void TIM_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

  // 輸出比較通道 GPIO 初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

  // 輸出比較通道互補通道 GPIO 初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	// BKIN引腳預設先輸出低電平
	GPIO_ResetBits(ADVANCE_TIM_BKIN_PORT,ADVANCE_TIM_BKIN_PIN);
}

static void Advance_TIM_Config(void)
{
	  // 開啟定時器時鐘,即内部時鐘CK_INT=72M
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);

/*--------------------時基結構體初始化-------------------------*/
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	// 自動重裝載寄存器的值,累計TIM_Period+1個頻率後産生一個更新或者中斷
	TIM_TimeBaseStructure.TIM_Period= (200-1);	
	// 驅動CNT計數器的時鐘 = Fck_int/(psc+1)
	TIM_TimeBaseStructure.TIM_Prescaler= (7200-1);	
	// 時鐘分頻因子 ,用于配置死區時間,沒用到,随意
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;		
	// 計數器計數模式,設定為向上計數
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;		
	// 重複計數器的值,沒用到,可以随意設定
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	
	// 初始化定時器
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

	/*--------------------輸出比較結構體初始化-------------------*/		
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	// 配置為PWM模式2
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
	// 輸出使能
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	// 互補輸出使能
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; 
	// 設定占空比大小
	TIM_OCInitStructure.TIM_Pulse = 0;
	// 輸出通道電平極性配置
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	// 互補輸出通道電平極性配置
	TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
	// 輸出通道空閑電平極性配置
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
	// 互補輸出通道空閑電平極性配置
	TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
	TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
	
	// 使能計數器
	TIM_Cmd(TIM1, ENABLE);	
	// 主輸出使能,當使用的是通用定時器時,這句不需要
	TIM_CtrlPWMOutputs(TIM1, ENABLE);
}

void TIM_Init(void)
{
	TIM_GPIO_Config();
	Advance_TIM_Config();
}
           

在代碼中要特别注意的是時基結構體的TIM_Period(自動重裝載寄存器值,簡稱arr)和TIM_Prescaler(預分頻寄存器值,簡稱psc),因為這兩個決定了輸出PWM信号的周期。具體的周期計算公式為:周期=(arr+1)*(psc+1)/CLK。其中CLK為計數器的時鐘頻率,我的是72MHZ,也就是72000000。最後計算結果機關為秒,結果為0.02s,也就是20ms。這樣的配置就是為了讓輸出的PWM信号達到前面說到的舵機要求的20ms周期。

在初始化完成之後,就可以在main函數中實作信号的輸出了。

前面說過,在周期20ms的PWM信号中,不同的脈寬對應舵機不同的轉動角度,在0.5ms-2.5ms間有效,是以我們可以在main函數中配置幾個不同的脈寬。要注意的是stm32并不直接配置脈寬,而是通過配置占空比來配置脈寬的。

配置占空比有個重要的函數TIM_SetCompare1(),具體用法如果不懂可以去看手冊。main函數代碼如下。

#include "stm32f10x.h"
#include "bsp_Advance_tim.h"
#include "delay.h"

int main(void)
{
	int delay_time;
	delay_init(); //延時函數初始化
	TIM_Init(); //定時器初始化
	
	delay_time = 500;
	while(1)
	{
		delay_ms(delay_time);
		TIM_SetCompare1(ADVANCE_TIM, 175); //對應180度
        delay_ms(delay_time);
		TIM_SetCompare1(ADVANCE_TIM, 180); //對應135度
        delay_ms(delay_time);
		TIM_SetCompare1(ADVANCE_TIM, 185); //對應90度
        delay_ms(delay_time);
		TIM_SetCompare1(ADVANCE_TIM, 190); //對應45度
        delay_ms(delay_time);
		TIM_SetCompare1(ADVANCE_TIM, 195); //對應0度
	}
}
           

如果在定時器初始化時TIM_OCInitStructure.TIM_OCMode配置的是PWM1模式那麼main中的占空比就依次為25、20、15、10、5。在你們自己試驗時,可以将占空比設定成各種不同的值,看看有什麼不同的效果。

在這補充一點如何連線:可以用杜邦線将舵機的電源與stm32的5v或3.3v引腳連接配接,将地線與stm32的GND連接配接,将舵機的信号線與stm32的PWM信号輸出引腳連接配接。

stm32控制舵機旋轉到不同角度完整代碼

繼續閱讀