十分荣幸入围本次评测,感谢技术社区和灵动微电子举办这么好的活动。
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);
}
}