Understanding sprintf padding characters...

I'm trying to wrap my head around some example code, that I'm implementing into a sketch.
This all started trying to get rid of using lcd.clear() and horrible screen flickering. Starting looking into a LCD buffer.
Found a great tutorial for getting it going, but not much explanation on what each bit of code is doing. Trying to read about sprintf has led to more questions and confusion than answers.

My questions are:
Is there a resource you can point me to, to understand the padding characters/methodology for left justified, right justified, what characters I can pad with, etc.

And as a side note (I'm just realizing) is why my output is printing to line 0 and line 2, not line 0 and line 1.

There also seems to be a harsh relationship to the "outputTemp[]" array (the size of the array) and the number in the "&-7s" that I don't understand. IE: if that array is set to less than 10, it breaks the whole sketch and for some reason pin 13 starts blinking... I'm assuming that's some kind of overrun error or something. Not that concerned with it, but AM trying to figure out the relationship to that outputTemp array size, combined with the padding.

I hope I explained that well enough. I've tried truncating the sketch to only the relevant parts.

#include <LiquidCrystal.h>
// LCD Setup
const int rs = 22, en = 23, d4 = 24, d5 = 25, d6 = 26, d7 = 27;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// LCD Buffer
char line0[21];
char line1[21];
char line2[21];
char line3[21];

// Thermistor Pin - 10k pullup down
const int thermistorPin = A2;
const int pullUpResistor = 10000;

void setup() {
  lcd.begin(20, 4);
}

void loop() {
float testTemp = getTemp(thermistorPin, pullUpResistor);
      char outputTemp[10];
      dtostrf(testTemp,14,2,outputTemp);
      sprintf(line0, "___[Title Screen]___");
      sprintf(line1, "Temp:%-7sF", outputTemp);
      refreshLCD();

}

// Output LCD buffers
void refreshLCD() {
  lcd.setCursor(0, 0);
  lcd.print(line0);
  lcd.print(line1);
  lcd.print(line2);
  lcd.print(line3);
}

// Read Analog Thermistor
float getTemp(int analogPin, int pullupValue) {
  int Vo;
  float logR2, R2, Temp;
  float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;
  Vo = analogRead(analogPin);
    R2 = pullupValue * (1023.0 / (float)Vo - 1.0);
    logR2 = log(R2);
    Temp = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
    Temp = Temp - 273.15;
    Temp = (Temp * 9.0)/ 5.0 + 32.0;
    return Temp;
}

This code

void loop() {
  float testTemp = getTemp(thermistorPin, pullUpResistor);
  char outputTemp[10];
  dtostrf(testTemp, 14, 2, outputTemp);

says you have a variable 'outputTemp' that can hold 10 chars but your dtostr() function call says you want the output to be a minimum of 14 chars. You can't fit 14 chars into a 10 char array.

then, this line

  sprintf(line1, "Temp:%-7sF", outputTemp);

fills line1 with 5 chars + 7 chars + 1 char = 13 chars which will not entirely fill the display line

This is a good reference: http://www.cplusplus.com/reference/cstdio/printf/.

blh64 is right, when you want to update without the clear, then fill the text with spaces to remove the previous text.

I don't see how those four seperate buffer can solve a problem. I would use a single common buffer of 40 or 80 bytes and create a line for the display and immediate write it.

To test the sprintf(), it is easier to do that without the display, send the text the serial monitor.

And as a side note (I'm just realizing) is why my output is printing to line 0 and line 2, not line 0 and line 1.

Presumably you are using an LCD display with an HD44780 controller chip, or a clone of that chip. Because of the way the controller chip organizes and handles its memory, a 20x4 display will have a line-wrap sequence of line 0 > line 2 > line 1 > line 3. Not sure if any of the LCD libraries are set up to adjust for that, have not seen any personally. Easiest way to get around the problem is to use an lcd.setCursor() command before printing each line. That also makes a 40 or 80 character buffer difficult to use.

Reprinting the entire line is not really needed on a data display screen when you only want the numeric field to change. Print all the static text once, then when you want to update the data position the cursor at the appropriate location and overwrite only the data you want to update (possibly overwriting it with spaces first to eliminate any residual characters from the previous data). That will pretty much eliminate any apparent blinking of the display resulting from clearing the entire display and reprinting everything.

david_2018:
Presumably you are using an LCD display with an HD44780 controller chip, or a clone of that chip. Because of the way the controller chip organizes and handles its memory, a 20x4 display will have a line-wrap sequence of line 0 > line 2 > line 1 > line 3. Not sure if any of the LCD libraries are set up to adjust for that, have not seen any personally. Easiest way to get around the problem is to use an lcd.setCursor() command before printing each line. That also makes a 40 or 80 character buffer difficult to use.

Makes perfect sense. The example was taken from a 16 x 2 LCD so it would not have that issue. I have changed the refreshLCD function to the following and it works perfectly! Thank you! I had this as what I thought was a "band aid" fix, but you're confirming it's expected behavior. It works, that's all that matters. :slight_smile:

// Output LCD buffers
void refreshLCD() {
  lcd.setCursor(0, 0);
  lcd.print(line0);
  lcd.setCursor(0, 1);
  lcd.print(line1);
  lcd.setCursor(0, 2);
  lcd.print(line2);
  lcd.setCursor(0, 3);
  lcd.print(line3);
}

Reprinting the entire line is not really needed on a data display screen when you only want the numeric field to change. Print all the static text once, then when you want to update the data position the cursor at the appropriate location and overwrite only the data you want to update (possibly overwriting it with spaces first to eliminate any residual characters from the previous data). That will pretty much eliminate any apparent blinking of the display resulting from clearing the entire display and reprinting everything.

Yes I realise it's "wasteful" of resources, however as much as I'm struggling, I'm ok with a little wasted resources/slow refresh time. This was the easiest solution to get rid of the flicker. I'm only going to be updating the screen every second anyways (millis timer not put into code as wasn't relevant) so eh? There will also be alot more values on the screen, so all in all half will need refreshed every second anyways, so what's another 40 characters between friends right?

blh64:
This code

void loop() {

float testTemp = getTemp(thermistorPin, pullUpResistor);
  char outputTemp[10];
  dtostrf(testTemp, 14, 2, outputTemp);



says you have a variable 'outputTemp' that can hold 10 chars but your dtostr() function call says you want the output to be a minimum of 14 chars. You can't fit 14 chars into a 10 char array.

If I'm understanding correctly, the "outputTemp" is the ACTUAL "thing" being written to the screen, the sprintf function is just tacking on additional characters first. Correct?

then, this line

  sprintf(line1, "Temp:%-7sF", outputTemp);

fills line1 with 5 chars + 7 chars + 1 char = 13 chars which will not entirely fill the display line

So if I'm understanding correctly, 5 chars = "Temp:", 7 is the number of characters to pad, "%s" is the space/blank character, and - means pad to the left, 1 char = "F"? Am I assuming correct here?

Koepel:
This is a good reference: http://www.cplusplus.com/reference/cstdio/printf/.

blh64 is right, when you want to update without the clear, then fill the text with spaces to remove the previous text.

I don't see how those four seperate buffer can solve a problem. I would use a single common buffer of 40 or 80 bytes and create a line for the display and immediate write it.

To test the sprintf(), it is easier to do that without the display, send the text the serial monitor.

This was the easiest solution (that I could figure out) how to refrain from clearing the LCD every loop, and taking care of unused characters that linger.

I have seen other examples using the method you mentioned, but have not A) fully understood the code and B) found a way to implement it into my sketch. So I'm settling for this.

FYI

will have a line-wrap sequence of line 0 > line 2 > line 1 > line 3. Not sure if any of the LCD libraries are set up to adjust for that,

The hd44780 library has the facility to handle line wrapping correctly.

I feel like I'm jumping the gun on this, but while I have you here:

Is it possible (easily) to insert a custom character into the line buffer?

byte partFillBoxChar[8] = {
  0b11111,
  0b10001,
  0b10001,
  0b11111,
  0b11111,
  0b11111,
  0b11111,
  0b00000
};
lcd.createChar(0, partFillBoxChar);

Normally inserted with lcd.write((uint8_t)0);
Not sure how to "insert" that special character within the line.

Yes, but do not start with 0, start with 1, because 0 is also a zero-terminator.

In a string use \1 \2 and so on. They are from the beginning of the C-language and are actually octal numbers. For \1 up to \7 you can use them.

You can also use hexadecimal number \x01 and so on, but just a \1 is easier to read.

Suppose the degrees symbol in 1:

char x[] = "It is 12.3 \1C"; // It is 12.3 °C

You can design them online:

and:
https://omerk.github.io/lcdchargen/

You can't insert the special char '\0' since that is the null character and is used to mark the end of a string, which is what you are printing to the display.

You could define your special character as 1..7 and then put that into your string. You could do something like line1[5] = 1; to put it into the 6th spot of line 1.

poor_red_neck:
If I'm understanding correctly, the "outputTemp" is the ACTUAL "thing" being written to the screen, the sprintf function is just tacking on additional characters first. Correct?

So if I'm understanding correctly, 5 chars = "Temp:", 7 is the number of characters to pad, "%s" is the space/blank character, and - means pad to the left, 1 char = "F"? Am I assuming correct here?

outputTemp is the buffer you are filling with the ASCII representation of your temperature value. (Which needs to be larger). In the sprintf(), you are filling the line1 buffer with some constant text, plus the contents of outputTemp that will be exactly 7 chars wide, right justified, followed by "F"
%s is the format character for inserting a string, which is what outputTemp is.