slides

Hands-On Arduino
Incremental Encoders II
Sample Code: Polling
unsigned long count=0; unsigned long timep, time, etime; byte A,Ap; !
void setup() { Serial.begin(9600); //connect Channel A to pin 3 pinMode(3, INPUT); //set the initial time timep = micros(); //set the initial value of A Ap = digitalRead(3); } Hands On Arduino: Encoders II
void loop() { A = digitalRead(3); if (A^Ap)//is there a difference? { count++;//if so, increment. } Ap = A; time = micros(); etime = time -­‐ timep; if (etime > 1000000)//every 1 sec { Serial.println(count); timep = time;//reset timer } }
Sample Code:
2x Decoding Using Interrupts
unsigned long count=0; unsigned long timep, time, etime; void setup() { Serial.begin(9600); //connect Channel A to pin 3 pinMode(3, INPUT); attachInterrupt(1,transition, CHANGE); //set the initial time timep = micros(); } !
void transition() { count++; } !
Hands On Arduino: Encoders II
void loop() { time = micros(); etime = time -­‐ timep; if (etime > 1000000)// 1 second { Serial.println(count); timep = time; //reset timer } } Sample Code:
Velocity Estimation
//This displays the number of transitions // per second. unsigned long count=0; unsigned long timep, time, etime; void setup() { Serial.begin(9600); //connect Channel A to pin 3 pinMode(3, INPUT); attachInterrupt(1,transition, CHANGE); //set the initial time timep = micros(); } !
void transition() { count++; } !
Hands On Arduino: Encoders II
void loop() { time = micros(); etime = time -­‐ timep; if (etime > 1000000)// 1 second { Serial.println(count); count = 0; //reset the counter timep = time; //reset timer } } BD4x: Switch…Case
long count=0; unsigned long timep, time, etime; boolean A,B; byte state, statep; void setup() { Serial.begin(9600); pinMode(2, INPUT);//Channel A pinMode(3, INPUT);//Channel B attachInterrupt(0,Achange,CHANGE); attachInterrupt(1,Bchange,CHANGE); timep = micros(); //set the initial time //read the initial value of A & B A = digitalRead(2); B = digitalRead(3); //set initial state value if ((A==HIGH)&&(B==HIGH)) statep = 1; if ((A==HIGH)&&(B==LOW)) statep = 2; if ((A==LOW)&&(B==LOW)) statep = 3; if ((A==LOW)&&(B==HIGH)) statep = 4; }
Hands On Arduino: Encoders II
void loop() { time = micros(); etime = time -­‐ timep; if (etime > 1000000) { Serial.println(count); timep = time; } } BD4x: Switch…Case
void Achange() { A = digitalRead(2); B = digitalRead(3); //determine state value if ((A==HIGH)&&(B==HIGH)) state = 1; if ((A==HIGH)&&(B==LOW)) state = 2; if ((A==LOW)&&(B==LOW)) state = 3; if ((A==LOW)&&(B==HIGH)) state = 4; switch (state) { case 1: { if (statep == 2) count-­‐-­‐; if (statep == 4) count++; break; } Hands On Arduino: Encoders II
case 2: { if (statep == 1) count++; if (statep == 3) count-­‐-­‐; break; } case 3: { if (statep == 2) count++; if (statep == 4) count-­‐-­‐; break; } default: { if (statep == 1) count-­‐-­‐; if (statep == 3) count++; } } statep = state; }
BD4x: Array
void Achange() { A = digitalRead(2); B = digitalRead(3); //determine state value if ((A==HIGH)&&(B==HIGH)) state = 0; if ((A==HIGH)&&(B==LOW)) state = 1; if ((A==LOW)&&(B==LOW)) state = 2; if ((A==LOW)&&(B==HIGH)) state = 3; index = 4*state + statep; count = count + QEM[index]; statep = state; } Hands On Arduino: Encoders II
void Bchange() { A = digitalRead(2); B = digitalRead(3); //determine state value if ((A==HIGH)&&(B==HIGH)) state = 0; if ((A==HIGH)&&(B==LOW)) state = 1; if ((A==LOW)&&(B==LOW)) state = 2; if ((A==LOW)&&(B==HIGH)) state = 3; index = 4*state + statep; count = count + QEM[index]; statep = state; } Overview
• Motion Input!
• Encoder Basics!
• Unidirectional Decoding!
• Bi-Directional Decoding!
• Using Pin Change Interrupts!
• Using Assembly Language
Hands On Arduino: Encoders II
Using Pin-Change Interrupts:
ADAEncoder
• The ADAEncoder library provides a way to use
encoders!
• works with any I/O (analog or digital) pins!
• Based on Object-Oriented (C++) programming!
• Can work with switch-based encoders or optical.!
• Tutorials available online
Hands On Arduino: Encoders II
BD4x: Pin Position
• It is not always possible to have the A & B
channels connected to digital pins 2 & 3.!
• If more than one motor is used, it is not possible.!
• Pin Change Interrupts may be used on any
analog or digital pin.!
• There is a Pin Change Interrupt Vector for each
PORT (B, C and D).
Hands On Arduino: Encoders II
Review PinChange Interrupts
• Need to set appropriate pins to be inputs.!
• If input pullups are needed, !
• using a “rotary pot,” then set them. !
• using an optical encoder, don’t set them.!
• Set the appropriate Pin Change Interrupt Enable
bit (PCIE0, PCIE1, or PCIE2) in PCICR.!
• Set the appropriate Pin Change Masks (PCINTnn).!
• One ISR for each Port.
Hands On Arduino: Encoders II
BD4X: Pin Change Interrupt
volatile long count=0; unsigned long timep, time, etime; volatile byte portCval, index; volatile byte state, statep; volatile int QEM[16]={0,-­‐1,0,1,1,0,-­‐1,0,0,1,0,-­‐1,-­‐1,0,1,0}; !
ISR (PCINT1_vect) { cli(); statep = state; portCval = PINC & 0b00011000; if (portCval == 0b00011000) state = 0; if (portCval == 0b00010000) state = 1; if (portCval == 0b00000000) state = 2; if (portCval == 0b00001000) state = 3; index = 4*state + statep; count = count + QEM[index]; sei(); } Hands On Arduino: Encoders II
void setup() { Serial.begin(9600); DDRC = 0b00000000;// all are set to be inputs PORTC = 0b00011000;//input pullups timep = micros(); //set the initial time //read the initial value of A & B portCval = PINC & 0b00011000;//mask pins 3 & 4 //set initial state value if (portCval == 0b00011000) state = 0; if (portCval == 0b00010000) state = 1; if (portCval == 0b00000000) state = 2; if (portCval == 0b00001000) state = 3; PCICR |= (1<<PCIE1); PCMSK1 |= (1<<PCINT11)|(1<<PCINT12); } !
void loop() { time = micros(); etime = time -­‐ timep; if (etime > 1000000) { Serial.println(count); timep = time; } } BD4x Decoding: Assembly
#include "pinCasm.h" unsigned long timep, time, etime; void setup() { byte portCval; Serial.begin(9600); DDRC = 0b00000000;// all are set to be inputs //PORTC = 0b00011000;//input pullups timep = micros(); //set the initial time //read the initial value of A & B portCval = PINC & 0b00011000;//mask pins 3 & 4 //set initial state value if (portCval == 0b00011000) state = 0; if (portCval == 0b00010000) state = 1; if (portCval == 0b00000000) state = 2; if (portCval == 0b00001000) state = 3; PCICR |= (1<<PCIE1); PCMSK1 |= (1<<PCINT11)|(1<<PCINT12); count = 0x00000000; } Hands On Arduino: Encoders II
#include <stdint.h> !
extern "C" int32_t count; extern "C" uint8_t state; extern "C" void PCINT1_vect(void); void loop() { time = micros(); etime = time -­‐ timep; if (etime > 1000000) { Serial.print(count,BIN); Serial.print(", "); Serial.println(count,DEC); timep = time; } } BD4x Decoding: Assembly
save
registers
disable
interrupts
statep = state
branch1
portC =
PINC & 0b00011000
portC ==
0b00011000
?
portC ==
0b00010000
?
no
branch2
no
branch2
portC ==
0b00000000
?
branch3
no
branch3
portC ==
0b00001000
?
yes
yes
yes
state = 1
state = 2
state = 3
no
branch1
yes
statep
== 0
?
state = 0
yes
increment
no
statep
== 1
?
yes
increment
no
statep
== 2
?
increment
decrement
copy counter
copy counter
finish
increment
32bit
counter
decrement
32bit
counter
enable
interrupts
finish
yes
restore
registers
increment
no
copy counter
statep
== 3
?
yes
increment
no
statep
== 1
?
statep
== 2
?
yes
decrement
statep
== 3
?
yes
decrement
statep
== 0
?
no
no
no
finish
finish
finish
yes
decrement
no
finish
Hands On Arduino: Encoders II
yes
decrement
finish
return
BD4x Decoding: Assembly
save
registers
disable
interrupts
statep = state
Hands On Arduino: Encoders II
portC =
PINC & 0b00011000
#include <avr/io.h> .file "pinCasm.s" .data .comm state, 1 .global state .comm count, 4 .global count .comm statep, 1 .comm portC, 1 !
.text .global PCINT1_vect PCINT1_vect: push r1 ; push r0 ; in r0, 0x3f ; SREG push r0 ;save SREG eor r1, r1 ;clear r1 push r24 ; push r25 ; push r26 ; push r27 ; cli ;disable interrupts save
registers
BD4x Decoding: Assembly
disable
interrupts
statep = state
portC =
PINC & 0b00011000
portC ==
0b00011000
?
no
branch1
yes
state = 0
statep
== 3
?
yes
increment
no
statep
== 1
?
yes
decrement
no
finish
Hands On Arduino: Encoders II
lds r24, state ;put state into r24 sts statep, r24 ;put state into statep in r24, PINC-­‐0x20 ;put PINC into r24 andi r24, 0x18 ;AND PINC with 0b00011000 sts portC, r24 ;put r24 into portC branch0: cpi r24, 0x18 ;compare r24 with 0b00011000 brne branch1 ;if NE goto branch1 sts state, r1 ;set state = 0 lds r24, statep ;put statep into r24 cpi r24, 0x03 ;compare with 3 breq increm ;if statep = 3 goto increm lds r24, statep ;set r24 to statep cpi r24, 0x01 ;compare with 1 breq decrem ;if statep = 1 goto decrem rjmp fini ;goto fini
BD4x Decoding: Assembly
branch1
portC ==
0b00010000
?
no
branch2
yes
state = 1
statep
== 0
?
yes
increment
no
statep
== 2
?
yes
decrement
no
finish
Hands On Arduino: Encoders II
branch1: lds r24, portC ;put portC into r24 cpi r24, 0x10 ;AND portC with 0b00010000 brne branch2 ;if NE goto branch2 ldi r24, 0x01 ;put 1 into r24 sts state, r24 ;put 1 into state lds r24, statep ;put statep into r24 and r24, r24 ;and r24 with itself comp w/0 breq increm ;if statep = 0 goto increm lds r24, statep ;put statep into r24 cpi r24, 0x02 ;compare with 2 breq decrem ;if statep = 2 goto decrem rjmp fini ; goto fini BD4x Decoding: Assembly
branch2
portC ==
0b00000000
?
no
branch3
yes
state = 2
statep
== 1
?
yes
increment
no
statep
== 3
?
yes
decrement
no
finish
Hands On Arduino: Encoders II
branch2: lds r24, portC ;put portC into r24 and r24, r24 ;compare with zero brne branch3 ;if NE goto branch3 ldi r24, 0x02 ;put 2 into r24 sts state, r24 ;put 2 into state lds r24, statep ;put statep into r24 cpi r24, 0x01 ;compare with 1 breq increm ;if statep = 1 goto increm lds r24, statep ;put statep into r24 cpi r24, 0x03 ;compare with 3 brne fini ;if NE goto fini rjmp decrem ;otherwise goto decrem BD4x Decoding: Assembly
branch3
portC ==
0b00001000
?
no
finish
yes
state = 3
statep
== 2
?
yes
increment
no
statep
== 0
?
yes
decrement
no
finish
Hands On Arduino: Encoders II
branch3: lds r24, portC ;put portC into r24 cpi r24, 0x08 ;compare with 0b00001000 brne fini ;if NE goto fini ldi r24, 0x03 ;put 3 into r24 sts state, r24 ;put 3 into state lds r24, statep ;put statep into r24 cpi r24, 0x02 ;compare with 2 breq increm ;if statep = 2 goto increm lds r24, statep ;put statep into r24 and r24, r24 ;compare with zero breq decrem ;if statep = 0 goto decrem rjmp fini ;goto fini BD4x Decoding: Assembly
increment
decrement
copy counter
copy counter
increment
32bit
counter
decrement
32bit
counter
copy counter
finish
Hands On Arduino: Encoders II
increm: lds r24, count ;low byte lds r25, count+1 ;2nd byte lds r26, count+2 ;3rd byte lds r27, count+3 ;high byte adiw r24, 0x01 ;increment bottom 2 bytes adc r26, r1 ;add carry to 3rd adc r27, r1 ;add carry to 4th rjmp updatecount ;goto updatecount decrem: lds r24, count ;low byte lds r25, count+1 ;2nd byte lds r26, count+2 ;3rd byte lds r27, count+3 ;4th byte sbiw r24, 0x01 ;decrement low bytes sbc r26, r1 ;borrow from 3rd sbc r27, r1 ;borrow from 4th updatecount: sts count, r24 ;write low sts count+1, r25 ;write 2nd sts count+2, r26 ;write 3rd sts count+3, r27 ;write 4th
BD4x Decoding: Assembly
finish
enable
interrupts
restore
registers
return
Hands On Arduino: Encoders II
fini: sei ; pop r27 ; pop r26 ; pop r25 ; pop r24 ; pop r0 ; out 0x3f, r0 ;SREG pop r0 ; pop r1 ; reti