PIC & LCD problem

Thread Starter

Andy206

Joined Nov 17, 2010
8
Hi everyone,

I know, there must be 100s of threads to this topic... I believe my problem is a bit different though. Probably something really stupid, but I just can't find it... and it frustrates the h$#@ out of me!

Just trying to interface an LCD (16x2) to my PIC (16F690). The worst thing is I had this working before a lot of times, unfortunately though I lost the project with the code for it. D'oh!

Setup is as follows:
RA2 - RW
RA4 - RS
RA5 - E
RC0-RC3 - D4-D7

Now the odd part, it's initialising the LCD perfectly fine... I get the cursor, either as underline, or blinking cursor... but I can't write anything on it!! Bascially it's not showing anything but a cursor. No characters. I've tried another LCD and another PIC as well, so I doubt it's hardware related.

I would appreciate it if someone could have a look through my code... something's obviously not right there.

Thanks already!

main.c
Rich (BB code):
#include <htc.h>
#include <time.h>
#define _XTAL_FREQ 125000
#include "lcd.h"
#include "delay.h"
char counter;
__CONFIG(WDTDIS & PWRTEN & MCLRDIS & UNPROTECT & BORDIS & INTIO);
void init(void){
 OPTION = 0;
 OSCCON = 0b00100000;
 TRISA = 0b00000000;
 TRISB = 0b00000000;
 TRISC = 0b00000000;
 PORTA = 0b00000000;
 PORTB = 0b00000000;
 PORTC = 0b00000000;
}
time_t time (time_t * t){
 time_t timeVar;
 return timeVar;
}
void interrupt myIsr(void){
 //if(PIR1.TMR1IF){
  TMR1IF = 0 ;                             // clear interrupt flag
    //}
}
void main(void){
 LCDInit(LS_ULINE);
 //LCDClear();
 //LCDHome();
 //LCDWriteInt(212, 5);
 LCDWriteString("test");
 //LCDWriteStringXY("test", 2, 2);
 
 //ei(); //enable interrupts
 //di(); // disable interrupts
 // counter = 0;
 // while (1){
 // //RB7 = counter >> 7;
 // DelayMs(1);
 // counter++;
 // }
 while(1);
}

lcd.h
Rich (BB code):
/********************************************************************
16X2 ALPHANEUMERIC LCD INTERFACING LIBRARY FOR PIC 18F MCUS
-----------------------------------------------------------
Easy to use library for interfacing 16x2 lcd in 4 bit mode.
MCU: PIC18FXXXX Series from Microchip.
Compiler: HI-TECH C Compiler for PIC18 MCUs (http://www.htsoft.com/)
Copyrights 2008-2009 Avinash Gupta
eXtreme Electronics, India
For More Info visit
http://www.eXtremeElectronics.co.in
Mail: me@avinashgupta.com
********************************************************************/
 
#include <htc.h>
#define _XTAL_FREQ 125000
#include "myutils.h"
 
#ifndef _LCD_H
#define _LCD_H
typedef unsigned char uint8_t;
/*_________________________________________________________________________________________*/
/************************************************
 LCD CONNECTIONS
*************************************************/
#define LCD_DATA C //Port PD0-PD3 are connected to D4-D7
#define LCD_E A  //Enable/strobe signal
#define LCD_E_POS 5 //Position of enable in above port
#define LCD_RS A 
#define LCD_RS_POS 4
#define LCD_RW A
#define LCD_RW_POS 2
 
//************************************************
#define LS_BLINK 0B00000001
#define LS_ULINE 0B00000010
 
/***************************************************
   F U N C T I O N S
****************************************************/
 
void LCDInit(uint8_t style);
void LCDWriteString(const char *msg);
void LCDWriteInt(int val,unsigned int field_length);
void LCDGotoXY(uint8_t x,uint8_t y);
//Low level
void LCDByte(uint8_t,uint8_t);
#define LCDCmd(c) (LCDByte(c,0))
#define LCDData(d) (LCDByte(d,1))
void LCDBusyLoop();
 
