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
© Copyright 2025 ExpyDoc