0
\$\begingroup\$

I want to display certain messages on an LCD using a PIC MCU (16F887) and mikroC PRO for programming.

I have stored the words in a 2D string array like in the following program:

char text[21][11]={"GAS","DETECTED","MODE","SENSOR","TEST","SPRAY","GAS","ON",
                    "THE","PERFECT!!!","OVER","DOES","NOT","RESPONDE","PLEASE",
                    "REDO","FAILURE","SUSPECTED","CAUTION","NO"};

Now, for example, if I want to display "GAS DETECTED" I proceed as follows:

lcd_out(1,1,text[1][11]);
lcd_out(1,13,text[2][11]);

Here, I have noticed that:

  1. When I simulate the program as above I get a message error that says "Not enough RAM 'text'", So I understood that RAM is saturated, and I have declared my array with the const modifier as follows:
const char text[21][11]={"GAS","DETECTED","MODE","SENSOR","TEST","SPRAY","GAS","ON",
                    "THE","PERFECT!!!","OVER","DOES","NOT","RESPONDE","PLEASE",
                    "REDO","FAILURE","SUSPECTED","CAUTION","NO"};

Here again, I did not get the message error, but when I load the program to the PIC, nothing is displayed on the LCD.

NB: The LCD connections are correct, and it works perfectly with simple programs like: Lcd_out(1,1,"Hello");

Could anyone explain to me where the problem is, and what the best solution is to display a sentence on a 2x16 LCD?

\$\endgroup\$
1
  • \$\begingroup\$ What's the interface to the lcd_out()? If it is provided by the compiler environment, is there a manual you can read? \$\endgroup\$
    – Justme
    Aug 19, 2022 at 15:37

2 Answers 2

3
\$\begingroup\$

The correct usage is lcd_out(1, 1, text[0]) to display "GAS", lcd_out(1, 13, text[1]) to display "DETECTED".

Edit: I have never used either a PIC processor or MikroC before, so I had to do a little research. The Lcd_Out function prototype is:

void Lcd_Out(char row, char column, char *text)

It appears the PIC processor needs to know exactly where data resides (Flash, SRAM, EEPROM) in order to access it. The prototype for Lcd_Out function indicates it expects the data to be in volatile (SRAM) memory. The compiler rightfully gave an error to my solution because the strings are in flash memory. What you will need to do is use the other Lcd_ functions instead of Lcd_Out, for example:

int i;

Lcd_Cmd(_LCD_FIRST_ROW); /* Set cursor to first row */

for (i = 0; text[0][i] != 0; ++i) /* Loop until end of string */
    Lcd_Chr_Cp(text[0][i]); /* Write next character in string */

Lcd_Cmd(_LCD_SECOND_ROW); /* Same process for second string */

for (i = 0; text[1][i] != 0; ++i)
    Lcd_Chr_Cp(text[1][i]);
\$\endgroup\$
4
  • \$\begingroup\$ The compiler returns a message error "illegal pointer conversion" \$\endgroup\$ Aug 19, 2022 at 15:26
  • 1
    \$\begingroup\$ This gives a warning, but works in my IDE (TI CCS). Can you see the prototype for the lcd_out function in your IDE? Maybe it is fussy about const conversions, try casting: lcd_out(1, 1, (char*)text[0]) \$\endgroup\$
    – Mattman944
    Aug 19, 2022 at 15:51
  • \$\begingroup\$ Yes the whole problem resides in the location of that array, as it is const, it means it is stored in flash memory, so you have to retreive first the data to a temporary array than send it to LCD, \$\endgroup\$ Aug 20, 2022 at 5:31
  • \$\begingroup\$ So the reason for this might actually be that it's a Harvard MCU? Since von Neumann MCUs will typically be able to print directly from flash without some middle copy-down into RAM. On the other hand, on MCUs with paged flash (some PICs have this), libs might not be able to directly access a flash page beyond the 16 bit addressable address space, so you would have to copy it for that reason - and that's true on von Neumann MCUs with paged flash as well. \$\endgroup\$
    – Lundin
    Aug 22, 2022 at 13:24
3
\$\begingroup\$

First, don't declare the size of the strings: you are wasting space, and you'll have issues when you change some text and it becomes longer. Use a char * rather than char[11] for each string.

You should probably not declare the size of the array either, the compiler will allocate an array of the size required for the number of strings.

Just write:

const char *text[] =
{
    "GAS",
    "DETECTED",
    "MODE",
    "SENSOR",
    "TEST",
    "SPRAY",
    "GAS",
    "ON",
    "THE",
    "PERFECT!!!",
    "OVER",
    "DOES",
    "NOT",
    "RESPONDE",
    "PLEASE",
    "REDO",
    "FAILURE",
    "SUSPECTED",
    "CAUTION",
    "NO",
};

This will give you an array of pointers.

Next, when you want to print the first string, use text[0]. Don't add another index (it would return the character at that position, not the string). And indexes in C are 0-based, so the first item in an array is index 0, the second is index 1, etc.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ The correct declaration of a read-only string table is rather const char *const text[] = because you don't want to be able to modify string literals nor do you want that pointer table to get allocated in RAM instead of flash. Also, Harvard architectures like PIC might require some special snowflake keyword in the declaration to enable data reads from flash. \$\endgroup\$
    – Lundin
    Aug 22, 2022 at 13:18
  • \$\begingroup\$ Also, if you want to enable bootloader-like abilities to flash the strings without changing the rest of the program, you wouldn't be able to use a string pointer table but then you must allocate them with fixed sizes as in the OP's code. \$\endgroup\$
    – Lundin
    Aug 22, 2022 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.