The following example is my first attempt at printing to an LCD display using the dsPIC30F4011 microcontroller. The display I’m using is a 16×1 character screen with what I think is a standard Hitachi interface. It’s my first time using one of these, so the code is a bit long-winded at the moment, but the good news is that it’s working!
This LCD module uses the Hitachi interface, which has 4-bit and 8-bit operating modes. Here, the 4-bit mode is used, which means that each byte transmitted from the dsPIC to the LCD module is split into two 4-bit nibbles which are transmitted one after the other. The advantage of 4-bit mode is that less microcontroller pins are required – 7 digital outputs in total: 3 control lines and 4 data lines. (Actually, strictly speaking, you could get away with only 6 lines.)
The circuit diagram is shown below. Note that the 5 connections to the PICkit 2 USB programmer are not shown. (Link to editable SVG version of this image, created using Inkscape.)
The 7 connections between the dsPIC’s digital outputs and the LCD module are:
LCD pin number | LCD pin name | LCD pin description | dsPIC pin number | dsPIC pin name |
---|---|---|---|---|
4 | RS | 0: command transfer 1: data transfer |
16 | RC14 |
5 | R/W | 0: write data 1: read data (always 0 here) |
15 | RC13 |
6 | E | D4-D7 latched on falling edge of E |
14 | RC15 |
11 | D4 | Bit 0 (lsb) | 2 | RB0 |
12 | D5 | Bit 1 | 3 | RB1 |
13 | D6 | Bit 2 | 4 | RB2 |
14 | D7 | Bit 3 (msb) | 5 | RB3 |
The LCD module I’m using is shown below (front and back views of the same device). The 6-pin header at one end of the breadboard is the connector for the PICkit 2 USB programmer.
This is the complete breadboard circuit including the dsPIC and LCD module (two views of the same circuit):
I was surprised to discover that 16×1 LCD modules of this type (1 line with 16 characters of text) are typically structured as if they had 2 lines of 8 characters. The first 8 characters are “line 1″ and the second 8 characters are “line 2″. As a result, in the program below, half of the single line of text to be displayed is written to “line 1″ and half is written to “line 2″.
This is the C code for the dsPIC program:
// // LCD display program for dsPIC30F4011 // Written by Ted Burke - Last updated 16-4-2013 // #include <xc.h> #include <libpic30.h> // Configuration settings _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz _FWDT(WDT_OFF); // Watchdog timer off _FBORPOR(MCLR_DIS); // Disable reset pin #define RS_PIN _LATC14 #define RW_PIN _LATC13 #define E_PIN _LATC15 void delay_ms(unsigned int n); void send_nibble(unsigned char nibble); void send_command_byte(unsigned char byte); void send_data_byte(unsigned char byte); int main() { _TRISD0 = 0; // Make RD0 an output TRISC = 0; // RC13-15 as digital outputs TRISB = 0xFFF0; // RB0-3 as digital outputs _PCFG0 = 1; // AN0 is digital _PCFG1 = 1; // AN1 is digital _PCFG2 = 1; // AN2 is digital _PCFG3 = 1; // AN3 is digital // Let's just write to the LCD and never read! // We'll wait 2ms after every command since we can't // check the busy flag. RW_PIN = 0; RS_PIN = 0; E_PIN = 1; // Initialisation delay_ms(16); // must be more than 15ms send_nibble(0b0011); delay_ms(5); // must be more than 4.1ms send_nibble(0b0011); delay_ms(1); // must be more than 100us send_nibble(0b0011); delay_ms(5); // must be more than 4.1ms send_nibble(0b0010); // select 4-bit mode // Display settings send_command_byte(0b00101000); // N=0 : 2 lines (half lines!), F=0 : 5x7 font send_command_byte(0b00001000); // Display: display off, cursor off, blink off send_command_byte(0b00000001); // Clear display send_command_byte(0b00000110); // Set entry mode: ID=1, S=0 send_command_byte(0b00001111); // Display: display on, cursor on, blink on // Define two 8 character strings const char line1[] = " Ted's d"; const char line2[] = "sPIC30F "; // Write the two strings to lines 1 and 2 int n; send_command_byte(0x02); // Go to start of line 1 for (n=0 ; n<8 ; ++n) send_data_byte(line1[n]); send_command_byte(0xC0); // Go to start of line 2 for (n=0 ; n<8 ; ++n) send_data_byte(line2[n]); // Now just blink LED indefinitely while(1) { _LATD0 = 1 - _LATD0; delay_ms(500); } } // Delay by specified number of milliseconds void delay_ms(unsigned int n) { while(n--) __delay32(30000); } void send_nibble(unsigned char nibble) { // Note: data is latched on falling edge of pin E LATB = nibble; delay_ms(1); E_PIN = 0; delay_ms(1); E_PIN = 1; delay_ms(2); // Enough time even for slowest command } // Send a command byte (i.e. with pin RS low) void send_command_byte(unsigned char byte) { RS_PIN = 0; send_nibble(byte >> 4); send_nibble(byte & 0xF); } // Send a data byte (i.e. with pin RS high) void send_data_byte(unsigned char byte) { RS_PIN = 1; send_nibble(byte >> 4); send_nibble(byte & 0xF); }
I compiled this with Microchip’s XC16 compiler, using the following simple build script.
xc16-gcc main.c -mcpu=30F4011 -Wl,--script=p30F4011.gld if errorlevel 0 xc16-bin2hex a.out
To use the build script:
- Create a new folder.
- Save the C program in that folder as “main.c”.
- Save the build script in the same folder as “build.bat”.
- Open a console window and navigate to that folder.
- Type “build.bat” to compile the program.
- Use the PICkit 2 application (or another program) to download the compiled program (file “a.hex”) onto the dsPIC.
References
- Wikipedia article on Hitachi HD44780 LCD controller (contains useful summary of connections and commands)
- Book: PIC Microcontrollers, Appendix B: Examples (scroll down to the example titled “LCD DISPLAY”)
- HD44780 LCD controller datasheet, containing all the gory details (courtesy of Sparkfun who sell lots of LCD modules)
