PWM电机调速(寄存器版)
我的上一篇博客已经写了如何用定时器产生PWM来实现LED灯的呼吸灯效果,当我想实现PWM来控制电机调速时,网上翻阅了很多的资料但是大多数是在呼吸灯的基础上改一下代码实现的,没有一定的代表性。并且基本上是只产生两路PWM
网上更多的代码是库函数版本的,对于刚学完51上手32的人来说可能不太适应。最近刚好学习了STM32的PWM,同时用来做一辆4轮小车来练练手。只有动手才能知道自己的问题出在哪里会还是不会。那么我就分享一下我做小车的经验。
一、定时器的两路通道产生两路PWM
这里我用的是定时器3的通道1和通道3,主要步骤如下:
1、开启 TIM3 时钟,配置 PB0和PA0 为复用输出
要使用 TIM3,我们必须先开启 TIM3 的时钟(通过 APB1ENR 设置),这里我们还要配置 PB0和PA6为复用输出,这是因为 TIM3_CH1 通道将映射到 PB0上,TIM3-CH3映射到PA6上此时, PB0和PA6属于复用功能输出。
2、设置 TIM3 的 ARR 和 PSC
在开启了 TIM3 的时钟之后,我们要设置 ARR 和 PSC 两个寄存器的值来控制输出 PWM 的周期。当 PWM 周期太慢(低于 50Hz)的时候,我们就会明显感觉到闪烁了。因此, PWM 周期在这里不宜设置的太小。
3、设置 TIM3_CH1和TIM3_CH3 的 PWM 模式
接下来,我们要设置 TIM3_CH1 和TIM3_CH3为 PWM 模式(默认是冻结的),因为我们的电机是低电平转的快,而我们希望当 CCR1 和CCR3的值小的时候, 就暗, CCR1和CCR2值大的时候,电机的转速就快,所以我们要通过配置 TIM3_CCMR1 的相关位来控制 TIM3_CH1的模式,通过TIM_CCMR2的相关位来控制TIM3_CH3的模式。
4、使能 TIM3 的 CH2 输出,使能 TIM3
在完成以上设置了之后,我们需要开启TIM3 的通道 1和通道3输出以及 TIM3。前者通过TIM3_CCER1和TIM_CCMR2 来设置,是单个通道的开关,而后者则通过 TIM3_CR1 来设置,是整个 TIM3 的总开关。只有设置了这两个寄存器,这样我们才能在 TIM3 的通道1和通道3 上看到 PWM 波输出。
5、修改 TIM3_CCR1和TIM_CCR3 来控制占空比。
最后,在经过以上设置之后, PWM 其实已经开始输出了,只是其占空比和频率都是固定的,而我们通过修改 TIM3_CCR1和TIM_CCR3则可以控制 CH1和CH2的输出占空比。继而控制 两个电机的速度。
通过以上 65个步骤,我们就可以控制 TIM3 的 CH1CH3输出 PWM 波了。 这里特别提醒一下大家,高级定时器虽然和通用定时器类似,但是高级定时器要想输出 PWM,必须还要设置一个MOE 位(TIMx_BDTR 的第 15 位),以使能主输出,否则不会输出 PWM!!
两路PWM代码片:
1、配置定时器3
在该工程下新建一个文件夹命名为TIMER,里面包括两个文件:timer.c和timer.h.
timer.c主要包括以下两段代码定时器3的初始化和PWM的初始化。
(1)定时器3初识化
- <font face="微软雅黑" size="3">void TIM3_Int_Init(u16 arr,u16 psc)
- {
- RCC->APB1ENR|=1<<1; //TIM3时钟使能
- TIM3->ARR=arr; //设定计数器自动重装值//刚好1ms
- TIM3->PSC=psc; //预分频器7200,得到10Khz的计数时钟
- TIM3->DIER|=1<<0; //允许更新中断
- TIM3->CR1|=0x01; //使能定时器3
- MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占1,子优先级3,组2
- }
- </font>
复制代码 (2)TIM3 PWM初始化:
- <font face="微软雅黑" size="3">void TIM3_PWM_Init(u16 arr,u16 psc)
- {
- //此部分需手动修改IO口设置
- RCC->APB1ENR|=1<<1; //TIM3时钟使能
- RCC->APB2ENR|=1<<3; //使能PORTB时钟
- RCC->APB2ENR|=1<<2; //使能PORTA时钟
- GPIOB->CRL&=0XFFFFFFF0; //PB0输出
- GPIOB->CRL|=0X0000000B; //复用功能输出
- GPIOA->CRL&=0XF0FFFFFF; //PA6输出
- GPIOA->CRL|=0X0B000000; //复用输出
- TIM3->ARR=arr; //设定计数器自动重装值
- TIM3->PSC=psc; //预分频器不分频
-
- TIM3->CCMR1|=6<<4; //CH1 PWM2模式
- TIM3->CCMR1|=1<<3; //CH1预装载使能
- TIM3->CCMR2|=6<<4; //CH3预装载使能
- TIM3->CCMR2|=1<<3; //CH3输出使能
- TIM3->CCER|=1<<0; //OC1 输出使能
- TIM3->CCER|=1<<8;
- TIM3->CR1=0x0080; //ARPE使能
- TIM3->CR1|=0x01; //使能定时器3
- STBY=1;
- }
- </font>
复制代码 timer.h代码如下:
- <font face="微软雅黑" size="3">#ifndef __TIMER_H
- #define __TIMER_H
- #include "sys.h"
- //1,增加TIM3_PWM_Init函数。
- //2,增加left和right宏定义,控制TIM3_CH1脉宽
- //通过改变TIM3->CCR1和TIM->CR3的值来改变占空比,从而控制电机的速度
- #define left TIM3->CCR1
- #define right TIM3->CCR3
- void TIM3_Int_Init(u16 arr,u16 psc);
- void TIM3_PWM_Init(u16 arr,u16 psc);
- #endif
- </font>
复制代码
2.电机模块IO口初识化:
在该工程下新建一个文件夹命名为MOTER,里面包括两个文件:moter.c和moter.h,moter.c代码如下
- <font face="微软雅黑" size="3">#include "moter.h"
- void MOTER_Init(void)
- {
- RCC->APB2ENR|=1<<2; //使能PORTA时钟
- RCC->APB2ENR|=1<<3; //使能PORTB时钟
- RCC->APB2ENR|=1<<4; //使能PORTC时钟
-
- GPIOA->CRL&=0XFF0FFFFF;
- GPIOA->CRL|=0X00300000;
- GPIOA->ODR|=1<<5;
-
- GPIOA->CRL&=0X0FFFFFFF;
- GPIOA->CRL|=0X30000000;
- GPIOA->ODR|=1<<7;
-
- GPIOB->CRL&=0XFFFFFF0F;
- GPIOB->CRL|=0X00000030;
- GPIOB->ODR|=1<<1;
-
- GPIOB->CRL&=0XFFFFF0FF;
- GPIOB->CRL|=0X00000300;
- GPIOB->ODR|=1<<2;
- GPIOB->CRL&=0XFFFF0FFF;
- GPIOB->CRL|=0X00003000;
- GPIOB->ODR|=1<<3;
- GPIOB->CRL&=0XFFF0FFFF;
- GPIOB->CRL|=0X00030000;
- GPIOB->ODR|=1<<4;
-
- GPIOC->CRL&=0XFFF0FFFF;
- GPIOC->CRL|=0X00030000;
- GPIOC->ODR|=1<<4;
-
- GPIOC->CRL&=0XFF0FFFFF;
- GPIOC->CRL|=0X00300000;
- GPIOC->ODR|=1<<5;
- }
- </font>
复制代码 moter.h代码如下:
- <font face="微软雅黑" size="3">#ifndef __MOTER_H
- #define __MOTER_H
- #include "sys.h"
- //电机端口定义(PWMA PB0 PWMB PA6)
- #define AIN2 PBout(1)
- #define AIN1 PBout(2)
- #define STBY PBout(3)
- #define BIN2 PCout(5)
- #define BIN1 PCout(4)
- void MOTER_Init(void); //初始化
- #endif
- </font>
复制代码
3.test.c
主要包括小车前进、后退、左右的一些函数,然后再通过改变left和right的值来改变TIM3->CCR1和TIM3->CR3的值来改变电机的速度:
- <font face="微软雅黑" size="3">#include "sys.h"
- #include "delay.h"
- #include "usart.h"
- #include "moter.h"
- #include "timer.h"
- void HOU(void)//定义后退函数
- {
- AIN1=0;
- AIN2=1;
- BIN1=0;
- BIN2=1;
- }
- void STOP(void)//停
- {
- AIN1=0;
- AIN2=0;
- BIN1=1;
- BIN2=1;
- }
- void YOU(void)//右拐
- {
- AIN1=1;
- AIN2=0;
- BIN1=1;
- BIN2=1;
- }
- void ZUO(void)//左拐
- {
- AIN1=0;
- AIN2=0;
- BIN1=1;
- BIN2=0;
- }
- void GO(void)//前进
- {
- AIN1=1;
- AIN2=0;
- BIN1=1;
- BIN2=0;
- }
- int main(void)
- {
- Stm32_Clock_Init(9); //系统时钟设置
- uart_init(72,115200); //串口初始化为115200
- delay_init(72); //延时初始化
- TIM3_PWM_Init(899,0); //不分频。PWM频率=72000/(899+1)=80Khz
- MOTER_Init();
- while(1)
- {
- left=400;
- right=400;
- GO();
- }
- }
- </font>
复制代码
|