/* LCD routines by Adam Davis January 2000 This specifies a 4-bit interface to any intelligent LCD based on the HD44780 text LCD controller. The LCD is connected as follows: LCD PIC Data4 PORTA:0 Data5 PORTA:1 Data6 PORTA:2 Data7 PORTA:3 RS PORTA:4 EN PORTA:5 RW Not used in this example, The LCD is always written to. Tie to Ground (low) I have written routines for reading from the LCD, but they did not work as expected, and I did not need that functionality, so they are not included here. It is a simple matter to change the writing routine into a reading routine, and connect the RW wire to another PIC pin. If you want to change the port or bits used, you'll need to change some pragma statements below, as well as the functions write4() and main(). After initializing the LCD, you can select the register (data or instruction) by setting RS to 1 or 0. Then use write8(byte) to write a byte to the LCD. */ #include "c:\progra~1\ccs\16c66.h" #define CP_off |= 0x3F30 // This CP_off is specific to the 16c66 #pragma config CP_off,PWRTE=on,WDTE=off,FOSC=HS,BODEN=on,ID=0x0001 #pragma bit RS @ PORTA.4 #pragma bit EN @ PORTA.5 char initmsg(char number); void delayms(uns8 ms); void write4(uns8 nyble); void write8(uns8 byte); void initlcd(void); char initmsg(char number) { skip(number); #pragma return[16] = "Adam's LCD Test!" // This is the text which will be displayed } void delayms(uns8 ms) { // Delay ms Milliseconds (1/1000 of a second) // Can delay from 1 to 255 ms // This is NOT an exact delay routine! // The inner loop is about 8 instructions, // so the entire delay is a few uS over time. uns8 tempcount; // Temporary register while(ms != 0) // If ms still has time left, delay another ms { tempcount = 125; // This loop is about 8 instructions while(tempcount != 0) // 125 loops is 1000 instructions tempcount--; // Run at 4MHz is 1ms ms--; // Decrement ms } return; // Return nothing } void write4(uns8 nyble) { uns8 temp; nyble &= 0xf; // Prepare to send the nibble (4 bits) by getting rid of the top four temp = PORTA & 0xf0; // Store the current state of bits 7-4 of PORTA in temp temp |= nyble; // OR the PORTA state and nibble to be sent together PORTA = temp; // Write 7-4 of PORTA and 3-0 of nyble to PORTA EN=1; // Bring enable high nop(); // Wait a teensy bit EN=0; // Bring Enable Low return; // Return nothing } void write8(uns8 byte) { uns8 nibble; nibble = (byte & 0xf0) >> 4; // Rotate the high 4 bits (7-4) of byte into bits (3-0) of nibble write4(nibble); // Write the high 4 bits to the LCD nibble = byte & 0xf; // Copy the low four bits of byte into the low four bits of nibble write4(nibble); // Write the low 4 bits to the LCD } void initlcd(void) { delayms(20); // Wait for LCD to power up ( >15ms ) RS=0; // Set RS low for instruction write4(3); // Set interface to 8 bits delayms(5); // Wait for LCD execute instruction ( >4.1ms ) write4(3); // Set interface to 8 bits delayms(1); // Wait for LCD execute instruction ( >100us ) write4(3); // Set interface to 8 bits delayms(5); // Wait for LCD execute instruction (At this point // we could actually start using the busy flag) write4(2); // Set the display to 4 bit interface delayms(5); // Wait for LCD execute instruction write8(0x28); // Set the display to two line and ??? delayms(5); // Wait for LCD execute instruction write8(6); // ??? delayms(5); // Wait for LCD execute instruction write8(1); // Clear the LCD delayms(5); // Wait for LCD execute instruction write8(0xf); // ??? delayms(5); // Wait for LCD execute instruction return; } void main(void) { uns8 x; // x is a temporary variable, unsigned byte (0-255) PORTA = 0b.0000.0000; // All ports low at start PORTB = 0b.0000.0000; PORTC = 0b.0000.0000; TRISA = 0b.1100.0000; // 7:6 Input(1), 5:0 Output(0) TRISB = 0b.1111.1111; // 7:0 Input TRISC = 0b.1111.1111; // 7:0 Input initlcd(); // Initialize LCD while(1) { // This loop will 'blink' the init message by writing // it to the LCD and clearing it twice a second delayms(250); // Delay for 1/4 of a second RS=1; // Select the data register for(x=0;x < 16;x++) // Initmsg has 16 characters, send each one in turn write8(initmsg(x)); // Write the initmsg on the screen delayms(250); // Delay for 1/4 of a second RS=0; // Select the Instruction Register write8(0x01); // Clear LCD and move to position one, line one } }