1

I recently got a STM8 MCU and it has the built in function LCD_GLASS_DisplayString("STRING")

The problem with that function is, as you can see below, that I cannot directly display an integer on it:

void LCD_GLASS_DisplayString(uint8_t* ptr)
{
  uint8_t i = 0x01;

    LCD_GLASS_Clear();
  /* Send the string character by character on lCD */
  while ((*ptr != 0) & (i < 8))
  {
    /* Display one character on LCD */
    LCD_GLASS_WriteChar(ptr, FALSE, FALSE, i);

    /* Point on the next character */
    ptr++;

    /* Increment the character counter */
    i++;
  }
}

How could I modify it so I could send integers directly? Also, I'm not sure I can use any libraries, so just pure C would help.

I was thinking of something like this, but it didn't work:

void LCD_GLASS_DisplayINT(uint16_t integer)
{
  uint8_t i = 0x01;

    LCD_GLASS_Clear();
  /* Send the string character by character on lCD */
  while ((integer != 0) & (i < 8))
  {
    /* Display one number on LCD */
    LCD_GLASS_WriteChar("0" + integer%10, FALSE, FALSE, i);

    /* Point on the next number*/
    integer=integer/10;

    /* Increment the character counter */
    i++;
  }
}

Any idea on how to make it work? I need to either make a function to display the integers or a way to convert them to strings before I send them over to the LCD. The code is pure C, as what I'm programming are pure drivers right now.

glts
  • 21,808
  • 12
  • 73
  • 94
rajeev
  • 27
  • 1
  • 6

2 Answers2

2

You're not far off with "0" + integer%10 - but you need to treat it as a character - '0' + integer%10 - and you need to pass LCD_GLASS_WriteChar a pointer to this character.

One way to do this is:

char* digits = "0123456789";
LCD_GLASS_WriteChar(&digits[integer % 10], FALSE, FALSE, i);

Also, your loop condition - while ((integer != 0) & (i < 8)) should not use bitwise and (&), but rather logical and (&&).

while ((integer != 0) && (i < 8))
Daniel Kleinstein
  • 5,262
  • 1
  • 22
  • 39
  • Yep, it worked!! Just a problem now that I didn't have while displaying strings, the number is displayed backwards 30 will be 03 and so on – rajeev Aug 20 '21 at 11:38
  • :) There are a few solutions for this - the standard way is to just use a function like `sscanf` to convert the number into a string, but you might not have access to this functionality on your embedded system.. you can "flip" the number numerically (`123` -> `321`) and then print it.. or you can use a static buffer of up to eight characters, write your digits to the buffer starting from its end character, and then print the buffer from the last digit you parsed onwards. – Daniel Kleinstein Aug 20 '21 at 11:46
  • 1
    I flipped the number, it was easier to code. Thank you so much for your help! <3 – rajeev Aug 20 '21 at 12:01
  • Agree about _should_, yet `while ((integer != 0) & (i < 8))` functions the same. It may emit tigher code. – chux - Reinstate Monica Aug 20 '21 at 13:54
0

You'll want to store the digits in a buffer to get the left-to-right order. On a microcontroller you'll probably want to allocate that buffer in .bss so that it doesn't take up stack. Use static to make that happen. For a 16 bit number you'll have at most 5 digits + null term, so:

static char buf[5+1] = {0};

The conversion is essentially the code you've written, except you mixed up '0' and "0":

for(uint8_t i=0; i<5; i++)
{
  buf[5-i-1] = val%10 + '0';
  val/=10;
}

Note that this code always leaves item buf[5] untouched and leaves a zero null terminator there.

Complete code with tests in standard C. Obviously drop puts for your custom LCD routine.

#include <stdio.h>
#include <stdint.h>

void display_int (uint16_t val)
{
  static char buf[5+1] = {0};
  char* p;
  
  for(uint8_t i=0; i<5; i++)
  {
    buf[5-i-1] = val%10 + '0';
    val/=10;
  }
  
  // trim leading zeroes
  for(p=buf; *p!='\0'; p++)
  {
    if(*p!='0' ||    // stop looking at first non zero or 
       p[1]=='\0')   // in case there is only one zero character
      break;
  }
  
  puts(p); // use whatever string printing routine you got
}

int main (void)
{
  display_int(0);
  display_int(5);
  display_int(666);
  display_int(12345);
}

Division on STM8 is very expensive. We can optimize the code a bit by not filling up the whole buffer if we don't have to. This saves us several DIV calls. Optimized version, faster but harder to read:

void display_int (uint16_t val)
{
  static char buf[5+1] = {0};
  char* p;
  char* start;
  
  for(uint8_t i=0;;i++)
  {
    buf[5-i-1] = val%10 + '0';
    val/=10;
    if(val==0)
    {
      start = &buf[5-i-1];
      break;
    }
  }
  
  // trim leading zeroes
  for(p=start; *p!='\0'; p++)
  {
    if(*p!='0' ||    // stop looking at first non zero or 
       p[1]=='\0')   // in case there is only one zero character
      break;
  }
  puts(p); // use whatever string printing routine you got
}
Lundin
  • 195,001
  • 40
  • 254
  • 396