1. 引言
舵机,全称为伺服电机(Servo Motor),是一种能够精确控制角度位置的电机。它不仅仅是一个简单的电机,而是集成了电机、传感器和控制电路的完整闭环控制系统。广泛应用于机械臂关节、转向控制等。
2. 舵机的基本工作原理
重要提示:舵机工作电流较大(可达100-300mA),切勿直接使用STM32的3.3V引脚供电,必须使用外部电源!
(1)舵机的工作原理(一个脉宽对应一个转动角度)
舵机的控制信号为周期20ms 的脉宽调制(PWM)信号,其中脉冲宽度从0.5ms~2.5ms,相对应舵机转动角度为0~180度,呈线性变化。也就是说,给它提供一定的脉宽,它的输出轴就会保持在一个相对应的角度上,无论外界转矩怎样改变,直到给它提供一个另外宽度的脉冲信号,它才会改变输出角度到新的对应的位置上。舵机输出转动角度与输入信号脉冲宽度的关系见下图。
3.代码实现
(1)硬件连接
单片机+5V----舵机红色线;
单片机GND----舵机棕色线;
单片机PWM输出引脚----舵机橙色线;
(2)编程思路:第一步配置PWM输出,第二步通过函数TIM_SetComparex(TIMx, CCRx)设置脉冲宽度。
(3)使用定时器13,通道1(PF8或PA6)输出PWM信号
//PWM输出配置void TIM13_PWM_Init(){GPIO_InitTypeDef GPIO_InitStruct; //GPIO口结构体TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;//时基结构体TIM_OCInitTypeDef TIM_OCInitStruct;//比较输出结构体/*1-开定时器和GPIO口时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM13,ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);/*2-配置定时器输入引脚*/GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;//选择F8引脚GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//复用功能模式GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;//输出速度GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;GPIO_Init(GPIOF, &GPIO_InitStruct);GPIO_PinAFConfig(GPIOF,GPIO_PinSource8,GPIO_AF_TIM13);//复用功能配置/*3-时基配置*/TIM_TimeBaseStruct.TIM_Period =200-1;//自动重装载ARR值,周期20msTIM_TimeBaseStruct.TIM_Prescaler =8400-1;//预分频PSC值10KHzTIM_TimeBaseStruct.TIM_ClockDivision=TIM_CKD_DIV1;//1分频TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式TIM_TimeBaseInit(TIM13, &TIM_TimeBaseStruct);//完成初始化/*4-比较输出配置*/TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//PWM模式1TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性高电平TIM_OC1Init(TIM13, &TIM_OCInitStruct); //初始化TIM5比较输出通道3/*5-使能预装载寄存器*/TIM_OC1PreloadConfig(TIM13, TIM_OCPreload_Enable);/*6-使能自动重装载寄存器*/TIM_ARRPreloadConfig(TIM13, ENABLE);/*7-使能定时器*/TIM_Cmd(TIM13,ENABLE);}
//角度控制函数void Set_Servo_Angle(float angle){uint16_t pulse;// 角度限幅if(angle < 0) angle = 0;if(angle > 180) angle = 180;// 角度到脉冲宽度的线性转换// 角度: 0° ~ 180° → 脉宽(CCR值): 5 ~ 25//0°~5,45°~10,90°~15,135°~20,180°~25pulse = (uint16_t)(5 + (angle / 180.0f) * 20);TIM_SetCompare1(TIM13, pulse);}
int main(void){int angle = 0;TIM13_PWM_Init();while(1){Set_Servo_Angle(0);delay_ms(1000);Set_Servo_Angle(90);delay_ms(1000);Set_Servo_Angle(180);delay_ms(1000);for(angle = 0; angle <= 180; angle += 5){Set_Servo_Angle(angle);delay_ms(100);}for(angle = 180; angle >= 0; angle -= 5){Set_Servo_Angle(angle);delay_ms(100);}}}
//延时函数void delay_ms(uint32_t ms){// 计算重装载值uint32_t reload = (SYSTEM_CORE_CLOCK / 1000) - 1;uint32_t i;for(i = 0; i < ms; i++){// 设置重装载值并清空计数器SysTick->LOAD = reload;SysTick->VAL = 0;// 使能计数器(使用处理器时钟,不使能中断)SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk;// 等待计数完成while(!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)){// 空循环等待}// 禁用计数器SysTick->CTRL = 0;}}

