I'm trying to get a rotary encoder working on my STM32.
- I have channel A & B being pulled up to 3V and debounced with 1uF capacitors.
- The board has channel A & B connected to PA11 & PA10 respectively and have configured hardware interrupts for both
- I've tried a number of different algorithms to decode the direction of rotation but no matter what I do I can't get consistent alternating interrupts (ie. ABABAB)
- I've tried triggering on both edges, just falling, just rising and no matter what I get the interrupts triggering seemingly randomly.
Is there something I'm doing wrong? Are the interrupts not enough to keep up with the speed of the encoder? Is the debouncing not enough (Looks okay on a scope but maybe the interrupts are more sensitive)? Is there a better way to do this in general? I've been stuck on this for a while so any help would be great. Let me know if more info is necessary.
*Code Edited to reflect changes (working algorithm)
INTERRUPT HANDLER
static int8_t states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
uint8_t RotaryCurrentState = 0x00;
uint8_t RotaryTransition = 0;
int8_t RotaryPosition = 0;
/*Rotary Encoder Interrupt Handler
Channel A (IRQ11) & B (IRQ10)
CW --->
A (IRQ11) ¯|___|¯¯¯¯|___|¯¯¯¯
Interrupts ^ ^ ^ ^
B (IRQ 10) ¯¯¯|___|¯¯¯¯¯|___|¯
Interrupts ^ ^ ^ ^
CCW <---
void EXTI4_15_IRQHandler(void)
{
RotaryCurrentState = (Read_IO(ROTARY_A) << 1) | Read_IO(ROTARY_B);
RotaryTransition = (RotaryTransition <<2 ) | RotaryCurrentState;
RotaryPosition = RotaryPosition + states[RotaryTransition & 0x0F];
EXTI_ClearITPendingBit(EXTI_Line10); //Clear Channel B
EXTI_ClearITPendingBit(EXTI_Line11); //Clear Channel A
}
MAIN.C
//Initialize
RotaryTransition = Read_IO(ROTARY_A) << 3 | Read_IO(ROTARY_B) << 2 | \
Read_IO(ROTARY_A) << 1 | Read_IO(ROTARY_B);
while(1)
{
//CW Transition
if (RotaryPosition == 4)
{
STM_EVAL_LEDToggle(LED4);
RotaryPosition = 0;
}
//CCW Transition
else if (RotaryPosition == -4)
{
STM_EVAL_LEDToggle(LED3);
RotaryPosition = 0;
}
}