硬件:STM32F103C8T6、电机驱动模块tb6612、25GA370带编码器测速盘直流减速电机。
1.电机驱动
1.1 电机驱动模块tb6612
(1)电机驱动模块tb6612简介
电机驱动需要使用电机驱动模块,电机驱动模块把3.3V的电机信号转换成12V的电机的驱动信号。
上面两个驱动模块主要区别是橙色部分的钽电容,红色驱动模块耐压值16V,除以1.5为工作电压等于10.6V;黑色模块耐压值35V,除以1.5还有23.3V。因此红色模块驱动12V电机可能有一定概率导致钽电容损坏,可以自己更换一个电容,如果不换也可以直接剪掉,这个模块也能使用,只是不能滤波了,效果差一些。
(2)电机驱动模块tb6612使用
stm32学习探究:利用TB6612驱动直流电机-CSDN博客
1.2 硬件电路及引脚配置
(1)硬件电路
(2)HAL库引脚配置
两个电机(平衡小车左右两个电机):PA11和PA8使用定时器生成PWM波 ,使用定时器来生成;PB12~PB15用来控制电机方向
PWM频率:,让f的10kHz,分频PSC=0,ARR=7199。
占空比设置:,全速运行设置Paulse=7200。
1.3 驱动程序编写
(1)创建motor.c和motor.h文件
(2)motor.h
cpp
#ifndef _MOTOR_H
#define _MOTOR_H
#include "stm32f1xx_hal.h"
void Load(int moto1,int moto2);
#endif
(3)motor.c
cpp
#include "motor.h"
extern TIM_HandleTypeDef htim1;
/*取绝对值函数*/
int abs(int p)
{
if(p>0)
return p;
else
return -p;
}
/*电机加载函数*/
void Load(int moto1,int moto2) //-7200~7200,参数表示左右两个电机转速(占空比),100%为7200
{
if(moto1<0)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET); //一高一低电机才能转动
}
else
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
}
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_4,abs(moto1)); //加载占空比
if(moto2<0)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET);
}
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,abs(moto2));
}
(3)main.c
①打开 PWM
cpp
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_4);
②电机装载速度
cpp
Load(-1000,1000);
这款电机满转速330,设置为1000时候转速大概为46转每分钟。
CN1反接(AO1接AM2,AO2接AM1), CN2正接(BO1接BM1,BO2接BM2);因为两个电机左右对称,为了方便程序的编写,其中一个反接时候才能向前。
2.编码器测速
这一节要在上一节的基础上进行。
编码器计数原理与电机测速原理------多图解析 - 知乎 (zhihu.com)
减速比1:30的意思是我们的电机主轴转1圈的话,编码器磁环的轴转30圈。如果电机主轴转1圈的话,输出330个脉冲。
2.1 引脚配置
编码器引脚必须是PA0和PA1、PB6和PB7。
时钟来源是编码器,本事就不是特别快,所以不需要再进行分频。
编码器原理就是统计一段时间内的脉冲信号个数,然后换算到1s下对应脉冲信号个数,就是相应频率。
选择这种模式,A相和B相只要有上升沿都会触发 计数器里面+1,所以比只选择T1或者T2,计数值是快1倍的,这样才小转速情况下也可以读到较大值。
2.2 驱动编写
(1)添加encoder.c和encoder.h
(2)Encoder.h
cpp
#ifndef __ENCODER_H__
#define __ENCODER_H__
#include "stm32f1xx_hal.h"
int Read_Speed(TIM_HandleTypeDef *htim);
#endif
(3)Encoder.c
stm32中编码器模式读出"负数"的问题_为什么stm32读取编码电机数值为负值-CSDN博客
cpp
#include "encoder.h"
int Read_Speed(TIM_HandleTypeDef *htim)
{
int temp;
temp=(short)__HAL_TIM_GetCounter(htim); //读取编码器的值,这里一定要用short进行转换,因为我们的计数器是16位的,向下计数,-1对应65535,不进行转换会出错
__HAL_TIM_SetCounter(htim,0); //定时器寄存器清零
return temp;
}
(4)main.c
cpp
HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL); //初始化定时器编码器功能
HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_ALL);
我们10ms获得一次编码器值,为了获得准确得时间,使用系统滴答定时器获得编码器值:
cpp
uint32_t sys_tick;
int Encoder_Left,Encoder_Right;
添加编码器获取函数:
cpp
/*每个10ms读取一次编码器值*/
void Read(void)
{
if(uwTick-sys_tick<10) //uwTick是一个全局变量,默认情况下每个1ms递增一次
return;
sys_tick=uwTick; //sys_tick和uwTick之间值刚好相差10时更新sys_tick的值,然后读取编码器值
Encoder_Left=Read_Speed(&htim2);
Encoder_Right=-Read_Speed(&htim4); //和电机原因一样
}
关于 uwTick:
uwTick从0加到满能够使用40多天才会溢出。