#include #include #include "uart.h" #define True 1 #define False 0 //Global variables: // Although one should generally try to avoid the use of global variables // in normal c programming, they are sometimes required when working // with programs for microcontrollers. Here we define a global variable // so that we can share data between a ISR and and the main(). Also note the // volatile keyword. This just tells the compiler to not try and do any fancy // optimizations on this variable. volatile int32_t position = 0; //Signed 32bit integer volatile uint8_t do_speed_calc = False; //ISR that gets triggered on Timer1 OCRA compare, about every 500 ms. ISR(TIMER1_COMPA_vect) { //While we could do the actual speed calculation and UART output here in // this ISR, we want to avoid doing that as the ATmega's can only handle // one interrupt at a time. If we're busy doing calculations in this ISR // while a rising edge from the encoder comes in, the other ISR won't fire. // So we just set a variable here and check for it in main(). do_speed_calc = True; } //This ISR gets called on every rising edge of the encoder A signal. If the B // signal is high we increment the position counter. Otherwise we decrement. ISR(INT0_vect) { if (PIND & _BV(PD3)) position++; else position--; } void init(); int main() { int32_t current_position = 0; int32_t previous_position = 0; int32_t position_change = 0; init(); printf("\x1B[2J\x1B\x63"); //VT100 clear screen command. printf("Welcome to the Encoder Lab!"); while(1) { if(do_speed_calc) { current_position = position; position_change = current_position - previous_position; printf("\x1B[2;1H"); //VT100 set position command. Row:2 Column:1 printf("Current speed: %+.5li, Current position: %+.8li", position_change*2, current_position); previous_position = current_position; do_speed_calc = False; } } return 0; } void init() { //Init Ports PORTD |= _BV(PD2) | _BV(PD3); //Turn on pull-up resistors on pin D2 and D3. //Enable global interrupts sei(); //Init UART uart_init(); //Init Timer 1 TCCR1A = 0; //Normal timer operation. TCCR1B = _BV(WGM12) | _BV(CS12); //Clear Timer on Compare Match (CTC) Mode, Set timer clock signal to system clock/256 OCR1AH = (15624 & 0xFF00) >> 8; //Setting the Output Compare Register to 15624 gives us an interrupt about every OCR1AL = (15624 & 0x00FF); // 500ms. Note that we have to first write to the high byte and then the low. TIMSK = _BV(OCIE1A); //Init External Interrupt on PD2 MCUCR |= _BV(ISC01) | _BV(ISC00); //Trigger interrupt on rising edge. GICR |= _BV(INT0); //Enable interrupts. }