Program listing is after the jump. (It's been tweaked slightly since first publication; now uses PROGMEM to store the digit bitmaps and instructions in program memory, sparing precious Arduino RAM.)
/* Arduinodometer! (GLO-216 and Arduino Uno) This program demonstrates a fun visual effect in which the final digit of a counter is animated to 'roll up,' like the tenths-of-a-mile digit on a mechanical odometer. Connect the GLO- to the Arduino +5 and GND, with serial input from pin 3 (using NewSoftSerial library or Arduino v1.0+). If the Spol jumper on your GLO- has been cut (for UART-direct input), change the parameter "inverted" to "noninverted" in the program line: SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin, inverted); */ #include <avr/pgmspace.h> // needed for PROGMEM #include <SoftwareSerial.h> // use any pin for serial out #define rxPin 255 // Not used, set to invalid pin # #define txPin 3 // Plug GLO's serial input into this pin. #define inverted 1 // If GLO- Spol jumper is intact (COM-polarity) #define noninverted 0 // If GLO Spol jumper is cut (UART polarity) #define odoChar 0x8F // Custom character 15, at ASCII 143 // Bitmaps for the digits "0" - "9". Using PROGMEM to store them // in Flash. This saves 80 bytes of Arduino RAM (at the expense of // some code overhead). const byte digitPatterns[] PROGMEM = { 0x0E,0x11,0x13,0x15,0x19,0x11,0x0E,0x80, // 0 0x04,0x0C,0x04,0x04,0x04,0x04,0x1F,0x80, // 1 0x0E,0x11,0x11,0x02,0x04,0x08,0x1F,0x80, // 2 0x1F,0x02,0x04,0x02,0x01,0x11,0x0E,0x80, // 3 0x02,0x06,0x0A,0x12,0x1F,0x02,0x02,0x80, // 4 0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E,0x80, // 5 0x06,0x08,0x10,0x1E,0x11,0x11,0x0E,0x80, // 6 0x1F,0x01,0x02,0x04,0x08,0x08,0x08,0x80, // 7 0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E,0x80, // 8 0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C,0x80 // 9 } ; // This program includes a GLO-216 instruction that expects 8 bytes of data. // If the program is reset during this download, the GLO would consume // our setup instructions thinking they were the expected data. So we'll // feed it some harmless characters as insurance. After that, clear // the screen (0x0C), set the tall 1x16 font (0x03,0x02) and specify // text-style numbers (0x14). const prog_char clsSetBigFont[ ] PROGMEM = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, //reset insurance 0x0C,0x03,0x02,0x14,0x00 } ; // This instruction consists of ctrl-A, ctrl-R, and the // text number "6". Translation: 'Move to screen position 0, // then right-align the number that follows in a 6-character // field.' Starting at position 0 and moving backward with ctrl-R // causes the text to align to the righthand end of the screen. const prog_char setPosRightAlign[ ] PROGMEM = { 0x01,0x12,0x36,0x00} ; // Instruction ESC d 7, sets up redefinition of // custom character 15 (ASCII 143). The eight bytes sent // after this instruction define the character bitmap. const prog_char defineCC[ ] PROGMEM = { 0x1B,0x64,0x37,0x00} ; // Main-count variable: 0-65535 unsigned int odoCount = 1024 ; // RAM buffer for strings used by serial output, which can't // directly access strings stored in program memory with PROGMEM. char buffer[15] ; // Define a new serial port using the pin definitions above. // Using inverted serial; if Spol is cut, change to noninverted. SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin, inverted); // SETUP: // Initialize the serial output, send some bytes to complete a // pending instruction, clear the screen and set the font, then // print a label. void setup() { digitalWrite(txPin, LOW); // Stop bit state for inverted serial pinMode(txPin, OUTPUT); // set the data rate for the SoftwareSerial port mySerial.begin(9600); // give the GLO ample time to start up delay(500); strcpy_P(buffer, clsSetBigFont); mySerial.print(buffer) ; mySerial.print("Odometer:") ; } // LOOP: // Print the main count, invoke the function that updates the // rolling custom-character pattern, and update the main count // when the final digit rolls over. void loop() { // right align at the end of the display strcpy_P(buffer, setPosRightAlign); mySerial.print(buffer); // print the main count mySerial.print(odoCount) ; // now print the rolling final digit mySerial.write(odoChar) ; // roll up the last digit, and if it has // rolled over to 0, increment main count if (incOdoChar() == 0) { odoCount++ ; } delay(25) ; } // incOdoChar() // Moves a pointer (odoIndex) through the digitPattern[] // array to redefine the odo-digit custom character. // This causes the "0" bitmap to scroll up row-by-pixel- // row to be replaced by the "1" bitmap, which scrolls up... // Function returns the index value; when this rolls over // to zero, the odoCount value should increment, just like // a real mechanical odometer. byte incOdoChar() { static byte odoIndex = 0 ; // send the instruction to redefine custom character strcpy_P(buffer, defineCC); mySerial.print(buffer); // send the eight-byte bitmap of the new CC pattern for (int i=0; i < 8; i++) { //retrieve the next byte from the flash/program memory table //and write it to the serial output mySerial.write(pgm_read_byte(&digitPatterns[(i+odoIndex)%80])); } // increment for next time-- %80 to restrict // to 0-79 (valid index range of digitPatterns[]) odoIndex = ++odoIndex%80 ; // return index to signal rollover (0) return odoIndex ; }
Nice poject, but what is it do.
ReplyDeleteArduino
Thanks. Program shows how to communicate with the GLO-216 from an Arduino, how to define a custom character, and how to use a custom character to create an animated effect. And it shows off the bright, hi-contrast OLED in one of its four font sizes (unlike LCDs, it can make seamless characters from 2 lines by 16 to 1 line by 8 (1x16 shown).
ReplyDeleteOther than that, nothing much :)