Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Help Required with 'String to LCD' Program

Status
Not open for further replies.
Hello,

I wrote this code to send a string to an lcd. It sends a character at a time and works. Have been trying without success to send a string 'properly'. Tried adopting relevent bits of Futz's code from the sticky with no luck.

What do I need to do to send the characters as one string? I start off by doing this with the characters I want to send as a string?

Code:
char text1[] = "A String";
  char text2[] = "Another String";
Code:
/* 04.01.11 */

#include <p18f2420.h>
#include <Delays.h>

#pragma config OSC  = INTIO67                 // internal oscillator with I/O on RA6 & RA7
#pragma config WDT = OFF
#pragma config PBADEN = ON                    // portb bits 0 thru 4 as digital input (analog by default at POR)

//LCD_RS: 0 = select instruction register, 1 = select data register
#define LCD_RS           LATCbits.LATC4        // RS = Register Select [lcd pin 04] pic pin 15
#define LCD_RW            LATCbits.LATC5        // RW = Read / Write [lcd pin 05] pic pin 16
#define LCD_En            LATCbits.LATC6        // En = Enable [lcd pin 06] pic pin 17

#define LCD_BF            PORTCbits.RC3         // BF = Busy Flag [pic pin 14]
#define LCDdata2port    LATC

void LCD_init (void);                        // subroutine for initialising lcd
void LCD_E (void);                            // subroutine for toggling lcd enable pin
void LCD_busy (void);                        // subroutine for reading lcd busy flag
void write2LCD (void);                        // subroutine for sending data to lcd
void LCD_char(void);                        // subroutine sets lcd RS pin and calls 'write to lcd' routine

#pragma udata
unsigned char data2LCD;                        // 8 bit variable
unsigned char RS_flag;                        // 8 bit variable


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#pragma code
void main (void)
{
    OSCCON = 0b01100010;                 // set Fosc = 4Mhz = 1uS instruction cycle time
    ADCON1 = 0xF;                        // sets all analog channels as digital inputs
    
    TRISC = 0;
    LATC = 0;
    PORTC = 0;
    LCD_RS = 0;
    LCD_RW = 0;
    LCD_En = 0;
    RS_flag = 0;
    data2LCD = 0;
    
    LCD_init();                            //initialise lcd
    
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    while(1)                            // main program 'start'
    {
            
    data2LCD = 'A';                        // 0b01001000;
    LCD_char();                            // display it on lcd
    
    data2LCD = ' ';                        // 0b01100101;                    
    LCD_char();
        
    data2LCD = 'S';                        // 0b01101100;                    
    LCD_char();
        
    data2LCD = 't';                        // 0b01101100;                    
    LCD_char();
        
    data2LCD = 'r';                        // 0b01101111;                    
    LCD_char();
    
    data2LCD = 'i';                        // 0b00100000;                    
    LCD_char();
        
    data2LCD = 'n';                        // 0b01001011;                
    LCD_char();
        
    data2LCD = 'g';                        // 0b01101100;                    
    LCD_char();    

                                        
    while (!LCD_En);                    // stop and wait here - everything is done
    }
}    

void LCD_char (void)
{
    LCD_RS = 1;                            // set for writing to data register
    RS_flag = 1;                        // memory flag (resets RS in write routine if req)
    write2LCD();                        // send data or instruction to lcd                            
    LCD_RS = 0;
}

void LCD_init (void)    // ***** Start of LCD initialization *****

{    // See the HD47780 or ST7066 data sheets
    //8 bit_mode;
    //start of software reset.
    
    Delay10KTCYx(3);                    // wait 30mS - allow Vcc to settle
    
    LCDdata2port = 0b00000011;            // put the data on portC             
    LCD_E();    
    Delay1KTCYx(4);                        // wait 4mS as per data sheet
    
    LCDdata2port = 0b00000011;     
    LCD_E();    
    Delay100TCYx(1);                    // wait 100uS as per data sheet
    
    LCDdata2port = 0b00000011;             // data sheet bit hazy as to when exactly 
    LCD_E();                            // 'busy' flag can be read
    LCD_busy();

    LCDdata2port = 0b00000010;             // can wait for busy flag from here
    LCD_E();
    LCD_busy();
    
    // end of software reset


    // 4 bit mode from here

    // (1) function set
    // Data Length = 4 bits, 2 (or 4) line display, 5x8 font
    //
    data2LCD = 0b00101000;
    write2LCD();
    
    //(2) display on/off control
    // turn on display, cursor and cursor flash
    //
    data2LCD = 0b00001111;
    write2LCD();
    
    // (3) clear display
    //
    data2LCD = 0b00000001;
    write2LCD();

    // (4) entry mode set
    //  cursor moves to right
    //
    data2LCD = 0b00000110;
    write2LCD();    
                
}    
// ********* end of LCD initialization **********

void write2LCD (void)    
{        
    if (RS_flag)                    // to this routine from 'char' routine
        LCDdata2port = (((data2LCD >> 4) & 0xf) | 0x10); // as above, but 'OR' port bit 5
    else LCDdata2port = ((data2LCD >> 4) & 0xf);// shift left and 'AND' to clear port upper nyyble                
    LCD_E();
    LCD_busy();
    
    if (RS_flag)                // set indicates read / write data; clear  'instructions'
        {
        LCD_RS = 1;                // set the flag again (cleared at last visit to 'LCD_busy' routine)
        LCDdata2port = ((data2LCD & 0xf) | 0x10);
        }
    else LCDdata2port = (data2LCD & 0xf) ;                    
    LCD_E();                    // latch data into lcd
    LCD_busy();
}

