/* rpg_int.c rotary pulse encoder with interrupt on change */ // Arduino UNO R3 // AVR_ATmega328P #define F_CPU 16000000UL #include // register names/addresses and bit names/numbers #include #include void init_uart( void ); unsigned char getchar_uart( void ); void putchar_uart( unsigned char ); void string_out_uart( char * ); // uses strings stored in RAM void decimal_out_uart( signed int ); signed int pos = 0; unsigned char Astate=0, Bstate=0, state=0, oldstate = 0 ; int main(void) { DDRD &= ~( 1 << PD3 ); // PD3 '0' is input, ch A PORTD |= ( 1 << PD3 ); // activate internal pullup DDRD &= ~( 1 << PD4 ); // PD4 '0' is input, ch B PORTD |= ( 1 << PD4 ); // activate internal pullup init_uart( ); setup_pcint( ); while(1) { string_out_uart("\r\nPosition: "); decimal_out_uart( pos ); _delay_ms(500); } } /* *********************************** */ /* INTERRUPTS */ /* *********************************** */ // Interrupt Service Routine attached to PCINT2 vector ISR( PCINT2_vect ) { // read Astate if( ( PIND & ( 1 << PD3 )) == 0 ) Astate = 0; else Astate = 1; // read Bstate if( ( PIND & ( 1 << PD4 )) == 0 ) Bstate = 0; else Bstate = 1; state = Bstate*2 + Astate; if( (state == 0b01) && (oldstate == 0b00) ) pos++; if( (state == 0b00) && (oldstate == 0b01) ) pos--; oldstate = state; } void setup_pcint(void) { // Bits in PCICR register: "- - - - - PCIE2 PCIE1 PCIE0" PCICR |= ( 1 << PCIE2 ); // Local Enable pin change interrupt PCINT2 // Bits in PCMSK2 register: "PCINT23 PCINT22 PCINT21 PCINT20 PCINT19 PCINT18 PCINT17 PCINT16" PCMSK2 |= ( 1 << PCINT19 )|( 1 << PCINT20 ); // "---11---" int on change ck(A),dt(B) sei(); // Global Enable interrupts } /* *********************************** */ /* FUNCTIONS */ /* *********************************** */ void init_uart( void ) { // Bits in UCSR0B register: "RXCIE0 TXCIE0 UDRIE0 RXEN0 TXEN0 UCSZ02 RXB80 TXB80" UCSR0B |= (1<<(RXEN0)) | (1<<(TXEN0)); // "----1---" // Bits in UCSR0C register: "UMSEL01 UMSEL00 UPM01 UPM00 USBS0 UCSZ01/UCPHA0 UCSZ01/UCPHA0 UCPOL0" UCSR0C |= (1<<(UCSZ01)) | (1<<(UCSZ00)); // "-----11-" UBRR0 = 103; // Baud prescaler 103 -> 9600 Baud } void putchar_uart( unsigned char ch ) { // Bits in UCSR0A register: "RXC0 TXC0 UDRE0 FE0 DOR0 UPE0 U2X0 MPCM0" // wait until the port is ready to be written to while( ( UCSR0A & ( 1<<(UDRE0) ) ) == 0 ){} // write the byte to the serial port UDR0 = ch; } void decimal_out_uart( signed int number ) { unsigned char i; unsigned int divisor = 10000; if (number < 0 ) { putchar_uart( '-' ); number = -number; } else putchar_uart( '+' ); for(i=0; ;i++) { putchar_uart( (unsigned char)(number/divisor) + '0' ); if( i==4 ) break; number %= divisor; divisor /= 10; } } void string_out_uart( char * string ) // use for strings in RAM { while (* string != '\0') putchar_uart(*string ++); } /* *********************************** */ /* HARDWARE */ /* *********************************** */ /* Chip ATMega328 Arduino Uno R3 stackable header _______ Digital: _____/ \__ Analog: ______________ ______________ txd ->-|D00 >RXD A5|- | \/ | rxd -<-|D01 -|D03~ A2|- txd ->-(D01)-|03 PD1/TXD PC3 26|-(A3)- dt(B)->-|D04 A1|- -(D02)-|04 PD2/INT0 PC2 25|-(A2)- -|D05~ A0|- ck(A)->-(D03)-|05 PD3/INT1/PWM PC1 24|-(A1)- -|D06~ | Power: dt(B)->-(D04)-|06 PD4 PC0 23|-(A0)- -|D07 Vin|- +5V ---|07 VCC GND 22|--- Gnd | GND|--- GND Gnd ---|08 GND AREF 21|--- Vin -|D08 GND|- Xtal |X|--|09 PB6/OSC1 AVCC 20|--- +5V -|D09~ +5V|--- +5V 16MHz |X|--|10 PB7/OSC2 SCK/PB5 19|-(D13)- -|D10~ +3.3V|- -(D05)-|11 PD5/PWM MISO/PB4 18|-(D12)- -|D11~ Res|- -(D06)-|12 PD6/PWM PWM/MOSI/PB3 17|-(D11)- -|D12 IOREF|- -(D07)-|13 PD7 PWM/SS'/PB2 16|-(D10)- -|D13 LED --- | -(D08)-|14 PB0 PWM/PB1 15|-(D09)- -|GND | |______________________________| -|AREF | -|SCL | ck(A)=PD3=PCIN19 dt(B)=PD4=PCINT20 in PCMSK2 -|SDA | |________________| */