sujingliang · 2024年12月23日

【Mini-F5265-OB开发板试用测评】1、PWM驱动舵机

十分荣幸入围本次评测,感谢技术社区和灵动微电子举办这么好的活动。

Mini-F5265-OB开发板设计紧凑,板载外设丰富,例程详实,编码风格良好。总之这一一款非常适合初学者和开发者快速上手的产品。

本文通过修改定时器例程实现PWM驱动舵机。
原例程位于LibSamples_MM32F5260_V0.11.3\Samples\LibSamples\TIM1_8\TIM1_8_PWM_Output

一、驱动舵机原理

舵机控制信号通常是PWM(脉宽调制)信号。

PWM信号的脉宽直接影响舵机的转动角度。通常,PWM信号的周期固定为20毫秒,而脉冲宽度则决定了舵机的目标角度。例如:

脉冲宽度为0.5毫秒时,对应舵机的最小角度(如0°)。
脉冲宽度为1.5毫秒时,对应舵机的中间位置(如90°,对于180°舵机而言)。
脉冲宽度为2.5毫秒时,对应舵机的最大角度(如180°)

二、PWM配置

这里使用TIM1定时器的通道1和通道2分别控制两个舵机

参数:

Prescaler1=TIM_GetTIMxClock(TIM1)/10000-1;
TimerPeriod1=199;
Channel1Pulse1=10;
Channel2Pulse1=15;

通过预分频器,设置定时器时钟10000hz。
计数器:199+1。
PWM周期=(1/100000)*(199+1)=20ms
通道1占空比时间=10/(199+1)*20=1.0ms
通道2占空比时间=25/(199+1)*20=2.5ms
占空比时间会在程序运行时被修改,以改变舵机角度。

初始化:

 /* TIM1 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

    TIM_TimeBaseStructInit(&TIM_TimeBaseStruct);
    TIM_TimeBaseStruct.TIM_Prescaler         = Prescaler1;
    TIM_TimeBaseStruct.TIM_CounterMode       = TIM_CounterMode_Up;
    TIM_TimeBaseStruct.TIM_Period            = TimerPeriod1;
    TIM_TimeBaseStruct.TIM_ClockDivision     = TIM_CKD_Div1;
    TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct);

    TIM_OCStructInit(&TIM_OCInitStruct);
    TIM_OCInitStruct.TIM_OCMode       = TIM_OCMode_PWM1;
    TIM_OCInitStruct.TIM_OutputState  = TIM_OutputState_Enable;
    TIM_OCInitStruct.TIM_Pulse        = 0;
    TIM_OCInitStruct.TIM_OCPolarity   = TIM_OCPolarity_High;
    TIM_OCInitStruct.TIM_OCIdleState  = TIM_OCIdleState_Set;

    TIM_OCInitStruct.TIM_Pulse = Channel1Pulse1;
    TIM_OC1Init(TIM1, &TIM_OCInitStruct);
        
    TIM_OCInitStruct.TIM_Pulse = Channel2Pulse1;
    TIM_OC2Init(TIM1, &TIM_OCInitStruct);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_1);    /* TIM1_CH1 */
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);    /* TIM1_CH2 */
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_8 | GPIO_Pin_9 ;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    TIM_Cmd(TIM1, ENABLE);
    TIM_CtrlPWMOutputs(TIM1, ENABLE);

三、改变舵机角度

定义一个变量,保存角度信息
uint8_t servo_angle=0;

change_servor_angle()函数:

void change_servor_angle()
{
    if(servo_angle==0){
        TIM_SetCompare1(TIM1,5);//0度
        TIM_SetCompare2(TIM1,5);//0度
    }else if(servo_angle==180)
    {
        TIM_SetCompare1(TIM1,10);//45度
        TIM_SetCompare2(TIM1,10);//45度
        PLATFORM_DelayMS(1000);
        servo_angle=0;
    }else if(servo_angle==90)
    {
        TIM_SetCompare1(TIM1,15);//90度
        TIM_SetCompare2(TIM1,15);//90度
        PLATFORM_DelayMS(1000);
        servo_angle=0;
    }
}

TIM_SetCompare1、TIM_SetCompare2分别改变通道1和通道2的占空比时间。

四、外部中断改变舵机角度值

将板载用户按键配置为外部中断输入:

void EXTI_Configure(void)
{
    EXTI_InitTypeDef EXTI_InitStruct;
    GPIO_InitTypeDef GPIO_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

    /* KEY1->PB0->EXTI_Line0 */
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_0;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource0);

    EXTI_StructInit(&EXTI_InitStruct);
    EXTI_InitStruct.EXTI_Line    = EXTI_Line0;
    EXTI_InitStruct.EXTI_Mode    = EXTI_Mode_Interrupt;
    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStruct.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStruct);

    /* KEY2->PB1->EXTI_Line1 */
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_1;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource1);

    EXTI_StructInit(&EXTI_InitStruct);
    EXTI_InitStruct.EXTI_Line    = EXTI_Line1;
    EXTI_InitStruct.EXTI_Mode    = EXTI_Mode_Interrupt;
    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStruct.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStruct);

    /* EXTI Interrupt */
    NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    NVIC_InitStruct.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}    

外部中断处理函数:
按下按键,改变舵机角度

void EXTI0_IRQHandler(void)
{
    /* KEY1 */
    if (SET == EXTI_GetITStatus(EXTI_Line0))
    {
        PLATFORM_LED_Toggle(LED1);
                servo_angle=180;

        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}
void EXTI1_IRQHandler(void)
{
    /* KEY2 */
    if (SET == EXTI_GetITStatus(EXTI_Line1))
    {
        PLATFORM_LED_Toggle(LED2);
                servo_angle=90;
        EXTI_ClearITPendingBit(EXTI_Line1);
    }
}

五、主循环

void TIM1_8_PWM_Output_Sample(void)
{
    printf("\r\nTest %s", __FUNCTION__);

    TIM1_8_Configure();
    EXTI_Configure();
    while (1)
    {
        change_servor_angle();
        PLATFORM_DelayMS(200);
    }
}

六、运行效果

tutieshi_480x270_14s.gif

推荐阅读
关注数
0
文章数
4
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息