Time of Day Clock with 60 Alarms and PWM Sequence Output

Submitted by Ed_B on Mon, 02/14/2011 - 13:50

Printer-friendly versionPrinter-friendly version

The so-far-unnamed-project is moving forward. See here and here and here for the rest of the story. The time of day clock now prints onto a serial-input Vaccum Flourescent Display. The clock has up to 60 alarms. All of the alarms fire off a function called runTask(). In the previous version of the code, each alarm task could be tied to a uinque function call. It turns out that the  so-far-unnamed-project only needs one task. The alarm setpoints are held in a header file, also called an include file, which will probably be generated by a Processing app when the arduino stuff is done. The runTask() function requires an array containing about 2000 pwm values. These values live in a header file called performanceData.h. I was very surprised to learn that a user's .h files could not be included at the top of the arduino sketch. It's a long saga, but in short, it's an IDE bug. I wound up making an arduino library to get around the problem. In a library, the .h with the same name as the library, can referece other .h files included by the user. There seem to be programming issues with what you can put in the files (why?), but constant variables will work. The constant arrays are stored in program memory using the PROGMEM macro. This avoids chewing up all the RAM and crashing the AVR chip.

CLICK READ MORE TO SEE THE REST OF THE POST

Here are the files. The .pde file is the normal Arduino sketch. The other files are in
/home/myhome/sketchbook/libraries/performanceTimes/

 

// LEDtimer4.pde -- steps toward an RTC based low power timer controller. 
// by Ed Bennett, 2011

#include <avr/sleep.h>
#include <string.h>

#include <performanceTimes.h>

#define RUN           1
#define FINISHED      0


//array indexes for performanceTimes
#define SECONDS  2
#define MINUTES  1
#define HOURS    0

// time of day
char seconds;
char minutes;
char hours;

// alarm times; also if taskHours == 255, reset task list counter
char taskHours;
char taskMinutes;
char taskSeconds;

int task_flag;

int led1val;
int LED1 = 7;
int led2val;
int LED2 = 6;

int performanceTimesIdx;

void setup(){

  pinMode(LED1, OUTPUT);  
  pinMode(LED2, OUTPUT);
  Serial.begin(9600);  
  Serial.println("");

  setTime();

  rtc_init();  //initialise the timer
  sei();

  set_sleep_mode(SLEEP_MODE_PWR_SAVE); 

}


void runTask(void){ 
/*
  // blinky test
  for(int i=1; i<50; i++){
   
   led2val ^= 1;
   digitalWrite(LED2, led2val);
   delay(100);
  } 
*/

  for (word index = 0; index<=loopPoint; index ++) {
    char temp = pgm_read_byte(&performanceData[index]);
    analogWrite (LED2, temp);
    delay (res); 
  }
}


void loop(){

  if(task_flag == RUN){
    task_flag = FINISHED; // clearing here allows continous retriggering
    runTask();
  }
  gnight();
}

void rtc_init(void)
{  
  TCCR2A = 0x00;  //overflow
  TCCR2B = 0x05;  //5 gives 1 sec. prescale 
  TIMSK2 = 0x01;  //enable timer2A overflow interrupt
  ASSR  = 0x20;   //enable asynchronous mode
}

//set the clock to the time of day based on compile time
void setTime(void){  
  char CompileTime[9];
  char tmpString[3];


  strncpy(CompileTime,__TIME__,8);

  tmpString[0] = CompileTime[0];
  tmpString[1] = CompileTime[1];
  hours=atoi(tmpString); // automatic promotion to int,
                         // demotion to char 

  tmpString[0] = CompileTime[3];
  tmpString[1] = CompileTime[4];
  minutes=atoi(tmpString);

  tmpString[0] = CompileTime[6];
  tmpString[1] = CompileTime[7];
  seconds=atoi(tmpString);
}

