STM32F429使用PWM控制电机转速

时间:2024-04-03 12:46:58
  • 功能简介
  • 实验前准备工作
  • 原理介绍
  • 程序源码

  • 功能简介
    本次实验实现的是使用F429输出PWM,从而控制减速电机的速度。实验主要是通过对定时器3的通道3和通道4的配置来实现PWM的输出,并且可以通过调整占空比来实现对电机转速的控制。

  • 实验前准备
    本次实验需要用到的器材有:STM32F429开发板、两路减速电机、L298N电机驱动模块、杜邦线,电机及其驱动模块如下图:
    STM32F429使用PWM控制电机转速
    STM32F429使用PWM控制电机转速

  • 原理介绍

  • PWM工作原理
    PWM,即脉冲宽度调制(Pulse Width Modulation)的缩写,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制, PWM 原理如下图所示:
    STM32F429使用PWM控制电机转速
    上图就是一个简单的 PWM 原理示意图。图中,我们假定定时器工作在向上计数 PWM模式,且当 CNT<CCRx 时,输出 0,当 CNT>=CCRx 时输出 1。那么就可以得到如上的 PWM示意图:当 CNT 值小于 CCRx 的时候, IO 输出低电平(0),当 CNT 值大于等于 CCRx 的时候,IO 输出高电平(1),当 CNT 达到 ARR 值的时候,重新归零,然后重新向上计数,依次循环。改变 CCRx的值,就可以改变 PWM 输出的占空比,改变 ARR 的值,就可以改变 PWM 输出的频率,这就是 PWM 输出的原理。

  • 定时器输出PWM
    STM32F429 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4 路的 PWM 输出!这里我们仅使用 TIM3 的CH3和CH4 产生两路 PWM 输出。要使 STM32F429 的通用定时器 TIMx 产生 PWM 输出,除了配置定时器的几个基本的寄存器外,还会用到 3 个寄存器,来控制 PWM 的。这三个寄存器分别是:捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。详细介绍参考正点原子配套资料教程:STM32F429开发指南-HAL库版本——定时器中断实验和PWM输出实验,里面有更为详细的介绍。

  • 程序源码
    程序改自正点原子的配套源码——实验八PWM输出实验:
    STM32F429使用PWM控制电机转速
    在该项目工程文件中,编写了两个主要的.c文件,分别是定时器中断配置文件和管脚输出文件各部分代码如下:

  • timer.c文件:

#include "timer.h"
#include "motor.h" 

TIM_HandleTypeDef TIM3_Handler;         //定时器3PWM句柄 
TIM_OC_InitTypeDef TIM3_CH3Handler;//定时器3通道3句柄
TIM_OC_InitTypeDef TIM3_CH4Handler;//定时器3通道4句柄

//TIM3 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{ 
    TIM3_Handler.Instance=TIM3;            //定时器3
    TIM3_Handler.Init.Prescaler=psc;       //定时器分频
    TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式
    TIM3_Handler.Init.Period=arr;          //自动重装载值
    TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_PWM_Init(&TIM3_Handler);       //初始化PWM
    
    TIM3_CH3Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
    TIM3_CH3Handler.Pulse=arr/2;            //设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%
    TIM3_CH3Handler.OCPolarity=TIM_OCPOLARITY_LOW; //输出比较极性为低 
    HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH3Handler,TIM_CHANNEL_3);//配置TIM3通道3
	
    HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_3);//开启PWM通道3
	
	TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
    TIM3_CH4Handler.Pulse=arr/2;            //设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%
    TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_LOW; //输出比较极性为低 
    HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4);//配置TIM3通道4
	
    HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4);//开启PWM通道4
}


//定时器底层驱动,时钟使能,引脚配置
//此函数会被HAL_TIM_PWM_Init()调用
//htim:定时器句柄
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef GPIO_Initure;
	__HAL_RCC_TIM3_CLK_ENABLE();			//使能定时器3
    __HAL_RCC_GPIOB_CLK_ENABLE();			//开启GPIOB时钟
	
    GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1;           	//PB1/0
    GPIO_Initure.Mode=GPIO_MODE_AF_PP;  	//复用推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
	GPIO_Initure.Alternate= GPIO_AF2_TIM3;	//PB1复用为TIM3_CH4
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}


//设置TIM通道4的占空比
//compare:比较值
void TIM_SetTIM3Compare3(u32 compare1)
{
	TIM3->CCR3=compare1;
}

void TIM_SetTIM3Compare4(u32 compare2)
{
	TIM3->CCR4=compare2;
}


  • timer.h文件:
#ifndef __PWM_H
#define __PWM_H
#include "sys.h"

extern TIM_HandleTypeDef TIM3_Handler;      //定时器3PWM句柄 
extern TIM_OC_InitTypeDef TIM3_CH3Handler;  //定时器3通道3句柄
extern TIM_OC_InitTypeDef TIM3_CH4Handler;  //定时器3通道4句柄

void TIM3_Init(u16 arr,u16 psc);
void TIM3_PWM_Init(u16 arr,u16 psc);
void TIM_SetTIM3Compare3(u32 compare1);
void TIM_SetTIM3Compare4(u32 compare2);
#endif


  • motor.c文件:
#include "motor.h"
#include "delay.h"

void MOTOR_Init(void)
{
    GPIO_InitTypeDef GPIO_Initure;
    __HAL_RCC_GPIOB_CLK_ENABLE();           //开启GPIOB时钟
	
    GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1; //PB1,0
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
	
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);	//PB0置1 
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);	//PB1置1  

}

  • motor.h文件:
#ifndef _MOTOR_H
#define _MOTOR_H
#include "sys.h"
	
#define LED0 PBout(1)   //LED0
#define LED1 PBout(0)   //LED1

void MOTOR_Init(void);
#endif

  • main.c文件:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "motor.h"
#include "timer.h"

int main(void)
{
    //u8 dir=1;
    u16 motor0pwmval=420; //具体数值(范围可取0~499)
	u16 motor1pwmval=100;//具体数值(范围可取0~499)
    HAL_Init();                     //初始化HAL库   
    Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhz
    delay_init(180);                //初始化延时函数
    uart_init(115200);              //初始化USART
    MOTOR_Init();                     //初始化LED 
    TIM3_PWM_Init(500-1,90-1);      //90M/90=1M的计数频率,自动重装载为500,那么PWM频率为1M/500=2kHZ
    while(1)
    {
		delay_ms(10);
		
		/*if(dir)led0pwmval++;				//dir==1 led0pwmval递增
		else led0pwmval--;				//dir==0 led0pwmval递减 
		if(led0pwmval>300)dir=0;			//led0pwmval到达300后,方向为递减
		if(led0pwmval==0)dir=1;	*/		//led0pwmval递减到0后,方向改为递增
		
		TIM_SetTIM3Compare3(motor0pwmval);	//修改比较值,修改占空比
		TIM_SetTIM3Compare4(motor1pwmval);	//修改比较值,修改占空比
    }
}

至于硬件电路连接,这里就不列出来了,要注意的是,要是驱动步进电机的话最好通过L298N去驱动,毕竟是大电流电机。

程序文件包如下:
百度网盘链接