I have a question with Serial Print. I want the Sensor reading values to fall under 3 columns, and each column should have the readings from the same sensor.
Raw Value | Sensor 1 | Sensor 2 | Sensor 3
how can I modify this code do this?
Below I have posted my code and what I currently see using the Serial Monitor
void loop(){
RawValue0 = analogRead(analogIn0);
Voltage0 = (RawValue0 / 1023.0) * 5000; // 5000 to get millivots.
tempC0 = (Voltage0-500) * 0.1; // 500 is the offset
tempF0 = (tempC0 * 1.8) + 32; // conver to F
Serial.print("Raw Value = " ); // shows pre-scaled value
Serial.print(RawValue0);
Serial.print("\t milli volts = "); // shows the voltage measured
Serial.print(Voltage0,0); //
Serial.print("\t Sensor 1: Temperature in C = ");
Serial.print(tempC0,1);
Serial.print("\t Sensor 1: Temperature in F = ");
Serial.println(tempF0,1);
delay(500);
2 Answers 2
Columns with lines?
The sprintf
function can fill data with spaces to align them. However, the Arduino sprintf
function does not support floating point variables. The dtostrf
function has already a fixed output width by itself.
The sketch below is a combination of UTF-8 characters and the dtostrf
and sprintf
functions.
void setup() {
Serial.begin(9600);
Serial.println();
Serial.println("┏━━━━━━┳━━━━━━━━┳━━━━━━━━┓");
Serial.println("┃ raw ┃ °C ┃ °F ┃");
Serial.println("┣━━━━━━╋━━━━━━━━╋━━━━━━━━┫");
}
void loop() {
int raw = random(0, 1024);
float c = random(-1000, 1000) / 10.0;
float f = random(-500, 1500) / 10.0;
char buffer_c[20];
char buffer_f[20];
dtostrf(c, 6, 1, buffer_c);
dtostrf(f, 6, 1, buffer_f);
char buffer[80];
sprintf(buffer, "┃ %4d ┃ %s ┃ %s ┃", raw, buffer_c, buffer_f);
Serial.println(buffer);
delay(500);
}
The strlen() function can not be used before printing a floating point number to the serial port, since its length is determined while printing characters to the serial port. The final number of bytes that is written is the return value.
There is a way to use that return value, by using a dummy write to a dummy serial port. After that the number of spaces to align the floating point number can be calculated.
That reduces the code size from 6160 to 4708 for an Arduino Uno.
class DummyClass : public Stream
{
int available() {return 0;}
int read() {return 0;}
int peek() {return 0;}
void flush() {return;}
size_t write(uint8_t) {return 1;}
using Print::write;
};
DummyClass Dummy;
const int width_r = 4;
const int width_c = 6;
const int width_f = 6;
void setup() {
Serial.begin(9600);
Serial.println();
Serial.println("┏━━━━━━┳━━━━━━━━┳━━━━━━━━┓");
Serial.println("┃ raw ┃ °C ┃ °F ┃");
Serial.println("┣━━━━━━╋━━━━━━━━╋━━━━━━━━┫");
}
void loop() {
int raw = random(0, 1024);
float c = random(-1000, 1000) / 10.0;
float f = random(-500, 1500) / 10.0;
int i;
Serial.print("┃ ");
Spaces(width_r - Dummy.print(raw));
Serial.print(raw);
Serial.print(" ┃ ");
Spaces(width_c - Dummy.print(c,1));
Serial.print(c,1);
Serial.print(" ┃ ");
Spaces(width_f - Dummy.print(f,1));
Serial.print(f,1);
Serial.print(" ┃");
Serial.println();
delay(500);
}
void Spaces(int n)
{
for(int i=0; i<n; i++) {
Serial.print(' ');
}
}
I advise not to use this "Dummy" trick. It is mere a coding exercise. I can not find a problem with this trick, but I'm not 100% sure that it is okay.
-
use dtostrf for
raw
too and and save 1kB flash onsprintf
2019年04月15日 09:53:27 +00:00Commented Apr 15, 2019 at 9:53 -
1@Juraj I can do better than that. After reading your answer here: arduino.stackexchange.com/questions/62783/… I tried a dummy class. To my surprise it worked.Jot– Jot2019年04月15日 11:00:37 +00:00Commented Apr 15, 2019 at 11:00
Here is a sketch that uses a different approach than Jot uses in his answer. There is no question that Jot's answer is excellent and takes very few lines of code to accomplish.
I thought it would look nice if the Raw Value, an integer, was centered under the "Raw Value" column when it was at it's maximum value of 1023. A value of 1 would be right-ish justified, but still aligned with the center in mind.
The floating point numbers, which could be positive or negative, should be right justified I thought, so I wrote a second function to deal with those numbers.
int RawValue0;
float Voltage0, tempC0, tempF0;
void setup(){
Serial.begin(9600);
Serial.println();
Serial.println("Raw Value | Sensor 1 | Sensor 2 | Sensor 3");
Serial.println("------------------------------------------");
RawValue0 = 1023; //analogRead(analogIn0);
Voltage0 = 11.0; //(RawValue0 / 1023.0) * 5000; // 5000 to get millivots.
tempC0 = -100.0; //(Voltage0-500) * 0.1; // 500 is the offset
tempF0 = 1212.0; //(tempC0 * 1.8) + 32; // conver to F
}
void loop(){
// Increment the variables to simulate test data.
RawValue0 += 51;
if(RawValue0 > 1023){RawValue0 = 0;}
Voltage0 += 99.99;
if(Voltage0 > 9999.99){Voltage0 = 0.0;}
tempC0 -= 99.99;
if(tempC0 < -9999.99){tempC0 = 0.0;}
// Print out the data in columns.
printNumber(RawValue0);
Serial.print(" | ");
printNumber(Voltage0);
Serial.print(" | ");
printNumber(tempC0);
Serial.print(" | ");
printNumber(tempF0);
Serial.println();
delay(250);
}
long printNumber(int number){
Serial.print(" ");
int spaces = 0;
if(number < 1000){spaces = 1;}
if(number < 100){spaces = 2;}
if(number < 10){spaces = 3;}
for(int i = 0; i < spaces; i++){
Serial.print(" ");
}
Serial.print(number);
}
float printNumber(float number){
int spaces = 0;
if(number > -1000.00){Serial.print(" ");}
if(number < 1000){spaces = 1;}
if(number < 100){spaces = 2;}
if(number < 10){spaces = 3;}
if(number < 0){spaces = 0;}
if(number == -99.99){spaces = 1;}
for(int i = 0; i < spaces; i++){
Serial.print(" ");
}
Serial.print(number);
}
When I compile Jot's sketch, it's 6640 bytes. If you remove his "fancy" header, it drops to 6414 bytes. My sketch is 5124 bytes. There is a certain amount of "overhead" involved when using sprintf()
.
The question you have to ask yourself is, "Does saving 1000 bytes matter?".
Raw Value | Sensor 1 | Sensor 2 | Sensor 3
?