1.电机如何转动
只需要给电机两个端子加一正一负的极性就会转起来了,但是要注意的是不要将电机两端直接接在5v和gnd之间,这种电机一般要提供几百毫安的电流,而GPIO口只能提供几毫安,所以我们使用一个DRV8833来驱动
DRV8833输入口要接PA0,PA1,并且供电,通过OUT1,OUT2连接电机
IN1,IN2对应PA0,PA1。
如果要使电机转速发生改变,我们可以将通入DRV8833的IN1,IN2接PWM即可。通过改变高电平时间实现转速的快慢
2.DRV8833
因为有两对输出口,则一个DRV8833可以驱动两个电机,对应SLEEP引脚是如果开启,则驱动芯片停止工作,实现低功耗,FAULT引脚是出现控制错误时提醒单片机
3.DRV8833驱动代码
drv8833.h
#ifndef __DRV8833_H_
#define __DRV8833_H_
#include <stdint.h>
/**
* @brief 衰减模式枚举
*/
typedef enum {
SLOW_DECAY, /**< 慢衰减模式 */
FAST_DECAY /**< 快衰减模式 */
} DecayMode;
/**
* @brief 初始化DRV8833
*/
void DRV8833_Init(void);
/**
* @brief 设置衰减模式
* @param mode 衰减模式
*/
void DRV8833_SetDecayMode(DecayMode mode);
/**
* @brief 控制电机前进
* @param speed 速度值(0-100)
*/
void DRV8833_Forward(uint8_t speed);
/**
* @brief 控制电机后退
* @param speed 速度值(0-100)
*/
void DRV8833_Backward(uint8_t speed);
/**
* @brief 电机刹车
*/
void DRV8833_Brake(void);
/**
* @brief 电机滑行
*/
void DRV8833_Coast(void);
#endif /* __DRV8833_H_ */
drv8833.c
/**
* @file drv8833.c
* @brief DRV8833双H桥电机驱动器控制实现
*/
#include "drv8833.h"
#include "tim.h"
/** @brief IN1引脚的定时器 */
#define IN1_TIM &htim2
/** @brief IN2引脚的定时器 */
#define IN2_TIM &htim2
/** @brief IN1引脚的定时器通道 */
#define IN1_CH TIM_CHANNEL_1
/** @brief IN2引脚的定时器通道 */
#define IN2_CH TIM_CHANNEL_2
/** @brief 最大速度值 */
#define MAX_SPEED 100
/** @brief 当前衰减模式 */
static DecayMode currentDecayMode = SLOW_DECAY;
/**
* @brief 设置IN1引脚的PWM占空比
* @param duty 占空比值
*/
static inline void __SetIn1PWM(uint8_t duty)
{
__HAL_TIM_SET_COMPARE(IN1_TIM, IN1_CH, duty);
}
/**
* @brief 设置IN2引脚的PWM占空比
* @param duty 占空比值
*/
static inline void __SetIn2PWM(uint8_t duty)
{
__HAL_TIM_SET_COMPARE(IN2_TIM, IN2_CH, duty);
}
/**
* @brief 初始化DRV8833
*/
void DRV8833_Init(void)
{
HAL_TIM_PWM_Start(IN1_TIM, IN1_CH);
HAL_TIM_PWM_Start(IN2_TIM, IN2_CH);
}
/**
* @brief 设置衰减模式
* @param mode 衰减模式
*/
void DRV8833_SetDecayMode(DecayMode mode)
{
currentDecayMode = mode;
}
/**
* @brief 控制电机前进
* @param speed 速度值(0-100)
*/
void DRV8833_Forward(uint8_t speed)
{
if (speed > MAX_SPEED)
speed = MAX_SPEED;
if (currentDecayMode == FAST_DECAY) {
__SetIn1PWM(speed);
__SetIn2PWM(0);
} else {
__SetIn1PWM(MAX_SPEED);
__SetIn2PWM(MAX_SPEED - speed);
}
}
/**
* @brief 控制电机后退
* @param speed 速度值(0-100)
*/
void DRV8833_Backward(uint8_t speed)
{
if (speed > MAX_SPEED)
speed = MAX_SPEED;
if (currentDecayMode == FAST_DECAY) {
__SetIn1PWM(0);
__SetIn2PWM(speed);
} else {
__SetIn1PWM(MAX_SPEED - speed);
__SetIn2PWM(MAX_SPEED);
}
}
/**
* @brief 电机刹车
*/
void DRV8833_Brake(void)
{
__SetIn1PWM(MAX_SPEED);
__SetIn2PWM(MAX_SPEED);
}
/**
* @brief 电机滑行
*/
void DRV8833_Coast(void)
{
__SetIn1PWM(0);
__SetIn2PWM(0);
}
4.使用
使用旋转编码器控制电机转动,旋转编码器顺时针转实现电机正转,并且越转越快。
旋转编码器逆时针转实现电机反转并且越转越快
PA0,PA1刚好是定时器2的1通道和2通道
使用屏幕配置i2c
5.代码
#include "drv8833.h"
#include "oled.h"
#include <stdio.h>
#define MAX_COUNT 20
int main(void)
{
MX_GPIO_Init();
MX_I2C1_Init();
MX_TIM1_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
HAL_TIM_Encoder_Start(&htim1,TIM_CHANNEL_ALL);//打开编码器计数
DRV8833_Init();//打开PWM通道
int count;
char message[50]="";
int speed;//电机的占空比0~100
__HAL_TIM_SET_COUNTER(&htim1,MAX_COUNT);//先设置为20,让电机不转
while (1)
{
count=__HAL_TIM_GET_COUNTER(&htim1);//获取编码器计数
if(count>60000)//逆时针转 //保证编码器计数在0~40
{
count=0;
__HAL_TIM_SET_COUNTER(&htim1,0);
}
else if(count>MAX_COUNT*2)
{
count=MAX_COUNT*2;
__HAL_TIM_SET_COUNTER(&htim1,MAX_COUNT*2);
}
if(count<MAX_COUNT)//反转,count越接近0,越快
{
speed=(MAX_COUNT-count)*100/MAX_COUNT;//speed在0~100,先×100,如果0~20数/20会为0
DRV8833_Forward(speed);
}
else//正转,count越接近40,越快,count为20,speed为0,不转
{
speed=(count-MAX_COUNT)*100/MAX_COUNT;
DRV8833_Backward(speed);
}
OLED_NewFrame();
sprintf(message,"count:%d",count);//显示编码器计数
OLED_PrintString(10,0,message,&font16x16, OLED_COLOR_NORMAL);
sprintf(message,"speed:%d",speed);//显示速度
OLED_PrintString(10,20,message,&font16x16, OLED_COLOR_NORMAL);
if(count<20)
OLED_PrintString(10,40,"反转",&font16x16, OLED_COLOR_NORMAL);
else if(count>20)
OLED_PrintString(10,40,"正转",&font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
HAL_Delay(10);
}
}
DRV8833_Forward(speed);
DRV8833_Forward(speed);//操作定时器2的1,2通道通过设置比较寄存器的值来改变占空比,控制转速