1. 程式人生 > >STM32驅動舵機

STM32驅動舵機

    舵機控制原理:

提供週期為20ms的pwm訊號,調節pwm的佔空比為0.5ms-2.5ms可使舵機從0-180度線性變化

舵機控制程式:

首先我們要利用stm32定時器產生合適週期的pwm輸出訊號,這裡使用的是PWM高階定時器1的CH1(即PA8),可以通過配置輸入引數arr和psc產生合適的頻率的pwm脈衝訊號。

//高階定時器1pwm輸出初始化
//arr:自動重灌值(週期)  psc:時鐘預分頻數
void tim1_pwmInit(uint16_t arr, uint16_t psc)
{
  GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); // 使能定時器1的外設時鐘
 	RCC_APB2PeriphClockCmd(TIM1_CH1_GPIO_CLK, ENABLE);  //使能GPIO外設時鐘使能                               	

   //設定該引腳為複用輸出功能,輸出TIM1 CH1的PWM脈衝波形
	GPIO_InitStructure.GPIO_Pin = TIM1_CH1_PIN; //TIM_CH1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //複用推輓輸出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(TIM1_CH1_PORT, &GPIO_InitStructure);
	
	TIM_TimeBaseStructure.TIM_Period = arr; //設定在下一個更新事件裝入活動的自動重灌載暫存器週期的值	 80K
	TIM_TimeBaseStructure.TIM_Prescaler = psc; //設定用來作為TIMx時鐘頻率除數的預分頻值  不分頻
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設定時鐘分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上計數模式
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的引數初始化TIMx的時間基數單位

 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //選擇定時器模式:TIM脈衝寬度調製模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
	//TIM_OCInitStructure.TIM_Pulse = 0; //設定待裝入捕獲比較暫存器的脈衝值
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出極性:TIM輸出比較極性低
	TIM_OC1Init(TIM1, &TIM_OCInitStructure);  //根據TIM_OCInitStruct中指定的引數初始化外設TIMx

  TIM_CtrlPWMOutputs(TIM1,ENABLE);	//MOE 主輸出使能	
	
	TIM_Cmd(TIM1, ENABLE);  //使能TIM1
}

在有了pwm訊號源之後我們便可以根據舵機的控制原理構建舵機驅動函數了。

// 72M / (719 + 1) = 0.1M 故記一個數的時間為10us  定時週期:(1999 + 1) * 10us = 20ms
#define SERVO_TIM_ARR  1999
#define SERVO_TIM_PSC  719
void servo_init(void)
{
  tim1_pwmInit(SERVO_TIM_ARR,SERVO_TIM_PSC);
  TIM_SetCompare1(TIM1,150);  //使舵機恢復到中間位置
}

//0.5ms--0°  2.5ms--180°
void servo_angle(uint16_t angle)
{
  uint16_t pulse;
  
  //針對舵機可轉角度限輻
  if(angle <= 5)
    angle = 5;
  if(angle >= 175)
    angle = 175;
  //將角度值轉換為脈衝值  
  pulse = (uint16_t)(50 + angle * 100/90.0);  //此轉換公式需根據pwm的arr及psc配置來做相應變化
  TIM_SetCompare1(TIM1, pulse);
  
}


void servo_debug(void)
{
  uint8_t i;
  for(i = 0; i < 10; ++i)
  {
    delay_ms(500);
    servo_angle(45);
    delay_ms(500);
    servo_angle(90);
    delay_ms(500);
    servo_angle(135);
    delay_ms(500);
    servo_angle(90);
  }
}

在主函式中初始化舵機驅動後,便可以呼叫servo_angle(uint16_t angle)函式實現舵機在5-175度之間任意角度的旋轉,選擇5-175度限輻是為了保護舵機(防止舵機處於打死的狀態),也可改為0-180度。