这是主函数:
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); Delay_Init(); USART_Printf_Init(115200); PWM_Init(2000-1, 720-1); while(1) { Delay_Init(); Servo_SetAngle2(0); Delay_Ms(1000); Servo_SetAngle2(45); Delay_Ms(1000); Servo_SetAngle2(90); Delay_Ms(1000); Servo_SetAngle2(135); Delay_Ms(1000); Servo_SetAngle2(180); Delay_Ms(1000); } }
按照程序,舵机的角度应该从0°开始,依次变为45°、90°、135°、180°,然后循环往复。但实际情况是舵机不能稳定地实现上述过程,如本应该:0°(停顿1000ms)->45°(停顿1000ms)->90°(停顿1000ms)->135°(停顿1000ms)->180°(停顿1000ms)······,但实际情况却可能是0°(停顿1000ms)->45°(停顿1000ms)->90°(停顿1000ms)->135°(停顿时间超过1000ms)->90°。
尤其是板子刚上电的时候,舵机常常在两个固定的角度上不断来回运动,复位几次后会稳定到预计过程,但是运行几个周期后又会乱跑,然后再次稳定到预计过程,这样不断循环。
下面是舵机控制函数
void PWM_Init(u16 arr, u16 psc) { /*------------------------GPIO初始化-----------------------*/ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //设置该引脚为复用输出功能,输出TIM1 CH1的PWM脉冲波形 GPIOA.8 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM1_CH1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //设置该引脚为复用输出功能,输出TIM1 CH3的PWM脉冲波形 GPIOA.10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//TIM1_CH2 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 开启定时器时钟,即内部时钟CK_INT=72M RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //打开管脚复用AFIO时钟 /*--------------------定时器时基结构体初始化------------------*/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler = psc; 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; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 输出通道电平极性配置 //PA8设置 TIM_OCInitStructure.TIM_Pulse = 0;//设置占空比大小 TIM_OC1Init(TIM1, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);//使能TIM1在CCR1上的预装载寄存器 TIM_ARRPreloadConfig(TIM1, DISABLE);//允许或禁止在定时器工作时向ARR(自动重装载值)的缓冲器中写入新值,以便在更新事件发生时载入覆盖以前的值,此处为不允许 //PA10设置 TIM_OCInitStructure.TIM_Pulse = 0;//设置占空比大小 TIM_OC3Init(TIM1, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);//使能TIM1在CCR1上的预装载寄存器 TIM_ARRPreloadConfig(TIM1, DISABLE);//允许或禁止在定时器工作时向ARR(自动重装载值)的缓冲器中写入新值,以便在更新事件发生时载入覆盖以前的值,此处为不允许 TIM_Cmd(TIM1, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE);// 主输出使能,当使用的是通用定时器时,这句不需要 } /********************************************************************* * @fn Servo_SetAngle1 * * @brief 舵机1的角度控制 * * @return none */ void Servo_SetAngle1(float angle) { u16 ccp=50+angle/0.9; TIM_SetCompare1(TIM1,ccp); Delay_Ms(100); } /********************************************************************* * @fn Servo_SetAngle1 * * @brief 舵机2的角度控制 * * @return none */ void Servo_SetAngle2(float angle) { if(angle > 180) { angle = 180; } if(angle < 0 ) { angle = 0; } u16 ccp=50+angle/0.9; TIM_SetCompare3(TIM1,ccp); } /*********************************************************************