![]() | ![]() | ![]() |
| | |||||||
| Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc. |
| | LinkBack | Thread Tools | Display Modes |
| | (permalink) |
| Hi im trying to control a 44870 lcd with a pic18f4550. It seems everytime i try and do LCD i run into problems. Im running out of hair to pull out. I have tried the microchip c18 XLCD library, and my own lcd code, but neither work. I have included my code, and circuit diagram. The code project is a slightly modified Microchip usb framework. The code that im trying to get working resides inside LCD.c and PinDefs.h. it would seem that Im failing to initialise the lcd properly. Can anyone see any obvious mistakes im making? Many thanks. Chris LCD.C code Code: #include "LCD.h"
void Delay1mS(void);
void Delay15mS(void);
void Delay5mS(void);
void Delay200uS(void);
void PulseE(void);
void SendCommand1(byte);
void SendCharacter(char);
byte Swap(byte);
//Sends a byte command to the HD44780 display.
void SendCommand(byte command)
{
Delay15mS();
command = 0;
}
//Swaps nibbles of byte
byte Swap(byte command)
{
byte temp = command <<4;
temp |= command >>4;
return temp;
}
//Initialises the display
void OpenLCD(void)
{
//Make port outputs
LCDPORT = 0;
LCDTRIS = 0;
//Wait for display
Delay15mS();
//Send 0x03
SendCommand1(0x20);
SendCommand1(0x28);
SendCommand1(0x06);
SendCommand1(0x0c);
SendCommand1(0x01);
SendCharacter('a');
}
void SendCommand1(byte command)
{
LCDTRIS &= 0x0F;
LCDPORT &= 0x0F;
//Swap nibbles
LCDPORT |= command;
//LCDPORT |= command & 0xF0;
PulseE();
Delay15mS();
}
void SendCharacter(char character)
{
LCDPORT =0;
LCD_RS =1;
LCDPORT |= character & 0xF0;
PulseE();
LCDPORT |= Swap(character) & 0xF0;
PulseE();
Delay15mS();
}
void PulseE(void)
{
LCD_E = 1;
Delay200uS();
LCD_E = 0;
Delay1mS();
} PinDefs.h Code: /* Pin definitions and macros Chris Dec 07 */ #include <P18F4550.h> //Power check pins #define PIN_SELFPOWER PORTBbits.RB5 #define PIN_USBPOWER PORTDbits.RD3 //Switch pins #define PIN_SWITCH1 PORTBbits.RB4 #define PIN_SWITCH2 PORTBbits.RB3 //LED pins #define PIN_LED1 LATBbits.LATB2 #define PIN_LED2 LATBbits.LATB1 #define PIN_ONLED LATBbits.LATB0 //Piezo pins #define PIN_PIEZO1 LATCbits.LATC0 #define PIN_PIEZO2 LATCbits.LATC1 //LM35 #define PIN_LM35 PORTEbits.RE1 //LCD pins - bit 3 is not used for LCD and should not be manipulated #define PIN_BACKLIGHT LATCbits.LATC6 #define LCDPORT PORTD #define LCDTRIS TRISD #define LCD_RS PORTDbits.RD0 #define LCD_RW PORTDbits.RD1 #define LCD_E PORTDbits.RD2 //Macros #define ScreenOn() PIN_BACKLIGHT = 1; #define ScreenOff() PIN_BACKLIGHT = 0; Last edited by HerbertMunch; 22nd December 2007 at 04:17 PM. | |
| |
| | (permalink) |
| An obvious problem is no contrast control, depending on your specific LCD (and the ambient temperature) you may very well not be able to see if it's working or not?. Add a contrast control, and then try adjusting it - if the LCD isn't initialised you should be able to adjust it so you can see a single row of solid black squares (this works without the PIC there at all). | |
| |
| | (permalink) |
| I had a quick look at the code and the only thing I immediately spotted is that to send a command you have to still send both nibbles and clear RS. Also, your initialisation doesn't appear correct, there is a sequence of writes and delays that have to be preformed. Mike. | |
| |
| | (permalink) |
| OK cheers mate, ill have a go atthe contrast thing. I had completely overlooked that My code is messy and horrible, because it is the product of many hours of tedious pointless modification. It doesn't work with the Microchip code either. Anyway thanks for the quick reply | |
| |
| | (permalink) |
| Hi Herbert, You better make one function to write 1 byte to the LCD independently if it's an instruction or a command. The only difference between both is the RS line, 0 for instruction and 1 for a command. So first set the RS line then call your "WriteByte" routine. This is my "WriteByte" routine (for 8051 Code: ;LCD_Write_Acc ;Write acc value to LCD in two consequtive writes ; LCD_Write_Acc: push acc ;Store acc for later orl LCD_Data,#0F0h ;Send high nibble orl a,#00Fh anl LCD_Data,a setb LCD_EN clr LCD_EN pop acc ;Send low nibble swap a orl LCD_Data,#0F0h orl a,#00Fh anl LCD_Data,a setb LCD_EN clr LCD_EN RET ;END LCD_Write_Acc The caller sets the RS line accordingly and then calls the "LCD_Write_Acc" routine. Please also notice that you need to pulse the Enable line twice. Something you do correctly in your "SendCharacter" routine but not in your "SendCommand1" routine Regarding the initialize sequence you need to send the following bytes: 1) 3 times 30h 2) 1 time 20h 3) 1 time "Function set" byte, depend on display lines & font 4) 1 time 08h 5) 1 time 01h 6) 1 time "Entry mode set" byte, depend on what you want Between all these bytes you need to wait a certain time (I always wait 30ms). After that you can use the busy flag to check the status of the LCD. Hope this helped... | |
| |
| | (permalink) |
| When i started poking around at the board, I discovered something foolish. What I appear to have done is instead of connecting 5v+ to pin2, i connected it to pin3(CONTRAST). My schematic shows that both pin2 and 3 are connected to vdd, so why has eagle forgotten to connect an air wire to pin2? Cheers | |
| |
| | (permalink) | |
| Quote:
Nice one mate. thanks | ||
| |
| | (permalink) |
| Its still not working! I have made needed modifications to the board, but i still cant init the module. LCD.C Code: /*
Lcd functions
*/
#include "LCD.h"
void Delay1mS(void);
void Delay15mS(void);
void Delay5mS(void);
void Delay200uS(void);
void PulseE(void);
void SendCommand(byte);
void SendCharacter(char);
void SendCmdNibble(byte);
int LCDBusy(void);
void SendLCD(byte);
byte Swap(byte);
//Swaps nibbles of byte
byte Swap(byte command)
{
byte temp = command <<4;
temp |= command >>4;
return temp;
}
//Initialises the display
void OpenLCD(void)
{
//Make port outputs
LCDPORT = 0;
LCDTRIS = 0x08; //All outputs except for pin3 which is USb bus sense
//Wait for display
Delay15mS();
Delay15mS();
PIN_LED1 =1;
PIN_LED2 = 0;
//Send 0x03
SendCmdNibble(0x03);
SendCmdNibble(0x03);
SendCmdNibble(0x03);
SendCmdNibble(0x02);
SendCommand(0x23);
SendCommand(0x08);
SendCommand(0x01);
SendCommand(0x06);
PIN_LED1 =0;
PIN_LED2 = 1;
while (LCDBusy())
PIN_LED1 =0;
PIN_LED2 = 0;
}
void SendCmdNibble(byte command)
{
LCD_RS = 0;
LCDPORT &= 0x0F; //Discard high nibble (data)
LCDPORT |= Swap(command) & 0xF0; //Set high nibble to port (
PulseE();
Delay15mS();
}
int LCDBusy(void)
{
int result=0;
LCD_BUSY = 0;//reset busy pin
LCD_TRIS_BUSY = 1; //set pin to input
LCD_RS = 0;
LCD_RW = 1;
result = (LCDPORT & 0x80) ? 1: 0;
LCD_TRIS_BUSY = 0; //Set pin to output
return result;
}
void SendCommand(byte command)
{
//setup to send command
LCD_RS = 0;
//send command
SendLCD(command);
}
//Sends a character to the LCD
void SendCharacter(char chr)
{
LCD_RS = 1;//Setup to send character
//Send character
SendLCD((byte) chr );
}
//Sends message/command to lcd. Requires the RS line to be set appropriately
void SendLCD(byte message)
{
//Send high nibble first
LCDPORT |= message & 0xF0;
PulseE();
LCDPORT &= 0x0F;//clear data pins, but leave control pins alone
LCDPORT |= (Swap(message & 0x0F)); //swap nibbles and discard old high nibble
PulseE();
Delay15mS();
}
void PulseE(void)
{
LCD_E = 1;
LCD_E = 0;
Delay1mS();
} I just dont understand, its completley doing my head in now Any ideas? | |
| |
| | (permalink) |
| Your initialisation is still wrong. The data sheet states, After Power On, Wait more than 15mS Send Nibble 0x30 Wait more than 5mS Send Nibble 0x30 Wait more than 100uS Send Nibble 0x30 Send Nibble 0x20 The display is now initialised in 4 bit mode. In you case you will send 0x03 instead of 0x30 as you swap nibbles in your routine. Mike. | |
| |
| | (permalink) |
| Have you got the single line of black squares as you adjust the contrast? - do this without the PIC in place first, then try with the PIC. | |
| |
| | (permalink) |
| Please keep in mind that the LCD won't do anything as long as it didn't receive 8 bits = 1 byte, even in 4 bit mode. So forget your "SendCmdNibble" routine. After sending 1 nibble, the LCD won't execute nothing, since it's still missing 4 bits. You always need to send 8 bits or 1 byte!! So when Pommie writes "Send Nibble 0x30" its not correct You always need to send 8 bits (1 byte), that's why I made one routine "LCD_Write_Acc". In ALL cases I send 8 bits to the LCD. With your code Code: SendCmdNibble(0x03); SendCmdNibble(0x03); SendCmdNibble(0x03); SendCmdNibble(0x02); With your routines your initialize routine would be something like Code: LCD_RS = 0 SendLCD(0x30); Delay15mS(); SendLCD(0x30); Delay15mS(); SendLCD(0x30); Delay15mS(); SendLCD(0x20); Delay15mS(); | |
| |
| | (permalink) | |
| Quote:
![]() Mike. Edit, Maybe I should point out that until the data width is set to 4 bits then sending a nibble and sending a byte are the same thing. Last edited by Pommie; 6th July 2008 at 05:13 PM. | ||
| |
| | (permalink) |
| Thanks all for your replies. You must think im so stupid! I know i do. Has no one ever have any problems with HD44780? Last time I started on LCD, i was doing it ASM, and I spent about 2 days trying to get it to work (and many posts here as well). Nigel, heres what happens: Power ON Top row of 16 blocks shows. Bottom row flashes about 3 times and then turns off. Busy flag never clears, so led stays on, and while loop never finishes. After making modifications to the board, The LCD now turns on, before it was just the backlight! I can also see the 16x2 'place holder' blocks now i have connected the contrast directly to ground(before it was routed to vdd). Any way thanks again everyone for the replies, i really appreciate all your help on this matter. Cheers, Chris p.s will post again when it doesnt work! | |
| |
| | (permalink) | |
| Quote:
| ||
| |
| | (permalink) |
| EDITED: erroneous information removed. Last edited by eng1; 23rd December 2007 at 06:51 PM. | |
| |