# [AVR]Atmega328p-rotary encoder Assembly help!

#### kgavionics

##### Full Member level 3
Hello guys
I'm have a rotary encoder hooked up to an Arduino UNO and trying to write a code to turn on a led1 if it turns clockwise, otherwise a led2 if it turns counterclockwise.
I'm found a lot of c code online to make this work, but I want to implement it first in assembly, so I can understand how it works fully (so please no negative comment why I'm using assembly in 2021)
This is my code, and my problem is I'm getting only one direction.
The idea behind my code is:
When I rotate the RE it sends an interrupt to PD2 Pin on a falling edge, then in the ISR, I check the signal B (PD3 pin), if it's high, it means that the RE is turned clockwise, otherwise it is turned counterclockwise.
I know I'm missing something, and I would appreciate if someone can help me to fix this code!
Code:
;Rotary encoder hoocked up to an Arduino Uno.Signal A is going to pin INt0 and signal B is going to pin pd3.If the Rotary encoder is turned clock wise, Led 1 ( PC0) is turned ON, if turned CCW then led 2 ( PC1) is turn on.
.device Atmega328P
.org 0x0

jmp main
.org 0x002
jmp int0_isr

main:
sbi ddrc,0
sbi ddrc,1
sbi portd,2  ; pull up resistor on Pd2
sbi portd,3; pull up resistor on Pd3  ; B signal
cbi ddrd,3
cbi ddrd,2
ldi r16,0x01 ;Int0 enabled
out eimsk,r16
ldi r16,0x02 ; falling edge
sts eicra,r16
sei
loop:
rjmp loop

.org 0x100
int0_isr:
sbis portd,3
rjmp ccw
sbi portc,1
cbi portc,0
rjmp exit
ccw:
sbi portc,0
cbi portc,1

exit:
reti

#### KlausST

##### Super Moderator
Staff member
Hi,

ports have input anpd output registers.
Like PIND and PORTD.

in your ISR you (try to) read PORTD, but it should be PIND.

Klaus

### kgavionics

Points: 2

#### FvM

##### Super Moderator
Staff member
For better resolution and symmetrcial behavior, use pin change interrupt sensitive for both encoder inputs. Compare actual AB input stage with stored previous state to determine rotation direction, use XOR for simple detection. If both inputs have changed, flag an overrun or hardware error.

kgavionics

### kgavionics

Points: 2

#### kgavionics

##### Full Member level 3
Hi,

ports have input anpd output registers.
Like PIND and PORTD.

in your ISR you (try to) read PORTD, but it should be PIND.

Klaus
Thank you KlausST for your input
I changed it to PIND, but now, I have erratic behaviour where both LED's turn on alternatively! ( see video)

#### KlausST

##### Super Moderator
Staff member
Hi,

maybe it´s a mechanic switch, which may bounce. Thus you need to use a debouncing techniquie on the input.
This could be done with software, but maybe an external capacitor could do the job.
I don´t know your pullup resistor value: Try a capacitor with 0.00001/R. No exact value needed.

Klaus

### kgavionics

Points: 2

#### kgavionics

##### Full Member level 3
Hi,

maybe it´s a mechanic switch, which may bounce. Thus you need to use a debouncing techniquie on the input.
This could be done with software, but maybe an external capacitor could do the job.
I don´t know your pullup resistor value: Try a capacitor with 0.00001/R. No exact value needed.

Klaus

Hi,

maybe it´s a mechanic switch, which may bounce. Thus you need to use a debouncing techniquie on the input.
This could be done with software, but maybe an external capacitor could do the job.
I don´t know your pullup resistor value: Try a capacitor with 0.00001/R. No exact value needed.

Klaus
The RE I use already has a low pass filter included, so I don't think it's a debounce problem, but I'm not sure, because I don't have an oscilloscope to check it!

#### FvM

##### Super Moderator
Staff member
The RE is use already has a low pass filter included, so I don't think it's a debounce problem
Can you refer to a datasheet specifying the filter feature?

Your decoder logic isn't good because it acts only on 1 out of 4 encoder output transitions. Better use state-of-the-art qudrature logic as sketched in post #3. Debouncing might be also achieved by scanning the inputs at a fixed rate controlled by a timer.

kgavionics

### kgavionics

Points: 2

#### kgavionics

##### Full Member level 3
Can you refer to a datasheet specifying the filter feature?

Your decoder logic isn't good because it acts only on 1 out of 4 encoder output transitions. Better use state-of-the-art qudrature logic as sketched in post #3. Debouncing might be also achieved by scanning the inputs at a fixed rate controlled by a timer.
You guys are right! My RE has a lot of noise, because even with this Arduino sketch(not mine), I still get some noise!so now I'm sure that the problem is coming for my RE!
C-like:
 /*
Rotary Encoder Demo
rot-encode-demo.ino
Demonstrates operation of Rotary Encoder
Displays results on Serial Monitor
DroneBot Workshop 2019
https://dronebotworkshop.com
*/

// Rotary Encoder Inputs
#define inputCLK 4
#define inputDT 5

