# 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 = { " ", "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};

char Days = {" ", "SUNDAY ", "MONDAY ", "TUESDAY ",
"WEDNESDAY ", "THURSDAY", "FRIDAY ", "SATURDAY "};

short DaysInMonth = { 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;
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

Author
MrChips
Views
2,088
Comments
3
Last update