Time Routine
This Demo shows how to use a time keeping routine, read a switch press and how long the switch is down.
Advance display handling, using the 74HC595.
Source code for project:
// MSP430G2231 RTC Clock
// and display on 7 segment displays via two 74hc595 shift registers
#include <msp430x20x2.h>
#include <io.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
// Led table: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, b, C, d, E, F, blank, -
char ledtable[18] = { 0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b, 0x77, 0x1f, 0x4e, 0x3d, 0x4f, 0x47, 0x00, 0x01 };
void Initializeports(void);
static void __inline__delay(register unsigned int n);
int binary2bcd16( unsigned char *bcd, int t ); // 16bit
int display_led(int t, int display);
void display_refresh( void );
// Time function varibles
volatile unsigned char days = 0, hours = 0, minutes = 0, seconds = 0, e_hours = 0, e_minutes = 0, e_seconds = 0;
volatile unsigned int milliseconds = 0, milliseconds_t = 0;
// Display buffer/control
volatile int display_buffer[6];
volatile int display_ctl[6];
volatile int display_blink = 0;
volatile int display_blink_rate;
volatile int display_position;
// Switch, mode control
char d_mode = 0, e_mode = 0, d_mode_digit = 0, switch1, switch2;
unsigned int switch1_dt, switch2_dt;
void main(void)
{
unsigned char i;
int t;
unsigned char digit[5], alt_digit = 0;
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
//1Mhz
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation */
CCTL0 = CCIE; // CCR0 interrupt enabled
CCR0 = 1000;
TACTL = TASSEL_2 + MC_2; // SMCLK, contmode
Initializeports();
_EINT();
/* Main Application Loop */
while(1)
{
if ( switch1_dt > 299 ) // Mode switch down
{
switch1 = 1;
if ( switch1_dt > 2000 ) // Mode switch held down
{
display_ctl[d_mode_digit + 1] = 0x01;
display_ctl[d_mode_digit] = 0x01;
e_mode++;
if ( e_mode == 1 )
{
e_hours = hours;
e_minutes = minutes;
e_seconds = seconds;
}
if ( e_mode > 1 )
{
e_mode = 0;
display_ctl[d_mode_digit + 1] = 0x00;
display_ctl[d_mode_digit ] = 0x00;
hours = e_hours;
minutes = e_minutes;
seconds = e_seconds;
}
switch1_dt = 1;
}
}
// Switch one release
if ( (switch1 == 1) && (switch1_dt == 0 ) )
{
if (e_mode == 1 )
{
display_ctl[d_mode_digit + 1] = 0x00;
display_ctl[d_mode_digit ] = 0x00;
d_mode_digit = d_mode_digit + 2;
if (d_mode_digit > 5) d_mode_digit = 0;
display_ctl[d_mode_digit + 1] = 0x01;
display_ctl[d_mode_digit] = 0x01;
switch1 = 0;
}else{
d_mode ++;
if (d_mode > 1) d_mode = 0;
switch1 = 0;
}
}
if ( switch2_dt > 299 )
{
switch2 = 1;
if ( switch2_dt > 2000 )
{
switch2_dt = 1;
if ( d_mode_digit < 2 ) e_hours++;
if ( e_hours > 24 ) e_hours = 1;
if ( ( d_mode_digit > 1 ) && ( d_mode_digit < 4 ) ) e_minutes++;
if ( e_minutes > 59 ) e_minutes = 0;
if ( d_mode_digit > 3 ) e_seconds++;
if ( e_seconds > 59 ) e_seconds = 0;
switch2_dt = 299;
}
}
if ( (switch2 == 1) && (switch2_dt == 0 ) )
{
if ( d_mode_digit < 2 ) e_hours++;
if ( e_hours > 24 ) e_hours = 1;
if ( (d_mode_digit > 1 ) && ( d_mode_digit < 4 ) ) e_minutes++;
if ( e_minutes > 59 ) e_minutes = 0;
if ( d_mode_digit > 3 ) e_seconds++;
if ( e_seconds > 59 ) e_seconds = 0;
switch2 = 0;
}
if ( e_mode )
{
t = e_seconds; // Display Edit mode time
binary2bcd16( digit, t);
display_buffer[4] = digit[1];
display_buffer[5] = digit[0];
t = e_minutes;
binary2bcd16( digit, t);
display_buffer[2] = digit[1];
display_buffer[3] = digit[0];
t = e_hours;
binary2bcd16( digit, t);
display_buffer[0] = digit[1];
display_buffer[1] = digit[0];
display_refresh( );
}else{
t = seconds; // Display Normal mode time
binary2bcd16( digit, t);
display_buffer[4] = digit[1];
display_buffer[5] = digit[0];
t = minutes;
binary2bcd16( digit, t);
display_buffer[2] = digit[1];
display_buffer[3] = digit[0];
t = hours;
binary2bcd16( digit, t);
display_buffer[0] = digit[1];
display_buffer[1] = digit[0];
}
}
}
int binary2bcd16( unsigned char *bcd, int t ) // 16bit to BCD conversion
{
int i;
while( i < 5)
{
bcd[i] = 0;
i++;
}
if ( t > 9999 ) bcd[4] = t / 10000;
if ( t > 999 ) bcd[3] = t / 1000 - bcd[4] * 10;
if ( t > 99 ) bcd[2] = t / 100 - (bcd[3] * 10 + bcd[4] * 100);
if ( t > 9 ) bcd[1] = t / 10 - (bcd[2] * 10 + bcd[3] * 100 + bcd[4] * 1000);
bcd[0] = t - (bcd[1] * 10 + bcd[2] * 100 + bcd[3] * 1000 + bcd[4] * 10000);
}
// Display
void display_refresh( void )
{
int d;
if ( (display_ctl[display_position] == 0x01) && (display_blink == 0x01))
{
d = 16;
}else{
d = display_buffer[display_position];
}
display_led( d, display_position);
display_position++;
if (display_position > 5) display_position = 0;
}
// Serial out of LED data to 74HC595
int display_led(int t, int display)
{
int j, i, mask;
mask = (~0x0100<<display) & 0xff00;
j = (ledtable[t]<<1) | mask;
P1OUT &= ~BIT2;
for(i=0; i < 16; i++)
{
P1OUT &= ~BIT1;
if (j & 0x8000)
{
P1OUT |= BIT0;
}else{
P1OUT &= ~BIT0;
}
P1OUT |= BIT1;
j = j<<1;
}
P1OUT |= BIT2;
}
// setup ports
void Initializeports(void)
{
int i = 0;
P1DIR |= 0x07;
P1SEL = 0x00;
P1OUT = 0x18; // P1.4 set, else reset
P1REN |= 0x18;
while( i < 5 )
{
display_buffer[i] = 0;
display_ctl[i] = 0;
i++;
}
}
// Delay Routine from mspgcc help file
static void __inline__delay(register unsigned int n)
{
__asm__ __volatile__ (
"1: \n"
" dec %[n] \n"
" jne 1b \n"
: [n] "+r"(n));
}
// Time keeping routine
interrupt(TIMERA0_VECTOR) Timer_A (void)
{
milliseconds++;
milliseconds_t++;
if (milliseconds > 999)
{
seconds++;
milliseconds = 0;
}
if (milliseconds_t > 59999)
{
milliseconds_t = 0;
}
if ( 0x10 & ~P1IN)
{
switch1_dt++;
}else{
switch1_dt = 0;
}
if ( 0x08 & ~P1IN)
{
switch2_dt++;
}else{
switch2_dt = 0;
}
if (seconds > 59)
{
minutes++;
seconds = 0;
}
if (minutes > 59 )
{
hours++;
minutes = 0;
}
if (hours > 23)
{
hours = 0;
days++;
}
display_blink_rate++;
if (display_blink_rate > 250) // LED Blink rate
{
display_blink = (~display_blink) & 0x01;
display_blink_rate = 0;
}
display_refresh( );
CCR0 += 999;
}