CH32V103C8T6输出PWM时不能及时改变占空比

这是主函数:

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);
}
/*********************************************************************



您好,建议你在初始化的时候将相关结构体清0,如下图。此外,关于延时函数的初始化,在main函数一开始初始化一次即可,无需在while循环中一直进行初始化。关于使用高级定时器,对于重复计数器值的配置,若没有用到,配置为0即可,这一项可不用注释掉。关于舵机运动,若你一开始不是在设定位置,上电后可能会进行一个回位,因为初始化开始时比较寄存器的值设置的是0.你可以按照上述要求配置一下,后续若有问题,可通过邮箱(lzs@wch.cn)和我进行沟通。

image.png


找到问题了,是舵机供电的原因,不能用板子直接给舵机供电


只有登录才能回复,可以选择微信账号登录