forked from luon/wordclock
488 lines
14 KiB
C++
488 lines
14 KiB
C++
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <DS1302.h> // I use the library that Matt Sparks created
|
|
#include <avr/interrupt.h>
|
|
#include <avr/io.h>
|
|
|
|
// uncomment the following to speed up the timer for testing
|
|
//#define TESTMODE
|
|
|
|
// Insert function prototypes -- Paul
|
|
void ledsoff(void);
|
|
void setup(void);
|
|
void SWversion(void);
|
|
|
|
// specify the language - defines the header to be included
|
|
// available choices - English, Danish, French, German
|
|
//#define LANGUAGE "English.h"
|
|
#define LANGUAGE "Dutch.h"
|
|
|
|
|
|
/**************************************************************************
|
|
* *
|
|
* W O R D C L O C K - A clock that tells the time using words. *
|
|
* *
|
|
* Hardware: Arduino Dumelove with a set of individual LEDs under a word *
|
|
* stencil. *
|
|
* *
|
|
* Copyright (C) 2009 Doug Jackson (doug@doughq.com) *
|
|
* *
|
|
***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the Free Software *
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
|
|
* MA 02111-1307 USA *
|
|
* *
|
|
***************************************************************************
|
|
*
|
|
* Revision History
|
|
*
|
|
* Date By What
|
|
* 20010205 DRJ Initial Creation of Arduino Version
|
|
* - based on Wordclock.c - from PIC version
|
|
* 20100428 DRJ Added support for DS1302 RTC Chip - Code verifies
|
|
* device is present - and if so, uses it for timekeeping
|
|
* 20100511 DRJ Added ability to detect old vs new Arduino boards
|
|
* New board uses diferent time button sense.
|
|
* 20100511 DRJ Minute LED support on Analog5-1 pins.
|
|
* 20100927 DRJ Added brightness support by enabling interrupts and
|
|
* using an ISR to control the display
|
|
*/
|
|
|
|
|
|
|
|
// DAY Brightness setting 0 = off 20 = full
|
|
#define DAYBRIGHTNESS 20
|
|
// NIGHT Brightness setting 0 = off 20 = full
|
|
#define NIGHTBRIGHTNESS 15
|
|
|
|
|
|
|
|
//#define LED1 Led1=1
|
|
//#define LED2 Led2=1
|
|
//#define LED3 Led3=1
|
|
//#define LED4 Led4=1
|
|
|
|
|
|
|
|
#define INIT_TIMER_COUNT 6
|
|
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT
|
|
|
|
|
|
|
|
|
|
int hour=12, minute=0, second=00;
|
|
static unsigned long msTick =0; // the number of Millisecond Ticks since we last
|
|
// incremented the second counter
|
|
int count;
|
|
int selftestmode; // 1 = in self test - flash display
|
|
int DS1302Present=0; // flag to indicate that the 1302 is there.. 1 = present
|
|
char Display1=0, Display2=0, Display3=0, Led1=0, Led2=0, Led3=0, Led4=0;
|
|
int OldHardware = 0; // 1 = we are running on old hardware
|
|
int BTNActive = 1; // the sense of the button inputs (Changes based on hardware type)
|
|
int timercount=10; // used for interrupt counting to determine the brightnes of the display
|
|
|
|
// hardware constants
|
|
int LEDClockPin=5; // Arduino Pin#11 - 4094 Pin 3 clock
|
|
int LEDDataPin=3; // Arduino Pin#5 - 4094 pin 2 Data
|
|
int LEDStrobePin=4; // Arduino Pin#6 - 4094 pin 1 Strobe
|
|
|
|
// buttons
|
|
int FWDButtonPin=6;
|
|
int REVButtonPin=7;
|
|
|
|
// 1302 RTC Constants
|
|
int DS1302IOPin=10;
|
|
int DS1302CEPin=8;
|
|
int DS1302CLKPin=9;
|
|
|
|
// Minute LED Pins
|
|
int LED1PIN=19; // Arduino analog 5
|
|
int LED2PIN=18; // Arduino analog 4
|
|
int LED3PIN=17; // Arduino analog 3
|
|
int LED4PIN=16; // Arduino analog 2
|
|
|
|
int current_brightnes=0;
|
|
|
|
|
|
// define the language to be used for this project:
|
|
#include LANGUAGE // The language pack
|
|
|
|
|
|
|
|
/* Create buffers */
|
|
char buf[50]; // time output string for debugging
|
|
|
|
|
|
// create an object that talks to the RTC
|
|
DS1302 rtc(DS1302CEPin, DS1302IOPin, DS1302CLKPin);
|
|
|
|
void print_DS1302time()
|
|
{
|
|
/* Get the current time and date from the chip */
|
|
Time t = rtc.time();
|
|
|
|
/* Format the time and date and insert into the temporary buffer */
|
|
snprintf(buf, sizeof(buf), "DS1302 time: %02d:%02d:%02d",
|
|
t.hr, t.min, t.sec);
|
|
|
|
/* Print the formatted string to serial so we can see the time */
|
|
Serial.println(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setup()
|
|
{
|
|
// initialise the hardware
|
|
// initialize the appropriate pins as outputs:
|
|
pinMode(LEDClockPin, OUTPUT);
|
|
pinMode(LEDDataPin, OUTPUT);
|
|
pinMode(LEDStrobePin, OUTPUT);
|
|
pinMode(FWDButtonPin, INPUT);
|
|
pinMode(REVButtonPin, INPUT);
|
|
|
|
// setup 1302
|
|
pinMode(DS1302IOPin, OUTPUT);
|
|
pinMode(DS1302CEPin, OUTPUT);
|
|
pinMode(DS1302CLKPin, OUTPUT);
|
|
|
|
// Minute LEDS
|
|
pinMode(LED1PIN, OUTPUT);
|
|
pinMode(LED2PIN, OUTPUT);
|
|
pinMode(LED3PIN, OUTPUT);
|
|
pinMode(LED4PIN, OUTPUT);
|
|
|
|
current_brightnes=DAYBRIGHTNESS;
|
|
|
|
|
|
Serial.begin(9600); // setup the serial port to 9600 baud
|
|
SWversion(); // Display the version number of the software
|
|
|
|
// test whether the DS1302 is there
|
|
Serial.print("Verifying DS1302 ");
|
|
// start by verifying that the chip has a valid signature
|
|
if (rtc.read_register(0x20) == 0xa5) {
|
|
// Signature is there - set the present flag and mmove on
|
|
DS1302Present=1;
|
|
Serial.println("present - Valid Signature");
|
|
rtc.write_protect(false);
|
|
rtc.halt(false);
|
|
}
|
|
else
|
|
{
|
|
// Signature isnt there - may be a new chip -
|
|
// do a write to see if it will hold the signature
|
|
rtc.write_register(0x20,0xa5);
|
|
if (rtc.read_register(0x20) == 0xa5) {
|
|
// We can store data - assume that it is a new chip that needs initialisation
|
|
// Start by turning off write protection and clearing the clock halt flag.
|
|
rtc.write_protect(false);
|
|
rtc.halt(false);
|
|
// Make a new time object to set the date and time
|
|
Time t(2010, 04, 28, 10, 19, 00, 01);
|
|
// Set the time and date on the chip
|
|
rtc.time(t);
|
|
// set the DS1302 present flag
|
|
DS1302Present=1;
|
|
Serial.println("present - new chip initialised.");
|
|
}
|
|
else Serial.println("absent");
|
|
}
|
|
|
|
// determine whether we are running on old or new hardware
|
|
// old hardware tied the push buttons to ground using 4k7 resistors
|
|
// and relied on the buttons to pull them high
|
|
// new hardware uses internal pullups, and uses the buttons
|
|
// to pull the inputs down.
|
|
|
|
digitalWrite(FWDButtonPin,HIGH); // Turn on weak pullups
|
|
digitalWrite(REVButtonPin,HIGH); // Turn on weak pullups
|
|
|
|
OldHardware=0;
|
|
if ( digitalRead(FWDButtonPin)==0 && digitalRead(REVButtonPin)==0)
|
|
{
|
|
Serial.println("Detected Old Hardware");
|
|
OldHardware=1; // we have old hardware
|
|
BTNActive = 1; // True = active for old hardware
|
|
digitalWrite(FWDButtonPin,LOW); // Turn off weak pullups
|
|
digitalWrite(REVButtonPin,LOW); // Turn off weak pullups
|
|
|
|
}
|
|
else
|
|
{
|
|
Serial.println("Detected New Hardware");
|
|
OldHardware=0; // we have old hardware
|
|
BTNActive = 0; // True = active for old hardware
|
|
}
|
|
|
|
|
|
// Initialise Timer2: Timer Prescaler /64,
|
|
TCCR2A = 0;
|
|
TCCR2B |= (1<<CS22);
|
|
TCCR2B &= ~((1<<CS21) | (1<<CS20));
|
|
// Use normal mode
|
|
TCCR2B &= ~((1<<WGM21) | (1<<WGM20));
|
|
// Use internal clock - external clock not used in Arduino
|
|
ASSR |= (0<<AS2);
|
|
//Timer2 Overflow Interrupt Enable
|
|
TIMSK2 |= 1<<TOIE2;
|
|
RESET_TIMER2;
|
|
sei();
|
|
|
|
Serial.println("Finished setting up Timer2 Interrupt");
|
|
|
|
|
|
msTick=millis(); // Initialise the msTick counter
|
|
|
|
selftest(); // validate the hardware for the user
|
|
|
|
selftestmode=0;
|
|
|
|
if (DS1302Present==1) {
|
|
// Get the current time and date from the chip
|
|
Time t = rtc.time();
|
|
second=t.sec;
|
|
minute=t.min;
|
|
hour=t.hr;
|
|
}
|
|
|
|
displaytime(); // display the current time
|
|
}
|
|
|
|
|
|
// Interrupt handler - Arduino runs at 16 Mhz, so we have 1000 Overflows per second...
|
|
// 1/ ((16000000 / 64) / 256) = 1 / 1000
|
|
ISR(TIMER2_OVF_vect) {
|
|
RESET_TIMER2;
|
|
|
|
if (timercount-- <= current_brightnes){
|
|
// Now we write the actual values to the hardware
|
|
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display3);
|
|
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display2);
|
|
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display1);
|
|
digitalWrite(LEDStrobePin,HIGH);
|
|
//delay(2);
|
|
digitalWrite(LEDStrobePin,LOW);
|
|
digitalWrite(LED1PIN,Led1);
|
|
digitalWrite(LED2PIN,Led2);
|
|
digitalWrite(LED3PIN,Led3);
|
|
digitalWrite(LED4PIN,Led4);
|
|
}
|
|
else
|
|
{
|
|
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, 0);
|
|
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, 0);
|
|
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, 0);
|
|
digitalWrite(LEDStrobePin,HIGH);
|
|
//delay(2);
|
|
digitalWrite(LEDStrobePin,LOW);
|
|
digitalWrite(LED1PIN,0);
|
|
digitalWrite(LED2PIN,0);
|
|
digitalWrite(LED3PIN,0);
|
|
digitalWrite(LED4PIN,0);
|
|
|
|
}
|
|
if (timercount==0) timercount=20;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void ledsoff(void) {
|
|
Display1=0;
|
|
Display2=0;
|
|
Display3=0;
|
|
Led1=0;
|
|
Led2=0;
|
|
Led3=0;
|
|
Led4=0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void incrementtime(void){
|
|
// increment the time counters keeping care to rollover as required
|
|
second=0;
|
|
if (++minute >= 60) {
|
|
minute=0;
|
|
if (++hour == 25) {
|
|
hour=1;
|
|
}
|
|
}
|
|
// debug outputs
|
|
Serial.println();
|
|
if (DS1302Present==1) print_DS1302time();
|
|
else Serial.print("Arduino Time: " );
|
|
Serial.print(hour);
|
|
Serial.print(":");
|
|
Serial.print(minute);
|
|
Serial.print(":");
|
|
Serial.print(second);
|
|
Serial.print(" ");
|
|
|
|
}
|
|
|
|
|
|
void SWversion(void) {
|
|
delay(2000);
|
|
Serial.println();
|
|
Serial.println("Wordclock -Arduino v3.0a - reduced brightness version");
|
|
Serial.print(LANGUAGE); Serial.println(" header file used");
|
|
Serial.println("(c)2009, 2010, 2011 Doug Jackson");
|
|
}
|
|
|
|
|
|
void loop(void)
|
|
{
|
|
|
|
#ifdef TESTMODE
|
|
second=59;
|
|
#endif
|
|
|
|
//Serial.println("Loop Started");
|
|
|
|
// heart of the timer - keep looking at the millisecond timer on the Arduino
|
|
// and increment the seconds counter every 1000 ms
|
|
if ( millis() - msTick >999) {
|
|
msTick=millis();
|
|
second++;
|
|
// Flash the onboard Pin13 Led so we know something is hapening!
|
|
digitalWrite(13,HIGH);
|
|
delay(50);
|
|
digitalWrite(13,LOW);
|
|
delay(50);
|
|
digitalWrite(13,HIGH);
|
|
delay(50);
|
|
digitalWrite(13,LOW);
|
|
|
|
#ifndef TESTMODE
|
|
if (second%5==0) {
|
|
Serial.print(second);
|
|
Serial.print("..");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
//test to see if we need to increment the time counters
|
|
if (second==60)
|
|
{
|
|
incrementtime();
|
|
displaytime();
|
|
}
|
|
|
|
if (DS1302Present==1) {
|
|
// Get the current time and date from the chip
|
|
Time t = rtc.time();
|
|
second=t.sec;
|
|
minute=t.min;
|
|
hour=t.hr;
|
|
}
|
|
|
|
// set the brightnes level based on the current hour - night=7pm - 6.59am
|
|
//
|
|
if ((hour <7) | (hour >=19))
|
|
current_brightnes=NIGHTBRIGHTNESS;
|
|
else
|
|
current_brightnes=DAYBRIGHTNESS;
|
|
|
|
|
|
// test to see if both buttons are being held down
|
|
// if so - start a self test till both buttons are held
|
|
// down again.
|
|
if ( digitalRead(FWDButtonPin)==BTNActive && digitalRead(REVButtonPin)==BTNActive)
|
|
{
|
|
selftestmode = !selftestmode;
|
|
if (selftestmode) Serial.println("Selftest Mode TRUE");
|
|
else Serial.println("Selftest mode FALSE");
|
|
}
|
|
|
|
if (selftestmode) {
|
|
for(int i=0; i<100; i++)
|
|
{
|
|
Display1=255; Display2=255; Display3=255; delay(101-i);
|
|
ledsoff();delay(101-i);
|
|
if (digitalRead(FWDButtonPin)==1) selftestmode=!selftestmode;
|
|
|
|
}
|
|
displaytime();
|
|
|
|
}
|
|
|
|
|
|
// test to see if a forward button is being held down
|
|
// for time setting
|
|
if (digitalRead(FWDButtonPin) ==BTNActive )
|
|
// the forward button is down
|
|
// and it has been more than one second since we
|
|
// last looked
|
|
|
|
{
|
|
Serial.println("Forward Button Down");
|
|
incrementtime();
|
|
second++; // Increment the second counter to ensure that the name
|
|
// flash doesnt happen when setting time
|
|
if (DS1302Present==1) {
|
|
// Make a new time object to set the date and time
|
|
Time t(2010, 04, 28, hour, minute, second, 01);
|
|
// Set the time and date on the chip
|
|
rtc.time(t);
|
|
}
|
|
delay(100);
|
|
displaytime();
|
|
}
|
|
|
|
// test to see if the back button is being held down
|
|
// for time setting
|
|
if (digitalRead(REVButtonPin)==BTNActive )
|
|
{
|
|
|
|
Serial.println("Backwards Button Down");
|
|
minute--;
|
|
minute--;
|
|
second=0; // decrement the minute counter
|
|
if (minute<0) {
|
|
minute=58;
|
|
if (--hour <0) hour=23;
|
|
}
|
|
incrementtime();
|
|
second++; // Increment the second counter to ensure that the name
|
|
// flash doesnt happen when setting time
|
|
|
|
|
|
if (DS1302Present==1) {
|
|
// Make a new time object to set the date and time
|
|
Time t(2010, 04, 28, hour, minute, second, 01);
|
|
// Set the time and date on the chip
|
|
rtc.time(t);
|
|
}
|
|
|
|
displaytime();
|
|
delay(100);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|