LCD With Shift Register

Discussion in 'Embedded Systems and Microcontrollers' started by ELECTRONERD, Jan 22, 2011.

  1. ELECTRONERD

    Thread Starter Senior Member

    May 26, 2009
    1,146
    16
    Hey Everyone,

    A couple weeks ago I worked with LCDs and managed to successfully utilize a 4-bit interface. Shown below!

    [​IMG]

    Now I am trying to implement a shift-register (74HC595) to control it instead, saving I/O pins. For some reason my data will not effectively transfer, do any of you see bugs?

    Code:

    Code ( (Unknown Language)):
    1. //**************************************//
    2. //        Program: LCD_2.C                //
    3. //        Author: Austin Schaller            //
    4. //        Date: January 16th, 2011        //
    5. //**************************************//
    6.  
    7. //******************************************//
    8. //        Configuration of Shift Register        //
    9. //        QA = RS                                //
    10. //        QB = EN                                //
    11. //        QC - QF = DATA                        //
    12. //******************************************//
    13.  
    14. #pragma config WDT = OFF
    15. #pragma config LVP = OFF
    16. #pragma config OSC = INTIO2
    17. #pragma config MCLRE = ON
    18. #pragma config DEBUG = OFF
    19. #pragma config PWRT = ON
    20. #pragma config BOR = OFF
    21.  
    22. // Define all other config bits so that PICkit2 doesn't moan
    23. #pragma config FSCM = OFF
    24. #pragma config IESO = OFF
    25. #pragma config STVR = OFF
    26. #pragma config CP0 = OFF
    27. #pragma config CP1 = OFF
    28. #pragma config CPB = OFF
    29. #pragma config CPD = OFF
    30. #pragma config WRT0 = OFF
    31. #pragma config WRT1 = OFF
    32. #pragma config WRTB = OFF
    33. #pragma config WRTC = OFF
    34. #pragma config WRTD = OFF
    35. #pragma config EBTR0 = OFF
    36. #pragma config EBTR1 = OFF
    37. #pragma config EBTRB = OFF                                                                                                                              
    38.  
    39. #include <p18F1320.h>
    40. #include <delays.h>
    41.  
    42. // The lower 4 bits of this port will be used
    43.  
    44. #define DATA LATAbits.LATA0         // Data pins QC-QF
    45. #define LATCH LATAbits.LATA1        // ST-CP pin of shift register
    46. #define CLOCK LATAbits.LATA2        // SH-CP pin of shift register
    47.  
    48. // Commands for Hitachi LCD
    49. #define CLEAR_DISPLAY    0x01
    50. #define FOUR_BIT       0b00101111  // 4-bit Interface
    51. #define EIGHT_BIT      0b00111111  // 8-bit Interface
    52. #define LINE_5X7       0b00110011  // 5x7 characters, single line
    53. #define LINE_5X10      0b00110111  // 5x10 characters
    54. #define LINES_5X7      0b00111011  // 5x7 characters, multiple line
    55.  
    56. #define DISPLAY_ON  0b00001111  // Display on
    57. #define DISPLAY_OFF 0b00001011  // Display off
    58. #define CURSOR_ON   0b00001111  // Cursor on
    59. #define CURSOR_OFF  0b00001101  // Cursor off
    60. #define BLINK_ON    0b00001111  // Cursor Blink
    61. #define BLINK_OFF   0b00001110  // Cursor No Blink
    62. #define UNDERLINE_ON    0b00001111
    63. #define UNDERLINE_OFF   0b00001101
    64.  
    65. #define INCREMENT    0b00000111    // Entry mode increment
    66. #define DECREMENT    0b00000101    // Entry mode decrement
    67. #define SHIFT_ON    0b00000111    // Display shift on
    68. #define SHIFT_OFF    0b00000110    // Display shift off
    69.  
    70. void LCDInit(void);
    71. void LCDCmd(unsigned char);
    72. void LCDChar(unsigned char);
    73. void shiftOut(unsigned char);
    74. void shiftOutRS(void);
    75. void PulseEnable(void);
    76. void outputData(unsigned char);
    77. // TODO: Add all prototypes
    78.  
    79. void Delay5ms(void)
    80. {
    81.     Delay1KTCYx(1); // Delay of 5ms
    82.     return;
    83. }
    84.  
    85. void Delay15ms(void)
    86. {
    87.     Delay1KTCYx(3); // Delay of 15ms
    88.     return;
    89. }
    90.  
    91. void LCDInit(void)
    92. {
    93.  
    94.     shiftOut(0x00);        // Clear all data
    95.     LCDCmd(FOUR_BIT);
    96.     LCDCmd(FOUR_BIT & LINES_5X7);
    97.     LCDCmd(INCREMENT & SHIFT_OFF);
    98.     LCDCmd(DISPLAY_ON & BLINK_OFF & UNDERLINE_OFF & CURSOR_ON);
    99.     LCDCmd(CLEAR_DISPLAY);
    100. }
    101.  
    102. void LCDCmd(unsigned char c)
    103. {
    104.     unsigned char DataHigh, DataLow;
    105.    
    106.     DataHigh |= (c >> 4);        // Shift upper nibble to take the place of low-side nibble (XXXX YYYY ---> 0000 XXXX)
    107.     outputData(DataHigh);        // Output upper nibble data to shift register
    108.    
    109.     DataLow |= (c & 0x0F);        // Retrieve lower nibble
    110.     outputData(DataLow);        // Output lower nibble data to shift register
    111.     PulseEnable();
    112.    
    113.     Delay5ms();
    114. }
    115.  
    116. void LCDChar(unsigned char c)
    117. {
    118.     unsigned char DataHigh, DataLow;
    119.     shiftOutRS();        // Enable RS (QA) for data register mode
    120.  
    121.     DataHigh |= (c >> 4);        // Shift upper nibble to take the place of low-side nibble (XXXX YYYY ---> 0000 XXXX)
    122.     outputData(DataHigh);        // Output upper nibble data to shift register
    123.    
    124.     PulseEnable();
    125.  
    126.     DataLow |= (c & 0x0F);        // Retrieve lower nibble
    127.     outputData(DataLow);        // Output lower nibble data to shift register
    128.    
    129.     PulseEnable();
    130.     Delay5ms();
    131. }    
    132.  
    133. void shiftOutRS(void)        // Shift a '1' to RS (QA)
    134. {
    135.     CLOCK = 0;
    136.     DATA = 1;
    137.     CLOCK = 1;
    138.     LATCH = 1;
    139.     LATCH = 0;
    140. }
    141.  
    142. void outputData(unsigned char data)
    143. {
    144.     if(0x80>data>0x03)        // Make sure data is within X constraints: 01XX XX11
    145.     {
    146.         data = (data<<2) & 0x3C;        // Shift data two places to the left, since RS and EN are on QA and QB
    147.         shiftOut(data);        // Output data to shift register
    148.     }
    149. }
    150.  
    151. void shiftOut(unsigned char data)
    152. {
    153.    int i;
    154.    for (i=7;i>=0;i--)
    155.    {
    156.       CLOCK = 0;        // Clear Clock
    157.       if (data & (1<<i))            // Make bit positive while incrementing with the counting variable 'i'
    158.       {
    159.          DATA = 1;
    160.       }
    161.       else
    162.       {
    163.          DATA = 0;
    164.       }
    165.       CLOCK = 1;        // Delineate between bits through clock transitions
    166.    }
    167.    LATCH = 1;        // Latch data to execute data
    168.    LATCH = 0;
    169. }
    170.  
    171. void PulseEnable()
    172. {
    173.     shiftOut(0x02);
    174.     Delay5ms();
    175.     shiftOut(0x00);
    176.     return;
    177. }
    178.  
    179. void main(void)
    180. {
    181.     OSCCON = 0x52;  // Set internal oscillator at 2 MHz
    182.     ADCON0 = 0x00;  // Disable internal ADC
    183.     ADCON1 = 0x7F;  // Set all PORTB to digital I/O
    184.     INTCON2bits.RBPU = 0;
    185.     TRISA = 0xF8;
    186.  
    187.     LCDInit();
    188.     Delay15ms();
    189.    
    190.     LCDChar('I');
    191.     LCDChar(' ');
    192.     LCDChar('a');
    193.     LCDChar('m');
    194.     LCDChar(' ');
    195.     LCDChar('a');
    196.     LCDChar('l');
    197.     LCDChar('i');
    198.     LCDChar('v');
    199.     LCDChar('e');
    200.     LCDChar('!');
    201.     LCDChar(' ');
    202.     LCDChar('=');
    203.     LCDChar(')');
    204.        
    205.     while(1);
    206. }
    Let me know if you have any questions!

    Thanks,

    Austin
     
  2. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,884
    1,001
    What do you mean "the data will not effectively transfer"?

    Have you done any troubleshooting? Can you see your "clock", "serial out" and latch being toggled?

    Is the shift register parallel out actually working and outputting expected data to pins on the LCD?
     
  3. ELECTRONERD

    Thread Starter Senior Member

    May 26, 2009
    1,146
    16
    The LCD is clear, and when I do a build it remains that way. Only when I re-connect power, however, do I see the cursor blink (which I never intended in the first place).

    This is mostly code I composed myself, so I'm wondering if the logic and algorithms seem adequate?

    I am inclined to think that it is a problem with my data being sent to the LCD from the shift register. Perhaps the data I send out the DATA port (LATAbits.LATA0) isn't correct either, I'm not entirely sure.
     
  4. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,884
    1,001
    Can you answer my other questions?


    I think you need to handle enable separately like it was done here I don't know how he get by with only using 3 data bits.

    But using a separate enable I would think you could tie latch high on the S/R and use that PIC pin for enable instead. But I have not tried this wiht the 74HC595 as the datasheet calls for a transition to latch the data.
     
    Last edited: Jan 22, 2011
  5. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    If you have PICKIT 2 it can be used as a logical analyser. It may help you some. I would have chosen a larger PIC. But you are perhaps doing this just to to see if it can be done.
     
  6. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    Don't push enable out of the shift register.

    There needs to be a 20uS delay between data ready (input) and enable going high to read that data. It's a timing issue, so you'll need to use another port for toggling enable 1-2 instructions after the shift register is dumped.
     
  7. rajbex

    New Member

    Nov 2, 2009
    22
    0
  8. ELECTRONERD

    Thread Starter Senior Member

    May 26, 2009
    1,146
    16

    So you actually have 4 pins on the PIC used, correct? This is the schematic diagram you have.

    EDIT: I see now what you did, you have pulse enable on the PIC, but SH_CP and ST_CP are wired together.

    Here is my updated code, but it still won't work!

    Code ( (Unknown Language)):
    1. //******************************************//
    2. //        Program: LCD_2.C                    //
    3. //        Author: Austin Schaller                //
    4. //        Date: February 1st, 2011            //
    5. //******************************************//
    6.  
    7. //******************************************//
    8. //        Configuration of Shift Register        //
    9. //        QA = RS                                //
    10. //        QB = EN                                //
    11. //        QC - QF = DATA                        //
    12. //******************************************//
    13.  
    14. #pragma config WDT = OFF
    15. #pragma config LVP = OFF
    16. #pragma config OSC = INTIO2
    17. #pragma config MCLRE = ON
    18. #pragma config DEBUG = OFF
    19. #pragma config PWRT = ON
    20. #pragma config BOR = OFF
    21.  
    22. // Define all other config bits so that PICkit2 doesn't moan
    23. #pragma config FSCM = OFF
    24. #pragma config IESO = OFF
    25. #pragma config STVR = OFF
    26. #pragma config CP0 = OFF
    27. #pragma config CP1 = OFF
    28. #pragma config CPB = OFF
    29. #pragma config CPD = OFF
    30. #pragma config WRT0 = OFF
    31. #pragma config WRT1 = OFF
    32. #pragma config WRTB = OFF
    33. #pragma config WRTC = OFF
    34. #pragma config WRTD = OFF
    35. #pragma config EBTR0 = OFF
    36. #pragma config EBTR1 = OFF
    37. #pragma config EBTRB = OFF                                                                                                                              
    38.  
    39. #include <p18F1320.h>
    40. #include <delays.h>
    41.  
    42. // The lower 4 bits of this port will be used
    43.  
    44. #define DATA LATAbits.LATA0         // Data pins QC-QF
    45. #define LATCH LATAbits.LATA1        // ST-CP pin of shift register
    46. #define CLOCK LATAbits.LATA2        // SH-CP pin of shift register
    47.  
    48. // Commands for Hitachi LCD
    49. #define CLEAR_DISPLAY    0x01
    50. #define FOUR_BIT       0b00101111  // 4-bit Interface
    51. #define EIGHT_BIT      0b00111111  // 8-bit Interface
    52. #define LINE_5X7       0b00110011  // 5x7 characters, single line
    53. #define LINE_5X10      0b00110111  // 5x10 characters
    54. #define LINES_5X7      0b00111011  // 5x7 characters, multiple line
    55.  
    56. #define DISPLAY_ON  0b00001111  // Display on
    57. #define DISPLAY_OFF 0b00001011  // Display off
    58. #define CURSOR_ON   0b00001111  // Cursor on
    59. #define CURSOR_OFF  0b00001101  // Cursor off
    60. #define BLINK_ON    0b00001111  // Cursor Blink
    61. #define BLINK_OFF   0b00001110  // Cursor No Blink
    62. #define UNDERLINE_ON    0b00001111
    63. #define UNDERLINE_OFF   0b00001101
    64.  
    65. #define INCREMENT    0b00000111    // Entry mode increment
    66. #define DECREMENT    0b00000101    // Entry mode decrement
    67. #define SHIFT_ON    0b00000111    // Display shift on
    68. #define SHIFT_OFF    0b00000110    // Display shift off
    69.  
    70. void LCDInit(void);
    71. void LCDCmd(unsigned char);
    72. void LCDChar(unsigned char);
    73. void shiftOut(unsigned char);
    74. void Delay5us(void);
    75. // TODO: Add all prototypes
    76.  
    77. void Delay5us()
    78. {
    79.     Nop();
    80. }
    81.  
    82. void Delay5ms(void)
    83. {
    84.     Delay1KTCYx(1); // Delay of 5ms
    85.     return;
    86. }
    87.  
    88. void Delay15ms(void)
    89. {
    90.     Delay1KTCYx(3); // Delay of 15ms
    91.     return;
    92. }
    93.  
    94. void LCDInit(void)
    95. {
    96.     shiftOut(0x00);
    97.     LCDCmd(FOUR_BIT);
    98.     LCDCmd(FOUR_BIT & LINES_5X7);
    99.     LCDCmd(INCREMENT & SHIFT_OFF);
    100.     LCDCmd(DISPLAY_ON & BLINK_OFF & UNDERLINE_OFF & CURSOR_ON);
    101.     LCDCmd(CLEAR_DISPLAY);
    102. }
    103.  
    104. void LCDCmd(unsigned char c)
    105. {
    106.     unsigned char UpperNibble, LowerNibble, bitsHigh, bitsLow;
    107.    
    108.     // Upper Nibble
    109.     UpperNibble = (c >> 4) & 0xF0;        // Shift upper nibble to take the place of low-side nibble (XXXX YYYY --> 0000 XXXX)
    110.     bitsHigh = (UpperNibble<<2) & 0x3C;
    111.     shiftOut(bitsHigh);        // Data
    112.    
    113.     bitsHigh = ((UpperNibble<<2) | 0x02) & 0x3C;
    114.     shiftOut(bitsHigh);        // Data + EN
    115.     Delay5us();
    116.    
    117.     bitsHigh = (UpperNibble<<2) & 0x3C;
    118.     shiftOut(bitsHigh);        // Data
    119.     Delay5ms();
    120.    
    121.     // Lower Nibble
    122.     LowerNibble = (c & 0x0F);
    123.     bitsLow = (LowerNibble<<2) & 0x3C;
    124.     shiftOut(bitsLow);        // Data
    125.    
    126.     bitsLow = ((LowerNibble<<2) | 0x02) & 0x3C;
    127.     shiftOut(bitsLow);        // Data + EN
    128.     Delay5us();
    129.    
    130.     bitsLow = (LowerNibble<<2) & 0x3C;
    131.     shiftOut(bitsLow);        // Data
    132.     Delay5ms();
    133. }
    134.  
    135. void LCDChar(unsigned char c)
    136. {
    137.     unsigned char UpperNibble, LowerNibble, bitsHigh, bitsLow;
    138.    
    139.     // Upper Nibble
    140.     UpperNibble = (c >> 4) & 0xF0;        // Shift upper nibble to take the place of low-side nibble (XXXX YYYY --> 0000 XXXX)
    141.     bitsHigh = ((UpperNibble<<2) | 0x01) & 0x3C;
    142.     shiftOut(bitsHigh);        // Data + RS
    143.    
    144.     bitsHigh = ((UpperNibble<<2) | 0x03) & 0x3C;
    145.     shiftOut(bitsHigh);        // Data + RS + EN
    146.     Delay5us();
    147.    
    148.     bitsHigh = ((UpperNibble<<2) | 0x01) & 0x3C;
    149.     shiftOut(bitsHigh);        // Data + RS
    150.    
    151.     // Lower Nibble
    152.     LowerNibble = (c & 0x0F);
    153.     bitsLow = ((LowerNibble<<2) | 0x01) & 0x3C;
    154.     shiftOut(bitsLow);        // Data + RS
    155.    
    156.     bitsLow = ((LowerNibble<<2) | 0x03) & 0x3C;
    157.     shiftOut(bitsLow);        // Data + RS + EN
    158.     Delay5us();
    159.    
    160.     bitsLow = ((LowerNibble<<2) | 0x01) & 0x3C;
    161.     shiftOut(bitsLow);        // Data + RS
    162.     Delay5us();
    163. }    
    164.  
    165. void shiftOut(unsigned char c)
    166. {
    167.    int i;
    168.    for (i=7;i>=0;i--)
    169.    {
    170.       CLOCK = 0;        // Clear Clock
    171.       if (c & (1<<i))            // Make bit positive while incrementing with the counting variable 'i'
    172.       {
    173.          DATA = 1;
    174.       }
    175.       else
    176.       {
    177.          DATA = 0;
    178.       }
    179.       CLOCK = 1;        // Delineate between bits through clock transitions
    180.    }
    181.    LATCH = 1;        // Latch data to execute data
    182.    LATCH = 0;
    183. }
    184.  
    185. void main(void)
    186. {
    187.     OSCCON = 0x52;  // Set internal oscillator at 2 MHz
    188.     ADCON0 = 0x00;  // Disable internal ADC
    189.     ADCON1 = 0x7F;  // Set all PORTB to digital I/O
    190.     INTCON2bits.RBPU = 0;
    191.     TRISA = 0xF8;
    192.  
    193.     LCDInit();
    194.     Delay15ms();
    195.    
    196.     LCDChar('I');
    197.     LCDChar(' ');
    198.     LCDChar('a');
    199.     LCDChar('m');
    200.     LCDChar(' ');
    201.     LCDChar('a');
    202.     LCDChar('l');
    203.     LCDChar('i');
    204.     LCDChar('v');
    205.     LCDChar('e');
    206.     LCDChar('!');
    207.     LCDChar(' ');
    208.     LCDChar('=');
    209.     LCDChar(')');
    210.        
    211.     while(1);
    212. }
    Notice now that I have the following patterns to output commands or data:

    To send Data Nibble:
    Code ( (Unknown Language)):
    1.  
    2. shiftOut[COLOR=#666600]([/COLOR][COLOR=#006666]0b00dddd01[/COLOR][COLOR=#666600]);[/COLOR]    // RS=1 (data), E=0  
    3. shiftOut[COLOR=#666600]([/COLOR][COLOR=#006666]0b00dddd11[/COLOR][COLOR=#666600]);[/COLOR]    // RS=1 (data), E=1 - clock data to LCD  
    4. shiftOut[COLOR=#666600]([/COLOR][COLOR=#006666]0b00dddd01[/COLOR][COLOR=#666600]);[/COLOR]    // RS=1 (data), E=0  
    5. // possible delay to allow LCD command to complete  
    To send Command Nibble:
    Code ( (Unknown Language)):
    1.  
    2. shiftOut[COLOR=#666600]([/COLOR][COLOR=#006666]0b00cccc00[/COLOR][COLOR=#666600]);[/COLOR]    // RS=0 (cmd), E=0  
    3. shiftOut[COLOR=#666600]([/COLOR][COLOR=#006666]0b00cccc10[/COLOR][COLOR=#666600]);[/COLOR]    // RS=0 (cmd), E=1 - clock command to LCD  
    4. shiftOut[COLOR=#666600]([/COLOR][COLOR=#006666]0b00cccc00[/COLOR][COLOR=#666600]);[/COLOR]    // RS=0 (cmd), E=0  
    5. // possible delay to allow LCD command to complete  
    I have no idea why it won't work, any further thoughts?
     
    Last edited: Feb 1, 2011
  9. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    Try:
    20mS from power on to first command to LCD
    5mS between commands (can be less for some cursor movements)
    200uS between each display character.

    Keep the enable a port on the PIC, rather than in the shift register, and allow at least 200uS "settling time" for the shift register outputs to be ready on the LCD inputs, then bring the enable high.
     
  10. ELECTRONERD

    Thread Starter Senior Member

    May 26, 2009
    1,146
    16
    Well I followed the algorithms that rajbex mentioned in his tutorial, and was able to get it working in C18! :)

    Final Code:

    Code ( (Unknown Language)):
    1. //******************************************//
    2. //        Program: LCD_2.C                    //
    3. //        Author: Austin Schaller                //
    4. //        Date: February 1st, 2011            //
    5. //******************************************//
    6.  
    7. //******************************************//
    8. //        Configuration of Shift Register        //
    9. //        QA = RS                                //
    10. //        QB = EN                                //
    11. //        QC - QF = DATA                        //
    12. //******************************************//
    13.  
    14. #pragma config WDT = OFF
    15. #pragma config LVP = OFF
    16. #pragma config OSC = INTIO2
    17. #pragma config MCLRE = ON
    18. #pragma config DEBUG = OFF
    19. #pragma config PWRT = ON
    20. #pragma config BOR = OFF
    21.  
    22. // Define all other config bits so that PICkit2 doesn't moan
    23. #pragma config FSCM = OFF
    24. #pragma config IESO = OFF
    25. #pragma config STVR = OFF
    26. #pragma config CP0 = OFF
    27. #pragma config CP1 = OFF
    28. #pragma config CPB = OFF
    29. #pragma config CPD = OFF
    30. #pragma config WRT0 = OFF
    31. #pragma config WRT1 = OFF
    32. #pragma config WRTB = OFF
    33. #pragma config WRTC = OFF
    34. #pragma config WRTD = OFF
    35. #pragma config EBTR0 = OFF
    36. #pragma config EBTR1 = OFF
    37. #pragma config EBTRB = OFF                                                                                                                              
    38.  
    39. #include <p18F1320.h>
    40. #include <delays.h>
    41.  
    42. // The lower 4 bits of this port will be used
    43.  
    44. #define DATA LATAbits.LATA0         // Data pins QC-QF
    45. #define LATCH_CLOCK LATAbits.LATA1
    46. #define EN LATAbits.LATA2        // Pulse enable pin
    47.  
    48. // Commands for Hitachi LCD
    49. #define CLEAR_DISPLAY    0x01
    50. #define FOUR_BIT       0b00101111  // 4-bit Interface
    51. #define EIGHT_BIT      0b00111111  // 8-bit Interface
    52. #define LINE_5X7       0b00110011  // 5x7 characters, single line
    53. #define LINE_5X10      0b00110111  // 5x10 characters
    54. #define LINES_5X7      0b00111011  // 5x7 characters, multiple line
    55.  
    56. #define DISPLAY_ON  0b00001111  // Display on
    57. #define DISPLAY_OFF 0b00001011  // Display off
    58. #define CURSOR_ON   0b00001111  // Cursor on
    59. #define CURSOR_OFF  0b00001101  // Cursor off
    60. #define BLINK_ON    0b00001111  // Cursor Blink
    61. #define BLINK_OFF   0b00001110  // Cursor No Blink
    62. #define UNDERLINE_ON    0b00001111
    63. #define UNDERLINE_OFF   0b00001101
    64.  
    65. #define INCREMENT    0b00000111    // Entry mode increment
    66. #define DECREMENT    0b00000101    // Entry mode decrement
    67. #define SHIFT_ON    0b00000111    // Display shift on
    68. #define SHIFT_OFF    0b00000110    // Display shift off
    69. #define PulseEnable { EN = 1; Nop(); Nop(); EN = 0; }
    70.  
    71. void LCDInit(void);
    72. void LCDCmd(unsigned char);
    73. void LCDChar(unsigned char);
    74. void shiftOut(unsigned char);
    75. void Delay5us(void);
    76. // TODO: Add all prototypes
    77.  
    78. void Delay5us()
    79. {
    80.     Nop();
    81.     Nop();
    82. }
    83.  
    84. void Delay5ms(void)
    85. {
    86.     Delay1KTCYx(1); // Delay of 5ms
    87.     return;
    88. }
    89.  
    90. void Delay15ms(void)
    91. {
    92.     Delay1KTCYx(3); // Delay of 15ms
    93.     return;
    94. }
    95.  
    96. void LCDInit(void)
    97. {
    98.     shiftOut(0x00);
    99.     LCDCmd(FOUR_BIT);
    100.     LCDCmd(FOUR_BIT & LINES_5X7);
    101.     LCDCmd(INCREMENT & SHIFT_OFF);
    102.     LCDCmd(DISPLAY_ON & BLINK_OFF & UNDERLINE_OFF & CURSOR_ON);
    103.     LCDCmd(CLEAR_DISPLAY);
    104. }
    105.  
    106. void LCDCmd(unsigned char c)
    107. {
    108.     unsigned char UpperNibble, LowerNibble;
    109.    
    110.     // Upper Nibble
    111.     UpperNibble = (c >> 4);        // Shift upper nibble to take the place of low-side nibble (XXXX YYYY --> 0000 XXXX)
    112.     Delay15ms();
    113.     shiftOut(UpperNibble);        // Data
    114.     PulseEnable;
    115.    
    116.     // Lower Nibble
    117.     LowerNibble = (c & 0x0F);
    118.     Delay15ms();
    119.     shiftOut(LowerNibble);        // Data
    120.     PulseEnable;
    121.    
    122.     Delay5ms();
    123. }
    124.  
    125. void LCDChar(unsigned char c)
    126. {
    127.     unsigned char UpperNibble, LowerNibble, bitsHigh, bitsLow;
    128.    
    129.     // Upper Nibble
    130.     UpperNibble = (c >> 4);        // Shift upper nibble to take the place of low-side nibble (XXXX YYYY --> 0000 XXXX)
    131.     bitsHigh = UpperNibble | 0x10;        // RS + Data
    132.     shiftOut(bitsHigh);
    133.     Delay15ms();
    134.     PulseEnable;
    135.    
    136.     // Lower Nibble
    137.     LowerNibble = (c & 0x0F);
    138.     bitsLow = LowerNibble | 0x10;        // RS + Data
    139.     Delay15ms();
    140.     shiftOut(bitsLow);
    141.     PulseEnable;
    142.    
    143.     Delay5ms();
    144. }    
    145.  
    146. void shiftOut(unsigned char c)
    147. {
    148.    int i;
    149.    for (i=7;i>=0;i--)
    150.    {
    151.       LATCH_CLOCK = 0;        // Clear Clock
    152.       if (c & (1<<i))            // Make bit positive while incrementing with the counting variable 'i'
    153.       {
    154.          DATA = 1;
    155.       }
    156.       else
    157.       {
    158.          DATA = 0;
    159.       }
    160.       LATCH_CLOCK = 0;
    161.       LATCH_CLOCK = 1;
    162.    }
    163.    LATCH_CLOCK = 0;
    164.    LATCH_CLOCK = 1;
    165. }
    166.  
    167. void main(void)
    168. {
    169.     int i;
    170.     OSCCON = 0x52;  // Set internal oscillator at 2 MHz
    171.     ADCON0 = 0x00;  // Disable internal ADC
    172.     ADCON1 = 0x7F;  // Set all PORTB to digital I/O
    173.     INTCON2bits.RBPU = 0;
    174.     TRISA = 0xF8;
    175.  
    176.     LCDInit();
    177.     Delay15ms();
    178.    
    179.     /*for(i=0;i<256;i++)
    180.     {
    181.         shiftOut(i);
    182.         Delay10KTCYx(15);
    183.     }*/
    184.    
    185.    
    186.     LCDChar('I');
    187.     LCDChar('t');
    188.     LCDChar(' ');
    189.     LCDChar('W');
    190.     LCDChar('o');
    191.     LCDChar('r');
    192.     LCDChar('k');
    193.     LCDChar('s');
    194.     LCDChar('!');
    195.     Delay15ms();
    196.        
    197.     while(1);
    198. }
    I appreciate everyone's assistance regarding the matter!

    I will post pictures tomorrow!
     
  11. blueroomelectronics

    AAC Fanatic!

    Jul 22, 2007
    1,758
    98
    Me too, the shift register probably costs more than a PIC with more pins.
     
  12. rajbex

    New Member

    Nov 2, 2009
    22
    0
  13. ELECTRONERD

    Thread Starter Senior Member

    May 26, 2009
    1,146
    16
    I was just doing this for practice, really.

    Here is a picture:

    [​IMG]

    Here is the final code:

    Code ( (Unknown Language)):
    1. //******************************************//
    2. //        Program: LCD_2.C                    //
    3. //        Author: Austin Schaller                //
    4. //        Date: February 2st, 2011            //
    5. //******************************************//
    6.  
    7. //******************************************//
    8. //        Configuration of Shift Register        //
    9. //        QA - QD = DATA                        //
    10. //        QE = RS                                //
    11. //******************************************//
    12.  
    13. #pragma config WDT = OFF
    14. #pragma config LVP = OFF
    15. #pragma config OSC = INTIO2
    16. #pragma config MCLRE = ON
    17. #pragma config DEBUG = OFF
    18. #pragma config PWRT = ON
    19. #pragma config BOR = OFF
    20.  
    21. // Define all other config bits so that PICkit2 doesn't moan
    22. #pragma config FSCM = OFF
    23. #pragma config IESO = OFF
    24. #pragma config STVR = OFF
    25. #pragma config CP0 = OFF
    26. #pragma config CP1 = OFF
    27. #pragma config CPB = OFF
    28. #pragma config CPD = OFF
    29. #pragma config WRT0 = OFF
    30. #pragma config WRT1 = OFF
    31. #pragma config WRTB = OFF
    32. #pragma config WRTC = OFF
    33. #pragma config WRTD = OFF
    34. #pragma config EBTR0 = OFF
    35. #pragma config EBTR1 = OFF
    36. #pragma config EBTRB = OFF                                                                                                                              
    37.  
    38. #include <p18F1320.h>
    39. #include <delays.h>
    40.  
    41. // The lower 4 bits of this port will be used
    42.  
    43. #define DATA LATAbits.LATA0         // Data pins QC-QF
    44. #define LATCH_CLOCK LATAbits.LATA1
    45. #define EN LATAbits.LATA2        // Pulse enable pin
    46.  
    47. // Commands for Hitachi LCD
    48. #define CLEAR_DISPLAY    0x01
    49. #define FOUR_BIT       0b00101111  // 4-bit Interface
    50. #define EIGHT_BIT      0b00111111  // 8-bit Interface
    51. #define LINE_5X7       0b00110011  // 5x7 characters, single line
    52. #define LINE_5X10      0b00110111  // 5x10 characters
    53. #define LINES_5X7      0b00111011  // 5x7 characters, multiple line
    54.  
    55. #define DISPLAY_ON  0b00001111  // Display on
    56. #define DISPLAY_OFF 0b00001011  // Display off
    57. #define CURSOR_ON   0b00001111  // Cursor on
    58. #define CURSOR_OFF  0b00001101  // Cursor off
    59. #define BLINK_ON    0b00001111  // Cursor Blink
    60. #define BLINK_OFF   0b00001110  // Cursor No Blink
    61. #define UNDERLINE_ON    0b00001111
    62. #define UNDERLINE_OFF   0b00001101
    63.  
    64. #define INCREMENT    0b00000111    // Entry mode increment
    65. #define DECREMENT    0b00000101    // Entry mode decrement
    66. #define SHIFT_ON    0b00000111    // Display shift on
    67. #define SHIFT_OFF    0b00000110    // Display shift off
    68. #define PulseEnable { EN = 1; Nop(); Nop(); EN = 0; }
    69.  
    70. void LCDInit(void);
    71. void LCDCmd(unsigned char);
    72. void LCDChar(unsigned char);
    73. void shiftOut(unsigned char);
    74. // TODO: Add all prototypes
    75.  
    76. void Delay5ms(void)
    77. {
    78.     Delay1KTCYx(10); // Delay of 5ms
    79.     return;
    80. }
    81.  
    82. void Delay15ms(void)
    83. {
    84.     Delay1KTCYx(30); // Delay of 15ms
    85.     return;
    86. }
    87.  
    88. void LCDInit(void)
    89. {
    90.     shiftOut(0x00);
    91.     LCDCmd(FOUR_BIT);
    92.     LCDCmd(FOUR_BIT & LINES_5X7);
    93.     LCDCmd(INCREMENT & SHIFT_OFF);
    94.     LCDCmd(DISPLAY_ON & BLINK_OFF & UNDERLINE_OFF & CURSOR_ON);
    95.     LCDCmd(CLEAR_DISPLAY);
    96. }
    97.  
    98. void LCDCmd(unsigned char c)
    99. {
    100.     unsigned char UpperNibble, LowerNibble;
    101.    
    102.     // Upper Nibble
    103.     UpperNibble = (c >> 4);        // Shift upper nibble to take the place of low-side nibble (XXXX YYYY --> 0000 XXXX)
    104.     Delay15ms();
    105.     shiftOut(UpperNibble);        // Data
    106.     PulseEnable;
    107.    
    108.     // Lower Nibble
    109.     LowerNibble = (c & 0x0F);
    110.     Delay15ms();
    111.     shiftOut(LowerNibble);        // Data
    112.     PulseEnable;
    113.    
    114.     Delay5ms();
    115. }
    116.  
    117. void LCDChar(unsigned char c)
    118. {
    119.     unsigned char UpperNibble, LowerNibble, bitsHigh, bitsLow;
    120.    
    121.     // Upper Nibble
    122.     UpperNibble = (c >> 4);        // Shift upper nibble to take the place of low-side nibble (XXXX YYYY --> 0000 XXXX)
    123.     bitsHigh = UpperNibble | 0x10;        // RS + Data
    124.     shiftOut(bitsHigh);
    125.     Delay15ms();
    126.     PulseEnable;
    127.    
    128.     // Lower Nibble
    129.     LowerNibble = (c & 0x0F);
    130.     bitsLow = LowerNibble | 0x10;        // RS + Data
    131.     Delay15ms();
    132.     shiftOut(bitsLow);
    133.     PulseEnable;
    134.    
    135.     Delay5ms();
    136. }    
    137.  
    138. void shiftOut(unsigned char c)
    139. {
    140.    int i;
    141.    for (i=7;i>=0;i--)
    142.    {
    143.       LATCH_CLOCK = 0;        // Clear Clock
    144.       if (c & (1<<i))            // Make bit positive while incrementing with the counting variable 'i'
    145.       {
    146.          DATA = 1;
    147.       }
    148.       else
    149.       {
    150.          DATA = 0;
    151.       }
    152.       LATCH_CLOCK = 0;
    153.       LATCH_CLOCK = 1;
    154.    }
    155.    LATCH_CLOCK = 0;
    156.    LATCH_CLOCK = 1;
    157. }
    158.  
    159. void main(void)
    160. {
    161.     OSCCON = 0x72;  // Set internal oscillator at 8 MHz
    162.     ADCON0 = 0x00;  // Disable internal ADC
    163.     ADCON1 = 0x7F;  // Set all PORTB to digital I/O
    164.     INTCON2bits.RBPU = 0;
    165.     TRISA = 0xF8;
    166.  
    167.     LCDInit();
    168.     Delay15ms();
    169.    
    170.    
    171.     LCDChar('I');
    172.     LCDChar('t');
    173.     LCDChar(' ');
    174.     LCDChar('W');
    175.     LCDChar('o');
    176.     LCDChar('r');
    177.     LCDChar('k');
    178.     LCDChar('s');
    179.     LCDChar('!');
    180.    
    181.     Delay15ms();
    182.        
    183.     while(1);
    184. }
    185.  
     
  14. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    I don't see any 0.1uF caps along your power rails. ;)

    Seriously they will help if you add more ICs to the board, if things act funny, add those first. It's cheap and easy to do, I put a 0.1uF mylar about every 15 pins across the power rails on both sides of the breadboard.

    If you have a breadboard that only has one power rail down the side, it gets a bit more difficult, use a jumper line and use 0.22uF caps (non-electrolytic).

    Now that that's covered.. Congrats! I'm sure this thread will be useful for others starting out trying to talk to an LCD (PIC or AVR useful!)
     
  15. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,884
    1,001
    Cool! How did you do it? Do you control Enable separately?
     
  16. ELECTRONERD

    Thread Starter Senior Member

    May 26, 2009
    1,146
    16
    I will implement those caps from now on, thanks.


    Yes, I have the pulse enable pin controlled with the μC and I combine the ST-CP and SH-CP pins of the shift register instead of using them individually.
     
    absf likes this.
  17. be80be

    Senior Member

    Jul 5, 2008
    431
    57
    How many pins on that bread board over 1000 ? let's say 1000 divide by 5 = 200 caps LOL

    Thats about how the bread board acts as capacitance. You can get by without them most times the real head ache comes,
    when you make a PCB and forget them LOL.
     
  18. absf

    Senior Member

    Dec 29, 2010
    1,492
    372
Loading...