如何读取带有 ESP32 中断和全局标志的旋转编码器
How to read a rotary encoder with interrupts on ESP32 and global flags
使用中断时,任何类型的 digitalRead 都应该过时,我认为是这样。让我解释一下我对此的理解以说明我的问题:
比如说,一个正交增量旋转编码器 (RE) 在两个信号引脚上都被拉高,因此空闲时处于高电平。如果我在两个引脚的下降沿配置一个中断服务例程 (ISR) 并让引脚 B 的 ISR 只将标志“flag_B”设置为 false(表示引脚的逻辑状态)和引脚 A 的 ISR 根据 A 的 ISR 期间 flag_B 的状态设置或重置标志“flag_clockwise”,那么我应该为每个转向步骤找到正确的方向,对吗?我唯一的任务是在 ISR 之后再次将引脚 B 的状态设置为高,我的代码应该为下一个中断做好准备。但这是行不通的,在旋转步骤的前半部分显示错误方向或显示逆时针方向的随机情况很多,而在转动旋钮时您会感到有点“颠簸”,然后在后半部分顺时针方向,当转轴完成一步时,基本上是在只转一步的情况下进行两个相反的动作。我的逻辑有问题吗?
所有信号都在硬件中去抖,在示波器上看起来与预期的一样。
ISR:
//re-CLK signal
void IRAM_ATTR reCLK_ISR(void){
if(myFlags->pinBstate){
//this means the first interrupt of a turning step comes from the clock, not data
myFlags->direction = CCW;
}
else{
//this means the interrupt of a turning step occured from data first
myFlags->direction = CW;
}
}
//re-DATA signal
void IRAM_ATTR reDATA_ISR(void){
myFlags->pinDATAstate = false;
}
进一步处理:
//some function
//scroll = CW / CCW
if((myFlags->direction) != STOP){
if(myFlags->direction == CW){
//DEBUG
digitalWrite(PIN_LED_DEBUG, LOW);
}
}
if(myFlags->direction == CCW){
//DEBUG
digitalWrite(PIN_LED_DEBUG, HIGH);
}
myFlags->pinDATAstate = true;
myFlags->direction = STOP; //direction has 3 states: CW, CCW and STOP
}
最后 2 条语句应该将所有受影响的标志恢复到触摸编码器之前的状态,这意味着为下一轮做好准备。 LED 只是替代不同的计算,应根据转动方向执行。
即使引脚被分配为中断,您仍然可以使用digitalRead()
来确定方向。例如:
const uint8_t pinA = 25;
const uint8_t pinB = 26;
volatile int counter;
void IRAM_ATTR isr(){
if(digitalRead(pinA) == digitalRead(pinB)) {
//Clockwise
counter++;
} else {
//Counter Clockwise
counter--;
}
}
您甚至不需要另一个 ISR 来确定方向。我用这个方法来确定速度和方向;
使用中断时,任何类型的 digitalRead 都应该过时,我认为是这样。让我解释一下我对此的理解以说明我的问题:
比如说,一个正交增量旋转编码器 (RE) 在两个信号引脚上都被拉高,因此空闲时处于高电平。如果我在两个引脚的下降沿配置一个中断服务例程 (ISR) 并让引脚 B 的 ISR 只将标志“flag_B”设置为 false(表示引脚的逻辑状态)和引脚 A 的 ISR 根据 A 的 ISR 期间 flag_B 的状态设置或重置标志“flag_clockwise”,那么我应该为每个转向步骤找到正确的方向,对吗?我唯一的任务是在 ISR 之后再次将引脚 B 的状态设置为高,我的代码应该为下一个中断做好准备。但这是行不通的,在旋转步骤的前半部分显示错误方向或显示逆时针方向的随机情况很多,而在转动旋钮时您会感到有点“颠簸”,然后在后半部分顺时针方向,当转轴完成一步时,基本上是在只转一步的情况下进行两个相反的动作。我的逻辑有问题吗? 所有信号都在硬件中去抖,在示波器上看起来与预期的一样。
ISR:
//re-CLK signal
void IRAM_ATTR reCLK_ISR(void){
if(myFlags->pinBstate){
//this means the first interrupt of a turning step comes from the clock, not data
myFlags->direction = CCW;
}
else{
//this means the interrupt of a turning step occured from data first
myFlags->direction = CW;
}
}
//re-DATA signal
void IRAM_ATTR reDATA_ISR(void){
myFlags->pinDATAstate = false;
}
进一步处理:
//some function
//scroll = CW / CCW
if((myFlags->direction) != STOP){
if(myFlags->direction == CW){
//DEBUG
digitalWrite(PIN_LED_DEBUG, LOW);
}
}
if(myFlags->direction == CCW){
//DEBUG
digitalWrite(PIN_LED_DEBUG, HIGH);
}
myFlags->pinDATAstate = true;
myFlags->direction = STOP; //direction has 3 states: CW, CCW and STOP
}
最后 2 条语句应该将所有受影响的标志恢复到触摸编码器之前的状态,这意味着为下一轮做好准备。 LED 只是替代不同的计算,应根据转动方向执行。
即使引脚被分配为中断,您仍然可以使用digitalRead()
来确定方向。例如:
const uint8_t pinA = 25;
const uint8_t pinB = 26;
volatile int counter;
void IRAM_ATTR isr(){
if(digitalRead(pinA) == digitalRead(pinB)) {
//Clockwise
counter++;
} else {
//Counter Clockwise
counter--;
}
}
您甚至不需要另一个 ISR 来确定方向。我用这个方法来确定速度和方向;