EC11旋转编码器
(一)原理
正转(顺时针)时,A相超前B相90°
反转(逆时针)时,B相超前A相90°
(二)硬件电路
(三)实现旋转编码器模块
这里参考博客
https://blog.csdn.net/qq_63434393/article/details/132489786
基本逻辑
-
配置一条EXTI线用来接收A(或B)相产生的外部中断脉冲
-
编码器消抖:
设置双边沿触发外部中断,判断A(或B)相下降沿->上升沿期间另一相的电平是否变化,不变则为抖动,反之则为有效旋转。这里的原理是两相位差90°(能保证一相电平跳变产生抖动时,另一相保持不变),见波形示意图
理想波形示意图:
tips:该编码器默认输入高电平(即不旋转时始终为高电平)
由以上原理分析一个正转波形可知,最终有效的边沿变化为图示绿色边沿,(其余变化为抖动,相互抵消)
关键代码
这里A相接PB14,B相接PB15(按实际接线更改代码)
-
初始化GPIO14和15口接收A、B相数字信号(输入模式)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE); //RCC使能GPIO、AFIO时钟 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure);
-
配置AFIO选择A相接收外部中断
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);
-
初始化EXTI
EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line14; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //设置双边沿触发 EXTI_Init(&EXTI_InitStructure);
-
配置NVIC
首先对中断优先级进行分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
这里只有一个中断随便分配了 注:中断优先级分组一个程序仅使用一种,否则可能会导致中断管理混乱。可以把中断优先级分组单独写在主程序
NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure);
-
中断处理函数
具体函数名参考启动文件中断向量表
中断里实现编码器消抖(原理见基本逻辑)
这里我们设置了几个标志变量:
EXTI_Flag
:0,处理下降沿;1,处理上升沿 确保中断触发后为下降沿->上升沿的先后处理次序(应该是因为硬件时序问题,中断的触发实际上并不会和理想波形完全一致 所以理想终究是理想啊)
Falling_B_Level
:记录下降沿B相电平
Rising_B_Level
:记录上升沿B相电平//中断边沿处理标志 uint8_t EXTI_Flag; //B相电平记录 uint8_t Falling_B_Level,Rising_B_Level; void EXTI15_10_IRQHandler(void){ //A相触发中断 if(EXTI_GetITStatus(EXTI_Line14) == SET){ if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) == 0 && EXTI_Flag == 0){ //先处理下降沿中断 ++EXTI_Flag; Falling_B_Level = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15); } else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) == 1 && EXTI_Flag == 1){ //后处理上升沿中断 EXTI_Flag = 0; Rising_B_Level = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15); if(Falling_B_Level == 1 && Rising_B_Level == 0){ //正转处理 /*User Code Begin*/ /*User Code End*/ } else if(Falling_B_Level == 0 && Rising_B_Level == 1){ //反转处理 /*User Code Begin*/ /*User Code End*/ } } EXTI_ClearITPendingBit(EXTI_Line14); } }