/************************************************************************/ /* */ /* Serial LCD Routines */ /* */ /* Test Program: Clock / Calendar */ /* */ /* Author: Peter Dannegger */ /* danni@specs.de */ /* */ /************************************************************************/ #pragma cd pl(9999) #include sbit LCD_E = P1^6; sbit LCD_CK = P1^5; sbit LCD_RS = P1^7; /* connections: 89C2051 74HCT164 LCD ---------------------------------------- P1.5 8 P1.6 E P1.7 1, 2 RS VCC 9, 14 VDD GND 7 VSS, R/W 3 D1 4 D3 5 D5 6 D7 10 D6 11 D4 12 D2 13 D0 */ #define XTAL 11.0592e6 #define uchar unsigned char void lcd_data( uchar d ); void lcd_text( uchar *t ); void lcd_command( uchar d ); void lcd_init( void ); void display_clock( void ); void clock( void ); struct time { uchar sec; uchar min; uchar hour; uchar day; uchar wday; uchar month; uchar year; }; extern struct time data time; extern bit F_1sec, F_1min, F_1hour; /************************************************************************/ /* */ /* LCD - Routines */ /* */ /************************************************************************/ #define TWAIT ( XTAL / 12 / 512 ) uchar position; void lcdout( uchar d, bit rs ) { uchar code BIT_NO[] = { 0x01, 0x04, 0x10, 0x40, 0x80, 0x20, 0x08, 0x02 }; uchar i; LCD_E = 0; for( i = 0; i < 8; i++ ){ LCD_CK = 0; LCD_RS = d & BIT_NO[i]; LCD_CK = 1; } LCD_RS = rs; LCD_E = 1; i = XTAL / 12 / 2 * 46e-6; LCD_E = 0; while( --i ); // wait 46us } void wait512( uchar t ) // Tw = 512 cycle * t { uchar i = 0; do while( --i ); while( --t ); } void lcd_command( uchar d ) { lcdout( d, 0 ); if( d & 0x80 ) position = d; switch( d ){ case 1: case 2: case 3: wait512( 2 + TWAIT * 1.6e-3 ); // wait 1.6ms } } void lcd_data( uchar d ) { lcdout( d, 1 ); position++; if( position == 0x90 ) position = 0xC0; else if( position == 0xD0 ) position = 0x80; else return; lcd_command( position ); } void lcd_init( void ) { wait512( 1 + TWAIT * 15e-3 ); // wait 15ms lcd_command( 0x30 ), wait512( 1 + TWAIT * 4.1e-3 ); // wait 4.1ms lcd_command( 0x30 ); wait512( 1 ); lcd_command( 0x30 ); lcd_command( 0x38 ); // 2 lines 5*7 lcd_command( 0x08 ); // display off lcd_command( 0x01 ); // display clear lcd_command( 0x06 ); lcd_command( 0x0C ); // no cursor, no blink position = 0x80; } /************************************************************************/ /* */ /* Clock / Calendar */ /* */ /* Author: Peter Dannegger */ /* danni@specs.de */ /* */ /************************************************************************/ struct time data time; void display_clock( void ) { lcd_command( 0x80 ); // line 1 lcd_data( time.hour / 10 + '0'); lcd_data( time.hour % 10 + '0'); lcd_data( ':' ); lcd_data( time.min / 10 + '0'); lcd_data( time.min % 10 + '0'); lcd_data( ':' ); lcd_data( time.sec / 10 + '0'); lcd_data( time.sec % 10 + '0'); lcd_command( 0xC0 ); // line 2 lcd_data( time.day / 10 + '0'); lcd_data( time.day % 10 + '0'); lcd_data( '.' ); lcd_data( time.month / 10 + '0'); lcd_data( time.month % 10 + '0'); lcd_data( '.' ); lcd_data( '2' ); lcd_data( '0' ); lcd_data( time.year / 10 + '0'); lcd_data( time.year % 10 + '0'); } void clock(void) { uchar code MDAYS[] = { 30, 32, 29, 32, 31, 32, 31, 32, 32, 31, 32, 31, 32 }; uchar i; time.sec++; if( time.sec == 60 ){ time.sec = 0; F_1min = 1; // to correct deviation per minute time.min++; if( time.min == 60 ){ time.min = 0; F_1hour = 1; time.hour++; switch( time.hour ){ case 24: time.hour = 0; time.day++; time.wday++; if( time.wday == 8 ) time.wday = 1; i = time.month; if( i == 2 && (time.year & 3) == 0 ) // leap year i = 0; if( MDAYS[i] == time.day ){ time.day = 1; time.month++; if( time.month == 13 ){ time.month = 1; time.year++; if( time.year == 100 ) time.year = 0; // next century } } break; // case 2: // case 3: summertime(); break; } } } } /************************************************************************/ /* */ /* High Precise Time Base */ /* */ /* Author: Peter Dannegger */ /* danni@specs.de */ /* */ /************************************************************************/ bit F_1sec, F_1min, F_1hour; #define T_INTERVAL (XTAL / 12.0 / 16384) #define PRESC_1S (uchar)(T_INTERVAL + 0.5) #define PRESC_1M (uchar)((T_INTERVAL - PRESC_1S) * 60 + PRESC_1S + 0.5) #define PRESC_1H (T_INTERVAL * 60 - PRESC_1S * 59 - PRESC_1M) * 60 + PRESC_1M + 0.5 void t0_int( void ) interrupt 1 { static uchar prescaler = PRESC_1S; TH0 |= 0xC0; // shorten T0 to 16384 if( --prescaler == 0 ){ prescaler = PRESC_1S; if( F_1min ){ prescaler = PRESC_1M; F_1min = 0; } if( F_1hour ){ prescaler = PRESC_1H; F_1hour = 0; } F_1sec = 1; } } /************************************************************************/ /* */ /* Main */ /* */ /************************************************************************/ void main( void ) { lcd_init(); time.day = 16; time.month = 3; time.year = 3; ET0 = 1; EA = 1; TMOD = 1; TR0 = 1; for(;;){ if( F_1sec ){ F_1sec = 0; clock(); display_clock(); } } }