/* Odometer/Speedometer Pendant v2 David Johnson-Davies - www.technoblogy.com - 11th March 2017 ATtiny84 @ 8 MHz (internal oscillator; BOD disabled) CC BY 4.0 Licensed under a Creative Commons Attribution 4.0 International license: http://creativecommons.org/licenses/by/4.0/ */ // Seven-segment definitions const int charArrayLen = 12; char charArray[] = { // ABCDEFG Segments 0b1111110, // 0 0b0110000, // 1 0b1101101, // 2 0b1111001, // 3 0b0110011, // 4 0b1011011, // 5 0b1011111, // 6 0b1110000, // 7 0b1111111, // 8 0b1111011, // 9 0b0000001, // 10 '-' 0b0000000 // 11 Space }; const int Dash = 10; const int Space = 11; const int ndigits = 4; const int dpSeg = 1; // PINB1 const int DataIn = PINA6; // USI DI volatile char Buffer[] = {Dash, Dash, Dash, Dash}; char dp = -1; // Decimal point position 0 to 3 char digit = 0; // Pin assignments // PINA3, PINB0, PINB2, PINB1 char Digits[] = {7, 0, 2, 1}; // Segments must all go to port A; this specifies how they're wired up: // g f e d c b a char Segments[] = {5, 3, 2, 4, 7, 1, 0}; // Display multiplexer ********************************************** void ReorderBits () { char segs, newsegs; for (int i=0; i> 1; } charArray[i]=newsegs; } } // Set up Timer/Counter1 to multiplex the display void InitialiseDisplay () { TCCR1A = 0<3999) { j=10000; dp=2; } else { j=1000; dp=1; } for (int d=0; d<4 ; d++) { int i = (number/j) % 10; if (!i && !dig && j>100) Buffer[d]=Space; else { Buffer[d]=i; dig = true; } j=j/10; } } // Timer interrupt - multiplexes display ISR (TIM1_COMPA_vect) { DisplayNextDigit(); } // GPS Parser ********************************************** // Example: $GPRMC,194509.000,A,4042.6142,N,07400.4168,W,2.03,5.84,160412,,,A*77 char fmt[]="$GPRMC,dddtdd.ddm,A,eeae.eeee,l,eeeae.eeee,o,djdk,djdc,dddy??,,,?*??"; int state = 0; unsigned int temp; long ltmp; // GPS variables volatile unsigned int Time, Msecs, Knots, Course, Date; volatile long Lat, Long; volatile boolean Fix; void ParseGPS (char c) { if (c == '$') { state = 0; temp = 0; } char mode = fmt[state++]; // If received character matches format string, or format is '?' - return if ((mode == c) || (mode == '?')) return; // d=decimal digit char d = c - '0'; if (mode == 'd') temp = temp*10 + d; // e=long decimal digit else if (mode == 'e') ltmp = (ltmp<<3) + (ltmp<<1) + d; // ltmp = ltmp*10 + d; // a=angular measure else if (mode == 'a') ltmp = (ltmp<<2) + (ltmp<<1) + d; // ltmp = ltmp*6 + d; // t=Time - hhmm else if (mode == 't') { Time = temp*10 + d; temp = 0; } // m=Millisecs else if (mode == 'm') { Msecs = temp*10 + d; ltmp=0; } // l=Latitude - in minutes*1000 else if (mode == 'l') { if (c == 'N') Lat = ltmp; else Lat = -ltmp; ltmp = 0; } // o=Longitude - in minutes*1000 else if (mode == 'o') { if (c == 'E') Long = ltmp; else Long = -ltmp; temp = 0; } // j/k=Speed - in knots*100 else if (mode == 'j') { if (c != '.') { temp = temp*10 + d; state--; } } else if (mode == 'k') { Knots = temp*10 + d; temp = 0; } // c=Course (Track) - in degrees*100 else if (mode == 'c') { Course = temp*10 + d; temp = 0; } // y=Date - ddmm else if (mode == 'y') { Date = temp*10 + d ; Fix = 1; } else state = 0; } // USI UART ********************************************** unsigned char ReverseByte (unsigned char x) { x = ((x >> 1) & 0x55) | ((x << 1) & 0xaa); x = ((x >> 2) & 0x33) | ((x << 2) & 0xcc); x = ((x >> 4) & 0x0f) | ((x << 4) & 0xf0); return x; } // Initialise USI for UART reception. void InitialiseUSI (void) { DDRA &= ~(1< Stationary) Distance = Distance + Speed; // Value of Mode determines what we display if (Mode == 0) Display(Distance*19/59438); else if (Mode == 1) Display((long)Speed*38/33); else Display(Clock); }