Help with LCD Program

Discussion in 'Embedded Systems and Microcontrollers' started by beeson76, Jun 24, 2010.

  1. beeson76

    Thread Starter Member

    Apr 19, 2010
    185
    1
    This is kind of a follow up post to Using 2 Different Ports for the Same Input post by me (beeson76). That post contains the main program and this post contains the LCD.c program.

    I have an LCD program that is from the samples directory of Hi-Tech complier. I would like to get all communication with the LCD and outputs on PORTC. Here is the program. As you can see the program uses both PORTA and PORTC. PORTA for communication with the LCD and PORTC with OUTPUT.

    Code ( (Unknown Language)):
    1.  
    2.  
    3. #include "htc.h"
    4. #include "lcd.h"
    5.  
    6. void pause(unsigned short usvalue);
    7.  
    8. #define         LCD_RS          RA2
    9. #define         LCD_RW          RA4
    10. #define         LCD_EN          RA1
    11. #define         LCD_DATA        PORTC
    12. #define         LCD_STROBE()    ((LCD_EN = 1),(LCD_EN = 0))
    13.  
    14. void
    15. lcd_write (unsigned char c)
    16. {
    17.         pause (1);
    18.         LCD_DATA = ((c >> 4) & 0x0F);
    19.         LCD_STROBE();
    20.         LCD_DATA = (c & 0x0F);
    21.         LCD_STROBE();
    22. }
    23.  
    24. void
    25. lcd_clear(void)
    26. {
    27.         LCD_RS = 0;
    28.         lcd_write (0x1);
    29.         pause(2);
    30. }
    31.  
    32. void
    33. lcd_puts(const char *s)
    34. {
    35.         LCD_RS = 1;
    36.         while (*s)
    37.                 lcd_write(*s++);
    38. }
    39.  
    40. void
    41. lcd_putch(char c)
    42. {
    43.         LCD_RS = 1;
    44.         lcd_write(c);
    45. }
    46.  
    47. void
    48. lcd_goto(unsigned char pos)
    49. {
    50.         LCD_RS = 0;
    51.         lcd_write (0x80 + pos);
    52. }
    53.  
    54. void
    55. lcd_init()
    56. {
    57.         char init_value;
    58.  
    59. //      ANSEL = 0;
    60.  
    61.         init_value = 0x3;
    62.         TRISA = 0;
    63.         TRISC = 0;
    64.         LCD_RS = 0;
    65.         LCD_EN = 0;
    66.         LCD_RW = 0;
    67.  
    68.         pause(15);
    69.         LCD_DATA = init_value;
    70.         LCD_STROBE();
    71.         pause(10);
    72.         LCD_STROBE();
    73.         pause(10);
    74.         LCD_STROBE();
    75.         pause(10);
    76.         LCD_DATA = 2;
    77.         LCD_STROBE();
    78.  
    79.         lcd_write (0x28);
    80.         lcd_write (0xF);
    81.         lcd_clear();
    82.         lcd_write(0x6);
    83. }
    84.  
    85. void lcd_putint (int i)
    86. {
    87.         LCD_RS = i;
    88.         lcd_write(i);
    89. }
    90.  

    I would like for
    LCD_EN to be RC0
    LCD_RS to be RC1
    LCD_RW to be RC2

    and I would like for DB4-DB7 of the LCD inputs to be RC4-RC7.

    Thanks for any help. Appreciate it very much.
     
  2. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    You can try this. It is just from the top of my head. Not compiled or tested.
    Code ( (Unknown Language)):
    1.  
    2. /*LCD_EN to be RC0
    3. LCD_RS to be RC1
    4. LCD_RW to be RC2
    5. write cycle R/_S=1,R/_W=0 EN=1*/
    6. lcd_write (unsigned char c)
    7. {       unsigned char low_nibble=c
    8.         low_nibble=(low_nibble >> 4) | (low_nibble << 4); //C version of swapf asm instruction
    9.         c=c|0b00000011;  //LCD_EN=1,LCD_RS=1
    10.         c=c&0b11111011;  //LCD_RW=0
    11.         low_nibble=low_nibble|0b00000011; //LCD_EN=1,LCD_RS=1
    12.         low_nibble=low_nibble&0b11111011; //LCD_RW=0
    13.         pause (1);
    14.         LCD_DATA =C;  //high_nibble out
    15.         LCD_STROBE();
    16.         LCD_DATA = low_nibble; //low_nibble out
    17.         LCD_STROBE();
    18. }
    19.  
    Edit: Remember to define LCD_EN, LCD_RS and LCD_RW as described in your post
     
    Last edited: Jun 25, 2010
  3. beeson76

    Thread Starter Member

    Apr 19, 2010
    185
    1
    Thanks t06afre for the reply. I will certainly look it over and try it.

    From what I understand, because this program assigns

    Code ( (Unknown Language)):
    1.  
    2. LCD_DATA = PORTC;
    3.  
    this will assign DB4-DB7 to PORTC0..C3. Thus when I

    Code ( (Unknown Language)):
    1.  
    2. #define     LCD_RS      RC1
    3. #define     LCD_RW      RC2                                    
    4. #define     LCD_EN      RC0
    5.  
    I have a conflict.

    Because of this, I need to move my DB4-DB7 to the upper bits (upper nibbles) of LCD_DATA. Is that right?
     
  4. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    In 4 bit mode you only use the d4 to d7 of the LCD databus. First you write the Hi nibble then low. However I think you need to modify you init ruotine somewhat.
    Code ( (Unknown Language)):
    1.  
    2. void
    3. lcd_init()
    4. {
    5. char init_value;
    6.  
    7. // ANSEL = 0;
    8.  
    9. //init_value = 0x3;
    10. TRISA = 0;//do we need this?
    11. TRISC = 0;
    12. /*LCD_RS = 0;
    13. LCD_EN = 0;
    14. LCD_RW = 0;
    15.  */
    16. pause(15);
    17. LCD_DATA = 0b00110000;
    18. LCD_STROBE();
    19. pause(10);
    20. LCD_STROBE();
    21. pause(10);
    22. LCD_STROBE();
    23. pause(10);
    24. LCD_DATA = 00100000;
    25. LCD_STROBE();
    26. pause(10);
    27. lcd_write (0x28);
    28. lcd_write (0xF);
    29. lcd_clear();
    30. lcd_write(0x6);
    31. }
    32.  
     
  5. BMorse

    Senior Member

    Sep 26, 2009
    2,675
    234
    in order to accomplish what you want, you will just have to write the data nibbles to the upper 4 bits of the port you are writing to instead of the lower 4 bits...


    Try this instead, instead of shifting the data 4 bits to the right, shift it 4 bits to the left and mask it with 0xF0 instead of 0x0F....

    Code ( (Unknown Language)):
    1. void
    2. lcd_write (unsigned char c)
    3. {
    4.         pause (1);
    5.         LCD_DATA = ((c << 4) & 0xF0);
    6.         LCD_STROBE();
    7.         LCD_DATA = (c & 0xF0);
    8.         LCD_STROBE();
    9. }
    10.  
    P.S.
    One thing I did notice with using the other 4 bits of the same port as the LCD, is that if you have those configured as outputs, their state will change when data is written to the LCD..... so if you are using those other 4 bits as outputs, expect them to change to low whenever you write to the LCD, it would be best if those pins are used as inputs, then they will not be affected by the LCD data.....

    B. Morse
     
  6. beeson76

    Thread Starter Member

    Apr 19, 2010
    185
    1
    Thanks (BMorse and T06afre) for the replies.

    I have a question about the lcd_init.

    Why did you:

    LCD_DATA = 0b00110000;

    and

    LCD_DATA = 0b00100000;

    Thanks. I appreciate the help.
     
  7. beeson76

    Thread Starter Member

    Apr 19, 2010
    185
    1
    Never mind as far as the 0b00110000 and 0b00100000. I figured it out. It is part of the initialization process for the 4 bit mode. Thanks for the nice explanation of it T06afre of 4 bit initialization.
     
  8. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
  9. beeson76

    Thread Starter Member

    Apr 19, 2010
    185
    1
    If I don't read from the LCD could all my pins on my chip be set as outputs? All my pins on PORTC are set as outputs. Is that correct?
     
  10. beeson76

    Thread Starter Member

    Apr 19, 2010
    185
    1
    Do these pieces of code do the same thing:

    Code ( (Unknown Language)):
    1.  
    2. void
    3. lcd_write (unsigned char c)
    4. {
    5.       pause (1);
    6.       LCD_DATA = ((c << 4) & 0xF0);
    7.       LCD_STROBE();
    8.       LCD_DATA = (c & 0xF0);
    9.       LCD_STROBE();
    10.  
    11. }
    12.  
    Code ( (Unknown Language)):
    1.  
    2. void
    3. lcd_write (unsigned char c)
    4. {
    5.         pause (1);
    6.     LCD_DATA &= 0x0F;                  
    7.     LCD_DATA |= (c & 0xF0);            
    8.     LCD_STROBE();                      
    9.         LCD_DATA &= 0x0F;                  
    10.         LCD_DATA = ((c << 4) & 0xF0);      
    11.         LCD_STROBE();                      
    12. }
    13.  
    Code ( (Unknown Language)):
    1.  
    2. void
    3. lcd_write (unsigned char c)
    4. {
    5.     pause(1);
    6.         LCD_DATA = (LCD_DATA & 0x0F) + (c & 0xF0);                             
    7.     LCD_STROBE();
    8.     LCD_DATA = (LCD_DATA & 0x0F) + ((c & 0x0F) << 4);                              
    9.     LCD_STROBE();
    10. }
    11.  
     
    Last edited: Jun 25, 2010
  11. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    Yes that is correct. You can even tie the R/W input on the display to GND. If you still struggle I have some code you can lock at. My first suggestion did not take care of R/S signal properly. And I think also that will be a problem in the suggestion from BMorse
     
  12. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    Here is something you can try. It take care off different RS line settings. It will compile in Lite mode. I have simulated and so far as I can see it should work. I have not included any __config() settings. So that must be done
    By the way here is the new Hi-tech C compiler. It take care of a bug then using __dealy_ms() function
    http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en542849
    Code ( (Unknown Language)):
    1.  
    2. #define _XTAL_FREQ 4000000
    3. #include <htc.h>
    4. #define  LCD_RS  RC1
    5. #define  LCD_RW  RC2          
    6. #define  LCD_EN  RC0
    7. #define         LCD_DATA        PORTC
    8. #define         LCD_STROBE()    ((LCD_EN = 1),(LCD_EN = 0))
    9. //3.2.4 Bit Instructions
    10. //Wherever possible, HI-TECH C will attempt to use the PIC10/12/16 bit instructions. For
    11. //example, when using a bitwise operator and a mask to alter a bit within an integral type,
    12. //the compiler will check the mask value to determine if a bit instruction can achieve the
    13. //same functionality.
    14. //unsigned int foo;
    15. //foo |= 0x40;
    16. //will produce the instruction:
    17. //BSF _foo,6
    18. //To set or clear individual bits within integral type, the following macros could be used:
    19. //#define bitset(var, bitno) ((var) |= 1UL << (bitno))
    20. //#define bitclr(var, bitno) ((var) &= ~(1UL << (bitno)))
    21. //To perform the same operation as above, the bitset macro could be employed as
    22. //follows:
    23. //bitset(foo,6);
    24. #define bitset(var, bitno) ((var) |= 1UL << (bitno))
    25. #define bitclr(var, bitno) ((var) &= ~(1UL << (bitno)))
    26. unsigned char control_bus;
    27.  
    28.  
    29. lcd_write ( unsigned char c)
    30. {       unsigned char low_nibble=c;
    31.         low_nibble=(low_nibble >> 4) | (low_nibble << 4); //C version of swapf asm instruction
    32.         bitset(control_bus,0);//Set EN=0x01
    33.         c=c&0xf0;  //mask 4 lower bits
    34.         c=c|control_bus;
    35.         low_nibble=low_nibble&0xf0;  //mask 4 lower bits
    36.         low_nibble=low_nibble|control_bus;
    37.         LCD_DATA =c;  //high_nibble out
    38.         LCD_STROBE();
    39.         LCD_DATA = low_nibble; //low_nibble out
    40.         LCD_STROBE();
    41.  __delay_us(50);
    42. }
    43. void lcd_clear(void)
    44. {
    45.         bitclr(control_bus, 1);//Set RS line=0
    46.         lcd_write (0x1);
    47.         __delay_ms(5);
    48. }
    49. void lcd_puts(const char *s)
    50. {
    51.         bitset(control_bus, 1);//Set RS line=0x01
    52.         while (*s)
    53.                 lcd_write(*s++);
    54. }
    55. void lcd_putch(char c)
    56. {
    57.      bitset(control_bus, 1);//Set RS line=0x01
    58.         lcd_write(c);
    59. }
    60. void lcd_goto(unsigned char pos)
    61. {
    62.         bitclr(control_bus, 1);//Set RS line=0x00
    63.         lcd_write (0x80 + pos);
    64. }
    65. void lcd_init()
    66. {
    67. //char init_value;
    68.  
    69. ANSEL = 0;
    70. ANSELH =0;
    71.  
    72. //init_value = 0x3;
    73. TRISA = 0;
    74. TRISC = 0;
    75. bitclr(control_bus,0);
    76. bitclr(control_bus,1);
    77. bitclr(control_bus,2);
    78.  
    79. __delay_ms(30);
    80. LCD_DATA = 0b00110000;
    81. LCD_STROBE();
    82. __delay_ms(15);
    83. LCD_STROBE();
    84. __delay_ms(5);
    85. LCD_STROBE();
    86. __delay_ms(5);
    87. LCD_DATA = 00100000;
    88. LCD_STROBE();
    89. __delay_ms(5);
    90. lcd_write (0x28);
    91. lcd_write (0xF);
    92. lcd_clear();
    93. lcd_write(0x6);
    94. }
    95. void lcd_putint (int i)
    96. {
    97.       bitclr(control_bus, 1);//Set RS line=0x00;
    98.         lcd_write(i);
    99. }
    100.  
    101. void main(void)
    102. {  
    103.     control_bus=0;
    104.  lcd_init();
    105.  lcd_goto(0); // select first line
    106.  lcd_puts("12345678");
    107.  lcd_goto(0x40); // Select second line
    108.  lcd_puts("Hello world");
    109.  for(;;);
    110.  
    111.  
     
  13. beeson76

    Thread Starter Member

    Apr 19, 2010
    185
    1
    Thanks T06afre for the replies. I appreciate it very much. Sorry for the delay in the "thanks". I wan't able to get to the website for a few days. I have worked up my code and here is what I got. It seems to work ok by way of simulator, but I am going to try to work up a circuit now, which I haven't yet done with a microcontroller. Here is my code.

    Code ( (Unknown Language)):
    1. #include <htc.h>
    2. #include "lcd.h"
    3.  
    4. void pause(unsigned short usvalue);
    5.  
    6. #define     LCD_RS      RC1
    7. #define     LCD_RW      RC2                                    
    8. #define     LCD_EN      RC0
    9. #define     LCD_DATA    PORTC
    10. #define     LCD_STROBE()    ((LCD_EN = 1),(LCD_EN = 0))
    11.  
    12. void
    13. lcd_write (unsigned char c)
    14. {
    15.                                         //(cccc) = clearing bit - this is what is LCD_STROBE()
    16.                                         //(kkkk) = keeping bit - this is kept because of LCD_RS, LCD_RW, LCD_EN
    17.  
    18.    
    19.                         //(& 0bcccckkkk) clearing top nibble of LCD_DATA and keeping bottom nibble of LCD_DATA
    20.                     //(| 0bkkkkcccc) filling top nibble of LCD_DATA with top nibble of c
    21.                             //sending top nibble to LCD
    22.                         //clearing top nibble of LCD_DATA and keeping bottom nibble of LCD_DATA
    23.             //moving bottom nibble of c to high bits of LCD_DATA
    24.                             //sending top nibble of LCD_DATA to LCD
    25.  
    26.     pause(1);
    27.     LCD_DATA = (LCD_DATA & 0x0F) + (c & 0xF0);                             
    28.     LCD_STROBE();
    29.     LCD_DATA = (LCD_DATA & 0x0F) + ((c & 0x0F) << 4);                              
    30.     LCD_STROBE();
    31.  
    32.  
    33. }
    34.  
    35. void
    36. lcd_clear(void)
    37. {
    38.     LCD_RS = 0;
    39.     lcd_write (0x1);
    40.     pause(2);
    41. }
    42.  
    43. void
    44. lcd_puts(const char *s)
    45. {
    46.     LCD_RS = 1;
    47.     while (*s)
    48.         lcd_write(*s++);
    49. }
    50.  
    51. void
    52. lcd_putch(char c)
    53. {
    54.     LCD_RS = 1;
    55.     lcd_write(c);
    56. }
    57.  
    58. void
    59. lcd_goto(unsigned char pos)
    60. {
    61.     LCD_RS = 0;
    62.     lcd_write (0x80 + pos);
    63. }
    64.  
    65. void
    66. lcd_init()
    67. {
    68.     TRISC = 0;
    69.     LCD_EN = 0;                                                  
    70.     LCD_RS = 0;
    71.     LCD_RW = 0;
    72.  
    73.     pause(15);
    74.    
    75.     LCD_DATA &=0x0F;
    76.     LCD_DATA = 0x30;
    77.     LCD_STROBE();
    78.    
    79.     pause(5);
    80.     LCD_STROBE();
    81.    
    82.     pause(1);
    83.     LCD_STROBE();
    84.    
    85.     pause(5);
    86.     LCD_DATA &= 0x0F;
    87.     LCD_DATA = 0x20;
    88.     LCD_STROBE();
    89.    
    90.  
    91.     lcd_write (0x28);                                      
    92.     lcd_write (0x0F);                                      
    93.     lcd_clear();                   
    94.     lcd_write(0x06);                                           
    95. }
     
    Last edited: Jul 5, 2010
Loading...