void eval(void){  // THIS IS ACTUALLY PART OF THE ISR

  // blinky for testing
  digitalWrite(LED1, 1);

  if (++seconds==60)        //keep track of time, date, month, and year
  {
    seconds=0;
    if (++minutes==60) 
    {
      minutes=0;
      if (++hours==24)
      {
        hours=0;
      }
    }
  }

  printTime();

  // hours == 255 is a flag. 
  // if the performance time hours == 255, start the performance sequence over

  char perftimeHour = pgm_read_byte(&performanceTimes[performanceTimesIdx][HOURS]);
  if(perftimeHour == 255){  // end of performance flag
    performanceTimesIdx = 0; // reset to the beginning and read again
    perftimeHour = pgm_read_byte(&performanceTimes[performanceTimesIdx][HOURS]);
  }

  char perftimeMin = pgm_read_byte(&performanceTimes[performanceTimesIdx][MINUTES]);
  char perftimeSec = pgm_read_byte(&performanceTimes[performanceTimesIdx][SECONDS]);

  // if it's time to run, set the run flag
  if((perftimeHour == hours) &&
    (perftimeMin == minutes) &&
    (perftimeSec == seconds)){ 
    task_flag = RUN;  
    if(++performanceTimesIdx >59) performanceTimesIdx=0;
  }

  digitalWrite(LED1, 0); 
}


void printTime(void){
  Serial.println("");
  if(hours <10)  Serial.print(0);
  Serial.print((int)hours);
  Serial.print(":");  
  if(minutes <10) Serial.print(0);
  Serial.print((int)minutes);  
  Serial.print(":");  
  if(seconds <10) Serial.print(0);
  Serial.print((int)seconds);
  delay(70); //MINIMUM buffer flush time
}

void gnight(void){

  digitalWrite(LED2, 0); // turn off White LED
  sleep_enable(); 
  sleep_mode();
  sleep_disable();
}

ISR(TIMER2_OVF_vect)
{
  eval();
}

This header file contains approximately 2000 values. They will be fed into the PWM function, 
analogWrite() of the arduno.

 

// performanceData.h -- lookup table with lamp brightness 
// levels for output as pwm -- Kyle Evans 2011  

/*
Actually this is just an ordinary include file written in the form of an 
arduino library. It's included from the library's cpp file as a hack to get
around an arduino IDE bug. The IDE keeps "userInclude.h" files from actually 
being included in the build. It says the files don't exist, even when
they're in th same folder as the pde file. Grrrr.
*/
 

const int res = 60;
const int loopPoint = 1988;


