MSP430 - 24hr Clock with Calendar

I was postponing this post until I got a chance to acquire and test a 2x20 3V LCD.

I have not gotten one as yet so the test will have to wait.

I wanted the display to show the date and time like this:



However, when Wednesday comes around, I need 18 characters across, hence the need for a 2x20 display.


The Calendar


The tricky part with all computerized calendars is how to determine leap years. We have been taught that a leap year occurs every four years. That is a simple approximation if we assume that the earth takes 365.25 days to make one complete orbit around the sun.

In reality, the earth takes slightly less than 365.25 days, more like 365.242196 days to make a year. Hence making every 4th year a leap year is over compensation.

To correct for this, every 100 years we make an exception and not make it a leap year. Hence the years 2100, 2200, 2300 are not leap years.

Aha! Now we have over compensated the first compensation. So we make every 400 years a leap year. So years 2000, 2400, 2800 are leap years.

Are you still with me?

We put all of this into a function IsLeapYear( ) which returns a boolean TRUE if the specified year is a leap year. I think we're good for 10,000 years!

The rest of the program simply displays the date, weekday and time on the screen.

Code:
//************************************************
// MSP430G2553 Clock/Calendar
//************************************************

/*-------------------------------------------------
2013.07.23 - MrChips
     
Notes: LCD E has been changed from P2.6 to P1.6
--------------------------------------------------*/

#include "io430.h"

//---------------------------------------------------
// Global Variables
//---------------------------------------------------

short Year, Month, Day, Weekday;
short Hour, Minute, Second;
short DaysThisMonth;

