#include <8051.h> #include "paulmon2.h" // variables that keep track of the time. Note the "volatile" keyword // should be used by all variables that are written by the interrupt // service routines and may be read by the main program. volatile unsigned char hours; volatile unsigned char minutes; volatile unsigned char seconds; volatile bit time_changed_flag; // function prototypes. The interrupt service routine must be // defined in the same file that includes the main() function void timer0_isr(void) interrupt 1; void print_time(void); void print_2digit_uchar(unsigned char n); void main() { IE = 0; // turn off all interrupts hours = minutes = seconds = 0; // zero hours, minutes, seconds TR0 = 0; // make sure timer 0 is stopped TF0 = 0; // clear the overflow flag TMOD &= 0xF0; // set to mode 0 (timer1 unchanged) TL0 = TH0 = 0; // clear the timer 0 value pm2_pstr("\r\n\r\n\r\n"); pm2_pstr("Timekeeping Example (Interrupts)\r\n"); pm2_pstr("Press ESC to stop...\r\n\r\n"); time_changed_flag = 0; TR0 = 1; // start the timing IP = 0; // set interrupt priorities (all low) IE = 0x82; // enable timer0 interrupt print_time(); while (1) { if (pm2_esc()) { pm2_pstr("\r\n\r\nStopped. Press a key to reboot"); pm2_restart(); } if (time_changed_flag) { time_changed_flag = 0; print_time(); } } } /* this interrupt service routine will run every time timer0 sets * the TF0 flag. The 8051 hardware automatically clears TF0 for * us. The special syntax "interrupt 1" causes SDCC to make this * function the interrupt service routine for timer 0. See the * SDCC manual for other interrupt numbers, and optional register * bank options. Special care is needed if this routine calls any * other functions or uses 16 or 32 mulitplication or division or * any floating point math. Usually, it is best to avoid these * inside interrupt service routines, and avoid calling any other * functions if possible. */ #pragma SAVE #pragma NOOVERLAY // disable overlaying local vars w/ other functions void timer0_isr(void) interrupt 1 { static unsigned char ov_countdown=225; if (--ov_countdown == 0) { ov_countdown = 225; if (++seconds == 60) { seconds = 0; if (++minutes == 60) { minutes = 0; if (++hours == 24) { hours = 0; } } } time_changed_flag = 1; } } #pragma RESTORE /* Print the time. The time is read quickly with the interrupt * disabled, to avoid any chance that the interrupt routine could * change the bytes while they're being read. */ void print_time(void) { unsigned char m_hours, m_minutes, m_seconds; ET0 = 0; // temporarily disable interrupt m_hours = hours; m_minutes = minutes; m_seconds = seconds; ET0 = 1; // reenable interrupt ASAP print_2digit_uchar(m_hours); pm2_cout(':'); print_2digit_uchar(m_minutes); pm2_cout(':'); print_2digit_uchar(m_seconds); pm2_newline(); } /* print a number as two digits with leading zero */ void print_2digit_uchar(unsigned char n) { pm2_cout((n / 10) + '0'); pm2_cout((n % 10) + '0'); }