一、预备知识
1.单片机与编码器配合使用:编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度。
2.每个高级定时器和通用定时器都只拥有1个编码器接口,两个输入引脚借用了输入捕获的通道1和通道2(CH1和CH2可以左右编码器输入引脚,CH3和CH4不能作为编码器输入引脚)
脉冲个数→位置(检测到一相跳边沿的同时检测另一相电平状态判断旋转方向,如果正转CNT++,如果反转CNT--)
脉冲频率→速度
两相脉冲边沿情况→方向
3.关于编码器
编码器种类:机械式,光电式,磁场/霍尔式,最终效果均是将电机旋转的状态转化为单片机可以识别的脉冲信号。
编码器接线:两根电源线(输入),两根正交相线(输出),一个固定位置输出脉冲线(0位校准)
4.编码器倍频:只计次单相脉冲的单个边沿为一倍频;计次单相脉冲的双边沿为二倍频,计次双相脉冲的双边沿为四倍频。倍频越高精度越高,且正交信号可以抵抗噪声干扰(A相发生电平变化但B相无变化则认为A相变化是由噪声引起不产生计次)
5.编码器接口电路结构
下面两排是TIM的输入捕获的通道1和通道2
6.编码器三种工作模式:
7.示例
二、CubeMX配置
1.选编码器模式,该模式可以直接读取脉冲数(不用特意设置捕获了,非常方便)
2.具体参数配置:
1)计数周期一般配置为最大值65535,可以disable自动重装
2)选择的encoderMode是TI1和TI2模式。这种模式下,AB两相的上升沿和下降沿都会计数,所以计数值是实际值的4倍,需要做分频。也就是第一个参数,分频值设为3,实际上是3+1=4分频。
3)还有个地方需要解释一下,Polarity参数设置的是Rising Edge。这个参数的意思是在检测到上升沿的时候就触发encoder捕获AB相的值,而并不是这里设置的是上升沿就只检测AB相的上升沿,下降沿还是同样会计数的。对于T1T2均计次模式下,极性配置用来选择是否反相
如果CNT增减和电机方向不一致可以通过反向设置某一相的极性解决,也可以将AB相线反接
4)Input Filter滤波值是从1-15,看情况设定,是用来滤除一些杂波的。
5)GPIO模式配置,上拉下拉与外部接口的默认电平保持一致,不确定时可以选择浮空输入,但是在无输入时会受噪声干扰
3.函数配置
在初始化中添加打开定时器的encoder模式:
HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL);
调用下面一句函数设定计数值:
__HAL_TIM_SET_COUNTER(&htim4, 0);
然后定期调用下面这一句函数就可以获取到encoder编码器的计数值:
enc1 = (uint32_t)(__HAL_TIM_GET_COUNTER(&htim2));//获取定时器的值
可以使用强制类型转换为有符号的int32_t
4.如果有z相的话,额外将CH3打开作为一个中断, 作为脉冲中断触发,找到每一圈的零点位置
同时打开中断
三、应用层代码编写(测速)
利用定时中断,每隔一定时间(闸门时间t)将CNT数值赋给一个变量后清零,得到t时间内CNT值,并基于该时间计算速度
w=CNT*2π/(4*3*t)
或者在mian函数中利用延时函数(不推荐)
相关函数介绍
//1.定时器3的通道1和通道2的Encoder Mode开启使能函数
HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_1 | TIM_CHANNEL_2);
//2.返回值当前脉冲计数值,也可对脉冲计数值进行重新置位
int cnt=__HAL_TIM_GET_COUNTER(&htim3);
__HAL_TIM_GET_COUNTER(&htim3)=0;//脉冲计数值清0
//3.返回值为bool类型,当计数器向下计数时,返回true,可以用来判断编码器旋转方向
__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3);
定义两个全局变量(之所以定义成全局变量,是为了方便后边将这个变量变量在debug模式中添加到watch窗口中查看)
/* USER CODE BEGIN PV */
uint8_t Direction;
uint16_t CaptureNumber;
/* USER CODE END PV */
在main函数中开启编码器模式
/* USER CODE BEGIN 2 */
HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_1 | TIM_CHANNEL_2);
/* USER CODE END 2 */
while(1)循环中不断循环检测当前的脉冲计数值
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
Direction=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3); //读取编码器旋转方向
CaptureNumber=__HAL_TIM_GET_COUNTER(&htim3); //读取脉冲计数值
}
/* USER CODE END 3 */