/************************************************************* * jl16-5.c - Demonstrate interface to a parallel LCD display * * This program will print a message on an LCD display * using the 4-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 4-7 - Outputs to DB4-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 * 06/21/06 A. Weber Modified for 4-bit interface * 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 * 03/06/09 A. Weber Added NIBBLE_HIGH condition * 07/09/12 A. Weber Removed code to set security bytes * 05/29/13 A. Weber Renamed CWJL-5.c to jl16-5.c *************************************************************/ #include /* for EnableInterrupts macro */ #include "derivative.h" /* include peripheral declarations */ /* The NIBBLE_HIGH condition determines whether PTB bits 4-7 or 0-3 are used to send the four bit nibble to the LCD. If NIBBLE_HIGH is declared, use PTB 4-7. If NIBBLE_HIGH not declared, use PTB 0-3. */ #define NIBBLE_HIGH // Use bits 4-7 for talking to LCD void initialize(void); void strout(int, unsigned char *); void iniout(unsigned char); void cmdout(unsigned char); void datout(unsigned char); void nibout(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 */ #ifdef NIBBLE_HIGH const unsigned char str1[] = ">> jl16-5.c hi<<78901234"; #else const unsigned char str1[] = ">> jl16-5.c lo<<78901234"; #endif const unsigned char str2[] = ">> USC EE459L <<78901234"; void main(void) { unsigned char one = 1; // EnableInterrupts; /* enable interrupts */ /* include your code here */ CONFIG1_COPD = 1; // disable COP reset #ifdef NIBBLE_HIGH DDRB = 0xf0; // Set PTB bits 4-7 for output #else DDRB = 0x0f; // Set PTB bits 0-3 for output #endif DDRD = 0x0e; // Set PTD1, 2, and 3 for output 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) { PTD = 0x02; // Set R/W=0, E=0, RS=1 nibout(x); // Put data bits 4-7 in PTB nibout(x << 4); // Put data bits 0-3 in PTB 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) { PTD = 0; // Set R/W=0, E=0, RS=0 nibout(x); // Output command bits 4-7 nibout(x << 4); // Output command bits 0-3 busywt(); // Wait for BUSY flag to reset } /* nibout - Puts bits 4-7 from x into the four bits of Port B that we're using to talk to the LCD. The other bits of Port B are unchanged. Toggle the E control line low-high-low. */ void nibout(unsigned char x) { #ifdef NIBBLE_HIGH PTB = (x & 0xf0) | (PTB & 0x0f); // Use bits 4-7 #else PTB = ((x >> 4) & 0x0f) | (PTB & 0xf0); // Use bits 0-3 #endif PTD_PTD3 = 1; // Set E to 1 PTD_PTD3 = 0; // Set E to 0 } /* 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 iniout(0x30); // Send a 0x30 iniout(0x20); // Function Set: 4-bit interface busywt(); // Wait for BUSY flag to reset cmdout(0x28); // Function Set: 4-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) { PTD = 0; // Set R/W=0, E=0, RS=0 nibout(x); } /* busywt - Wait for the BUSY flag to reset */ void busywt() { unsigned char bf; DDRB = 0; // Set PTB for input PTD = 0x04; // Set E=0, R/W=1, RS=0 do { PTD_PTD3 = 1; // Set E=1 #ifdef NIBBLE_HIGH bf = PTB & 0x80; // Read status register bits 4-7 #else bf = PTB & 0x08; // Read status register bits 4-7 #endif PTD_PTD3 = 0; // Set E=0 PTD_PTD3 = 1; // Set E=1, ignore bits 0-3 PTD_PTD3 = 0; // Set E=0 } while (bf != 0); // If Busy (PTB7=1), loop #ifdef NIBBLE_HIGH DDRB = 0xf0; // Set PTB for output #else DDRB = 0x0f; // Set PTB for output #endif } /* 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 } } }