STM32 编码器实现的2种方式比较
第一种方式:STM32的TIM本来就有编码器功能,需要接到TIM的CH1和CH2通道。
编程的时候,需要把对应的TIM配置成编码器模式,以下为cubeMX配置,需要注意的是编码模式的选择。
#define CMP_VALUE (500)
#define FAST_RANK_2 (200)
#define FAST_RANK_1 (30)
#define MSG_ENC_LEFT BIT8
#define MSG_ENC_RIGHT BIT9
unsigned char u8EncSpeedRank = 0;
unsigned char ENC_GetSpeedRank(void)
{
return u8EncSpeedRank;
}
unsigned short int Encoder_Process(void)
{
static unsigned char flag = 0;
unsigned short int enc_value;
if(__HAL_TIM_GET_COUNTER(&htim4) == CMP_VALUE) //获取定时器的值
{
flag = 0;
u8EncSpeedRank = ENC_SPEED_0;
return 0;
}
if(__HAL_TIM_GET_COUNTER(&htim4) > CMP_VALUE)
{
enc_value = MSG_ENC_RIGHT;
__HAL_TIM_GET_COUNTER(&htim4) = CMP_VALUE;
}else if(__HAL_TIM_GET_COUNTER(&htim4) < CMP_VALUE){
enc_value = MSG_ENC_LEFT;
__HAL_TIM_GET_COUNTER(&htim4) = CMP_VALUE;
}
if(!flag)
{
flag = 1;
ResetRunningMsecond();
return enc_value;
}
if(GetMsecondTicksCount() < FAST_RANK_2)
{
u8EncSpeedRank = ENC_SPEED_2;
if(GetMsecondTicksCount() <= FAST_RANK_1)
{
u8EncSpeedRank = ENC_SPEED_1;
}
ResetRunningMsecond();
}else{
u8EncSpeedRank = ENC_SPEED_0;
}
return enc_value;
}
其次就是判断编码器旋转的速度,这里使用了一个比较简单的思路,就是上一次旋钮到下一次的时间间隔来确定。时间的单位是毫秒。使用另一个TIM,配置成ms计时。
unsigned short int gRunningMs;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
if(htim->Instance == TIM2)
{
gRunningMs++;
}
}
void ResetRunningMsecond(void)
{
gRunningMs = 0;
}
unsigned long GetMsecondTicksCount(void)
{
return gRunningMs;
}
第二种方式:使用普通IO口实现,这个就只需要连接到带外部中断的IO口上即可。
同样,使用cubeMX配置编码器的一个IO口为中断输入,这是使用了编码器右方向的脚。
注意根据编码器的运行方式确定是否是用下边沿中断还是使用双边沿中断。
这里使用了EC11,如上图,选择了双边沿。
配置中断。
unsigned char EncoderValue = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_1)
{
if(KEY_DR_DATA())
{
if(KEY_DL_DATA())
{
EncoderValue = 1;
}
else
{
EncoderValue = 2;
}
}
else
{
if(KEY_DL_DATA())
{
EncoderValue = 2;
}
else
{
EncoderValue = 1;
}
}
}
}
在判断到上/下边沿以后,以2个IO口的状态判断是左旋还是右旋。同样,为了判断旋转的快慢,还是设置一个ms的TIM.
unsigned long enc_timer = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
if(htim->Instance == TIM2)
{
if (enc_timer)
{
--enc_timer;
}
}
}
接下来就是处理,同样还是判断2次旋钮之间的时间间隔来决定速度。
#define CMP_VALUE (500)
#define FAST_RANK_2 (200)
#define FAST_RANK_1 (30)
#define MSG_ENC_LEFT BIT8
#define MSG_ENC_RIGHT BIT9
unsigned char u8EncSpeedRank = 0;
unsigned char ENC_GetSpeedRank(void)
{
return u8EncSpeedRank;
}
unsigned short int Encoder_Process(void)
{
unsigned short int enc_value = 0;
if(enc_timer > (CMP_VALUE - FAST_RANK_1))
{
u8EncSpeedRank = ENC_SPEED_1;
}
else if(enc_timer > (CMP_VALUE - FAST_RANK_2))
{
u8EncSpeedRank = ENC_SPEED_2;
}
else
{
u8EncSpeedRank = ENC_SPEED_0;
}
if(EncoderValue == 1)
{
enc_value = MSG_ENC_RIGHT;
EncoderValue = 0;
enc_timer = CMP_VALUE;
}
else if(EncoderValue == 2)
{
enc_value = MSG_ENC_LEFT;
EncoderValue = 0;
enc_timer = CMP_VALUE;
}
return enc_value;
}
最后就是放到主函数循环里面运行了,根据速度等级调节值的大小。
unsigned short int u16Value;
for (;;)
{
uMsgValue = Encoder_Process();
if (uMsgValue != 0)
{
/* 处理器函数 */
if(ENC_GetSpeedRank() == ENC_SPEED_0)
{
if(uMsgValue == MSG_ENC_RIGHT )
{
u16Value += 1;
}
else
{
if(u16Value )
{
u16Value -= 1;
}
}
}
else if(ENC_GetSpeedRank() == ENC_SPEED_1)
{
if(uMsgValue == MSG_ENC_RIGHT )
{
u16Value += 50;
}
else
{
if(u16Value >= 50)
{
u16Value -= 50;
}
else
{
u16Value = 0;
}
}
}
else if(ENC_GetSpeedRank() == ENC_SPEED_2)
{
if(uMsgValue == MSG_ENC_RIGHT )
{
u16Value += 10;
}
else
{
if(u16Value >= 10)
{
u16Value -= 10;
}
else
{
u16Value = 0;
}
}
}
uMsgValue = 0;
}
}
最后就是,写程序的主要目的是实现功能。嗯,就是这样。