void LCD_E (void)                // toggle the lcd enable bit    
{    
    LCD_En = 1;    
    LCD_En = 0;                    // data read into lcd on high to low transition of E
}
    
void LCD_busy (void)            // read lcd 'busy' flag
{    
    LCD_RS = 0;                    // cannot read the busy flag if RS = 1!
    TRISCbits.TRISC3 = 1;         // When TRIS = 0 it's DB7, Tris = 1 it's lcd busy flag.
    LCD_RW = 1;
    LCD_En = 1;
    while (LCD_BF);                // wait until 'busy' flag clear
    LCD_En = 0;
    LCD_RW = 0;
    TRISCbits.TRISC3 = 0;                                                                     
}
        
    // 
    // 
    // tested ok on www.cct.com.my 16x2 display 03/01/11
    // 
    //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Any help greatly appreciated.
 
Last edited:
Hi Jason,

Just wanted to say thanks. Spent quite some time bashing my keyboard on this one and getting nowhere, well getting somewhere but the wrong place. Your snippets worked fine (apart from the asterisks but I forgive you for that :) ).
 
please explain below coding.i know little bit only




void lcd_data_str(char str[50]) //Function to send string
{
int p;
for (p=0;str[p]!='\0';p++)
{
lcd_data_str_pin = str[p];
rw = 0;
rs = 1;
en = 1;
delay(1);
en = 0;
}
return;
 
You shouldn't hijack threads, you should start a new one.

That aside,

The function takes in a max length of 50 chars.
Each char is in turn looped through until it reaches null ('\0'). This is what the whole "for" line is.

lcd_data_str_pin, rw, rs, en are all I/O lines connected to the lcd.

The sequence is as follows:
NOTE: lcd_data_str_pin is a bit ambiguous as it will more than likely be a port rather than a pin as it is either 4 bits (a nibble) or 8 bits (a byte), a char is by default 8 bits wide.

1. lcd_data_str_pin is set to the character you wish to write to the LCD, for example 'A'.
2. rw (read/write) is set to 0, 0 = write.
3. rs (register select) is set to 1, 1 = text mode (0 = command mode for ex, move line, move to next char position etc).
4. en (enable) is set to 1, 1 = tell LCD we are sending data.
5. delay(1), probably delay 1ms, this allows the LCD to register within itself that the "en" line has been pulled high.
6. en (enable) is set to 0, 0 = tell LCD we have finished sending data and is waiting for next instruction.

So, effectively "en" is a toggle with a small delay in between so the LCD driver (built into the LCD itself) can detect that the pin state has been changed.

Hope this helps.

Wilksey
 
void lcd_data_str(char str[50]) //Function to send string

This isn't standard C and isn't fairly useful. In order to understand why it is "incorrect" you need to understand how pointers work in C. Consider the following code:

Code:
#include <stdio.h>

void foo(char baz[5]) {
        printf("Got here!");
}

void main() {
        char bar[500];
        foo(bar);

        char *moo;
        foo(moo);
}

Both of the calls to the foo function are successful, even though one is an array of notional 500 values and the other is an uninitialised pointer (note that this compiles and runs fine).

In simpler terms: don't expect the 50 in "char str[50]" to do anything for you. Never rely on it for a guarantee of your input. In your example above it would be best to simply remove it.

Note that it would work in C++ with templated types as long as they do not decay to a pointer when they are passed.
 
Edeca.... Far too high.. I bet that went miles over his head..... All can say is Jason's code is fine.... You may need to change the text pointer to a 'const char*' as the text WILL be in ROM.

Edeca.. one other thing ' foo(*moo);' no!! you have to point at something first. ie..' moo = &bar;'
 
Last edited:
Edeca.... Far too high.. I bet that went miles over his head.....

You are absolutely correct. I wasn't particularly aiming it at him, more at "The function takes in a max length of 50 chars" from the post before mine which was an excellent explanation except that piece.

Edeca.. one other thing ' foo(*moo);' no!! you have to point at something first. ie..' moo = &bar;'

That was exactly my point. What is there compiles absolutely fine. It will run. You will run into nasty problems if you try to dereference the pointer by reading or writing from it.

The "50" in the function declaration gets you nothing. It doesn't enforce anything and wont even be picked up by the C compiler. You might get passed a null pointer (equivalent to "nothing"), or 50 char items, or 5 million.
 
Ok... I see what you mean.... I suppose on embedded systems its not so bad as the data starts at 0 anyway...

You know 'foo & bar' used extensively in C tutorials is derived from FUBAR..... I have never understood why they use that expression. ( I know what it means ););)
 
OK, I wasn't debugging the code just explaining that if something has char xxx[10], then the size of the array will be a maximum of 10 (zero indexed, 0-9).

If the poster didn't understand a for loop I am not going to try and explain pointers and memory management!

So, no it wont work correctly, but an explanation was only asked for.

FUBAR is good, SNAFU is also another good one!
 
OK, I wasn't debugging the code just explaining that if something has char xxx[10], then the size of the array will be a maximum of 10 (zero indexed, 0-9).

Not if that number is in the function declaration, in there it makes absolutely no difference.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top