本文隶属于《GD32 示波器项目软件部分重难点及相关疑问解决》
4-EC11的中断实验——NVIC&EXTI
4-1 实验目标以及原理图
- 上升沿触发
- 下降沿触发
- 任意沿触发
4-2 旋转编码器原理——"旋转编码器"协议
旋转编码器一般有效的线是3根线,一根按键,两根用于输出信号判断顺时针和逆时针。我们分别称之为K1,K2,K3。
除去K3(按键),另外两根在旋转的时候的波形应该是这样的。
从图中可得抽象的"编码器”协议——
1. 由两根信号线组成。
2. 当旋转到一定位置的时候,某根信号电平由默认电平变为动作电平,从而产生上升沿或者下降沿。
(注:可计数单位时间上升沿/下降沿次数,从而实现速度的测量)
3. 两信号线形状相同,但是相位相差一定角度,从而可以判断方向(正转/反转)。
4-3 EC11编码器内部原理及连线
实物图
封装图
引脚介绍:
A、B、C:编码器数据引脚,C为公共端,A、B为信号端。
D、E:按键引脚,相当于按键开关。
6,7:固定编码器引脚,不接入电路。
编码原理
EC11编码器原理上相当于两个“按键"开关,只是按键的方式很特殊——是通过旋转实现的;两个开关之间被”按“下去的时刻有相位差。
图 编码器等效原理图
而A和B上的信号在时间刻度上如下所示:
图 A、B两相电平图
关键点:
- 当向着箭头方向旋转的时候我们发现:A在下降沿的时刻B是高电平,A在上升沿的时刻B是低电平,
这可以表述为(A 下 B 1,A 上 B 0),记作表述1; - 当方向取图中反向的时候,可以看出当A在下降沿的时刻B是低电平,A在上升沿的时刻B是高电平,
这可以表述为(A 下 B 0,A 上 B 1),记作表述2。
通过区别 表述1 和 表述2 ,就可以区别编码器的转向。
应用电路——包括有上拉电阻&无上拉电阻
无上拉电阻:初始化的时候,IO要配置内部上拉电阻,否则无法编码(图中KEY_L, KEY_R 的GPIO应该配置为上拉输入模式);本试验原理图中为无上拉电阻的模式。
有上拉电阻:初始化的时候,IO不需要要配置内部上拉电阻,即配置普通模式(准双向、双向模式)即可。(图中R4、R5、R6非必要,可以不用接入电路)
防抖程序(软件消抖):
EC11没防抖几乎不能工作, 因为其抖动很厉害。在中断里写上串口打印语句,可以看到短时间内即使没有转动编码器,也会进入中断。
因此我们可以锁定A作为跳变沿检测中断引脚,在中断中记录下同一方向两个不同组合的状态,当完成一个【完整的表述】后我们就改变一次用于确定最终是否旋转的全局变量。
此处复习一下前面的内容:
A在下降沿的时刻B是高电平,A在上升沿的时刻B是低电平,这可以表述为(A 下 B 1,A 上 B 0),记作表述1;
A在下降沿的时刻B是低电平,A在上升沿的时刻B是高电平,这可以表述为(A 下 B 0,A 上 B 1),记作表述2。
所谓完整的表述,就是不仅仅检查A下降沿B的电平,也检查A上升沿B的电平。
例如,我们定义一个全局变量flag用于告诉主函数是否发生了旋钮旋转;定义一个全局变量val,当正向旋转编码器发生一次咔哒声后,我们将val++;当反向旋转编码器发生一次咔哒声后,我们将val--操作一次。
这样为了记录下完整的表述1和表述2,我们定义两个全局变量flag1和flag2,当没有进入中断的时候,默认我们将其初始化为0,当发生了属性为“下1”的中断后,我们将flag1=1;当发生了属性为“下0”的操作后我们记录flag2=1;这样下次再次进入中断后那结果只能是对应的“上0”或“上1”,这个时候我们将对val进行操作,同时将flag1和flag2清零,并记flag为1,这样我们可以在主函数识别出刚才发生了旋转操作,并在主函数中对其清零。
好了,思路有了,上程序的环节到了,先上没消抖的程序
仅仅检查A下降沿(几乎无法使用)
if(RESET != exti_interrupt_flag_get(EXTI_4)) //A相下降沿触发一次
{if((gpio_input_bit_get(GPIOB,GPIO_PIN_4) == RESET))//B相低电平,属于表述2{LED2(ON);LED3(OFF);}else//B相高电平,属于表述1{LED2(OFF);LED3(ON);}exti_interrupt_flag_clear(EXTI_4);
}
//不检查A相上升沿
再上消了抖的程序:
void EXTI4_15_IRQHandler(void)
{//消抖处理(需要首先配置成双向触发)if(gpio_input_bit_get(PHASE_A_GPIO,PHASE_A_PIN) == RESET)//如果是下降沿{//判断状态if(gpio_input_bit_get(PHASE_B_GPIO,PHASE_B_PIN) == RESET){flag1 = 1;}else if(gpio_input_bit_get(PHASE_B_GPIO,PHASE_B_PIN) == SET){flag2 = 1;}}else //如果是上升沿 gpio_input_bit_get(PHASE_A_GPIO,PHASE_A_PIN) == SET{if((flag1 == 1)&&(gpio_input_bit_get(PHASE_B_GPIO,PHASE_B_PIN) == SET)){val++;LED2(ON);LED3(OFF);flag1 = 0;//用于下一次检测flag2 = 0;//附加的一句,程序运行到这里,说明flag2==1是无效的,将之清零,防止其干扰下一步结果。}else if((flag2 == 1)&&(gpio_input_bit_get(PHASE_B_GPIO,PHASE_B_PIN) == RESET)){val--;LED2(OFF);LED3(ON);flag2 = 0;flag1 = 0;}printf("val =%d\r\n",val);}#endif
}
其他:采样法
硬件消抖的评论区讨论
为了提高抗干扰能力(硬件消抖),可以在A和B引脚分别使用一个0.1uF电容接地。
1. 并联的电容应该小,或者串联一个小限流电阻
2. 电容容值的考虑