3.11节 PWM电机转动实验
本节介绍使用STM32的TIM定时器输出PWM控制电机转动。
a.实验准备:码盘电机,USB转串口模块,ST-Llink下载器,CHEAPX机器人控制板
b.实验目的:STM32实现PWM输出
c.相关知识点:
PWM由STM32的定时器产生,通过设置计数频率实现PWM频率设置,设置最大计数值ARR和CCR调节PWM占空比
d.编程及运行
(1)初始化
void initMoter(void) { //LFT MOTOR PE13 PE14 //RGT MOTOR PE9 PE11 GPIO_InitTypeDef GPIO_InitStruct; TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; TIM_OCInitTypeDef TIM_OCInitStruct; //Config Clock 配置时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_TIM1|RCC_APB2Periph_GPIOE, ENABLE); GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE); //映射管脚 //配置GPIO GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_9|GPIO_Pin_11; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//推挽输出 GPIO_Init(GPIOE, &GPIO_InitStruct); //传入结构体GPIO_InitStruct,配置GPIO GPIO_SetBits(GPIOE,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_9|GPIO_Pin_11); //管脚电平置高,保证电机处于停止状态 //TIM1 PE13 CH3,PE14 CH4 //TIM1 PE9 CH1,PE11 CH2 TIM_TimeBaseStruct.TIM_ClockDivision = 0; //时钟分割,不分割,即为该定制器时钟最大值72M TIM_TimeBaseStruct.TIM_Prescaler = Motor_PSC-1;//预分频值, TIM_TimeBaseStruct.TIM_Period = Motor_ARR-1;//最大计数值 TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式 TIM_TimeBaseStruct.TIM_RepetitionCounter=0; //重复计数器 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct);//传入结构TIM_TimeBaseStruct,配置TIM1 TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;//TIM脉冲宽度调制模式2:CNT值小于比较器TIM_Period设定值时输出有效低电平,否者高电平 TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; //开启 OC正相输出到对应引脚 TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Disable; //关闭 OC反相输出到对应引脚 TIM_OCInitStruct.TIM_Pulse = 0; //重置计数器的值,保证电机处于停止状态 TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:高电平 TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set; //空闲状态下的TIM输出比较的引脚电平 TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Set;//空闲状态下的TIM互补输出比较的引脚电平 TIM_OC1Init(TIM1, &TIM_OCInitStruct);//传入结构TIM_OCInitStruct,配置TIM1 OC1通道 TIM_OC2Init(TIM1, &TIM_OCInitStruct);//传入结构TIM_OCInitStruct,配置TIM1 OC2通道 TIM_OC3Init(TIM1, &TIM_OCInitStruct);//传入结构TIM_OCInitStruct,配置TIM1 OC3通道 TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;//TIM脉冲宽度调制模式2:CNT值小于比较器TIM_Period设定值时输出有效低电平,否者高电平 TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//开启 OC正相输出到对应引脚 TIM_OCInitStruct.TIM_Pulse = 0; //重置计数器的值,保证电机处于停止状态 TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:高电平 TIM_OC4Init(TIM1, &TIM_OCInitStruct); //传入结构TIM_OCInitStruct,配置TIM1 OC4通道 TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);//开启OC1重装载,写入CCR1立即生效 TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);//开启OC2重装载,写入CCR2立即生效 TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);//开启OC3重装载,写入CCR3立即生效 TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);//开启OC4重装载,写入CCR4立即生效 TIM_CtrlPWMOutputs(TIM1, ENABLE); //使能PWM输出 TIM_ARRPreloadConfig(TIM1, ENABLE);//开启自动装载 TIM_Cmd(TIM1, ENABLE); //开启TIM1 // TIM1->CCR3=10000;TIM1->CCR4=10000; // TIM1->CCR1=10000;TIM1->CCR2=10000; }
(2)更新函数
//参数:左电机速度,左电机方向,右电机速度,右电机方向 //速度值范围[4000,30000],值过小电机可能会不转 //方向:参照小车朝向,0往后转,1向前转 void moterControl(u16 lv,u8 ldir, u16 rv,u8 rdir) { //限最大值,防止小车过快 if(lv>30000)lv=30000; if(rv>30000)rv=30000; //驱动器通过两路PWM控制,分别连接IN1、IN2。IN1低电平,IN2高电平时正传;IN1高电平,IN2低电平时反传。高电平的占空比决定电机转速。 if(ldir>0) { TIM1->CCR4=0;TIM1->CCR3=lv;//电机反转,参照小车朝向是向前转 } else { TIM1->CCR3=0;TIM1->CCR4=lv;//电机正转,参照小车朝向是向后转 } if(rdir>0) { TIM1->CCR1=0;TIM1->CCR2=rv;//电机正转,参照小车朝向是向前转 } else { TIM1->CCR2=0;TIM1->CCR1=rv;//电机反转,参照小车朝向是向后转 } }
(3)主函数
//PWM电机转动实验 int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //PriorityGroupConfig NVIC中断分组设置 组2(2位抢占优先级,2位响应优先级) initDebugSerial(500000);//初始化调试串口USART1,波特率500000 initSysTick();//初始化滴答定时器和TIM4定时器 showVersion();//显示版本 initMoter(); //初始化电机 //参数:左电机速度,左电机方向,右电机速度,右电机方向 //速度值范围[4000,30000],值过小电机可能会不转 //方向:参照小车朝向,0往后转,1向前转 moterControl(10000,1,10000,1); delay_ms(300); //moterControl(0,1,0,1);//停止 }
(4)实验结果:电机转动0.3秒后停止