一、参考信息
注意:
(1)此工程是建立在OLED的基础上,所以需要先把OLED的工程测试成功再开始编码器测速
(2)不管是霍尔编码器还是旋转编码器都是一样的学,不会有太大的区别
(3) 使用的是STM32F103C8T6的开发板
(4)快捷键:F7是编译;F8是下载
学习资料来源:(B站)
【15.定时器编码器接口【HAL库复现江协全部STM32例子合集】】
https://www.bilibili.com/video/BV1Q1421y7Us?vd_source=70e3aaa6cbfe13f5858272f48dacf336
【15.定时器编码器接口【HAL库复现江协全部STM32例子合集】】https://www.bilibili.com/video/BV1Q1421y7Us?vd_source=70e3aaa6cbfe13f5858272f48dacf336
二、基本原理
(1)电机的正反转判断
正转时,A信号比B信号会快半个周期先变成高电平
(A上升沿时B是低电平;A下降沿时B是高电平
B上升沿时A是高电平:B下降沿是A是低电平)
反转时,B信号比A信号会快半个周期先变成高电平
(A上升沿时B是高电平;A下降沿时B是低电平
B上升沿时A是低电平:B下降沿是A是高电平)
(2)电机的计数及编码器选择
一般使用TI1和TI2计数,B上升沿A此时高电平(电机正转,向上计数):A上升沿B此时高电平(电机反转,向下计数):选择编码器模式3
三、CubeMx配置
1、打开编码器模式
选择定时器-->选择编码器模式(不需要选择内部时钟)
2、设置定时器的相关参数。由于是检测速度,所以这里就不分频,尽可能让定时器快点。计数器设置最大,防止输入信号频率太高溢出
3、设置计数模式,TI1计数和TI2计数
4、A相和B相都设置为上升沿
5、GPIO端口配置
定时器中的编码器模式配置好之后,就可以看见板子上使用的端口是 PA6和PA7,所以此时接线就需要接在PA6和PA7上
6、OLED不需要在CubeMx中配置
OLED不需要在CubeMx中配置,但是需要看OLED.c文件里面的引脚是不是一致的。不一致的话是无法显示的
7、电机的定时器PWM
8、记住再开一个专门用中断的定时器
四、计数代码
(1)首先要引用OLED.h的头文件
(2)声明一下中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef
(3)重点
初始化OLED ,打开控制电机PWM的定时器,打开控制编码器的定时器,打开使用定时器中断的定时器
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);//PA0,控制电机的定时器
HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL);//PA6,PA7控制编码器的定时器
HAL_TIM_Base_Start_IT(&htim6);//开启中断函数的定时器
OLED_Init();
(4)在while函数下面写中断函数
(5)新知识点:获取并显示计数值位置
OLED_ShowSignedNum(2,5,__HAL_TIM_GET_COUNTER(&htim3),5);
这个函数就是获取编码器的计数值的
(6)改进为有符号的代码
编码器反转时计数器应该返回负数才对,这是因为__HAL_TIM_GET_COUNTER(&htim3)返回时一个无符号的uint32_t数,需要把它强制转换成有符号的int16_t数即可
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//定时器的中断函数
{
int16_t CNT;//强制转化成有符号的数
if(htim->Instance==TIM6)//控制中断的定时器
{
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,300);//电机的转动速度
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);//这个不要用0,1;因为会出现警报,最好底层函数不要出现警报
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_RESET);
CNT=__HAL_TIM_GET_COUNTER(&htim3);
OLED_ShowSignedNum(2,5,CNT,5);//把OLED的显示放在中断里面,不会卡顿
}
}
五、测速代码
原理就是1秒钟读取 一次定时器的计数值(编码器的脉冲)并清空。得到的数字就是当前的速度,单位就是(脉冲每秒)一秒钟有多少个脉冲
(1)测速的函数代码
int16_t hhGetEncoderSpeedCountAndReset()
{
int16_t Tmp;
Tmp=__HAL_TIM_GET_COUNTER(&htim3);//每隔一秒去获取一次这个计数值
__HAL_TIM_SET_COUNTER(&htim3,0);//获取之后就清空
return Tmp;
}
(2)放在中断里面测速
不能直接把TIM6设成1s来计算,因为这样很耽误进程。可以把TIM6设置成10ms,然后下面用计数的方式让他计数成1s之后再去显示你的速度
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//定时器的中断函数
{
int16_t CNT;//强制转化成有符号的数
uint16_t A;
if(htim->Instance==TIM6)//控制中断的定时器,此时是定义的10ms
{
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,300);//电机的转动速度
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);//这个不要用0,1;因为会出现警报,最好底层函数不要出现警报
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_RESET);
A++;
if(A>100)
{
OLED_ShowSignedNum(2,5,hhGetEncoderSpeedCountAndReset(),5);
A=0;
}
// CNT=__HAL_TIM_GET_COUNTER(&htim3);
// OLED_ShowSignedNum(2,5,CNT,5);//把OLED的显示放在中断里面,不会卡顿
}
}
六、额外补充
(1)编码器的端口
除了最上面和最下面的电机正负极其它的都是属于编码器的端口
(2)接线
2.1
如果不驱动电机,只需要实验编码器的话,可以电机不直接接在TB6612驱动板上,直接接在单片机上
编码器A相接在PA6上,编码器B相接在PA7上(VCC和GND可以接在单片机上)PA6和PA7正好是开的编码器的定时器的端口
2.2
电脑可以通过ST-Link来给单片机供电。也可以电源给TB6612驱动板供电,然后TB6612给电机以及单片机供电,只是需要注意用此种供电方法时,在电脑给单片机下载程序的时候,驱动板上要关掉开关或者拔掉单片机连接在TB6612驱动板上的VCC和GND
(3)开定时器中断读数
可以把这一句放在定时器的中断函数里面,不然在计数上面会有一些卡
(4)特别注意
一定要勾选这个,否则下载不进去程序