STM32小车——PWM电机调速

举报
万里羊 发表于 2021/08/25 22:48:51 2021/08/25
【摘要】 PWM电机调速(寄存器版) 我的上一篇博客已经写了如何用定时器产生PWM来实现LED灯的呼吸灯效果,当我想实现PWM来控制电机调速时,网上翻阅了很多的资料但是大多数是在呼吸灯的基础上改一下代码实现的,没...

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初识化

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									 
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

(2)TIM3 PWM初始化:

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;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

timer.h代码如下:

#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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.电机模块IO口初识化:
在该工程下新建一个文件夹命名为MOTER,里面包括两个文件:moter.c和moter.h,moter.c代码如下

#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; 	
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

moter.h代码如下:

#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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3.test.c
主要包括小车前进、后退、左右的一些函数,然后再通过改变left和right的值来改变TIM3->CCR1和TIM3->CR3的值来改变电机的速度:

#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();
	}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

通过以上的程序可以实现电机前进调速。希望对大家有所帮助。

文章来源: wlybsy.blog.csdn.net,作者:万里羊,版权归原作者所有,如需转载,请联系作者。

原文链接:wlybsy.blog.csdn.net/article/details/98029888

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。