/***************************************************
   F U N C T I O N S     E N D
****************************************************/
 
/***************************************************
 M A C R O S
***************************************************/
#define LCDClear() LCDCmd(0b00000001)
#define LCDHome() LCDCmd(0b00000010)
#define LCDWriteStringXY(x,y,msg) {\
 LCDGotoXY(x,y);\
 LCDWriteString(msg);\
}
#define LCDWriteIntXY(x,y,val,fl) {\
 LCDGotoXY(x,y);\
 LCDWriteInt(val,fl);\
}
/***************************************************/
 
 
/*_________________________________________________________________________________________*/
#endif
lcd.c
Rich (BB code):
/********************************************************************
16X2 ALPHANEUMERIC LCD INTERFACING LIBRARY FOR PIC 18F MCUS
-----------------------------------------------------------
Easy to use library for interfacing 16x2 lcd in 4 bit mode.
MCU: PIC18FXXXX Series from Microchip.
Compiler: HI-TECH C Compiler for PIC18 MCUs (http://www.htsoft.com/)
Copyrights 2008-2009 Avinash Gupta
eXtreme Electronics, India
For More Info visit
http://www.eXtremeElectronics.co.in
Mail: me@avinashgupta.com
********************************************************************/
#include <htc.h>
#include "lcd.h"
 
