[单片机]旋转编码器

实物图

 

引脚功能

时序图

 

防抖动

因为是两个金属片来回摩擦触碰, 产生的高低电平信号, 会产生抖动, 如果是使用外部中断触发或者计数器中断触发, 将会面临很大的问题, 就是转动一次将会产生很多的抖动信号. 解决方法有硬件防抖, 还有软件防抖.

硬件防抖动

在clk和dt两根引脚分别串联两个小电容, 实现滤波的功能.

软件防抖

因为购买的模块一般都是没有电容的, 所以需要我们在程序中实现防抖动, 有以下方法

1. 中断中加延时函数: 最简单粗暴的方法, 但是不可以的. 首先在中断里面加延时函数是会有风险的, 随着代码体量增大, 用到的传感器数量增多, 程序容易卡死在中断函数里面. 另一方面, 实际操作下来发现效果并不好, 因为具有了延时, 快速旋转将会体验非常卡顿而且还会出现大量的错误.

2.  双中断: 因为两个引脚分别产生波形, 所以在两根引脚上分别让他产生中断, 当两个中断均触发时, 判断为旋转了一次. 这个思想非常好, 避免了在中断中写延时函数, 而且效果提升了很多, 但是快速旋转, 偶尔也会出现问题. 这时候就有了第三个想法.

3. 双中断+记录3次中断为旋转一次: 简单的纠错程序, 因为连续三次判断错误的概率是比较低的, 基本不会出现问题.

参考代码(基于stm32f407)

//初始化旋转编码器
void encoder_init(void)
{//配置PA4外部中断,PA3为外部中断//使能时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_EXTIT, ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_InitStruct);SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource4);SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource3);//配置外部中断EXTI_InitTypeDef EXTI_InitStruct;EXTI_InitStruct.EXTI_Line = EXTI_Line4 | EXTI_Line3;EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿有效EXTI_InitStruct.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStruct);//配置NVIC, 抢占优先级和响应优先级最高.NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置优先级分组NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);NVIC_InitStruct.NVIC_IRQChannel = EXTI3_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);
}enum Direction
{JUMP,RIGHT,LIFT,
};static uint8_t flag = JUMP;void EXTI3_IRQHandler(void)
{if(EXTI_GetFlagStatus(EXTI_Line3) == SET){if(PAin(4) == 0 && flag == RIGHT) //右转{num++;flag = JUMP;}else if(PAin(4) == 1 && flag == LIFT) //左转{num--;flag = JUMP;}EXTI_ClearITPendingBit(EXTI_Line3);//清空中断标志位}
}void EXTI4_IRQHandler(void)
{    if(EXTI_GetFlagStatus(EXTI_Line4) == SET){if(PAin(3) == 1) //右转{flag = RIGHT;}else if(PAin(3) == 0) //左转{flag = LIFT;}EXTI_ClearITPendingBit(EXTI_Line4);//清空中断标志位}
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部