/* DISPLAY.C drives three kinds of displays: 1. LCD is HD44780-based 2x16 character display LM-11 in 4 bit mode connected to port P5 2. ICM is ICM7218A 8 Digit LED Display Driver memory mapped at 0x8000 with 8 LEDs for status display instead of D.P. segment. The display is broken into two 4 digit integer displays icm1 and icm2 3. Static serial display with four 3 1/2 (-188.8) displays with sign consists of twelve 74HC595 shift registers with each segment connected via resistor to 595. Decimal point is fixed. f_osc = 11.059 MHz -> 1 machine cycle = 12/f_osc = 1.085us */ #include <reg515.h> #include <intrins.h> #include "display.h" /* LCD display pin definition */ sbit LCD_E = 0xFB; /* P5.3 enable LCD */ sbit LCD_RW = 0xFA; /* P5.2 Read/Write LCD */ sbit LCD_RS = 0xF9; /* P5.1 Data/Instruction LCD */ sbit BUSY = 0xFF; /* P5.7 LCD Busy bit 7 */ sfr LCD_PORT=0xF8; /* P5 port high nibbles P5.4-P5.7 */ sbit IR7 = 0xFF; /* P5.7 */ sbit IR6 = 0xFE; /* P5.6 */ sbit IR5 = 0xFD; /* P5.5 */ sbit IR4 = 0xFC; /* P5.4 */ bit lcd_busy() { bit busy; IR7 = IR6 = IR5 = IR4 = 1; /* Prepare for read */ LCD_RS = 0; /* Instruction */ LCD_RW = 1; /* Read DISPLAY */ LCD_E = 1; /* enable LCD */ busy = BUSY; LCD_E = 0; LCD_E = 1; LCD_E = 0; return busy; } /* if RS == 0 then write instruction else write character to LCD */ void lcd_send(bit RS, unsigned char c) { unsigned int count = 0; while (lcd_busy()) { count++; if (count == 10000) { GATE = 1; icm_error(01); /* LCD failure - short circuit */ while (1) { WDT = 1; /* ensure WDT is reset */ SWDT = 1; } } } LCD_RS = RS; /* Data/Instruction select */ LCD_RW = 0; /* set write */ LCD_PORT = (c & 0xF0) | (LCD_PORT & 0x0F); /* high nibble to the LCD */ LCD_E = 1; /* enable LCD */ LCD_E = 0; /* write to LCD */ LCD_PORT = (c << 4 & 0xF0) | (LCD_PORT &0x0F); LCD_E = 1; LCD_E = 0; } void lcd_cgram_caron_init() { char i; char code *caron = "\x0a\x04\x0e\x10\x10\x11\x0e\x00" /* 1. c caron */ "\x0a\x04\x0e\x10\x0e\x01\x1e\x00" /* 2. s caron */ "\x0a\x04\x1f\x02\x04\x08\x1f\x00" /* 3. z caron */ "\x0a\x0e\x11\x10\x10\x11\x0e\x00" /* 4. C caron */ "\x0a\x0e\x11\x0e\x01\x11\x0e\x00" /* 5. S caron */ "\x0a\x1f\x02\x04\x08\x10\x1f\x00" /* 6. Z caron */ "\x00\x0e\x15\x1f\x15\x0e\x00\x00" /* 7. Selected */ "\x00\x0e\x11\x11\x11\x0e\x00\x00" /* 7. DeSelected */ ; lcd_send(0, 0x48); /* set CGRAM start address */ for (i = 0; i < 8*8; i++) lcd_send(1, caron[i]); } void lcd_cgram_symbols_init() { char i; char code *symbols = "\x00\x00\x1f\x1d\x05\x07\x00\x00" /* Burner */ "\x00\x0e\x04\x1e\x1f\x03\x00\x02" /* Water circulation */ "\x1f\x01\x1d\x05\x1d\x15\x11\x1f" /* Under floor heating */ "\x04\x15\x0e\x1b\x0e\x15\x04\x00" /* Sun */ "\x0e\x0b\x0a\x0a\x0a\x1a\x0e\x00" /* Solar Tank */ "\x02\x1d\x02\x00\x02\x1f\x02\x00" /* Preferences */ ; lcd_send(0, 0x48); /* set CGRAM start address */ for (i = 0; i < 6*8; i++) lcd_send(1, symbols[i]); } /* Initialise LCD in 4 bit without cursor display */ void lcd_init(void) { unsigned int i; LCD_E = 0; /* disable LCD */ LCD_RW = 0; /* we will Write */ LCD_RS = 0; /* instructions */ LCD_PORT = 0x30 | (LCD_PORT & 0x0f); for (i = 1800; i > 0; i--); /* wait 15 ms or more after poweron*/ /* i*8+i/256+4 cycles */ LCD_E=1; LCD_E=0; for (i = 600; i > 0; i--); /* wait 4.1 ms or more */ LCD_E=1; LCD_E=0; for (i = 19; i > 0; i--); /* wait 160 us or more */ LCD_E=1; LCD_E=0; LCD_PORT = 0x20 | (LCD_PORT & 0x0f); LCD_E=1; LCD_E=0; lcd_send(0, 0x28); /* set interface length */ lcd_send(0, 0x08); /* turn OFF */ lcd_send(0, 0x01); /* clear display */ lcd_send(0, 0x06); /* Enty mode set, Set cursor move direction */ lcd_send(0, 0x0C); /* Enable display without cursor and blink*/ lcd_cgram_symbols_init(); } void lcd_print(char code *message) { unsigned char i = 0; lcd_send(0, 0x01); /* clear display */ while(message[i]) { if (message[i] == '\n') { lcd_send(0, 0x80+0x40); /* new line */ i++; continue; } lcd_send(1, message[i++]); } } void lcd_princ(unsigned char position, char code *message) { unsigned char i = 0; lcd_send(0, 0x80|position); /* go to the left position */ while (message[i]) { if (message[i] == '\n') { lcd_send(0, 0x80+0x40); /* new line */ i++; continue; } lcd_send(1, message[i++]); } } void lcd_print_ulong(unsigned char position, unsigned long value) { char i = 8; lcd_send(0, 0x80|position); /* go to rightmost digit*/ lcd_send(0, 0x04); /* left move */ while(i--) { lcd_send(1, (value % 10)+'0'); value /= 10; } lcd_send(0, 0x06); /* back to right move */ } lcd_print_hms(unsigned char position, unsigned long value) { lcd_send(0, 0x80|position); /* go to rightmost digit*/ lcd_send(0, 0x04); /* left move */ lcd_send(1, (value % 10)+'0'); /* seconds */ value /= 10; lcd_send(1, (value % 6)+'0'); value /= 6; lcd_send(1, ':'); lcd_send(1, (value % 10)+'0'); /* minutes */ value /= 10; lcd_send(1, (value % 6)+'0'); value /= 6; lcd_send(1, ':'); do { lcd_send(1, (value % 10)+'0'); value /= 10; } while(value); lcd_send(0, 0x06); /* back to right move */ } void lcd_print_uchar(unsigned char position, unsigned long value) { char i = 3; lcd_send(0, 0x80|position); /* go to rightmost digit*/ lcd_send(0, 0x04); /* left move */ while(i--) { lcd_send(1, (value % 10) + '0'); value /= 10; } lcd_send(0, 0x06); /* back to right move */ } void lcd_print_temp(unsigned char position_right, int value) { char i = 4; lcd_send(0, 0x80|position_right); /* go to rightmost digit*/ lcd_send(0, 0x04); /* left move */ lcd_send(1, 'C'); lcd_send(1, 0xDF); while(i--) { lcd_send(1, (value % 10) + '0'); if (i == 2) lcd_send(1, 0x2E); value /= 10; } lcd_send(0, 0x06); /* back to right move */ } void lcd_print_time_of_day(unsigned char time_of_day) { if (time_of_day > 239) { lcd_princ(0x43, "Izklju\01eno"); } else { unsigned char minutes = (time_of_day % 10) * 6; lcd_princ(0x43, " "); lcd_send(0, 0xc8); /* go to rightmost digit*/ lcd_send(0, 0x04); /* left move */ lcd_send(1, (minutes % 10) + '0'); minutes /= 10; lcd_send(1, minutes + '0'); time_of_day /= 10; lcd_send(1, ':'); lcd_send(1, (time_of_day % 10)+'0'); time_of_day /= 10; lcd_send(1, time_of_day+'0'); lcd_send(0, 0x06); /* back to right move */ } } /*------------------------ ICM7218A section --------------------------*/ /* MODE is on A0 pin, ID is on DATA bus, WR\ in on A15\ pin */ #define icm_data *((unsigned char volatile xdata *)0x8000) #define icm_ctrl *((unsigned char volatile xdata *)0x8001) /* ICM mode control masks */ #define ICM_NORMAL 0x10 #define ICM_NO_DECODE 0x20 #define ICM_HEX 0x40 #define ICM_DATA_COMING 0x80 static unsigned char _leds; void icm1(unsigned int i) /* first line */ { char digit; lcd_print_temp(0x06, i); for (digit = 3; digit >=0 ; digit--) { icm_ctrl = ICM_NORMAL | digit; icm_data = i % 10 | ( _leds & 1 << digit ? 0x00 : 0x80); i /= 10; } } void icm2(unsigned int i) /* second line of the four digits */ { char digit; lcd_print_temp(0x46, i); for (digit = 7; digit >=4 ; digit--) { icm_ctrl = ICM_NORMAL | digit; icm_data = i % 10 | ( _leds & 1 << digit ? 0x00 : 0x80); i /= 10; } } /* Writes error number message to ICM display */ void icm_error(unsigned char number) { #define SEG_A 0x40 /* aaaa */ #define SEG_B 0x20 /* f b */ #define SEG_C 0x10 /* f b */ #define SEG_D 0x01 /* gggg */ #define SEG_E 0x08 /* e c */ #define SEG_F 0x02 /* e c */ #define SEG_G 0x04 /* dddd */ #define LED(i) (leds & 1 << i ? 0x00 : 0x80) icm_ctrl = ICM_NORMAL | ICM_NO_DECODE | ICM_DATA_COMING; icm_data = SEG_A | SEG_D | SEG_E | SEG_F | SEG_G | LED(0); /* E */ icm_data = SEG_E | SEG_G | LED(1); /* r */ icm_data = SEG_C | SEG_D | SEG_E | SEG_G | LED(2); /* o */ icm_data = SEG_E | SEG_G | LED(3); /* r */ icm_data = SEG_C | SEG_E | SEG_G | LED(4); /* n */ icm_data = SEG_C | SEG_D | SEG_E | SEG_G | LED(5); /* o */ icm_ctrl = ICM_NORMAL | 6; icm_data = (number / 10 ? number / 10 : 0xFF) | LED(6); icm_ctrl = ICM_NORMAL | 7 ; icm_data = (number % 10) | LED(7); } void icm_blank(void) { icm_ctrl = ICM_NORMAL | ICM_NO_DECODE | ICM_DATA_COMING; icm_data = LED(0); icm_data = LED(1); icm_data = LED(2); icm_data = LED(3); icm_data = LED(4); icm_data = LED(5); icm_data = LED(6); icm_data = LED(7); icm_ctrl = ICM_NORMAL; } /* Call icm1() or icm2() for leds update! */ void set_leds(unsigned char leds) { _leds = leds; } /* Writes tests to ICM display */ void icm_test(unsigned char number) { switch (number) { case 0: icm_ctrl = ICM_NORMAL | ICM_NO_DECODE | ICM_DATA_COMING; icm_data = 0x00; icm_data = 0x00; icm_data = 0x00; icm_data = 0x00; icm_data = 0x00; icm_data = 0x00; icm_data = 0x00; icm_data = 0x00; icm_ctrl = ICM_NORMAL; break; case 1: icm_ctrl = ICM_NORMAL | ICM_NO_DECODE | ICM_DATA_COMING; icm_data = 0xFF; icm_data = 0xFF; icm_data = 0xFF; icm_data = 0xFF; icm_data = 0xFF; icm_data = 0xFF; icm_data = 0xFF; icm_data = 0xFF; icm_ctrl = ICM_NORMAL; break; default: icm_ctrl = ICM_NORMAL | ICM_NO_DECODE | ICM_DATA_COMING; icm_data = SEG_A | SEG_D | SEG_E | SEG_F | SEG_G | LED(0); /* E */ icm_data = SEG_E | SEG_G | LED(1); /* r */ icm_data = SEG_C | SEG_D | SEG_E | SEG_G | LED(2); /* o */ icm_data = SEG_E | SEG_G | LED(3); /* r */ icm_data = SEG_C | SEG_E | SEG_G | LED(4); /* n */ icm_data = SEG_C | SEG_D | SEG_E | SEG_G | LED(5); /* o */ icm_ctrl = ICM_NORMAL | 6; icm_data = (number / 10 ? number / 10 : 0xFF) | LED(6); icm_ctrl = ICM_NORMAL | 7 ; icm_data = (number % 10) | LED(7); icm_ctrl = ICM_NORMAL; } } /* ------------------ static serial display --------------------- */ sbit SI = 0xEC; /* P4.4 negated serial input */ sbit SCK = 0xED; /* P4.5 negated serial clock */ sbit RCK = 0xEE; /* P4.6 negated reload clock */ static signed int idata display_data[4]; /* pomnozeno s 100 */ static void send_digit(unsigned char segment_data) { unsigned char i; for(i = 0; i < 8; i++) { SCK = 1; SI = segment_data & 0x80; SCK = 0; segment_data = segment_data << 1; } } /* Sends display_data via serial protocol to HC595 shits registers If blanking set then display is cleared! */ void update_serial_display(bit blanking) { unsigned char code segment[10] = { 0xEE, 0xC0, 0xB6, 0xF4, 0xD8, 0x7C, 0x7E, 0xE0, 0xFE, 0xFC}; unsigned char num; /* row counter */ unsigned char buffer[3]; /* segment buffer */ int value; /* current display_data */ bit negative; /* negative sign */ RCK = 1; for ( num = 0; num < 4; num ++) { if (blanking) { buffer[0] = buffer[1] = buffer[2] = 0; } else { value = display_data[3 - num]; if ( value < 0) { negative = 1; value = -value; } else negative = 0; value /= 10; buffer[2] = segment[value % 10] | negative; value /= 10; buffer[1] = segment[value % 10]; value /= 10; buffer[0] = segment[value % 10]; if ( value > 9 ) /* hundrets */ { buffer[1] |= 1; } else { if (value == 0) buffer[0] = negative; /* leading zero suppresion */ } } send_digit(buffer[0]); send_digit(buffer[1]); send_digit(buffer[2]); } RCK = 0; } /* The last digit is missing! To display a value multiply ii with 10 e.g. -12345 will be shown as -123.4 (no rounding is performed!) */ void set_serial_display(unsigned char display_number, signed int value) { display_data[display_number] = value; } #if 0 signed int get_serial_display(unsigned char display_number) { return display_data[display_number]; } #endif /* Generic part */ void halt(unsigned char errno, char code *message) { GATE = 1; /* disable all output */ icm_error(errno); if (errno != 0) { /* lcd_init(); */ lcd_princ(0x00, message); } while(1) { unsigned int i; for ( i = 10000; i > 0; i--) /* must wait*/ { WDT = 1; /* ensure WDT is reset */ SWDT = 1; } leds++; icm_error(errno); /* for leds refresh */ } }