/******* LCD.c ***************** * * Display a string received having a length of 9 characters (including * an optional decimal point). * * Because of the quirky translation of the starburst segments ABCDEFGHIJKLMNPX * into their positions in the LCDDATAi registers, the tables showing the coding * for numbers and letters are coded with two-byte table entries in the * following order: * J G F B I H X A N M D P K L E C * where P is the decimal point and X is the apostrophe. * Thus the letter "K" made up of segments EFGJN is translated into the table * entry db 0xe0,0x82 because * 1 1 1 0 0 0 0 0 1 0 0 0 0 0 1 0 * * Use Fosc = 8 MHz. Starburst display draws 6 uA. * Developed by Alex Singh. * ******* Program hierarchy ***** * * main * Initial * DisplayV * WriteCharacter * ******************************* */ #include /******************************* * Assembler directives ******************************* */ #pragma config OSC = INTIO7 // Internal osc, RA6=CLKO, RA7=I/O #pragma config WDT = OFF // WDT disabled (control through SWDTEN bit) #pragma config PWRT = ON // PWRT enabled #pragma config MCLRE = ON // MCLR pin enabled; RG5 input pin disabled #pragma config XINST = OFF // Instruction set extension disabled #pragma config BOREN = ON // Brown-out controlled by software #pragma config BORV = 3 // Brown-out voltage set for 2.0V, nominal /******************************* * Structure definitions ******************************* */ // Structures to map LCDDATA (as nibbles) typedef struct { long _4bytes; char _1byte; } _5bytes; typedef struct { unsigned nAL:4; // LCDDATA(x) unsigned nAH:4; _5bytes a; unsigned nBL:4; // LCDDATA(x+6) unsigned nBH:4; _5bytes b; _5bytes c; unsigned nCL:4; // LCDDATA(x+12) unsigned nCH:4; _5bytes d; unsigned nDL:4; // LCDDATA(x+18) unsigned nDH:4; } oneLCDSEG; /******************************* * Global variables ******************************* */ union { struct { unsigned int ALL; // To identify entire structure }; struct { unsigned nLL:4; // To identify 4 nibbles for each table entry unsigned nLH:4; unsigned nHL:4; unsigned nHH:4; }; struct { unsigned:4; unsigned P:1; // To identify the decimal point bit }; } LCDDATA; // Structure to handle table entries as // nibbles char DPFLAG; // Flag to handle a received decimal point unsigned char CHAR; // ASCII character from string unsigned char POSITION; // LCD character position (0 to 7) unsigned char i; // Used as index for loops and VSTRING unsigned int DELAY; // Sixteen-bit counter for obtaining a delay unsigned int j; // Used for delay in Initial unsigned int RECEIVED; // Used to keep track of characters received oneLCDSEG *ptr; // Pointer that maps to our LCD nibbles char *CLEARptr; // Pointer used to clear all LCDDATA unsigned char VSTRING[10]; // Variable string to display /******************************* * Constant strings ******************************* */ // Table-entry coding of segments: J G F B I H X A N M D P K L E C const rom unsigned int ASCII[] = { // ASCII column 0 0x0100, 0x1000, 0x0001, 0x0020, // Chris Bruhn's and Peter Ralston's 0x0002, 0x2000, 0x4000, 0x0400, // modification for PV.c, their 0x0800, 0x8000, 0x0008, 0x0080, // performance verification program 0x0040, 0x0004, 0x0200, 0x0010, // ASCII column 1 0xffff, 0xcedc, 0xffff, 0xffff, // CB and PR again 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // ASCII column 2 0x0000, 0xffff, 0xffff, 0x0480, // blank,!,",# 0xffff, 0xffff, 0xffff, 0x0200, // $,%,&,' 0x8080, 0x0404, 0xc48c, 0x4848, // (,),*,+ 0x0000, 0x4008, 0xb137, 0x8004, // , ,-,/ // ASCII column 3 0xb127, 0x1001, 0x512a, 0x1129, // 0,1,2,3 0x7009, 0x6129, 0x612b, 0x8140, // 4,5,6,7 0x712b, 0x7129, 0xb137, 0x0000, // 8,9,0, 0x8080, 0x4028, 0x0404, 0x7108, // <,= >,? // ASCII column 4 0xffff, 0x710b, 0x1969, 0x2122, // @,A,B,C 0x1961, 0x6122, 0x6102, 0x212b, // D,E,F,G 0x700b, 0x0960, 0x1023, 0xe082, // H,I,J,K 0x2022, 0xb403, 0x3483, 0x3123, // L,M,N,O // ASCII column 5 0x710a, 0x31a3, 0x718a, 0x6129, // P,Q,R,S 0x0940, 0x3023, 0xa006, 0x3087, // T,U,V,W 0x8484, 0x8440, 0x8124, 0xffff, // X,Y,Z 0xffff, 0xffff, 0x0084, 0xffff, // , ,^, // ASCII column 6 0xffff, 0x710b, 0x1969, 0x2122, // @,A,B,C 0x1961, 0x6122, 0x6102, 0x212b, // D,E,F,G 0x700b, 0x0960, 0x1023, 0xe082, // H,I,J,K 0x2022, 0xb403, 0x3483, 0x3123, // L,M,N,O // ASCII column 7 0x710a, 0x31a3, 0x718a, 0x6129, // P,Q,R,S 0x0940, 0x3023, 0xa006, 0x3087, // T,U,V,W 0x8484, 0x8440, 0x8124, 0xffff, // X,Y,Z 0xffff, 0xffff, 0xffff, 0xffff, // , , , }; /******************************* * Variable strings ******************************* */ /******************************* * Function prototypes ******************************* */ void Initial(void); void DisplayV(void); void WriteCharacter(void); /******************************* * Macros ******************************* */ #define Delay(x) DELAY = x; while(--DELAY){ Nop(); Nop(); } /******************************* * main() ******************************* */ void main() { Delay(30000); // Initial delay of 300/2 milliseconds Initial(); // Initialize everything while (1) { Sleep(); Nop(); CHAR = SSPBUF; // Clear buffer initially INTCONbits.INT0IF = 0; // Clear wake up flag TMR0L = 0; // Reset breakout timer INTCONbits.TMR0IF = 0; // Clear breakout timer flag for (RECEIVED = 0; RECEIVED < 9; RECEIVED++) // Receive 9 chars { PIR1bits.SSPIF = 0; // Clear SPI flag // Wait limited amount of time for character while ((!PIR1bits.SSPIF) && (!INTCONbits.TMR0IF)) ; if (INTCONbits.TMR0IF) { break; } VSTRING[RECEIVED] = SSPBUF; // Get character and put into string } DisplayV(); } } /******************************* * Initial() * * This subroutine performs all initializations of variables and registers. ******************************* */ void Initial() { OSCCON = 0b01110010; // Select 8 MHz internal oscillator LCDSE0 = 0b11111111; // Enable all LCD segments LCDSE1 = 0b11111111; LCDSE2 = 0b11111111; LCDSE3 = 0b11111111; LCDCON = 0b10001011; // 1/4 mux; INTRC clock LCDPS = 0b00110110; // 37 Hz frame frequency CLEARptr = (char *) &LCDDATA0; // Point to first segment for (i = 0; i < 28; i++) // Turn off all segments { *CLEARptr++ = 0x00; } LCDDATA21 = 0b00010000; // Turn on rightmost decimal point initially ADCON1 = 0b00111111; // Make all ADC/IO pins digital TRISA = 0; // Make all pins outputs but RB0, SCK, SDI TRISB = 0b00000001; TRISC = 0b00011000; PORTA = 0; PORTB = 0; PORTC = 0; SSPCON1 = 0b00110101; // Initialize SPI as slave SSPSTAT = 0b00000000; T0CON = 0b11000011; // Use Timer0 to timeout on incomplete input INTCON2bits.INTEDG0 = 0; // Wake up with falling edge on INT0 INTCONbits.INT0IF = 0; // Clear flag INTCONbits.INT0IE = 1; // Enable INT0 source // Don't enable interrupt, only wakeup DPFLAG = 0; Delay(30000); // Initial delay is 300/2 milliseconds RCONbits.SBOREN = 0; // Now disable brownout reset } /******************************* * DisplayV() * * This subroutine displays the string stored in VSTRING ******************************* */ void DisplayV() { // Iterate through all received for (i = 0, POSITION = 0; i < RECEIVED; i++, POSITION++) { CHAR = VSTRING[i]; // Save byte if (VSTRING[i + 1] == '.') // Deal with decimal point { // Check next character for decimal point DPFLAG = 1; // If it is, set flag i++; // and increment pointer past decimal point } WriteCharacter(); // Display current character } } /******************************* * WriteCharacter() * * This subroutine writes the selected character to the display ******************************* */ void WriteCharacter() { LCDDATA.ALL = ASCII[CHAR]; // Load table entry to be written // Ppoint to corresponding LCDDATAs ptr = (oneLCDSEG *) (&LCDDATA0 + POSITION / 2); if (DPFLAG) // if FLAG is set { LCDDATA.P = 1; // Write decimal point DPFLAG = 0; // and clear flag } if (!(POSITION % 2)) // If even position { ptr->nAL = LCDDATA.nHL; // write to lower nibbles ptr->nBL = LCDDATA.nHH; ptr->nCL = LCDDATA.nLL; ptr->nDL = LCDDATA.nLH; } else // If odd position { ptr->nAH = LCDDATA.nHL; // write to upper nibbles ptr->nBH = LCDDATA.nHH; ptr->nCH = LCDDATA.nLL; ptr->nDH = LCDDATA.nLH; } }