// LED Outputs
#define ledCW 8
#define ledCCW 9

int counter = 0;
int currentStateCLK;
int previousStateCLK;

String encdir ="";

void setup() {

// Set encoder pins as inputs
pinMode (inputCLK,INPUT);
pinMode (inputDT,INPUT);

// Set LED pins as outputs
pinMode (ledCW,OUTPUT);
pinMode (ledCCW,OUTPUT);

// Setup Serial Monitor
Serial.begin (9600);

// Read the initial state of inputCLK
// Assign to previousStateCLK variable

}

void loop() {

// Read the current state of inputCLK

// If the previous and the current state of the inputCLK are different then a pulse has occured
if (currentStateCLK != previousStateCLK){

// If the inputDT state is different than the inputCLK state then
// the encoder is rotating counterclockwise
counter --;
encdir ="CCW";
digitalWrite(ledCW, LOW);
digitalWrite(ledCCW, HIGH);

} else {
// Encoder is rotating clockwise
counter ++;
encdir ="CW";
digitalWrite(ledCW, HIGH);
digitalWrite(ledCCW, LOW);

}
Serial.print("Direction: ");
Serial.print(encdir);
Serial.print(" -- Value: ");
Serial.println(counter);
}
// Update previousStateCLK with the current state
previousStateCLK = currentStateCLK;
}

#### kgavionics

##### Full Member level 3
A little update:
I modified the code to use both INT0 and INT1 and I got better result (less debounce), next step is to build a good debounce cuircuit!
Thank you guys for all your inputs!
Code:
sbi portd,2  ; pull up resistor on Pd2
sbi portd,3; pull up resistor on Pd3  ; B signal
cbi ddrd,3
cbi ddrd,2
ldi r16,0x03 ;Int0 and Int1 enabled
out eimsk,r16
ldi r16,0x0b ;int0 rising edge /int1 falling edge
sts eicra,r16
sei
loop:
rjmp loop

.org 0x100
int0_isr:
sbic pind,3
rjmp ccw
sbi portc,1
cbi portc,0
rjmp exit
ccw:
sbi portc,0
cbi portc,1
exit:
reti

.org 0x150
int1_isr:
sbis pind,2
rjmp cw2
sbi portc,0
cbi portc,1
rjmp exit2
cw2:
sbi portc,1
cbi portc,0

exit2:
reti

#### FvM

##### Super Moderator
Staff member
Using INTO and INT1 is second best option, still only using half of the decoder signal transitions.

#### kgavionics

##### Full Member level 3
Last update:
With a low pass filter (10k and 100nF) on each pin (A and B), I got a perfect result!

#### kgavionics

##### Full Member level 3
Hello again guys
After, I got this fully working on the Arduino Uno, I tried the code on an Arduino Mega, because, I need more ports in my project. So this is the modified code, but the leds don't turn on (the interrupts are not triggered)

Code:
;Rotary encoder hooked up to an Arduino Mega. Signal A is going to pin INt0 (PD0) and signal B is going to pin Int1(PD1). If the Rotary encoder is turned clockwise, Led 1 (PC0) is turned ON, if turned CCW then led 2 (PC1) is turn on.
.device Atmega2560
.org 0x0

jmp main
.org 0x0002
jmp int0_isr
.org 0x0004
jmp int1_isr

main:
sbi ddrc,0 ;pc0 as output
sbi ddrc,1 ;pc1 as output
cbi ddrd,1 ;pd1 as input
cbi ddrd,0 ;pd0 as input
sbi portd,0  ; pull up resistor on Pd0 int0
sbi portd,1; pull up resistor on Pd1  ; B signal
ldi r16,0x03 ;Int0 and Int1 enabled
out eimsk,r16
ldi r16,0x0b ;int0 rising edge /int1 falling edge
sts eicra,r16
sei
loop:
rjmp loop

.org 0x100
int0_isr:
sbic pind,1
rjmp ccw
sbi portc,1
cbi portc,0
rjmp exit
ccw:
sbi portc,0
cbi portc,1
exit:
reti

.org 0x150
int1_isr:
sbis pind,0
rjmp cw2
sbi portc,0
cbi portc,1
rjmp exit2
cw2:
sbi portc,1
cbi portc,0

exit2:
reti
Can someone tell me why the code is not working on the atmega2560 plz?

#### KlausST

##### Super Moderator
Staff member
Hi,

What did you do to debug it?
Did you debug from input to output or the other way round?
What are the results?

Klaus

#### kgavionics

##### Full Member level 3
The result is neither of the cw nor ccw Leds are turning on!
Honestly, I didn't debug it, because I'm on Linux (I use a simple text editor and avrdude).
To debug do I have to be on Windows and use Atmel studio I guess?

#### KlausST

##### Super Moderator
Staff member
Hi,

Even a LED can be very helpful.....to show step by step which function is processed.

Klaus

#### kgavionics

##### Full Member level 3
I found the culprit, it was just a bad connection on the breadboard!
Thank you very much guys for the help!