/*! \file lcdtext.c \brief LCD font and text drawing functions. */ #include "lcd.h" #include "lcdtext.h" /* Digits look like this, and we index them with 0 being the leftmost. AAAAA F B F B F B GGGGG E C E C E C DDDDD dp */ //! This maps the segments of each digit. const int lcdmap[10][8]={ // A, B, C, D, E, F, G, dp digit {0x0b04, 0x0b40, 0x0b20, 0x0b01, 0x0a10, 0x0a20, 0x0b02, 0x0b10}, //0 {0x0940, 0x0a04, 0x0a02, 0x0910, 0x0901, 0x0902, 0x0920, 0x0a01}, //1 {0x0804, 0x0840, 0x0820, 0x0801, 0x0710, 0x0720, 0x0802, 0x0810}, //2 {0x0640, 0x0704, 0x0702, 0x0610, 0x0601, 0x0602, 0x0620, 0x0701}, //3 {0x0504, 0x0540, 0x0520, 0x0501, 0x0410, 0x0420, 0x0502, 0x0510}, //4 {0x0c02, 0x0404, 0x0402, 0x0310, 0x0302, 0x0304, 0x0340, 0x0401}, //5 {0x0204, 0x0220, 0x0210, 0x0201, 0x0110, 0x0120, 0x0202, 0x0301}, //6 {0x0040, 0x0104, 0x0102, 0x0010, 0x0001, 0x0002, 0x0020, 0x0240}, //7 }; //These are the fragments of the day of the week: 0x0904, 0x0a40, 0x0c01 //0x0c10 is beyond the screen. //0x0240 seems not to be wired to any visible segment, but we use it //as the rightmost decimal point because we don't seem to have that //cell. //! Bit flags for each of the eight segments. enum lcdmappos {A=1, B=2, C=4, D=8, E=0x10, F=0x20, G=0x40, DP=0x80}; //! Font for numbers. const int numfont[]={ A|B|C|D|E|F, //0 B|C, //1 A|B|G|E|D, //2 A|B|G|C|D, //3 F|G|B|C, //4 A|F|G|C|D, //5 A|F|G|E|C|D, //6 A|B|C, //7 A|B|C|D|E|F|G, //8 A|B|G|F|C|D, //9 A|F|B|G|E|C, //A F|E|G|C|D, //B A|F|E|D, //C E|G|C|D|B, //D A|F|E|G|D, //E A|G|F|E //F }; //! Font for letters. const int letterfont[]={ /* This font begins at 0x41 hex in the ASCII table, rendering letters as best they can be on the 7-segment display. */ A|F|B|G|E|C, //A F|E|G|C|D, //B A|F|E|D, //C E|G|C|D|B, //D A|F|E|G|D, //E A|G|F|E, //F A|F|G|E|C|D, //G F|G|E|C, //h F|E, //I, distinguished from a 1 by being on the left side. E|B|C|D, //J F|E|B|C|G|DP, //K, distinguished from an X by the DP. F|E|D, //L A|E|C, //M (Less nerdy than mu, but more readable.) E|G|C, //n A|B|C|D|E|F, //O F|A|B|G|E, //P F|A|B|C|D|E|DP,//Q E|G, //R A|F|G|C|D, //S (Looks like a 5.) F|E|G, //T F|E|D|C|B, //U F|E|D|C|B, //V (Same as U. Blame Rome.) F|E|D|C|B, //W (Same as U and V. Blame Germany.) F|G|E|B|C, //X F|G|B|E, //Y A|B|G|E|D //Z }; //! Sets a pixel. #define DRAWPOINT(todraw) lcdm[todraw>>8]|=todraw&0xFF //! Clears a pixel. #define CLEARPOINT(todraw) lcdm[todraw>>8]&=~(todraw&0xFF) //! Draws one LCD digit. void lcd_digit(int pos, int digit){ int segments=numfont[digit]; int bit; for(bit=0;bit<8;bit++){ if(segments&(1<='0' && c<='9'){ lcd_digit(pos, c&0x0F); return; }else if(c==' '){ lcd_cleardigit(pos); return; }else if(c=='.'){ lcd_cleardigit(pos); setperiod(pos,1); return; } c&=~0x20; segments=letterfont[c-'A']; for(bit=0;bit<8;bit++){ if(segments&(1<=0 && *str){ lcd_char(i--, *str++); } } //! Draws a decimal number on the screen. void lcd_number(long num){ static long bcd=0; static long oldnum=0; int i; /* This conversion takes too long at 32kHz, so we cache the last value for rendering. */ if(oldnum==num){ lcd_hex(bcd); return; } /* Otherwise we convert it with expensive divisions. */ bcd=0; oldnum=num; for(i=0;i<8 && num;i++){ bcd|=((num%10)<<(4*i)); num/=10; } lcd_hex(bcd); } //! Draws hex on the screen. void lcd_hex(long num){ /* So in an ideal world, we'd have characters arranged nicely into LCDM[] bytes as some development tools do, but in the real world, we're pretty much stuck with them as they are physically arranged. This function takes a buffer of eight hex characters and displays them on the screen. */ int i; for(i=0;i<8;i++) lcd_digit(i,(num>>(4*i))&0xf); } //! Activates a period, or turns it off. void setperiod(int digit, int on){ if(on) //On DRAWPOINT(lcdmap[digit][7]); else //Off CLEARPOINT(lcdmap[digit][7]); } //! Activates the colon. 2 for invert. void setcolon(int on){ if(on==2) //Blink lcdm[3]^=0x20; else if(on==1) //On lcdm[3]|=0x20; else //Off lcdm[3]&=~0x20; } //! Activates the am. 2 for invert. void setam(int on){ if(on==2) //Blink lcdm[0]^=0x04; else if(on==1) //On lcdm[0]|=0x04; else //Off lcdm[0]&=~0x04; } //! Activates the pm. 2 for invert. void setpm(int on){ if(on==2) //Blink lcdm[1]^=0x40; else if(on==1) //On lcdm[1]|=0x40; else //Off lcdm[1]&=~0x40; } //! Activates the mult sign. 2 for invert. void setmult(int on){ if(on==2) //Blink lcdm[4]^=0x40; else if(on==1) //On lcdm[4]|=0x40; else //Off lcdm[4]&=~0x40; } //! Activates the minus sign. 2 for invert. void setminus(int on){ if(on==2) //Blink lcdm[6]^=0x04; else if(on==1) //On lcdm[6]|=0x04; else //Off lcdm[6]&=~0x04; } //! Activates the plus sign. 2 for invert. void setplus(int on){ if(on==2) //Blink lcdm[7]^=0x40; else if(on==1) //On lcdm[7]|=0x40; else //Off lcdm[7]&=~0x40; } //! Activates the divide sign. 2 for invert. void setdivide(int on){ if(on==2) //Blink lcdm[0xc]^=0x04; else if(on==1) //On lcdm[0xc]|=0x04; else //Off lcdm[0xc]&=~0x04; }