The clock program is minimal. All I did was take the excellent Engblaze timer/interrupt framework and drop in functions to keep time and do the serial stuff to drive the display. What may be of interest to Arduino programmers is the way that I organized the time values: Rather than declare separate variables to hold the hours, minutes and seconds, I used a single char array.
Since a char array that ends with null/zero in the last position is also a string for the purposes of Arduino serial routines, this approach allowed me to avoid the typical Arduino bugaboo of needing multiple serial "print" instructions to print a list of variables.
/* Simple Clock Demo for GLO-216Y/G A tutorial at engblaze.com shows how to set up AVR timers to fire an interrupt at regular intervals--in this case 1.0000 second. The engblaze program toggles an LED every second. This version, for the Arduino Uno, runs a 24-hour clock and shows the time on a GLO-216Y/G serial OLED display. =Program is written for GLO-216Y/G with intact Spol jumper (inverted serial). Connect GLO SER to Arduino pin 3; power to +5 and GND. */ // avr-libc library includes for timer ISR #include <avr/io.h> #include <avr/interrupt.h> // Software Serial Stuff // #include <SoftwareSerial.h> #define rxPin 255 // Not used, set to invalid # #define txPin 3 // GLO input to this Arduino pin #define inverted 1 // If GLO-216 Spol jumper is intact // Instructions sent to GLO-216Y/G at startup. // 0x0c = clear the screen. // 0x03,0x02,0x02,0x02 = Set big font. // 0x19 = Use the 7-segment number font. char const gloSetup[] = { 0x0c,0x03,0x02,0x02,0x02,0x13,0x00 } ; // Dual-use char-array string ========================== // As an array, it stores the digits of the time // hh mm ss. Functions below increment the digits as // appropriate for their units (0-59 for minutes and // seconds, 0-23 for hours). Digits are stored as // ASCII characters rather than raw values, allowing for // the string to be printed without further processing. // In addition to the digits, the string also contains // a pair of ':' characters, and starts with the GLO // home-cursor instruction 0x01. Packing the digits, // colons and formatting instruction together in one // string allows the time to be updated in one "print." char hmsTime[10] = { 0x01, '1','2',':','4','1',':','5','0',0x00} ; // Defining names for the digit positions in the // time string makes it easier to read the functions // that increment the time #define sOnes 8 // Ones digit of seconds. #define sTens 7 // Tens digit of seconds. #define msColon 6 // ':' between minutes and seconds. #define mOnes 5 // Ones digit of minutes. #define mTens 4 // Tens digit of minutes. #define hmColon 3 // ':' between hours and minutes. #define hOnes 2 // Ones digit of hours. #define hTens 1 // Tens digit of hours. // Establish a soft serial port using the pin definitions above. SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin, inverted); // Set up the Soft Serial output and send the GLO its setup // instructions. Then, using code copied from engblaze.com, // set up a timer to fire an ISR at precise 1-second intervals. void setup() { digitalWrite(txPin, LOW); // Stop bit state pinMode(txPin, OUTPUT); mySerial.begin(9600); delay(500); mySerial.print(gloSetup); // initialize Timer1 cli(); // disable global interrupts TCCR1A = 0; // set entire TCCR1A register to 0 TCCR1B = 0; // same for TCCR1B // set compare match register to desired timer count: OCR1A = 15624; // turn on CTC mode: TCCR1B |= (1 << WGM12); // Set CS10 and CS12 bits for 1024 prescaler: TCCR1B |= (1 << CS10); TCCR1B |= (1 << CS12); // enable timer compare interrupt: TIMSK1 |= (1 << OCIE1A); // enable global interrupts: sei(); } // Nothing in the loop. All the action is in the ISR. void loop() { // Put your code here. } // Timer fires this ISR every second. ISR(TIMER1_COMPA_vect) { mySerial.print(hmsTime); // print the string. incSeconds() ; // update for next time. } // Timekeeping routines ======================= // The digits of the hours, minutes and // second are stored as characters in a char- // array string. Since the only math needed is // increment (and carry-the-one), it's efficient // to just work with the chars rather than // regular integers (or bytes, etc.). // ============================================ //Increment seconds. If seconds value exceeds //59, increment minutes. void incSeconds() { hmsTime[sOnes] += 1 ; if (hmsTime[sOnes] > '9') { hmsTime[sOnes] = '0' ; hmsTime[sTens] += 1 ; if (hmsTime[sTens] > '5') { hmsTime[sTens] = '0' ; incMinutes(); } } } //Increment minutes. If minutes value exceeds //59, increment hours. void incMinutes() { hmsTime[mOnes] += 1 ; if (hmsTime[mOnes] > '9') { hmsTime[mOnes] = '0' ; hmsTime[mTens] += 1 ; if (hmsTime[mTens] > '5') { hmsTime[mTens] = '0' ; incHours() ; } } } //Increment hours. If hours value exceeds //23, rollover to 0. void incHours() { if (hmsTime[hTens] == '2' && hmsTime[hOnes] == '3') { hmsTime[hOnes] = '0' ; hmsTime[hTens] = '0' ; } else { hmsTime[hOnes] += 1 ; if (hmsTime[hOnes] > '9') { hmsTime[hOnes] = '0' ; hmsTime[hTens] += 1 ; } } }
Arduino-compatible serial OLED: $39 at seetron. |
No comments:
Post a Comment