const char performanceData[]PROGMEM={
 30,12,15,36,20,9,4,0,0,0,0,1,8,18,35,24,51,43,38,13,19,44,45,49,19,35,27,16,8,16,36,38,18,3,0,0,12,2,27,38,16,5,23,7,1,3,3,3,0,0,0,0,6,4,23,23,3,21,2,11,14,8,4,4,5,4,0,0,0,0,0,0,0,0,0,0,0,0,11,46,28,5,2,6,16,7,15,16,2,0,0,0,0,0,1,5,3,1,0,0,0,0,0,1,3,7,5,1,0,0,1,23,15,6,2,17,6,4,1,11,14,2,13,12,5,3,1,0,1,5,6,1,0,1,0,0,8,52,57,51,6,1,0,1,0,0,0,0,0,0,0,0,1,3,3,3,3,5,4,3,1,3,2,1,1,0,0,0,0,4,0,0,1,4,1,0,0,0,0,0,0,0,0,0,0,6,4,2,22,29,32,35,23,32,22,12,15,11,17,8,4,5,0,2,7,8,20,7,6,3,15,27,23,22,10,6,0,1,0,5,7,1,6,2,1,0,1,10,1,4,1,1,9,7,2,2,7,12,13,14,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,2,4,5,0,0,0,1,0,0,1,0,0,7,5,2,0,1,1,2,6,0,0,2,5,6,23,32,30,27,20,20,8,4,3,7,7,4,1,0,1,2,0,0,0,0,0,0,1,1,1,3,7,4,2,1,1,3,7,6,5,3,9,2,2,1,0,3,4,3,1,1,0,2,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,2,5,1,0,0,0,0,0,0,1,0,0,4,5,7,4,8,17,31,15,7,2,12,5,3,20,30,23,8,9,6,8,22,26,31,12,6,3,16,27,23,25,10,1,0,0,0,0,0,0,3,10,12,9,3,5,1,0,0,0,0,0,1,1,4,3,0,1,1,0,0,0,0,1,0,4,2,1,1,0,0,0,2,0,0,0,0,0,0,0,0,1,3,1,1,1,0,0,0,0,5,13,4,0,12,34,36,24,20,16,9,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,2,1,0,2,2,8,15,4,5,23,27,20,23,21,14,8,3,28,30,31,23,10,11,6,14,6,12,10,8,0,0,2,21,40,9,3,16,5,0,0,0,4,3,5,2,1,1,14,2,0,1,1,13,9,1,16,21,11,23,21,11,15,7,0,0,3,5,10,32,45,34,28,21,4,1,1,4,7,3,5,41,50,44,15,8,5,1,0,0,0,0,0,0,0,0,0,0,0,1,2,36,8,12,12,2,2,2,16,20,2,3,5,4,3,2,0,0,0,0,3,1,0,3,6,1,2,5,4,5,8,4,9,8,7,2,3,2,8,42,51,57,48,35,30,19,5,0,15,20,10,5,17,25,14,16,5,1,10,19,1,6,4,7,2,14,37,14,1,3,17,9,2,1,0,1,1,1,1,0,0,0,0,0,0,0,0,2,0,0,0,0,2,17,14,14,4,6,13,3,1,0,0,19,51,53,49,38,14,16,13,8,2,0,0,9,21,20,19,17,7,2,1,1,3,0,0,1,1,0,0,0,0,0,2,7,7,13,3,6,3,3,24,24,24,22,14,9,4,1,0,5,10,2,7,15,9,3,5,3,3,4,7,3,2,1,22,15,5,3,1,9,26,29,22,10,2,2,4,4,1,1,4,5,6,2,1,3,1,0,0,6,12,7,27,40,30,35,33,25,23,10,7,5,2,3,4,2,8,32,30,2,0,0,0,3,0,20,40,48,47,10,3,0,0,0,0,1,1,0,0,0,0,1,1,1,4,0,0,2,1,3,7,6,4,4,0,0,0,0,6,6,6,6,13,7,10,12,10,3,2,1,4,0,0,0,5,3,4,3,1,8,33,1,1,11,2,0,5,8,34,45,34,19,16,17,17,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,1,0,0,3,0,0,0,2,0,0,0,4,9,12,8,7,5,10,7,8,0,3,2,0,0,0,0,1,2,7,2,3,4,1,3,13,7,5,5,1,1,1,0,0,0,7,6,2,1,1,2,1,12,3,0,0,1,3,20,25,11,0,1,2,9,22,28,23,17,16,8,7,24,7,0,0,0,0,0,7,28,32,26,22,21,16,8,6,6,5,10,10,5,4,16,16,8,3,2,1,1,1,0,0,0,0,0,2,1,0,0,0,0,0,0,4,7,4,1,13,15,5,3,21,6,0,2,4,8,8,4,3,6,20,18,26,36,24,5,1,5,7,1,1,4,13,15,16,13,2,1,2,6,4,6,3,4,13,7,4,10,18,30,3,1,3,13,6,2,9,29,17,35,37,30,5,0,0,0,0,6,2,1,5,0,0,0,0,2,0,1,30,37,35,14,6,7,3,14,12,9,9,10,14,17,4,5,3,2,3,0,0,0,1,4,6,6,1,0,1,2,2,25,11,18,30,8,9,52,48,7,13,11,3,1,3,3,2,0,0,4,2,21,59,37,10,7,31,20,18,2,16,23,40,33,4,24,27,14,8,8,5,2,3,1,1,1,14,33,27,14,1,3,2,1,3,1,0,1,2,5,43,38,27,29,4,55,41,28,24,13,3,25,33,43,34,45,21,19,19,22,14,4,3,6,4,3,15,32,41,14,4,2,0,16,13,10,343,4,3,1,5,5,2,0,0,0,0,32,56,37,6,40,51,55,61,53,27,7,1,1,0,0,0,0,0,0,1,4,0,0,0,0,0,9,10,4,4,1,1,0,0,0,16,44,22,12,3,48,38,22,9,3,4,40,12,33,36,18,15,4,1,2,1,3,2,1,0,0,0,0,0,0,5,6,13,10,1,0,3,2,0,2,15,26,40,59,21,3,42,46,44,14,20,2,3,48,44,11,8,6,1,1,2,0,0,0,0,0,0,0,0,0,0,16,16,18,48,24,31,36,17,7,4,17,20,30,28,9,8,3,29,12,27,20,11,9,1,1,0,3,1,0,0,1,1,0,0,0,0,0,0,0,0,3,2,1,1,2,2,34,31,13,41,10,15,15,11,32,49,44,6,0,1,5,2,0,0,0,13,34,7,12,18,3,8,25,30,27,49,7,8,24,49,5,23,16,11,24,20,15,8,9,5,26,25,5,2,5,0,24,24,19,0,0,0,0,0,0,0,2,13,12,8,17,13,14,11,29,2,5,45,44,10,9,8,2,8,3,3,2,1,0,0,1,0,0,0,0,0,0,0,1,2,1,5,1,0,2,4,20,45,25,27,40,26,11,17,18,12,7,30,19,15,23,7,7,33,3,34,16,0,16,31,22,6,8,20,31,5,1,24,21,40,39,16,2,14,3,1,11,2,4,8,19,1,51,29,3,10,7,11,3,2,21,4,15,15,43,23,9,6,4,6,2,4,7,1,0,0,0,3,15,5,1,0,0,0,0,0,0,0,0,3,37,30,39,22,11,6,36,36,38,4,0,2,11,38,4,28,32,7,10,11,5,9,5,25,35,26,9,8,9,0,4,10,19,0,5,20,11,2,0,0,0,1,2,2,5,30,14,1,12,16,8,2,6,6,4,39,13,29,25,12,26,16,5,7,5,0,7,9,0,0,0,0,1,0,9,15,0,8,7,7,3,5,13,5,1,0,0,0,0,1,3,1,1,2,19,15,7,2,12,12,0,0,10,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,4,4,2,3,7,10,5,3,2,1,5,5,2,2,0,0,1,1,2,0,0,0,1,3,4,3,6,3,1,2,1,0,0,0,1,4,2,1,3,5,3,1,1,1,1,1,2,2,5,45,35,7,21,40,10,7,1,4,36,20,9,3,2,6,37,49,48,14,42,10,3,8,9,1,8,14,6,2,3,33,37,32,24,4,1,22,27,6,7,3,8,39,50,16,41,9,4,9,15,13,1,0,0,0,2,1,3,3,3,2,1,2,2,1,1,3,0,1,0,1,0,0,5,20,25,9,21,17,6,4,5,9,21,32,19,2,1,2,5,3,2,0,2,8,3,1,4,17,11,34,37,34,26,11,3,2,1,0,2,1,1,0,0,0,1,1,1,0,1,1,1,2,8,6,5,4,2,0,6,19,10,5,2,1,10,38,46,45,35,19,3,2,0,0,6,2,1,2,
1,0,1,3,2,3,3,1,0,1,0
};