#define LCD_DATA_LAT  PORT(LCD_DATA)
#define LCD_E_LAT   PORT(LCD_E)
#define LCD_RS_LAT   PORT(LCD_RS)
#define LCD_RW_LAT   PORT(LCD_RW)
#define LCD_DATA_TRIS  TRIS(LCD_DATA)
#define LCD_E_TRIS   TRIS(LCD_E)
#define LCD_RS_TRIS  TRIS(LCD_RS)
#define LCD_RW_TRIS  TRIS(LCD_RW)
#define LCD_DATA_PORT PORT(LCD_DATA)
#define SET_E() (LCD_E_LAT|=(1<<LCD_E_POS))
#define SET_RS() (LCD_RS_LAT|=(1<<LCD_RS_POS))
#define SET_RW() (LCD_RW_LAT|=(1<<LCD_RW_POS))
#define CLEAR_E() (LCD_E_LAT&=(~(1<<LCD_E_POS)))
#define CLEAR_RS() (LCD_RS_LAT&=(~(1<<LCD_RS_POS)))
#define CLEAR_RW() (LCD_RW_LAT&=(~(1<<LCD_RW_POS)))
 
 
void LCDByte(uint8_t c,uint8_t isdata)
{
//Sends a byte to the LCD in 4bit mode
//cmd=0 for data
//cmd=1 for command
 
//NOTE: THIS FUNCTION RETURS ONLY WHEN LCD HAS PROCESSED THE COMMAND
uint8_t hn,ln;   //Nibbles
uint8_t temp;
hn=c>>4;
ln=(c & 0x0F);
if(isdata==0)
 CLEAR_RS();
else
 SET_RS();
__delay_us(0.500);  //tAS
SET_E();
//Send high nibble
temp=(LCD_DATA_LAT & 0XF0)|(hn);
LCD_DATA_LAT=temp;
__delay_us(1);   //tEH
//Now data lines are stable pull E low for transmission
CLEAR_E();
__delay_us(1);
//Send the lower nibble
SET_E();
temp=(LCD_DATA_LAT & 0XF0)|(ln);
LCD_DATA_LAT=temp;
__delay_us(1);   //tEH
//SEND
CLEAR_E();
__delay_us(1);   //tEL
LCDBusyLoop();
}
void LCDBusyLoop()
{
 //This function waits till lcd is BUSY
 uint8_t busy,status=0x00,temp;
 //Change Port to input type because we are reading data
 LCD_DATA_TRIS|=0x0F;
 //change LCD mode
 SET_RW();  //Read mode
 CLEAR_RS();  //Read status
 //Let the RW/RS lines stabilize
 __delay_us(0.5);  //tAS
 
 do
 {
  SET_E();
  //Wait tDA for data to become available
  __delay_us(0.5);
  status=LCD_DATA_PORT;
  status=status<<4;
  __delay_us(0.5);
  //Pull E low
  CLEAR_E();
  __delay_us(1); //tEL
  SET_E();
  __delay_us(0.5);
  temp=LCD_DATA_PORT;
  temp&=0x0F;
  status=status|temp;
  busy=status & 0b10000000;
  __delay_us(0.5);
  CLEAR_E();
  __delay_us(1); //tEL
 }while(busy);
 CLEAR_RW();  //write mode
 //Change Port to output
 LCD_DATA_TRIS&=0xF0;
}
void LCDInit(uint8_t style)
{
 /*****************************************************************
 
 This function Initializes the lcd module
 must be called before calling lcd related functions
 Arguments:
 style = LS_BLINK,LS_ULINE(can be "OR"ed for combination)
 LS_BLINK :The cursor is blinking type
 LS_ULINE :Cursor is "underline" type else "block" type
 *****************************************************************/
 
 //After power on Wait for LCD to Initialize
 __delay_ms(30);
 
 
 
 //Set IO Ports
 LCD_DATA_TRIS&=(0xF0);
 LCD_E_TRIS&=(~(1<<LCD_E_POS));
 LCD_RS_TRIS&=(~(1<<LCD_RS_POS));
 LCD_RW_TRIS&=(~(1<<LCD_RW_POS));
 LCD_DATA_LAT&=0XF0;
 CLEAR_E();
 CLEAR_RW();
 CLEAR_RS();
 //Set 4-bit mode
 __delay_us(0.3); //tAS
 SET_E();
 LCD_DATA_LAT|=(0b00000010); // To transfer 0b00100000 i was using LCD_DATA_PORT|=0b00100000
 __delay_us(1);
 CLEAR_E();
 __delay_us(1);
 
 //Wait for LCD to execute the Functionset Command
 LCDBusyLoop();                                    // Forgot this delay
 //Now the LCD is in 4-bit mode
 LCDCmd(0b00001100|style); //Display On
 LCDCmd(0b00101000);   //function set 4-bit,2 line 5x7 dot format
}
void LCDWriteString(const char *msg)
{
 /*****************************************************************
 
 This function Writes a given string to lcd at the current cursor
 location.
 Arguments:
 msg: a null terminated string to print
 
 *****************************************************************/
 while(*msg!='\0')
 {
 LCDData(*msg);
 msg++;
 }
}
void LCDWriteInt(int val,unsigned int field_length)
{
 /***************************************************************
 This function writes a integer type value to LCD module
 Arguments:
 1)int val : Value to print
 2)unsigned int field_length :total length of field in which the value is printed
 must be between 1-5 if it is -1 the field length is no of digits in the val
 ****************************************************************/
 char str[5]={0,0,0,0,0};
 int i=4,j=0;
 while(val)
 {
 str=val%10;
 val=val/10;
 i--;
 }
 if(field_length==-1)
  while(str[j]==0) j++;
 else
  j=5-field_length;
 if(val<0) LCDData('-');
 for(i=j;i<5;i++)
 {
 LCDData(48+str);
 }
}
void LCDGotoXY(uint8_t x,uint8_t y)
{
 if(x<40)
 {
  if(y) x|=0b01000000;
  x|=0b10000000;
  LCDCmd(x);
  }
}
 
 


myutils.h
Rich (BB code):
#ifndef MYUTILS_H
 #define MYUTILS_H
 #define _CONCAT(a,b) a##b
 #define PORT(x) _CONCAT(PORT,x)
 #define LAT(x) _CONCAT(LAT,x)
 #define TRIS(x) _CONCAT(TRIS,x)
 #define bitset(var,bitno) ((var) |= 1UL < < (bitno))
 #define bitclr(var,bitno) ((var) &= ~(1UL < < (bitno)))
#endif
main.h
Rich (BB code):
extern void init(void);
extern void main(void);
extern time_t time (time_t * t);
 

