Difference between revisions of "NU32: 16x2 LCD"
NickMarchuk (talk | contribs) (New page: '''-----***UNDER CONSTRUCTION NDM 1/17***-----''' == Parallel LCD == The popular HD44780 (and compatible chipsets) can be interfaced to the NU32 PIC32 board using 6 pins for easy charact...) |
NickMarchuk (talk | contribs) |
||
Line 1: | Line 1: | ||
'''-----***UNDER CONSTRUCTION NDM 1/17***-----''' |
|||
== Parallel LCD == |
== Parallel LCD == |
||
The popular HD44780 (and compatible chipsets) can be interfaced to the NU32 PIC32 board using |
The popular HD44780 (and compatible chipsets) can be interfaced to the NU32 PIC32 board using 11 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 |
This implementation of an HD44780 LCD uses 11 I/O on the PIC as output only, so it is not optimized for speed. |
||
== LCD Hookup == |
== LCD Hookup == |
||
The LCD uses the following connections with the NU32: |
|||
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> |
|||
<tr> |
|||
<td>[[Image: lcd_pins.jpg]]</td> |
|||
<td> |
|||
<table border = 1> |
|||
<tr><td>Pin</td><td>Description</td></tr> |
|||
<tr><td>1</td><td>VSS</td></tr> |
|||
<tr><td>2</td><td>VCC</td></tr> |
|||
<tr><td>3</td><td>VEE</td></tr> |
|||
<tr><td>4</td><td>RS</td></tr> |
|||
<tr><td>5</td><td>R/W</td></tr> |
|||
<tr><td>6</td><td>E</td></tr> |
|||
<tr><td>7</td><td>DB0</td></tr> |
|||
<tr><td>8</td><td>DB1</td></tr> |
|||
<tr><td>9</td><td>DB2</td></tr> |
|||
<tr><td>10</td><td>DB3</td></tr> |
|||
<tr><td>11</td><td>DB4</td></tr> |
|||
<tr><td>12</td><td>DB5</td></tr> |
|||
<tr><td>13</td><td>DB6</td></tr> |
|||
<tr><td>14</td><td>DB7</td></tr> |
|||
<tr><td>15</td><td>LED+</td></tr> |
|||
<tr><td>16</td><td>LED-</td></tr> |
|||
</table> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
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. |
|||
<table border = 1> |
<table border = 1> |
||
<tr><td>LCD Pin</td><td>PIC Pin</td></tr> |
<tr><td>LCD Pin</td><td>PIC Pin</td></tr> |
||
<tr><td>1 - VSS</td><td>GND</td></tr> |
<tr><td>1 - VSS</td><td>GND</td></tr> |
||
<tr><td>2 - |
<tr><td>2 - VDD</td><td>+5V</td></tr> |
||
<tr><td>3 - |
<tr><td>3 - V0</td><td>~1.5k resistor to GND</td></tr> |
||
<tr><td>4 - RS</td><td> |
<tr><td>4 - RS</td><td>G12</td></tr> |
||
<tr><td>5 - |
<tr><td>5 - RW</td><td>G13</td></tr> |
||
<tr><td>6 - E</td><td> |
<tr><td>6 - E</td><td>G15</td></tr> |
||
<tr><td>7 - |
<tr><td>7 - D0</td><td>E0</td></tr> |
||
<tr><td>8 - |
<tr><td>8 - D1</td><td>E1</td></tr> |
||
<tr><td>9 - |
<tr><td>9 - D2</td><td>E2</td></tr> |
||
<tr><td>10 - |
<tr><td>10 - D3</td><td>E3</td></tr> |
||
<tr><td>11 - |
<tr><td>11 - D4</td><td>E4</td></tr> |
||
<tr><td>12 - |
<tr><td>12 - D5</td><td>E5</td></tr> |
||
<tr><td>13 - |
<tr><td>13 - D6</td><td>E6</td></tr> |
||
<tr><td>14 - |
<tr><td>14 - D7</td><td>E7</td></tr> |
||
<tr><td>15 - |
<tr><td>15 - A</td><td>100 ohm resistor to 3.3V</td></tr> |
||
<tr><td>16 - |
<tr><td>16 - K</td><td>GND</td></tr> |
||
</table> |
</table> |
||
Line 68: | Line 35: | ||
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. |
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. |
The NU32 board is based on 3.3V logical outputs, which works fine for most LCDs, but this LCD must be supplied with 5V on VDD. |
||
== LCD Commands == |
== LCD Commands == |
||
Line 74: | Line 41: | ||
In the main.c file, before the main while loop, you must initialize the LCD |
In the main.c file, before the main while loop, you must initialize the LCD |
||
<code><pre> |
<code><pre> |
||
setupLCD(); |
|||
lcd_init(); // Always call this first |
|||
</pre></code> |
</pre></code> |
||
The basic command used to write to the LCD is |
The basic command used to write to the LCD is |
||
<code><pre> |
<code><pre> |
||
LCDWriteString("Hello World", 1, 2); |
|||
putsLCD("Hello World"); |
|||
</pre></code> |
</pre></code> |
||
where 1 is the first row (options are 1 or 2), and 2 is the location to start in (options 1-16). There are only 16 characters per row, so don't try to print a string with more than 16 characters! |
|||
You can |
You can clear everything on the LCD by using |
||
<code><pre> |
<code><pre> |
||
LCDClear(0); |
|||
// move the cursor to the second line, 3rd character position |
|||
lcd_gotoxy(3, 2) |
|||
</pre></code> |
</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 |
Write the contents of a variable using |
||
<code><pre> |
<code><pre> |
||
sprintf(LCD_Out_Buffer,"k = %5.2f", k); |
|||
char buffer[5]; // this will store the string |
|||
LCDWriteString(LCD_Out_Buffer, 2, 1); |
|||
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> |
</pre></code> |
||
LCD_Out_Buffer is a 16 element char array declared in LCD.h |
|||
Use sprintf just like in serial communication, but pay attention to the modifies to your variable. |
|||
In this case, k is a float, and we don't want to print every character in the decimal number. %5.2f means use at least 5 characters (including the .) to represent the number, but only two decimals, so we should see 12.34, not 12.345, but we could see 123.45, and _1.23, where _ is really a blank space. |
|||
== Files and Example Code == |
== Files and Example Code == |
||
Include the following h and c files to your project: [[Media:LCD_NU32.zip|h and c files]] |
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 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); |
|||
</pre></code> |
|||
'''LCD.c''' |
|||
<code><pre> |
|||
/* |
|||
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 |
|||
</pre></code> |
|||
To test these commands, here is a basic main file that writes some text: |
|||
'''main.c''' |
|||
<code><pre> |
|||
/* |
|||
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 |
|||
</pre></code> |
Revision as of 18:18, 25 January 2012
Parallel LCD
The popular HD44780 (and compatible chipsets) can be interfaced to the NU32 PIC32 board using 11 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 11 I/O on the PIC as output only, so it is not optimized for speed.
LCD Hookup
The LCD uses the following connections with the NU32:
LCD Pin | PIC Pin |
1 - VSS | GND |
2 - VDD | +5V |
3 - V0 | ~1.5k resistor to GND |
4 - RS | G12 |
5 - RW | G13 |
6 - E | G15 |
7 - D0 | E0 |
8 - D1 | E1 |
9 - D2 | E2 |
10 - D3 | E3 |
11 - D4 | E4 |
12 - D5 | E5 |
13 - D6 | E6 |
14 - D7 | E7 |
15 - A | 100 ohm resistor to 3.3V |
16 - K | 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, but this LCD must be supplied with 5V on VDD.
LCD Commands
In the main.c file, before the main while loop, you must initialize the LCD
setupLCD();
The basic command used to write to the LCD is
LCDWriteString("Hello World", 1, 2);
where 1 is the first row (options are 1 or 2), and 2 is the location to start in (options 1-16). There are only 16 characters per row, so don't try to print a string with more than 16 characters!
You can clear everything on the LCD by using
LCDClear(0);
Write the contents of a variable using
sprintf(LCD_Out_Buffer,"k = %5.2f", k);
LCDWriteString(LCD_Out_Buffer, 2, 1);
LCD_Out_Buffer is a 16 element char array declared in LCD.h Use sprintf just like in serial communication, but pay attention to the modifies to your variable. In this case, k is a float, and we don't want to print every character in the decimal number. %5.2f means use at least 5 characters (including the .) to represent the number, but only two decimals, so we should see 12.34, not 12.345, but we could see 123.45, and _1.23, where _ is really a blank space.
Files and Example Code
Include the following h and c files to your project: h and c files