/************************************************************* * jl16-4.c - Demonstrate interface to a parallel LCD display * * This program will print a message on an LCD display * using the 8-bit wide interface method * * Port D, bit 1 (0x02) - output to RS (Register Select) input of display * bit 2 (0x04) - output to R/W (Read/Write) input of display * bit 3 (0x08) - output to E (Enable) input of display * Port B, bits 0-7 - Outputs to DB0-DB7 inputs of display. * * The second line of the display starts at address 0x40. * * Revision History * Date Author Description * 11/17/05 A. Weber First Release for 8-bit interface * 01/13/06 A. Weber Modified for CodeWarrior 5.0 * 08/25/06 A. Weber Modified for JL16 processor * 05/08/07 A. Weber Some editing changes for clarification * 06/25/07 A. Weber Updated name of direct page segment * 08/17/07 A. Weber Incorporated changes to demo board * 01/15/08 A. Weber More changes to the demo board * 02/12/08 A. Weber Changed 2nd LCD line address * 04/22/08 A. Weber Added "one" variable to make warning go away * 07/09/12 A. Weber Removed code to set security bytes * 05/29/13 A. Weber Renamed CWJL-4.c to jl16-4.c *************************************************************/ #include /* for EnableInterrupts macro */ #include "derivative.h" /* include peripheral declarations */ void initialize(void); void strout(int, unsigned char *); void iniout(unsigned char); void cmdout(unsigned char); void datout(unsigned char); void busywt(void); void del1m(int); void del40u(int); /* This pragma sets the area for allocating variables to the zero page of RAM (0x00 to 0xff) for more efficient access. */ #pragma DATA_SEG __SHORT_SEG MY_ZEROPAGE unsigned char delay0; unsigned char delay1; unsigned char delay2; /* This pragma sets the area for allocating variables back to the default area of RAM as defined in the PRM file. */ #pragma DATA_SEG DEFAULT /* Declare these strings as "const" so they are allocated in ROM */ const unsigned char str1[] = ">>> jl16-4.c <<<78901234"; const unsigned char str2[] = ">> USC EE459L <<78901234"; /* Define some multiple bit fields in the I/O ports */ /* Port D */ volatile struct { byte :1; // bit 0 - not used byte LCD_RS:1; // bit 1 - LCD Register select byte LCD_RW:1; // bit 2 - LCD Read/Write byte LCD_E:1; // bit 3 - LCD Enable byte :4; // bits 4-7 - not used } MyPTD @0x0003; #define LCD_RS MyPTD.LCD_RS #define LCD_RW MyPTD.LCD_RW #define LCD_E MyPTD.LCD_E #define Bit_LCD_RS 0x02 #define Bit_LCD_RW 0x04 #define Bit_LCD_E 0x08 void main(void) { unsigned char one = 1; // EnableInterrupts; /* enable interrupts */ /* include your code here */ CONFIG1_COPD = 1; // disable COP reset DDRB = 0xff; // Set PTB bits 0-7 for output // Set PTD1, 2, and 3 for output DDRD = Bit_LCD_E|Bit_LCD_RW|Bit_LCD_RS; initialize(); // Initialize the LCD display strout(0, (unsigned char *) str1); // Print string on line 1 strout(0x40, (unsigned char *) str2); // Print string on line 2 while (one) { // Loop forever } } /* strout - Print the contents of the character string "s" starting at LCD RAM location "x". The string must be terminated by a zero byte. */ void strout(int x, unsigned char *s) { unsigned char ch; cmdout(x | 0x80); // Make A contain a Set Display Address command while ((ch = *s++) != (unsigned char) NULL) { datout(ch); // Output the next character } } /* datout - Output a byte to the LCD display data register (the display) and wait for the busy flag to reset. */ void datout(unsigned char x) { PTB = x; // Put data in PTB PTD = Bit_LCD_RS; // Set R/W=0, E=0, RS=1 LCD_E = 1; // Set E to 1 LCD_E = 0; // Set E to 0 busywt(); // Wait for BUSY flag to reset } /* cmdout - Output a byte to the LCD display instruction register and wait for the busy flag to reset. */ void cmdout(unsigned char x) { PTB = x; // Put command in PTB PTD = 0; // Set R/W=0, E=0, RS=0 LCD_E = 1; // Set E to 1 LCD_E = 0; // Set E to 0 busywt(); // Wait for BUSY flag to reset } /* initialize - Do various things to force a initialization of the LCD display by instructions, and then set up the display parameters and turn the display on. */ void initialize() { del1m(15); // Delay at least 15ms iniout(0x30); // Send a 0x30 del1m(4); // Delay at least 4msec iniout(0x30); // Send a 0x30 del40u(3); // Delay at least 100usec cmdout(0x38); // Function Set: 8-bit interface, 2 lines cmdout(0x0f); // Display and cursor on } /* iniout - Output a byte to the LCD control register. Same as the "cmdout" function but it doesn't wait for the BUSY flag since that flag isn't working during initialization. */ void iniout(unsigned char x) { PTB = x; // Put command in PTB PTD = 0; // Set R/W=0, E=0, RS=0 LCD_E = 1; // Set E to 1 LCD_E = 0; // Set E to 0 } /* busywt - Wait for the BUSY flag to reset */ void busywt() { unsigned char bf; DDRB = 0; // Set PTB for input PTD = Bit_LCD_RW; // Set E=0, R/W=1, RS=0 do { LCD_E = 1; // Set E=1 bf = PTB & 0x80; // Read status register LCD_E = 0; // Set E=0 } while (bf != 0); // If Busy (PTB7=1), loop DDRB = 0xff; // Set PTB for output } /* Note: these delay routines only work if the the delay0 and delay1 variables are located in the RAM zero page */ /* del40u - Delay about 40usec times the "d" argument */ void del40u(int d) { while (d--) { asm { ; The following code delays about 40 microseconds by looping. ; Total time is 4 + 13 * (4 + 3) = 95 cycles ; A 9.8304MHz external clock gives an internal CPU clock of ; 2.4576MHz (407ns/cycle). 95 x .407 usec = 38.7 usec. ; The JSR and RTS instructions will add a bit more. mov #13,delay0 ; 4 cycles u1: dec delay0 ; 4 cycles bne u1 ; 3 cycles } } } /* del1m - Delay about 1msec times the "d" argument. */ void del1m(int d) { while (d--) { asm { ; The following code delays 1 millisecond by looping. ; Total time is 4 + 5 * (4 + 68 * (4 + 3) + 4 + 3) = 2439 cycles ; A 9.8304MHz external clock gives an internal CPU clock of ; 2.4576MHz (407ns/cycle). Delay is then .993 milliseconds. mov #5,delay1 ; 4 cycles m1: mov #68,delay0 ; 4 cycles m0: dec delay0 ; 4 cycles bne m0 ; 3 cycles dec delay1 ; 4 cycles bne m1 ; 3 cycles } } }