Search code examples
c++stringasciiuint8t

Displaying integer on an LCD


I'm trying to display an integer on an LCD-Display. The way the Lcd works is that you send an 8-Bit ASCII-Character to it and it displays the character.

The code I have so far is:

unsigned char text[17] = "ABCDEFGHIJKLMNOP";
int32_t n = 123456;
lcd.printInteger(text, n);

//-----------------------------------------  

void LCD::printInteger(unsigned char headLine[17], int32_t number)
{
    //......


    int8_t str[17];
    itoa(number,(char*)str,10);


    for(int i = 0; i < 16; i++)
    {
        if(str[i] == 0x0)
        break;

        this->sendCharacter(str[i]);
        _delay_ms(2);

    }
}
void LCD::sendCharacter(uint8_t character)
{
    //....

    *this->cOutputPort = character;

    //...

}

So if I try to display 123456 on the LCD, it actually displays -7616, which obviously is not the correct integer.

I know that there is probably a problem because I convert the characters to signed int8_t and then output them as unsigned uint8_t. But I have to output them in unsigned format. I don't know how I can convert the int32_t input integer to an ASCII uint8_t-String.


Solution

  • On your architecture, int is an int16_t, not int32_t. Thus, itoa treats 123456 as -7616, because:

    123456 = 0x0001_E240
     -7616 = 0xFFFF_E240
    

    They are the same if you truncate them down to 16 bits - so that's what your code is doing. Instead of using itoa, you have following options:

    1. calculate the ASCII representation yourself;
    2. use ltoa(long value, char * buffer, int radix), if available, or
    3. leverage s[n]printf if available.

    For the last option you can use the following, "mostly" portable code:

    void LCD::printInteger(unsigned char headLine[17], int32_t number) {
      ...
      char str[17];
      if (sizeof(int) == sizeof(int32_t))
        snprintf(str, sizeof(str), "%d", num);
      else if (sizeof(long int) == sizeof(int32_t))
        snprintf(str, sizeof(str), "%ld", num);
      else if (sizeof(long long int) == sizeof(int32_t))
        snprintf(str, sizeof(str), "%lld", num);
      ...
    }
    

    If, and only if, your platform doesn't have snprintf, you can use sprintf and remove the 2nd argument (sizeof(str)). Your go-to function should always be the n variant, as it gives you one less bullet to shoot your foot with :)

    Since you're compiling with a C++ compiler that is, I assume, at least half-decent, the above should do "the right thing" in a portable way, without emitting all the unnecessary code. The test conditions passed to if are compile-time constant expressions. Even some fairly old C compilers could deal with such properly.

    Nitpick: Don't use int8_t where a char would do. itoa, s[n]printf, etc. expect char buffers, not int8_t buffers.