This header file is the main file in the performance times library. It contains the alarm times. 
They are stored in program memory.


// performanceTimes.h -- an arduino library. Ed Benett 2011 

// Lookup table with timer alarm values. Values should be in order
// with no gaps.

/*
Actually this is just an ordinary include file written in the form of an 
arduino library. It's included from the library's cpp file as a hack to get
around an arduino IDE bug. The IDE keeps "userInclude.h" files from actually 
being included in the build. It says the files don't exist, even when
they're in th same folder as the pde file. Grrrr.
*/
 
// hh,mm,ss  when hours == 255 means finished with peformances for the 
// night and the array index. Checking for 255 keeps the ISR from checking
// unassigned (empty) performance time members

#include <avr/pgmspace.h>
#include "performanceData.h" //the samples file

// array indexes are performanceTimes[sequence value][hh,mm,ss]
const char performanceTimes[60][3]PROGMEM={

11,13,0,

11,16,30,

11,19,0,

255,0,0,

255,0,0,

255,0,0,

255,0,0,

255,0,0,

255,0,0,

255,0,0,

255,0,0,

};


This is the actual library, as far as arduino is concered

// performanceTimes.cpp -- supports using include files in arduino

/*
Actually this is just an ordinary include file written in the form of an 
arduino library. It's included from the library's cpp file as a hack to get
around an arduino IDE bug. The IDE keeps "userInclude.h" files from actually 
being included in the build. It says the files don't exist, even when
they're in th same folder as the pde file. Grrrr.
*/

#include "performanceTimes.h"

// end of file