基本概念
龙邱的512线正交编码器,工作电压在3.3v-5v。
我们只需要关注该款编码器的LSB及DIR引脚。
LSP:该引脚在编码器转动时,会输出步进脉冲,在不同的转速下,步进脉冲的数量是不同的。
所以我们可以设置一个定时器,把定时器的时钟输入通道改为外部引脚输入,这样我们就可以把单片机时钟的GPIO引脚接到编码器的LSP端口处。然后读取定时器的计数数量,就能获取到当前编码器当前的脉冲数量。
一次脉冲定时器就会计数一次。
另外一种方案是设置引脚上升沿或者下降沿中断来记录脉冲次数。
本文使用的是定时器计数
DIR:该引脚在编码器正转反转时输出的电平是不一样的,可以人为的界定。
可以设为Dir为高电平为正转,Dir为低电平为反转。该引脚连接的GPIO端口只需要设置为输入模式读取高低电平就可以了
注意部分
- 要注意每次读取的时间间隔要是一定的。比如定时10ms读取一次。否则数值会与实际相差很大。
- 由于会有误差,可以采用一阶线性滤波,这样就可以是数据更加的稳定,本文已经提供
程序实现部分 (基于STC32)
.H文件
/**
******************************************************************************
* @file : encoder.h
* @author : 宋明泽
* @brief : None
* @attention : None
* @date : 2023/5/2
******************************************************************************
*/
#ifndef INC_0_TEST_ENCODER_H
#define INC_0_TEST_ENCODER_H
#include "STC32G_Timer.h"
#define my_TIM3 Timer3
#define my_TIM4 Timer4
#define my_TIM_Mode TIM_16BitAutoReload //16位自动重装载
#define my_TIM_CLOCK_Source TIM_CLOCK_Ext //外部引脚输入
#define my_TIM_CLOCK_Out DISABLE
#define my_TIM_Value 0
#define my_TIM_Run ENABLE
// DIR方向引脚
#define Left1_Port GPIO_P0
#define Left1_Pin GPIO_Pin_4
#define Left2_Port GPIO_P0
#define Left2_Pin GPIO_Pin_5
#define Left_Direction P05
#define Right1_Port GPIO_P0
#define Right1_Pin GPIO_Pin_6
#define Right2_Port GPIO_P0
#define Right2_Pin GPIO_Pin_7
#define Right_Direction P07
//a的取值决定了算法的灵敏度,a越大,新采集的值占的权重越大,算法越灵敏,但平顺性差;相反,a越小,新采集的值占的权重越小,灵敏度差,但平顺性好。
#define A_R 0.853f //右电机A参数
#define A_L 0.88f //左电机A参数
void Encoder_Init(void);
/**
* 函数说明: 读取编码器的值
* 参数: 左右编码器 'L'跟'R'
* 返回值: float 一阶线性滤波值
*/
float Read_Encoder(u8 encno);
/**
* 函数说明: 一阶滤波 本次滤波值 = a*本次采样值 + (1-a)*上次的滤波输出值
* 参数: 编码器测得值
* 返回值: 滤波后的值
*/
float First_Order_Filtering(int32 value, float A);
#endif //INC_0_TEST_ENCODER_H
.C文件
//a的取值决定了算法的灵敏度,a越大,新采集的值占的权重越大,算法越灵敏,但平顺性差;相反,a越小,新采集的值占的权重越小,灵敏度差,但平顺性好。
#define A_R 0.853f //右电机A参数
#define A_L 0.88f //左电机A参数
float last_Value;
void Encoder_Init(void)
{
TIM_InitTypeDef my_tim_init;
GPIO_InitTypeDef gpioInitTypeDef;
my_tim_init.TIM_Mode = my_TIM_Mode;
my_tim_init.TIM_ClkSource = my_TIM_CLOCK_Source;
my_tim_init.TIM_ClkOut = my_TIM_CLOCK_Out;
my_tim_init.TIM_Value = 0;
my_tim_init.TIM_Run = my_TIM_Run;
Timer_Inilize(my_TIM3, &my_tim_init);
Timer_Inilize(my_TIM4, &my_tim_init);
gpioInitTypeDef.Mode = GPIO_PullUp;
gpioInitTypeDef.Pin = Left1_Pin;
GPIO_Inilize(Left1_Port,&gpioInitTypeDef);
gpioInitTypeDef.Pin = Left2_Pin;
GPIO_Inilize(Left2_Port,&gpioInitTypeDef);
gpioInitTypeDef.Pin = Right1_Pin;
GPIO_Inilize(Right1_Port,&gpioInitTypeDef);
gpioInitTypeDef.Pin = Right2_Pin;
GPIO_Inilize(Right2_Port,&gpioInitTypeDef);
NVIC_Timer3_Init(DISABLE,Priority_2);// 中断优先级2
NVIC_Timer4_Init(DISABLE,Priority_2);// 中断优先级2
}
/**
* 函数说明: 读取编码器的值
* 参数: 左右编码器 'L'跟'R'
* 返回值: float 一阶线性滤波值
*/
float Read_Encoder(u8 encno)
{
int32 tm=0;
float value;
if(encno=='R')
{
T4T3M &= ~(1<<7); //暂停定时器4
tm = T4H;
if(Right_Direction)//编码器2计数A:P06 DIR:P07
tm=0-((tm<<8)|T4L);
else
tm=(tm<<8)|T4L;
T4H = 0;
T4L = 0;
T4T3M |= (1<<7); //启动定时器4
value = First_Order_Filtering(tm,A_R);
}
else if(encno=='L')
{
T4T3M &= ~(1<<3); //暂停定时器3
tm = T3H;
if(Left_Direction)//编码器2计数A:P04 DIR:P05
tm=0-((tm<<8)|T3L);
else
tm=(tm<<8)|T3L;
T3H = 0;
T3L = 0;
T4T3M |= (1<<3);//启动定时器3
value = First_Order_Filtering(tm,A_L);
}
return value;
}
/**
* 函数说明: 一阶滤波 本次滤波值 = a*本次采样值 + (1-a)*上次的滤波输出值
* 参数: 编码器测得值
* 返回值: 滤波后的值
*/
float First_Order_Filtering(int32 value, float A)
{
float out_value;
out_value = A*(float)value - (1-A)*last_Value;
last_Value = out_value;
return out_value;
}
标签:编码器,Pin,正交,TIM,GPIO,512,my,define
From: https://www.cnblogs.com/songmingze/p/17609706.html