maxpower097

Joined Feb 20, 2009
816
Sounds like timing issues. Try adding a couple delays after initing the LCD, and in between sending commands. Sometimes I'll have to add a 10ms delays before LCD commands for it to get em.
 

Thread Starter

Andy206

Joined Nov 17, 2010
8
Hi maxpower097,

tried that, again just now, added 200ms delays before init, after, and in between commands... still the same result. Just get a cursor in the first position. Doesn't make sense to me.

Any other ideas?
 

spinnaker

Joined Oct 29, 2009
7,830
Do you have a logic probe, logic analyzer,scope or even DMM? Go into debug mode and verify you are actually outputting something when writing a string.
 

Thread Starter

Andy206

Joined Nov 17, 2010
8
no unfortunately... got an oscilloscope and checked connections and port outputs and stuff, all good... well I guess kinda obvious if it's initialising fine. very basic scope tho, can't check what it's actually putting out when I'm writing stuff to it.

I remember when I first tried writing to an LCD a couple years ago I struggled with the initialisation part - writing to it was easy after that... guess I was wrong...
 

spinnaker

Joined Oct 29, 2009
7,830
Did you actually check it when it was outputting characters? Sounds to me like you have everything connected OK if you can see a cursor. I would be worried that you are outputting the init code but not the actual characters.

You should be able to step through your code and see when each byte (character) of the string is output.
 

cheezewizz

Joined Apr 16, 2009
82
just out of curiosity where'd you get the lcd routines? I use HTC with a 16f690 and the lcd code that comes with it in the samples folder works perfectly. Having said that the code I use relies on the proper timing of delays rather than checking whether the lcd is busy or not. As Spinnaker says, it's a bit odd that it seems to initialise OK but can't show any characters... Is it actually returning from the call to LCDByte() as it does say //NOTE: THIS FUNCTION RETURNS ONLY WHEN LCD HAS PROCESSED THE COMMAND. If you don't have the ICD header to debug on the chip can you stick some USART routines on there to debug it that way? or even just flash an LED before you hit the while loop to make sure it's actually getting that far...

Just noticed what it says at the top of lcd.h "16X2 ALPHANEUMERIC LCD INTERFACING LIBRARY FOR PIC 18F MCUS". I'd give the htc ones a go over the microchip libraries. Try using these
 

Attachments

Thread Starter

Andy206

Joined Nov 17, 2010
8
Just to finish this up... finally figured out what went wrong... only took me about a month! Plus the money for a usbee logic analyser... can highly recommend those, work a treat!

So, the problem in the end, RS didn't get set to actually write characters to the display. that's why it initialised without problems. turns out, RA4 which i used to drive RS, goes to H when I tell it to, but goes straight back to L. Maybe I missed something in the 16f690 documentation, haven't quite figured out why yet... but simply using another pin works a treat.

Thanks for all your help guys.
 

t06afre

Joined May 11, 2009
5,934
You have told your compiler that you use 125000 as your XTAL freq. The smallest delay you can create will then be a single instruction or 32 usec (4/125000). In your code you have a lot of __delay_us() with an argument smaller than 32 usec. I did a test. Using the __delay_us() function with a number less than 32 will not generate any assembler code. But using 32 will generate the simple CLRWDT as assembler code. This could perhaps be the source of your problem.
The __delay_ms and __delay_us is just simple macros
Rich (BB code):
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
I guess if the result of ((unsigned long)((x)*(_XTAL_FREQ/4000000.0))) is less than 1 no code will be generated
 

Thread Starter

Andy206

Joined Nov 17, 2010
8
Thanks Alberto and t06afre,

I did some further experimenting and couldn't actually find anything saying it was an open collector output... and even when I add a pullup it doesn't work. So I'm not sure if that's really the solution.

However, I don't think the timing is a problem either, given that it works if I use another port, and my first suspicion was timing and I changed that around a million times (at least :).

So in the end, Alberto's suggestion looks better, but I'm not sure if it's actually the solution.

Thanks for your help anyways...
 
Top