stm32定时器编码器模式,tim->cnt数据溢出问题处理
一、问题描述(背景)
之前板卡做编码器计数的时候,用的exit外部引脚中断处理;不过这样做不仅太占用cpu资源;偶尔还会丢掉脉冲,频率也上不去。后来了解到用定时器有编码器模式,所以我改了硬件,用定时器的编码器模式,来处理编码器计数。
改完之后,遇到了一个新的问题,那就是我想要count是一个int32_t类型的,而单片机的tim->cnt寄存器是16位的,所以不得不处理数据溢出问题。
被卡了一天多,用了ai的代码,一直不行,心烦气躁,偶然间,看到了野火的关于Encoder的处理。豁然开朗,处理方法如下。
二、溢出问题
因为tim->cnt寄存器是16位的的,编码器又有正反转,所以寄存器计数,就会出现上溢出,和下溢出。
向上溢出:cnt计数到0xffff,就又会从0开始计数。
向下溢出,cnt计数到0,又会从0ffff向下计数。
三、解决问题的方法
定时器存在溢出中断,所以我们只需要在中断里做溢出计数就可以。向上溢出我们+1,向下溢出我们-1,那么:
32位的编码器最终计数值,full_count = cnt+overflow_count*65536
最终代码如下:
static volatile int32_t overflow_count = 0; //溢出计数(要用有符号的)
static TIM_HandleTypeDef htim3;
//中断处理程序(只做溢出计数)
void TIM3_IRQHandler(void) {
if(__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_UPDATE))
{
if (TIM3->CR1 & TIM_CR1_DIR) {
overflow_count--;
} else {
overflow_count++;
}
__HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_UPDATE);
}
}
//定时器3的编码器模式初始化
void MX_TIM3_Init(void)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef gpio_init = {
.Pin = GPIO_PIN_6 | GPIO_PIN_7,
.Mode = GPIO_MODE_AF_INPUT,
.Pull = GPIO_PULLUP,
.Speed = GPIO_SPEED_FREQ_HIGH
};
HAL_GPIO_Init(GPIOA, &gpio_init);
__HAL_RCC_TIM3_CLK_ENABLE();
htim3.Instance = TIM3;
htim3.Init = (TIM_Base_InitTypeDef){
.Prescaler = 0,
.CounterMode = TIM_COUNTERMODE_UP,
.Period = 0xFFFF,
.ClockDivision = TIM_CLOCKDIVISION_DIV1,
.RepetitionCounter = 0
};
HAL_TIM_Base_Init(&htim3);
TIM_Encoder_InitTypeDef encoder_config = {
.EncoderMode = TIM_ENCODERMODE_TI12,
.IC1Filter = 4, // 滤波设置
.IC1Polarity = TIM_ICPOLARITY_RISING,
.IC1Prescaler = TIM_ICPSC_DIV1,
.IC1Selection = TIM_ICSELECTION_DIRECTTI,
.IC2Filter = 4, // 滤波设置
.IC2Polarity = TIM_ICPOLARITY_RISING,
.IC2Prescaler = TIM_ICPSC_DIV1,
.IC2Selection = TIM_ICSELECTION_DIRECTTI
};
HAL_TIM_Encoder_Init(&htim3, &encoder_config);
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
__HAL_TIM_ENABLE_IT(&htim3, TIM_IT_UPDATE);
TIM3->CNT = 0;
overflow_count = 0;
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
}
//获取最终计数值full_count(这里是result,不要注意这些小细节,嘿嘿)
int32_t Encoder_GetCount(void)
{
int32_t result;
__disable_irq();
result = TIM3->CNT + overflow_count * 65536;
__enable_irq();
return result;
}
通过上述代码,我们就将full_count的值,存到了int32类型里面,这个计数值,会在-2,147,483,648 到 2,147,483,647这个范围里循环计数,可以说相当够用了。
四,结果
实测发现,没有再出现什么稀奇古怪的问题。这么一看,逻辑也是非常的简单,代码也是非常的少,中断也就做了一件小事,可以说,非常之快乐。此帖完结(记录向)
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)