Difference between revisions of "PIC32MX: Parallel LCD"
NickMarchuk (talk | contribs) |
NickMarchuk (talk | contribs) |
||
(9 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
== Parallel LCD == |
|||
Using 7 pins on the PIC32 it is possible to interface with the popular HD44780 (and compatible chipsets) for easy character output to an LCD. This can be highly useful in either debugging or generating a more complex user interface for a PIC (or other microcontroller)-based device. |
|||
The popular HD44780 (and compatible chipsets) can be interfaced to the NU32 PIC32 board using 6 pins for easy character output to an LCD. This can be highly useful in either debugging or generating a more complex user interface for a PIC (or other microcontroller)-based device. |
|||
First you will need to locate the appropriate datasheet for the actual LCD you are using. What you will want to look up in there is the arrangement of connectors on the top-left of the display, and their names so that you can appropriately match the right connectors with the correct pins on the microcontroller, and in turn with the correct software identifiers for those connections. An example of one such pin arrangement is below. |
|||
This implementation of an HD44780 LCD uses only 6 I/O on the PIC, but is not optimized for speed. If you need more efficient output, more pins can be used for communication, and this code would need to be altered slightly, but for debugging purposes start with this implementation. |
|||
== LCD Hookup == |
|||
First you will need to locate the appropriate datasheet for the actual LCD you are using. What you will want to look up in there is the arrangement of connectors on the top-left of the display, and their names so that you can appropriately match the right connectors with the correct pins on the microcontroller, and in turn with the correct software identifiers for those connections. An example of one such pin arrangement is below. |
|||
<table> |
<table> |
||
Line 32: | Line 38: | ||
</table> |
</table> |
||
Your controller may differ from this one. |
Your controller may differ from this one. Occasionally even if you've got the right datasheet these pin numbers can be backwards. If it has a backlight, try powering that up first and ensure that works. |
||
Next, you'll need to wire up the LCD for power, and the connections with the pic. |
Next, you'll need to wire up the LCD for power, and the connections with the pic. |
||
Line 40: | Line 46: | ||
<tr><td>1 - VSS</td><td>GND</td></tr> |
<tr><td>1 - VSS</td><td>GND</td></tr> |
||
<tr><td>2 - VCC</td><td>+5V</td></tr> |
<tr><td>2 - VCC</td><td>+5V</td></tr> |
||
<tr><td>3 - VEE</td><td> |
<tr><td>3 - VEE</td><td>~1V</td></tr> |
||
<tr><td>4 - RS</td><td> |
<tr><td>4 - RS</td><td>D4</td></tr> |
||
<tr><td>5 - R/W</td><td> |
<tr><td>5 - R/W</td><td>GND</td></tr> |
||
<tr><td>6 - E</td><td> |
<tr><td>6 - E</td><td>D10</td></tr> |
||
<tr><td>7 - DB0</td><td>NC</td></tr> |
<tr><td>7 - DB0</td><td>NC</td></tr> |
||
<tr><td>8 - DB1</td><td>NC</td></tr> |
<tr><td>8 - DB1</td><td>NC</td></tr> |
||
<tr><td>9 - DB2</td><td>NC</td></tr> |
<tr><td>9 - DB2</td><td>NC</td></tr> |
||
<tr><td>10 - DB3</td><td>NC</td></tr> |
<tr><td>10 - DB3</td><td>NC</td></tr> |
||
<tr><td>11 - DB4</td><td> |
<tr><td>11 - DB4</td><td>D0</td></tr> |
||
<tr><td>12 - DB5</td><td> |
<tr><td>12 - DB5</td><td>D1</td></tr> |
||
<tr><td>13 - DB6</td><td> |
<tr><td>13 - DB6</td><td>D2</td></tr> |
||
<tr><td>14 - DB7</td><td> |
<tr><td>14 - DB7</td><td>D3</td></tr> |
||
<tr><td>15 - LED+</td><td>+3.3V</td></tr> |
<tr><td>15 - LED+</td><td>+3.3V</td></tr> |
||
<tr><td>16 - LED-</td><td>GND</td></tr> |
<tr><td>16 - LED-</td><td>GND</td></tr> |
||
</table> |
</table> |
||
The VEE pin on the LCD sets the contrast of the characters on the LCD. |
The VEE pin on the LCD sets the contrast of the characters on the LCD. Create with a voltage around 1V using a 10k pot to get a nice contrast, or hook it to GND through a 1.5kOhm resistor, which also seems to work well. |
||
If you power the LCD but do not send it any commands, the top row should fill with boxes. Use this to check that your LCD works. |
If you power the LCD but do not send it any commands, the top row should fill with boxes. Use this to set your contrast and check that your LCD works. |
||
The NU32 board is based on 3.3V logical outputs, which works fine for most LCDs. |
|||
We will use the following h and c files to standardize the communication: |
|||
== LCD Commands == |
|||
LCD.h |
|||
In the main.c file, before the main while loop, you must initialize the LCD |
|||
<code><pre> |
<code><pre> |
||
lcd_init(); // Always call this first |
|||
// NOTE THAT BECAUSE WE USE THE BOOTLOADER, NO CONFIGURATION IS NECESSARY |
|||
</pre></code> |
|||
// THE BOOTLOADER PROJECT ACTUALLY CONTROLS ALL OF OUR CONFIG BITS |
|||
The basic command used to write to the LCD is |
|||
// Let compile time pre-processor calculate the CORE_TICK_PERIOD |
|||
<code><pre> |
|||
// write Hello World |
|||
putsLCD("Hello World"); |
|||
</pre></code> |
|||
You can directly set the cursor position by using |
|||
<code><pre> |
|||
// move the cursor to the second line, 3rd character position |
|||
lcd_gotoxy(3, 2) |
|||
</pre></code> |
|||
Remember the LCD can display 16 x 2 characters. |
|||
Special characters can also be used to set the cursor position |
|||
<code><pre> |
|||
// clear the screen and put the cursor in the top left |
|||
putsLCD("\f"); |
|||
// put the cursor in the bottom right |
|||
putsLCD("\n"); |
|||
</pre></code> |
|||
Write the contents of a variable using |
|||
<code><pre> |
|||
char buffer[5]; // this will store the string |
|||
int n; // this is the number of characters in the string after it has been converted |
|||
short a = 10; // the number we will convert to a string |
|||
n=sprintf(buffer, "%d", a); // make the string and see how many characters there are |
|||
putsLCD("a = "); // write some text |
|||
putsLCD(buffer); // write the contents of the variable |
|||
</pre></code> |
|||
== Files and Example Code == |
|||
Include the following h and c files to your project: [[Media:LCD_NU32.zip|h and c files]] |
|||
'''LCD.h''' |
|||
<code><pre> |
|||
/* |
|||
LCD.h |
|||
For the NU32 PIC32 Board |
|||
Write to an HD44780 LCD in 4bit mode with no reading back data |
|||
*/ |
|||
#define FPB SYS_FREQ // Result of bootloader |
#define FPB SYS_FREQ // Result of bootloader |
||
Line 77: | Line 128: | ||
// out the following line. |
// out the following line. |
||
#define USE_LCD_RW 1 |
//#define USE_LCD_RW 1 |
||
//======================================== |
//======================================== |
||
Line 86: | Line 137: | ||
void Delayms(unsigned t); |
void Delayms(unsigned t); |
||
void Delayus(unsigned t); |
void Delayus(unsigned t); |
||
void Delaytus(unsigned t); |
|||
void lcd_init(void); |
void lcd_init(void); |
||
void lcd_send_nibble(short nibble); |
void lcd_send_nibble(short nibble); |
||
Line 91: | Line 143: | ||
void lcd_gotoxy(short x, short y); |
void lcd_gotoxy(short x, short y); |
||
void putsLCD(char *s); |
void putsLCD(char *s); |
||
</pre></code> |
</pre></code> |
||
LCD.c |
'''LCD.c''' |
||
<code><pre> |
<code><pre> |
||
// flex_lcd.c |
|||
/* |
|||
LCD.c |
|||
For the NU32 PIC32 Board |
|||
Write to an HD44780 LCD in 4bit mode with no reading back data |
|||
*/ |
|||
#include "Compiler.h" |
#include "Compiler.h" |
||
Line 101: | Line 159: | ||
#include <plib.h> |
#include <plib.h> |
||
#include "LCD.h" |
|||
// NOTE THAT BECAUSE WE USE THE BOOTLOADER, NO CONFIGURATION IS NECESSARY |
|||
// THE BOOTLOADER PROJECT ACTUALLY CONTROLS ALL OF OUR CONFIG BITS |
|||
// Define constants for PINS |
|||
// Let compile time pre-processor calculate the CORE_TICK_PERIOD |
|||
#define |
#define LCD_DB4 LATDbits.LATD0 |
||
#define LCD_DB5 LATDbits.LATD1 |
|||
#define FPB SYS_FREQ // Result of bootloader |
|||
#define |
#define LCD_DB6 LATDbits.LATD2 |
||
#define |
#define LCD_DB7 LATDbits.LATD3 |
||
// Define constants for PINS B0 - B6 |
|||
#define LCD_DB4 LATBbits.LATB0 |
|||
#define LCD_DB5 LATBbits.LATB1 |
|||
#define LCD_DB6 LATBbits.LATB2 |
|||
#define LCD_DB7 LATBbits.LATB3 |
|||
#define LCD_RS LATBbits.LATB4 |
|||
#define LCD_RW LATBbits.LATB5 |
|||
#define LCD_E LATBbits.LATB6 |
|||
// If you only want a 6-pin interface to your LCD, then |
|||
// connect the R/W pin on the LCD to ground, and comment |
|||
// out the following line. |
|||
#define USE_LCD_RW 1 |
|||
//======================================== |
|||
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines |
|||
#define lcd_line_two 0x40 // LCD RAM address for the 2nd line |
|||
void Delayms(unsigned t); |
|||
void Delayus(unsigned t); |
|||
void lcd_init(void); |
|||
void lcd_send_nibble(short nibble); |
|||
void lcd_send_byte(short address, short n); |
|||
void lcd_gotoxy(short x, short y); |
|||
void putsLCD(char *s); |
|||
#define LCD_RS LATDbits.LATD4 |
|||
//#define LCD_RW LATDbits.LATD9 |
|||
#define LCD_E LATDbits.LATD10 |
|||
short const LCD_INIT_STRING[4] = |
short const LCD_INIT_STRING[4] = |
||
Line 147: | Line 178: | ||
6 // Increment cursor |
6 // Increment cursor |
||
}; |
}; |
||
//---------------------------- |
//---------------------------- |
||
Line 153: | Line 183: | ||
{ |
{ |
||
short i; |
short i; |
||
// Set all analog pins to be digital I/O |
|||
// Comment out if you want to use the analog pins |
|||
AD1PCFG = 0xFFFF; |
|||
//Set |
//Set D0-4,D9-10 as a digital output, change if you change the pins |
||
LATB |= 0x00FF; TRISB &= 0xFF00; |
|||
LATD |= 0x061F; TRISD &= 0xF9E0; |
|||
// works fine off 3.3V, in fact the following line kills the timing |
|||
//mPORTDOpenDrainOpen(BIT_0 | BIT_1 | BIT_2 | BIT_3 | BIT_4 | BIT_9 | BIT_10); |
|||
Delayms(30); |
|||
LCD_RS = LOW; // Register Select Command Register |
LCD_RS = LOW; // Register Select Command Register |
||
#ifdef USE_LCD_RW |
//#ifdef USE_LCD_RW |
||
LCD_RW = LOW; |
//LCD_RW = LOW; |
||
#endif |
//#endif |
||
LCD_E = LOW; // Disable |
LCD_E = LOW; // Disable |
||
Line 174: | Line 205: | ||
{ |
{ |
||
lcd_send_nibble(0x03); |
lcd_send_nibble(0x03); |
||
Delayms( |
Delayms(4); |
||
} |
} |
||
Line 189: | Line 220: | ||
// that case, lets just do a 5 ms delay |
// that case, lets just do a 5 ms delay |
||
// after all four of them. |
// after all four of them. |
||
#ifndef USE_LCD_RW |
//#ifndef USE_LCD_RW |
||
Delayms(5); |
Delayms(5); |
||
#endif |
//#endif |
||
} |
} |
||
Delayms(5); |
|||
putsLCD("\f"); |
|||
Delayms(5); |
|||
} |
} |
||
Line 206: | Line 239: | ||
LCD_DB7 = !!(nibble & 8); |
LCD_DB7 = !!(nibble & 8); |
||
Delaytus(1); |
|||
LCD_E = HIGH; // Enable |
LCD_E = HIGH; // Enable |
||
Delayus(2); |
Delayus(2); |
||
Line 218: | Line 251: | ||
LCD_RS = LOW; |
LCD_RS = LOW; |
||
/ |
// Need to investiage bit_test |
||
#ifdef USE_LCD_RW |
//#ifdef USE_LCD_RW |
||
while(bit_test(lcd_read_byte(),7)) ; |
//while(bit_test(lcd_read_byte(),7)) ; |
||
#else |
//#else |
||
Delayms(1); |
|||
#endif |
//#endif |
||
if(address) |
if(address) |
||
Line 230: | Line 263: | ||
LCD_RS = LOW; |
LCD_RS = LOW; |
||
Delaytus(1); |
|||
#ifdef USE_LCD_RW |
//#ifdef USE_LCD_RW |
||
LCD_RW = LOW; |
//LCD_RW = LOW; |
||
//Delaytus(1); |
|||
#endif |
//#endif |
||
LCD_E = LOW; |
LCD_E = LOW; |
||
Line 242: | Line 275: | ||
lcd_send_nibble(n & 0xf); |
lcd_send_nibble(n & 0xf); |
||
} |
} |
||
//----------------------------------- |
|||
//----------------------------- |
//----------------------------- |
||
Line 252: | Line 283: | ||
switch(*s) |
switch(*s) |
||
{ |
{ |
||
case '\f': // First Line |
case '\f': // Clear, go to First Line |
||
{ |
{ |
||
mLED_1_On(); |
|||
lcd_send_byte(0,1); |
lcd_send_byte(0,1); |
||
Delayms(2); |
Delayms(2); |
||
Line 273: | Line 302: | ||
{ |
{ |
||
lcd_send_byte(1,*s); |
lcd_send_byte(1,*s); |
||
if (*s == 'H') |
|||
{ |
|||
mLED_2_On(); |
|||
} |
|||
if (*s == 'e') |
|||
mLED_3_On(); |
|||
break; |
break; |
||
} |
} |
||
Line 301: | Line 323: | ||
lcd_send_byte(0, 0x80 | address); |
lcd_send_byte(0, 0x80 | address); |
||
} |
} |
||
//------------------------------ |
|||
/* |
|||
// This sub-routine is only called by lcd_read_byte(). |
|||
// It's not a stand-alone routine. For example, the |
|||
// R/W signal is set high by lcd_read_byte() before |
|||
// this routine is called. |
|||
#ifdef USE_LCD_RW |
|||
int8 lcd_read_nibble(void) |
|||
{ |
|||
int8 retval; |
|||
// Create bit variables so that we can easily set |
|||
// individual bits in the retval variable. |
|||
#bit retval_0 = retval.0 |
|||
#bit retval_1 = retval.1 |
|||
#bit retval_2 = retval.2 |
|||
#bit retval_3 = retval.3 |
|||
retval = 0; |
|||
output_high(LCD_E); |
|||
delay_cycles(1); |
|||
retval_0 = input(LCD_DB4); |
|||
retval_1 = input(LCD_DB5); |
|||
retval_2 = input(LCD_DB6); |
|||
retval_3 = input(LCD_DB7); |
|||
output_low(LCD_E); |
|||
return(retval); |
|||
} |
|||
#endif |
|||
//--------------------------------------- |
|||
// Read a byte from the LCD and return it. |
|||
#ifdef USE_LCD_RW |
|||
int8 lcd_read_byte(void) |
|||
{ |
|||
int8 low; |
|||
int8 high; |
|||
output_high(LCD_RW); |
|||
delay_cycles(1); |
|||
high = lcd_read_nibble(); |
|||
low = lcd_read_nibble(); |
|||
return( (high<<4) | low); |
|||
} |
|||
#endif |
|||
//------------------------------ |
|||
#ifdef USE_LCD_RW |
|||
char lcd_getc(int8 x, int8 y) |
|||
{ |
|||
char value; |
|||
lcd_gotoxy(x,y); |
|||
// Wait until busy flag is low. |
|||
while(bit_test(lcd_read_byte(),7)); |
|||
output_high(LCD_RS); |
|||
value = lcd_read_byte(); |
|||
output_low(lcd_RS); |
|||
return(value); |
|||
} |
|||
#endif |
|||
*/ |
|||
//========================== |
//========================== |
||
int main() |
|||
{ |
|||
// Configure the proper PB frequency and the number of wait states |
|||
SYSTEMConfigPerformance(SYS_FREQ); |
|||
mInitAllLEDs(); |
|||
lcd_init(); // Always call this first. |
|||
putsLCD("\nH"); |
|||
//putsLCD("B"); |
|||
while(1); |
|||
} |
|||
void Delayms( unsigned t) |
void Delayms( unsigned t) |
||
// Notes: |
|||
// This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ |
// This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ |
||
{ |
{ |
||
Line 405: | Line 336: | ||
} |
} |
||
CloseTimer1(); |
CloseTimer1(); |
||
} // Delayms |
} // Delayms |
||
Line 416: | Line 346: | ||
while (ReadTimer1() < FPB/256/1000000); |
while (ReadTimer1() < FPB/256/1000000); |
||
} |
} |
||
CloseTimer1(); |
|||
CloseTimer1(); |
CloseTimer1(); |
||
}// Delayus |
}// Delayus |
||
void Delaytus( unsigned t) |
|||
{ |
|||
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF); |
|||
while (t--) |
|||
{ // t x 1ms loop |
|||
WriteTimer1(0); |
|||
while (ReadTimer1() < FPB/256/10000000); |
|||
} |
|||
CloseTimer1(); |
|||
}// Delaytus |
|||
</pre></code> |
</pre></code> |
||
To test these commands, here is a basic main file that writes some text: |
|||
main.c |
|||
'''main.c''' |
|||
<code><pre> |
<code><pre> |
||
#include "Compiler.h" |
|||
#include "HardwareProfile.h" |
|||
#include <plib.h> |
|||
//#include "LCD.h" |
|||
/* |
|||
#define SYS_FREQ 80000000L |
|||
main.c |
|||
For the NU32 PIC32 Board |
|||
Example code for how to write to an HD44780 LCD in 4bit mode with no reading back data |
|||
*/ |
|||
#include "Compiler.h" // tells MPLAB which compiler to use |
|||
#include "HardwareProfile.h" // info on how the PIC is used, based on the constant you defined above |
|||
#include "LCD.h" |
|||
#define SYS_FREQ (80000000L) // system clock is 80 MHz |
|||
void main(void) |
|||
{ |
{ |
||
SYSTEMConfigPerformance(SYS_FREQ); // tell PIC its operating frequency |
|||
// Configure the proper PB frequency and the number of wait states |
|||
mInitAllLEDs(); // initialize LED pins, defined in HardwareProfile_NU32.h |
|||
SYSTEMConfigPerformance(SYS_FREQ); |
|||
lcd_init(); // initialize the HD44780 LCD in 4 bit mode, do this immediately after power up |
|||
mInitAllLEDs(); |
|||
putsLCD("Hello World!"); |
|||
Delayms(1000); |
|||
putsLCD("\fHi"); // "\f" clears the screen and goes to the first position on the first line |
|||
lcd_gotoxy(3,2); // move cursor to x,y |
|||
putsLCD("there"); |
|||
Delayms(1000); |
|||
putsLCD("\f\nTest this"); // "\n" goes to the next line |
|||
Delayms(500); |
|||
putsLCD("\bA"); // "\b" moves the cursor back one position |
|||
Delayms(1000); |
|||
putsLCD("\f"); |
|||
// this is how you write the contents of a variable |
|||
char buffer[5]; // this will store the string |
|||
int n; // this is the number of characters in the string after it has been converted |
|||
short a = 10; // the number we will convert to a string |
|||
n=sprintf(buffer, "%d", a); // make the string and see how many characters there are |
|||
putsLCD("a = "); // write some text |
|||
putsLCD(buffer); // write the contents of the variable |
|||
while(1) { // loop forever |
|||
if(swUser) { // swUser is high (true) until pressed |
|||
mLED_0_Off(); |
|||
mLED_1_On(); |
|||
mLED_2_Off(); |
|||
mLED_3_On(); |
|||
} |
|||
else { // swUser is low (false) if pressed |
|||
mLED_0_On(); |
|||
mLED_1_Off(); |
|||
mLED_2_On(); |
|||
mLED_3_Off(); |
|||
} |
|||
a--; // change the variable and write it to the LCD |
|||
n=sprintf(buffer, "%d", a); |
|||
putsLCD("\fa = "); |
|||
putsLCD(buffer); |
|||
Delayms(500); |
|||
} // end of while loop |
|||
} // end of main.c |
|||
lcd_init(); // Always call this first. |
|||
putsLCD("\nH"); |
|||
//putsLCD("B"); |
|||
while(1); |
|||
} |
|||
</pre></code> |
</pre></code> |
Latest revision as of 14:27, 11 January 2010
Parallel LCD
The popular HD44780 (and compatible chipsets) can be interfaced to the NU32 PIC32 board using 6 pins for easy character output to an LCD. This can be highly useful in either debugging or generating a more complex user interface for a PIC (or other microcontroller)-based device.
This implementation of an HD44780 LCD uses only 6 I/O on the PIC, but is not optimized for speed. If you need more efficient output, more pins can be used for communication, and this code would need to be altered slightly, but for debugging purposes start with this implementation.
LCD Hookup
First you will need to locate the appropriate datasheet for the actual LCD you are using. What you will want to look up in there is the arrangement of connectors on the top-left of the display, and their names so that you can appropriately match the right connectors with the correct pins on the microcontroller, and in turn with the correct software identifiers for those connections. An example of one such pin arrangement is below.
|
Your controller may differ from this one. Occasionally even if you've got the right datasheet these pin numbers can be backwards. If it has a backlight, try powering that up first and ensure that works.
Next, you'll need to wire up the LCD for power, and the connections with the pic.
LCD Pin | PIC Pin |
1 - VSS | GND |
2 - VCC | +5V |
3 - VEE | ~1V |
4 - RS | D4 |
5 - R/W | GND |
6 - E | D10 |
7 - DB0 | NC |
8 - DB1 | NC |
9 - DB2 | NC |
10 - DB3 | NC |
11 - DB4 | D0 |
12 - DB5 | D1 |
13 - DB6 | D2 |
14 - DB7 | D3 |
15 - LED+ | +3.3V |
16 - LED- | GND |
The VEE pin on the LCD sets the contrast of the characters on the LCD. Create with a voltage around 1V using a 10k pot to get a nice contrast, or hook it to GND through a 1.5kOhm resistor, which also seems to work well.
If you power the LCD but do not send it any commands, the top row should fill with boxes. Use this to set your contrast and check that your LCD works.
The NU32 board is based on 3.3V logical outputs, which works fine for most LCDs.
LCD Commands
In the main.c file, before the main while loop, you must initialize the LCD
lcd_init(); // Always call this first
The basic command used to write to the LCD is
// write Hello World
putsLCD("Hello World");
You can directly set the cursor position by using
// move the cursor to the second line, 3rd character position
lcd_gotoxy(3, 2)
Remember the LCD can display 16 x 2 characters.
Special characters can also be used to set the cursor position
// clear the screen and put the cursor in the top left
putsLCD("\f");
// put the cursor in the bottom right
putsLCD("\n");
Write the contents of a variable using
char buffer[5]; // this will store the string
int n; // this is the number of characters in the string after it has been converted
short a = 10; // the number we will convert to a string
n=sprintf(buffer, "%d", a); // make the string and see how many characters there are
putsLCD("a = "); // write some text
putsLCD(buffer); // write the contents of the variable
Files and Example Code
Include the following h and c files to your project: h and c files
LCD.h
/*
LCD.h
For the NU32 PIC32 Board
Write to an HD44780 LCD in 4bit mode with no reading back data
*/
#define FPB SYS_FREQ // Result of bootloader
#define HIGH 1
#define LOW 0
// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.
//#define USE_LCD_RW 1
//========================================
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the 2nd line
void Delayms(unsigned t);
void Delayus(unsigned t);
void Delaytus(unsigned t);
void lcd_init(void);
void lcd_send_nibble(short nibble);
void lcd_send_byte(short address, short n);
void lcd_gotoxy(short x, short y);
void putsLCD(char *s);
LCD.c
/*
LCD.c
For the NU32 PIC32 Board
Write to an HD44780 LCD in 4bit mode with no reading back data
*/
#include "Compiler.h"
#include "HardwareProfile.h"
#include <plib.h>
#include "LCD.h"
// Define constants for PINS
#define LCD_DB4 LATDbits.LATD0
#define LCD_DB5 LATDbits.LATD1
#define LCD_DB6 LATDbits.LATD2
#define LCD_DB7 LATDbits.LATD3
#define LCD_RS LATDbits.LATD4
//#define LCD_RW LATDbits.LATD9
#define LCD_E LATDbits.LATD10
short const LCD_INIT_STRING[4] =
{
0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};
//----------------------------
void lcd_init(void)
{
short i;
//Set D0-4,D9-10 as a digital output, change if you change the pins
LATD |= 0x061F; TRISD &= 0xF9E0;
// works fine off 3.3V, in fact the following line kills the timing
//mPORTDOpenDrainOpen(BIT_0 | BIT_1 | BIT_2 | BIT_3 | BIT_4 | BIT_9 | BIT_10);
Delayms(30);
LCD_RS = LOW; // Register Select Command Register
//#ifdef USE_LCD_RW
//LCD_RW = LOW;
//#endif
LCD_E = LOW; // Disable
Delayms(15);
for(i=0; i < 3; i++)
{
lcd_send_nibble(0x03);
Delayms(4);
}
lcd_send_nibble(0x02);
for(i=0; i < sizeof(LCD_INIT_STRING); i++)
{
lcd_send_byte(0, LCD_INIT_STRING[i]);
// If the R/W signal is not used, then
// the busy bit can't be polled. One of
// the init commands takes longer than
// the hard-coded delay of 60 us, so in
// that case, lets just do a 5 ms delay
// after all four of them.
//#ifndef USE_LCD_RW
Delayms(5);
//#endif
}
Delayms(5);
putsLCD("\f");
Delayms(5);
}
//-------------------------------------
void lcd_send_nibble(short nibble)
{
// Note: !! converts an integer expression
// to a boolean (1 or 0).
LCD_DB4 = !!(nibble & 1);
LCD_DB5 = !!(nibble & 2);
LCD_DB6 = !!(nibble & 4);
LCD_DB7 = !!(nibble & 8);
Delaytus(1);
LCD_E = HIGH; // Enable
Delayus(2);
LCD_E = LOW; // Disable
}
//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(short address, short n)
{
LCD_RS = LOW;
// Need to investiage bit_test
//#ifdef USE_LCD_RW
//while(bit_test(lcd_read_byte(),7)) ;
//#else
Delayms(1);
//#endif
if(address)
LCD_RS = HIGH;
else
LCD_RS = LOW;
Delaytus(1);
//#ifdef USE_LCD_RW
//LCD_RW = LOW;
//Delaytus(1);
//#endif
LCD_E = LOW;
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
//-----------------------------
void putsLCD(char *s)
{
while( *s != '\0')
{
switch(*s)
{
case '\f': // Clear, go to First Line
{
lcd_send_byte(0,1);
Delayms(2);
break;
}
case '\n': // Next Line
{
lcd_gotoxy(1,2);
break;
}
case '\b':
{
lcd_send_byte(0,0x10);
break;
}
default:
{
lcd_send_byte(1,*s);
break;
}
}
s++;
Delayus(10);
}
}
//----------------------------
void lcd_gotoxy(short x, short y)
{
short address;
if(y != 1)
address = lcd_line_two;
else
address=0;
address += x-1;
lcd_send_byte(0, 0x80 | address);
}
//==========================
void Delayms( unsigned t)
// This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ
{
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF);
while (t--)
{ // t x 1ms loop
WriteTimer1(0);
while (ReadTimer1() < FPB/256/1000);
}
CloseTimer1();
} // Delayms
void Delayus( unsigned t)
{
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF);
while (t--)
{ // t x 1ms loop
WriteTimer1(0);
while (ReadTimer1() < FPB/256/1000000);
}
CloseTimer1();
}// Delayus
void Delaytus( unsigned t)
{
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF);
while (t--)
{ // t x 1ms loop
WriteTimer1(0);
while (ReadTimer1() < FPB/256/10000000);
}
CloseTimer1();
}// Delaytus
To test these commands, here is a basic main file that writes some text:
main.c
/*
main.c
For the NU32 PIC32 Board
Example code for how to write to an HD44780 LCD in 4bit mode with no reading back data
*/
#include "Compiler.h" // tells MPLAB which compiler to use
#include "HardwareProfile.h" // info on how the PIC is used, based on the constant you defined above
#include "LCD.h"
#define SYS_FREQ (80000000L) // system clock is 80 MHz
void main(void)
{
SYSTEMConfigPerformance(SYS_FREQ); // tell PIC its operating frequency
mInitAllLEDs(); // initialize LED pins, defined in HardwareProfile_NU32.h
lcd_init(); // initialize the HD44780 LCD in 4 bit mode, do this immediately after power up
putsLCD("Hello World!");
Delayms(1000);
putsLCD("\fHi"); // "\f" clears the screen and goes to the first position on the first line
lcd_gotoxy(3,2); // move cursor to x,y
putsLCD("there");
Delayms(1000);
putsLCD("\f\nTest this"); // "\n" goes to the next line
Delayms(500);
putsLCD("\bA"); // "\b" moves the cursor back one position
Delayms(1000);
putsLCD("\f");
// this is how you write the contents of a variable
char buffer[5]; // this will store the string
int n; // this is the number of characters in the string after it has been converted
short a = 10; // the number we will convert to a string
n=sprintf(buffer, "%d", a); // make the string and see how many characters there are
putsLCD("a = "); // write some text
putsLCD(buffer); // write the contents of the variable
while(1) { // loop forever
if(swUser) { // swUser is high (true) until pressed
mLED_0_Off();
mLED_1_On();
mLED_2_Off();
mLED_3_On();
}
else { // swUser is low (false) if pressed
mLED_0_On();
mLED_1_Off();
mLED_2_On();
mLED_3_Off();
}
a--; // change the variable and write it to the LCD
n=sprintf(buffer, "%d", a);
putsLCD("\fa = ");
putsLCD(buffer);
Delayms(500);
} // end of while loop
} // end of main.c