PIC & LCD problem

Discussion in 'Embedded Systems and Microcontrollers' started by Andy206, Nov 17, 2010.

  1. Andy206

    Thread Starter New Member

    Nov 17, 2010
    8
    0
    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
    Code ( (Unknown Language)):
    1. #include <htc.h>
    2. #include <time.h>
    3. #define _XTAL_FREQ 125000
    4. #include "lcd.h"
    5. #include "delay.h"
    6. char counter;
    7. __CONFIG(WDTDIS & PWRTEN & MCLRDIS & UNPROTECT & BORDIS & INTIO);
    8. void init(void){
    9.  OPTION = 0;
    10.  OSCCON = 0b00100000;
    11.  TRISA = 0b00000000;
    12.  TRISB = 0b00000000;
    13.  TRISC = 0b00000000;
    14.  PORTA = 0b00000000;
    15.  PORTB = 0b00000000;
    16.  PORTC = 0b00000000;
    17. }
    18. time_t time (time_t * t){
    19.  time_t timeVar;
    20.  return timeVar;
    21. }
    22. void interrupt myIsr(void){
    23.  //if(PIR1.TMR1IF){
    24.   TMR1IF = 0 ;                             // clear interrupt flag
    25.     //}
    26. }
    27. void main(void){
    28.  LCDInit(LS_ULINE);
    29.  //LCDClear();
    30.  //LCDHome();
    31.  //LCDWriteInt(212, 5);
    32.  LCDWriteString("test");
    33.  //LCDWriteStringXY("test", 2, 2);
    34.  
    35.  //ei(); //enable interrupts
    36.  //di(); // disable interrupts
    37.  // counter = 0;
    38.  // while (1){
    39.  // //RB7 = counter >> 7;
    40.  // DelayMs(1);
    41.  // counter++;
    42.  // }
    43.  while(1);
    44. }

    lcd.h
    Code ( (Unknown Language)):
    1. /********************************************************************
    2. 16X2 ALPHANEUMERIC LCD INTERFACING LIBRARY FOR PIC 18F MCUS
    3. -----------------------------------------------------------
    4. Easy to use library for interfacing 16x2 lcd in 4 bit mode.
    5. MCU: PIC18FXXXX Series from Microchip.
    6. Compiler: HI-TECH C Compiler for PIC18 MCUs ([URL]http://www.htsoft.com/[/URL])
    7. Copyrights 2008-2009 Avinash Gupta
    8. eXtreme Electronics, India
    9. For More Info visit
    10. [URL]http://www.eXtremeElectronics.co.in[/URL]
    11. Mail: [EMAIL="me@avinashgupta.com"]me@avinashgupta.com[/EMAIL]
    12. ********************************************************************/
    13.  
    14. #include <htc.h>
    15. #define _XTAL_FREQ 125000
    16. #include "myutils.h"
    17.  
    18. #ifndef _LCD_H
    19. #define _LCD_H
    20. typedef unsigned char uint8_t;
    21. /*_________________________________________________________________________________________*/
    22. /************************************************
    23.  LCD CONNECTIONS
    24. *************************************************/
    25. #define LCD_DATA C //Port PD0-PD3 are connected to D4-D7
    26. #define LCD_E A  //Enable/strobe signal
    27. #define LCD_E_POS 5 //Position of enable in above port
    28. #define LCD_RS A
    29. #define LCD_RS_POS 4
    30. #define LCD_RW A
    31. #define LCD_RW_POS 2
    32.  
    33. //************************************************
    34. #define LS_BLINK 0B00000001
    35. #define LS_ULINE 0B00000010
    36.  
    37. /***************************************************
    38.    F U N C T I O N S
    39. ****************************************************/
    40.  
    41. void LCDInit(uint8_t style);
    42. void LCDWriteString(const char *msg);
    43. void LCDWriteInt(int val,unsigned int field_length);
    44. void LCDGotoXY(uint8_t x,uint8_t y);
    45. //Low level
    46. void LCDByte(uint8_t,uint8_t);
    47. #define LCDCmd(c) (LCDByte(c,0))
    48. #define LCDData(d) (LCDByte(d,1))
    49. void LCDBusyLoop();
    50.  
    51. /***************************************************
    52.    F U N C T I O N S     E N D
    53. ****************************************************/
    54.  
    55. /***************************************************
    56.  M A C R O S
    57. ***************************************************/
    58. #define LCDClear() LCDCmd(0b00000001)
    59. #define LCDHome() LCDCmd(0b00000010)
    60. #define LCDWriteStringXY(x,y,msg) {\
    61.  LCDGotoXY(x,y);\
    62.  LCDWriteString(msg);\
    63. }
    64. #define LCDWriteIntXY(x,y,val,fl) {\
    65.  LCDGotoXY(x,y);\
    66.  LCDWriteInt(val,fl);\
    67. }
    68. /***************************************************/
    69.  
    70.  
    71. /*_________________________________________________________________________________________*/
    72. #endif
    73.  
    74.  
    75.  
    lcd.c
    Code ( (Unknown Language)):
    1. /********************************************************************
    2. 16X2 ALPHANEUMERIC LCD INTERFACING LIBRARY FOR PIC 18F MCUS
    3. -----------------------------------------------------------
    4. Easy to use library for interfacing 16x2 lcd in 4 bit mode.
    5. MCU: PIC18FXXXX Series from Microchip.
    6. Compiler: HI-TECH C Compiler for PIC18 MCUs ([URL]http://www.htsoft.com/[/URL])
    7. Copyrights 2008-2009 Avinash Gupta
    8. eXtreme Electronics, India
    9. For More Info visit
    10. [URL]http://www.eXtremeElectronics.co.in[/URL]
    11. Mail: [EMAIL="me@avinashgupta.com"]me@avinashgupta.com[/EMAIL]
    12. ********************************************************************/
    13. #include <htc.h>
    14. #include "lcd.h"
    15.  
    16. #define LCD_DATA_LAT  PORT(LCD_DATA)
    17. #define LCD_E_LAT   PORT(LCD_E)
    18. #define LCD_RS_LAT   PORT(LCD_RS)
    19. #define LCD_RW_LAT   PORT(LCD_RW)
    20. #define LCD_DATA_TRIS  TRIS(LCD_DATA)
    21. #define LCD_E_TRIS   TRIS(LCD_E)
    22. #define LCD_RS_TRIS  TRIS(LCD_RS)
    23. #define LCD_RW_TRIS  TRIS(LCD_RW)
    24. #define LCD_DATA_PORT PORT(LCD_DATA)
    25. #define SET_E() (LCD_E_LAT|=(1<<LCD_E_POS))
    26. #define SET_RS() (LCD_RS_LAT|=(1<<LCD_RS_POS))
    27. #define SET_RW() (LCD_RW_LAT|=(1<<LCD_RW_POS))
    28. #define CLEAR_E() (LCD_E_LAT&=(~(1<<LCD_E_POS)))
    29. #define CLEAR_RS() (LCD_RS_LAT&=(~(1<<LCD_RS_POS)))
    30. #define CLEAR_RW() (LCD_RW_LAT&=(~(1<<LCD_RW_POS)))
    31.  
    32.  
    33. void LCDByte(uint8_t c,uint8_t isdata)
    34. {
    35. //Sends a byte to the LCD in 4bit mode
    36. //cmd=0 for data
    37. //cmd=1 for command
    38.  
    39. //NOTE: THIS FUNCTION RETURS ONLY WHEN LCD HAS PROCESSED THE COMMAND
    40. uint8_t hn,ln;   //Nibbles
    41. uint8_t temp;
    42. hn=c>>4;
    43. ln=(c & 0x0F);
    44. if(isdata==0)
    45.  CLEAR_RS();
    46. else
    47.  SET_RS();
    48. __delay_us(0.500);  //tAS
    49. SET_E();
    50. //Send high nibble
    51. temp=(LCD_DATA_LAT & 0XF0)|(hn);
    52. LCD_DATA_LAT=temp;
    53. __delay_us(1);   //tEH
    54. //Now data lines are stable pull E low for transmission
    55. CLEAR_E();
    56. __delay_us(1);
    57. //Send the lower nibble
    58. SET_E();
    59. temp=(LCD_DATA_LAT & 0XF0)|(ln);
    60. LCD_DATA_LAT=temp;
    61. __delay_us(1);   //tEH
    62. //SEND
    63. CLEAR_E();
    64. __delay_us(1);   //tEL
    65. LCDBusyLoop();
    66. }
    67. void LCDBusyLoop()
    68. {
    69.  //This function waits till lcd is BUSY
    70.  uint8_t busy,status=0x00,temp;
    71.  //Change Port to input type because we are reading data
    72.  LCD_DATA_TRIS|=0x0F;
    73.  //change LCD mode
    74.  SET_RW();  //Read mode
    75.  CLEAR_RS();  //Read status
    76.  //Let the RW/RS lines stabilize
    77.  __delay_us(0.5);  //tAS
    78.  
    79.  do
    80.  {
    81.   SET_E();
    82.   //Wait tDA for data to become available
    83.   __delay_us(0.5);
    84.   status=LCD_DATA_PORT;
    85.   status=status<<4;
    86.   __delay_us(0.5);
    87.   //Pull E low
    88.   CLEAR_E();
    89.   __delay_us(1); //tEL
    90.   SET_E();
    91.   __delay_us(0.5);
    92.   temp=LCD_DATA_PORT;
    93.   temp&=0x0F;
    94.   status=status|temp;
    95.   busy=status & 0b10000000;
    96.   __delay_us(0.5);
    97.   CLEAR_E();
    98.   __delay_us(1); //tEL
    99.  }while(busy);
    100.  CLEAR_RW();  //write mode
    101.  //Change Port to output
    102.  LCD_DATA_TRIS&=0xF0;
    103. }
    104. void LCDInit(uint8_t style)
    105. {
    106.  /*****************************************************************
    107.  
    108.  This function Initializes the lcd module
    109.  must be called before calling lcd related functions
    110.  Arguments:
    111.  style = LS_BLINK,LS_ULINE(can be "OR"ed for combination)
    112.  LS_BLINK :The cursor is blinking type
    113.  LS_ULINE :Cursor is "underline" type else "block" type
    114.  *****************************************************************/
    115.  
    116.  //After power on Wait for LCD to Initialize
    117.  __delay_ms(30);
    118.  
    119.  
    120.  
    121.  //Set IO Ports
    122.  LCD_DATA_TRIS&=(0xF0);
    123.  LCD_E_TRIS&=(~(1<<LCD_E_POS));
    124.  LCD_RS_TRIS&=(~(1<<LCD_RS_POS));
    125.  LCD_RW_TRIS&=(~(1<<LCD_RW_POS));
    126.  LCD_DATA_LAT&=0XF0;
    127.  CLEAR_E();
    128.  CLEAR_RW();
    129.  CLEAR_RS();
    130.  //Set 4-bit mode
    131.  __delay_us(0.3); //tAS
    132.  SET_E();
    133.  LCD_DATA_LAT|=(0b00000010); //[B] To transfer 0b00100000 i was using LCD_DATA_PORT|=0b00100000
    134.  __delay_us(1);
    135.  CLEAR_E();
    136.  __delay_us(1);
    137.  
    138.  //Wait for LCD to execute the Functionset Command
    139.  LCDBusyLoop();                                    //[B] Forgot this delay
    140.  //Now the LCD is in 4-bit mode
    141.  LCDCmd(0b00001100|style); //Display On
    142.  LCDCmd(0b00101000);   //function set 4-bit,2 line 5x7 dot format
    143. }
    144. void LCDWriteString(const char *msg)
    145. {
    146.  /*****************************************************************
    147.  
    148.  This function Writes a given string to lcd at the current cursor
    149.  location.
    150.  Arguments:
    151.  msg: a null terminated string to print
    152.  
    153.  *****************************************************************/
    154.  while(*msg!='\0')
    155.  {
    156.  LCDData(*msg);
    157.  msg++;
    158.  }
    159. }
    160. void LCDWriteInt(int val,unsigned int field_length)
    161. {
    162.  /***************************************************************
    163.  This function writes a integer type value to LCD module
    164.  Arguments:
    165.  1)int val : Value to print
    166.  2)unsigned int field_length :total length of field in which the value is printed
    167.  must be between 1-5 if it is -1 the field length is no of digits in the val
    168.  ****************************************************************/
    169.  char str[5]={0,0,0,0,0};
    170.  int i=4,j=0;
    171.  while(val)
    172.  {
    173.  str[i]=val%10;
    174.  val=val/10;
    175.  i--;
    176.  }
    177.  if(field_length==-1)
    178.   while(str[j]==0) j++;
    179.  else
    180.   j=5-field_length;
    181.  if(val<0) LCDData('-');
    182.  for(i=j;i<5;i++)
    183.  {
    184.  LCDData(48+str[i]);
    185.  }
    186. }
    187. void LCDGotoXY(uint8_t x,uint8_t y)
    188. {
    189.  if(x<40)
    190.  {
    191.   if(y) x|=0b01000000;
    192.   x|=0b10000000;
    193.   LCDCmd(x);
    194.   }
    195. }
    196.  
    197.  
    198. [/i][/i][/B][/B]


    myutils.h
    Code ( (Unknown Language)):
    1. #ifndef MYUTILS_H
    2.  #define MYUTILS_H
    3.  #define _CONCAT(a,b) a##b
    4.  #define PORT(x) _CONCAT(PORT,x)
    5.  #define LAT(x) _CONCAT(LAT,x)
    6.  #define TRIS(x) _CONCAT(TRIS,x)
    7.  #define bitset(var,bitno) ((var) |= 1UL < < (bitno))
    8.  #define bitclr(var,bitno) ((var) &= ~(1UL < < (bitno)))
    9. #endif
    10.  
    main.h
    Code ( (Unknown Language)):
    1. extern void init(void);
    2. extern void main(void);
    3. extern time_t time (time_t * t);
     
  2. maxpower097

    Well-Known Member

    Feb 20, 2009
    795
    388
    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.
     
  3. Andy206

    Thread Starter New Member

    Nov 17, 2010
    8
    0
    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?
     
  4. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,884
    1,002
    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.
     
  5. Andy206

    Thread Starter New Member

    Nov 17, 2010
    8
    0
    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...
     
  6. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,884
    1,002
    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.
     
  7. cheezewizz

    Active Member

    Apr 16, 2009
    82
    10
    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
     
  8. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    You can use MPLAB SIM to debug your code. Then using MPLAB SIM you simulate the program in MPLAB.
    In order to debug the 16f690 realtime. You must have at least a PICKIT 2 or 3 and some hardware named a "header"
    Take a look at the first posting, the recommended Webseminars. It will help you to understand the use of MPLAB SIM
    http://forum.allaboutcircuits.com/showthread.php?t=44852
     
  9. Andy206

    Thread Starter New Member

    Nov 17, 2010
    8
    0
    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.
     
  10. John P

    AAC Fanatic!

    Oct 14, 2008
    1,634
    224
    True on some PIC processors, but not the 16F690.
     
  11. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    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
    Code ( (Unknown Language)):
    1.  
    2. #define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
    3. #define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
    4.  
    I guess if the result of ((unsigned long)((x)*(_XTAL_FREQ/4000000.0))) is less than 1 no code will be generated
     
  12. Andy206

    Thread Starter New Member

    Nov 17, 2010
    8
    0
    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...
     
Loading...