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