STM32第八课:PWM控制直流电机

avatar
作者
筋斗云
阅读量:0

一:TB6612电机驱动简介

1.1 简介

        TB6612FNG是一款新型驱动器件,能独立双向控制2个直流电机,它具有很高的集成度,同时能提供足够的输出能力,运行性能和能耗方面也具有优势因此在集成化、小型化的电机控制系统中,它可以作为理想的电机驱动器件。

                                工作电流:1.2A                          峰值电流:3.2A

1.2 引脚简介

        AINI/AIN2、BIN1/BIN2、PWMA/PWMB为控制信号输入端;

        A01/A02、B01/B2为2路电机控制输出端;

        STBY为正常工作/待机状态控制引脚:

        VM(<10V和VCC(27~55V分别为电机驱动电压输入和逻辑电平输入端。

 具体的引脚方面的定义如下:

 二:电路接线图示

        电路图有关于接线的方法如下图所示:

三:代码编写思路

         此处的直流电机的转速也是通过PWM波形进行控制的,有关于PWM.c和PWM.h两个关于STM32生成PWM波的代码文件,此处不再赘述,有兴趣的可以参考我的前两篇通过PWM波控制的文章。需要强调一点,此时PWM.c与上一篇的不同之处在于:

1.引脚变为GPIO_Pin_2

2.  计数周期和预分频器有所改变

        其他并未有什么变化。 有关于OLED和Key的代码驱动文件也是一模一样的。

        主要就在于直流电机的驱动文件Motor.c和Motor.h的代码编写。在Motor.c文件中,我们需要首先定义一个电机引脚初始化函数Motor_Init,用于直流电机引脚的初始化。

        然后设置可以控制电机转速的Motor_SetSpeed函数,用于控制电机的旋转速度。主要代码如下:

Key.c

#include "stm32f10x.h"                  // Device header #include "Delay.h"  /**   * 函    数:按键初始化   * 参    数:无   * 返 回 值:无   */ void Key_Init(void) { 	/*开启时钟*/ 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟 	 	/*GPIO初始化*/ 	GPIO_InitTypeDef GPIO_InitStructure; 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11; 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 	GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB1和PB11引脚初始化为上拉输入 }  /**   * 函    数:按键获取键码   * 参    数:无   * 返 回 值:按下按键的键码值,范围:0~2,返回0代表没有按键按下   * 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手   */ uint8_t Key_GetNum(void) { 	uint8_t KeyNum = 0;		//定义变量,默认键码值为0 	 	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)			//读PB1输入寄存器的状态,如果为0,则代表按键1按下 	{ 		Delay_ms(20);											//延时消抖 		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);	//等待按键松手 		Delay_ms(20);											//延时消抖 		KeyNum = 1;												//置键码为1 	} 	 	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)			//读PB11输入寄存器的状态,如果为0,则代表按键2按下 	{ 		Delay_ms(20);											//延时消抖 		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);	//等待按键松手 		Delay_ms(20);											//延时消抖 		KeyNum = 2;												//置键码为2 	} 	 	return KeyNum;			//返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0 } 

Key.h

#ifndef __KEY_H #define __KEY_H  void Key_Init(void); uint8_t Key_GetNum(void);  #endif 

PWM.c

#include "stm32f10x.h"                  // Device header  /**   * 函    数:PWM初始化   * 参    数:无   * 返 回 值:无   */ void PWM_Init(void) { 	/*开启时钟*/ 	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟 	 	/*GPIO初始化*/ 	GPIO_InitTypeDef GPIO_InitStructure; 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 	GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA2引脚初始化为复用推挽输出	 																	//受外设控制的引脚,均需要配置为复用模式 	 	/*配置时钟源*/ 	TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟 	 	/*时基单元初始化*/ 	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量 	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能 	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数 	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;                 //计数周期,即ARR的值 	TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;               //预分频器,即PSC的值 	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到 	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元 	 	/*输出比较初始化*/  	TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量 	TIM_OCStructInit(&TIM_OCInitStructure);                         //结构体初始化,若结构体没有完整赋值 	                                                                //则最好执行此函数,给结构体所有成员都赋一个默认值 	                                                                //避免结构体初值不确定的问题 	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;               //输出比较模式,选择PWM模式1 	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       //输出极性,选择为高,若选择极性为低,则输出高低电平取反 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //输出使能 	TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值 	TIM_OC3Init(TIM2, &TIM_OCInitStructure);                        //将结构体变量交给TIM_OC3Init,配置TIM2的输出比较通道3 	 	/*TIM使能*/ 	TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行 }  /**   * 函    数:PWM设置CCR   * 参    数:Compare 要写入的CCR的值,范围:0~100   * 返 回 值:无   * 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比   *           占空比Duty = CCR / (ARR + 1)   */ void PWM_SetCompare3(uint16_t Compare) { 	TIM_SetCompare3(TIM2, Compare);		//设置CCR3的值 } 

PWM.h

#ifndef __PWM_H #define __PWM_H  void PWM_Init(void); void PWM_SetCompare3(uint16_t Compare);  #endif 

Motor.c

#include "stm32f10x.h"                  // Device header #include "PWM.h"  /**   * 函    数:直流电机初始化   * 参    数:无   * 返 回 值:无   */ void Motor_Init(void) { 	/*开启时钟*/ 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);		//开启GPIOA的时钟 	 	GPIO_InitTypeDef GPIO_InitStructure; 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 	GPIO_Init(GPIOA, &GPIO_InitStructure);						//将PA4和PA5引脚初始化为推挽输出	 	 	PWM_Init();													//初始化直流电机的底层PWM }  /**   * 函    数:直流电机设置速度   * 参    数:Speed 要设置的速度,范围:-100~100   * 返 回 值:无   */ void Motor_SetSpeed(int8_t Speed) { 	if (Speed >= 0)							//如果设置正转的速度值 	{ 		GPIO_SetBits(GPIOA, GPIO_Pin_4);	//PA4置高电平 		GPIO_ResetBits(GPIOA, GPIO_Pin_5);	//PA5置低电平,设置方向为正转 		PWM_SetCompare3(Speed);				//PWM设置为速度值 	} 	else									//否则,即设置反转的速度值 	{ 		GPIO_ResetBits(GPIOA, GPIO_Pin_4);	//PA4置低电平 		GPIO_SetBits(GPIOA, GPIO_Pin_5);	//PA5置高电平,设置方向为反转 		PWM_SetCompare3(-Speed);			//PWM设置为负的速度值,因为此时速度值为负数,而PWM只能给正数 	} } 

Motor.h

#ifndef __MOTOR_H #define __MOTOR_H  void Motor_Init(void); void Motor_SetSpeed(int8_t Speed);  #endif 

main.c

#include "stm32f10x.h"                  // Device header #include "Delay.h" #include "OLED.h" #include "Motor.h" #include "Key.h"  uint8_t KeyNum;		//定义用于接收按键键码的变量 int8_t Speed;		//定义速度变量  int main(void) { 	/*模块初始化*/ 	OLED_Init();		//OLED初始化 	Motor_Init();		//直流电机初始化 	Key_Init();			//按键初始化 	 	/*显示静态字符串*/ 	OLED_ShowString(1, 1, "Speed:");		//1行1列显示字符串Speed: 	 	while (1) 	{ 		KeyNum = Key_GetNum();				//获取按键键码 		if (KeyNum == 1)					//按键1按下 		{ 			Speed += 20;					//速度变量自增20 			if (Speed > 100)				//速度变量超过100后 			{ 				Speed = -100;				//速度变量变为-100 											//此操作会让电机旋转方向突然改变,可能会因供电不足而导致单片机复位 											//若出现了此现象,则应避免使用这样的操作 			} 		} 		Motor_SetSpeed(Speed);				//设置直流电机的速度为速度变量 		OLED_ShowSignedNum(1, 7, Speed, 3);	//OLED显示速度变量 	} } 

四:实操效果显示

 与君共勉 დ,关注我,持续更新中~ 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!