char Months[13][4] = { " ", "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
                        "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};

char Days[8][12] = {" ", "SUNDAY ", "MONDAY ", "TUESDAY ",
                     "WEDNESDAY ", "THURSDAY", "FRIDAY ", "SATURDAY "};

short DaysInMonth[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

//---------------------------------------------------
// Defines
//---------------------------------------------------

#define title1 "MrChips Clock"
#define title2 "Version 1.00"

#define TRUE 1
#define FALSE 0
#define ON 1
#define OFF 0

#define LED1 P1OUT_bit.P0

// ASCII codes

#define SP 32
#define COLON 58

//---------------------------------------------------
// Function Prototypes
//---------------------------------------------------

short DaysInThisMonth(short year, short month);

//---------------------------------------------------
// LCD Interface
//---------------------------------------------------

void LCD_init(void);
void LCD_ready(void);
void LCD_ir(char ch);
void LCD_dr(char ch);
void LCD_txt(char *s);
void LCD_Home(void);
void LCD_Clear(void);
void LCD_Line1(void);
void LCD_Line2(void);
void LCD_Line3(void);
void LCD_Line4(void);
void LCD_Posn(char n);

// define LCD interface on PORT2
#define LCD_OUT P2OUT
#define LCD_IN P2IN
#define LCD_DDR P2DIR
#define LCD_RS P2OUT_bit.P4
#define LCD_RW P2OUT_bit.P5
#define LCD_E P1OUT_bit.P6

void LCD_init(void)
{
  LCD_ir(0x28); // dual line, 4 bits
  LCD_ir(0x06); // increment mode
  LCD_ir(0x0C); // cursor turned off
  LCD_ir(0x10); // cursor right
  LCD_ir(0x01); // clear display
}

void LCD_Clear(void)
{
  LCD_ir(0x01);
}

void LCD_Home(void)
{
  LCD_ir(0x02);
}

void LCD_Line1(void)
{
  unsigned char i;
  LCD_ir(0x80);
  for (i = 0; i < 16; i++)
  {
    LCD_dr(SP);
  }
  LCD_ir(0x80);
}

void LCD_Line2(void)
{
  unsigned char i;
  LCD_ir(0xC0);
  for (i = 0; i < 16; i++)
  {
    LCD_dr(SP);
  }
  LCD_ir(0xC0);
}

void LCD_Line3(void)
{
  LCD_ir(0x94);
}

void LCD_Line4(void)
{
  LCD_ir(0xD4);
}

void LCD_Posn(char n)
// direct positioning where n = 0-79
{
  char ch;
  ch = n;
  if (ch >= 40) ch += 24;
  LCD_ir(ch | 0x80);
}

void LCD_ready(void)
{
  char busy;
  LCD_DDR = 0x30;
  LCD_RW = 1;
  LCD_RS = 0;
  do
  {
    LCD_E = 1;
    // high 4 bits read first
    // busy flag is D7 of LCD = bit 3 of P2IN
    busy = (LCD_IN & 0x08);
    LCD_E = 0;
    LCD_E = 1;
    LCD_E = 0;
  } while (busy);
  LCD_OUT = 0;
  LCD_DDR = 0x3F;
}

void LCD_ir(char ch)
{
  LCD_ready();
  //LCD_RS = 0; // not needed // select instruction register
  //LCD_RW = 0; // not needed
  LCD_OUT |= ((ch >> 4) & 0x0F);
  LCD_E = 1;
  LCD_E = 0;
  LCD_OUT = 0;
  LCD_OUT |= (ch & 0x0F);
  LCD_E = 1;
  LCD_E = 0;
}

void LCD_dr(char ch)
{
  LCD_ready();
  LCD_RS = 1; // select data register
  //LCD_RW = 0; // not needed
  LCD_OUT |= ((ch >> 4) & 0x0F);
  LCD_E = 1;
  LCD_E = 0;
  LCD_OUT = 0;
  LCD_RS = 1;
  LCD_OUT |= (ch & 0x0F);
  LCD_E = 1;
  LCD_E = 0;
}

void LCD_txt(char *s)
{
  while(*s) LCD_dr(*s++);
}

void LCD_bcd5(short n)
  // display 5 digits
{
  short i;
  short d[5];
  for (i = 0; i < 5; i++)
  {
    d[i] = n % 10;
    n = n / 10;
  }
  for (i = 0; i < 5; i++)
  {
    LCD_dr('0' + d[4-i]);
  }
}

void LCD_bcd2(short n)
// display two digits
{
  LCD_dr('0' + n / 10);
  LCD_dr('0' + n % 10);
}

//---------------------------------------------------
// Date & Time Display
//---------------------------------------------------

void ShowDate(void)
{
  LCD_Line1();
  LCD_bcd5(Year);
  LCD_dr(SP);
  LCD_txt(Months[Month]);
  LCD_dr(SP);
  LCD_bcd2(Day);
  LCD_dr(SP);
}

void ShowTime(void)
{
  LCD_Line2();
  LCD_txt(Days[Weekday]);
  LCD_Posn(48);
  LCD_bcd2(Hour);
  LCD_dr(COLON);
  LCD_bcd2(Minute);
  LCD_dr(COLON);
  LCD_bcd2(Second);
}

//---------------------------------------------------
// Hardware Initialization
//---------------------------------------------------

void init(void)
{
   // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
  
    // Set up 32768Hz crystal
  BCSCTL1 |= DIVA_3; // divide by 8
  BCSCTL3 |= XCAP_3; // select 12pF caps

  P1DIR = 0xFF; // configure output ports
  P1OUT = 0x00;
  
  P2DIR = 0x3F;
  P2OUT = 0x00;
  
  // initialize Timer0_A
  TA0CCR0 = 511; // set up terminal count
  TA0CTL = TASSEL_1 + ID_3 + MC_1; // configure and start timer

  // enable interrupts
  TA0CCTL0_bit.CCIE = 1; // enable timer interrupts
  __enable_interrupt(); // set GIE in SR
}

#pragma vector = TIMER0_A0_VECTOR
__interrupt void myTimerISR(void)
{
  if (++Second >= 60)
  { // next mimute
    Second = 0;
    if (++Minute >= 60)
    { // next hour
      Minute = 0;
      if (++Hour >=24)
      { // next day
        Hour = 0;
        if (++Weekday > 7) Weekday = 1;
        if (++Day > DaysThisMonth)
        { // next month
          Day = 1;
          ++Month;
          DaysThisMonth = DaysInThisMonth(Year, Month);
          if (Month > 12)
           { // new year
             ++Year;
             Month = 1;
             DaysThisMonth = 31;  // January
           } // new year
        } // next month
      } // next day
    } // next hour
  } // next minute
  ShowDate();
  ShowTime();
}

//-----------------------------------
// Calendar
//-----------------------------------

void init_Date_Time(void)
{
  Year = 2013;
  Month = 7;
  Day = 23;
  Weekday = 3; // Sunday = 1
  
  Hour = 21;
  Minute = 59;
  Second = 0;
  
  DaysThisMonth = DaysInThisMonth(Year, Month);
}

short IsLeapYear(short thisyear)
// is thisyear a leap year?
{
  short result;
  result = FALSE;
  if ( (thisyear % 1000) == 0 )
  { // millenium
    result = ((thisyear / 1000) % 2) == 0;
  } // millenium
  else
  { // not millenium
    if ( (thisyear % 400) == 0)
    { // every 400 years
      result = TRUE;
    } // every 400 years
    else
    { // not 400 years
      if ( (thisyear % 100) == 0)
      { // every 100 years
        result = FALSE;
      } // every 100 years
      else
      { // not 100 years
        if ( (thisyear % 4) == 0)
        { // every 4 years
          result = TRUE;
        } // every 4 years
      } // not 100 years
    } // not 400 years
  } // not millenium
  return result;
}

short DaysInThisMonth(short year, short month)
// how many days in year, month
{
  short days;
  days = 28;
  if (month == 2)
  { // February
    if ( IsLeapYear(year) ) days = 29;
  } // February
  else
  { // Not February
    days = DaysInMonth[month];
  } // Not February
  return days;
}

//-----------------------------------
// Main
//-----------------------------------

void main(void)
{
  init();
  init_Date_Time();
  LCD_init();
  
  LCD_txt(title1);
  LCD_Line2();
  LCD_txt(title2);
  
  // enter low power mode
  LPM3;
}

//-----------------------------------
// end of Main
//-----------------------------------
Notes:

1) The code will have to be modified once I get the 2x20 LCD.

Coming Next: Running on solar power

Blog entry information

Author
MrChips
Views
2,088
Comments
3
Last update

More entries in General

More entries from MrChips

Share this entry

Top