Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[AVR] Atmega328p-rotary encoder Assembly help!

Status
Not open for further replies.

kgavionics

Full Member level 3
Full Member level 3
Joined
Jun 12, 2012
Messages
167
Helped
7
Reputation
14
Reaction score
11
Trophy points
1,298
Location
Alberta.Canada
Activity points
2,482
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!
Thank you in advance!
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
 

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
    Helpful Answer Positive Rating
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.
 
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)

 

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
    Helpful Answer Positive Rating
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!
 

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.
 
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
   previousStateCLK = digitalRead(inputCLK);
 
 }
 
 void loop() {
 
  // Read the current state of inputCLK
   currentStateCLK = digitalRead(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
     if (digitalRead(inputDT) != currentStateCLK) {
       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;
 }
 

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
 

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?
 

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
 

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?
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top