Проблема с отступом данных последовательной печати в Serial Monitor

У меня вопрос по поводу Serial Print. Я хочу, чтобы значения показаний датчика попадали в 3 столбца, и каждый столбец должен содержать показания одного и того же датчика.

Необработанная стоимость | Датчик 1 | Датчик 2 | Датчик 3

как я могу изменить этот код?

Ниже я разместил свой код и то, что я сейчас вижу с помощью Serial Monitor

    void loop(){

  RawValue0 = analogRead(analogIn0);
  Voltage0 = (RawValue0 / 1023.0) * 5000; // 5000, чтобы получить милливоты.
  tempC0 = (Voltage0-500) * 0.1; // 500 — это смещение
  tempF0 = (tempC0 * 1.8) + 32; // конвертируем в F
  Serial.print("Raw Value = " );  // показывает предварительно масштабированное значение
  Serial.print(RawValue0);    
  Serial.print("\t milli volts = "); // показывает измеренное напряжение
  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

Обсуждение

у вас нет кода для работы с датчиком 2 и датчиком 3.....нет возможности модифицировать несуществующий код, @jsotola

это школьное задание?, @jsotola

вы уже умеете печатать в формате столбца.... совершенно непонятно, с чем у вас проблема, @jsotola

подумайте об этом очень внимательно.... действительно ли вам нужна «Raw Value | Датчик 1 | Датчик 2 | Датчик 3`?, @jsotola


2 ответа


2

Столбцы со строками?

Функция sprintf может заполнять данные пробелами для их выравнивания. Однако функция Arduino sprintf не поддерживает переменные с плавающей запятой. Функция dtostrf сама по себе имеет фиксированную ширину вывода.
Приведенный ниже скетч представляет собой комбинацию символов UTF-8 и функций dtostrf и sprintf.

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);
}

Функция strlen() не может использоваться перед печатью числа с плавающей запятой в последовательный порт, поскольку его длина определяется при печати символов в последовательный порт. Окончательное количество записанных байтов является возвращаемым значением.
Существует способ использовать это возвращаемое значение, используя фиктивную запись в фиктивный последовательный порт. После этого можно вычислить количество пробелов для выравнивания числа с плавающей запятой.

Это уменьшает размер кода с 6160 до 4708 для 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(' ');
  }
}

Советую не использовать этот «пустышка». Это просто упражнение по кодированию. Я не могу найти проблему с этим трюком, но я не уверен на 100%, что с ним все в порядке.

,

также используйте dtostrf для raw и сохраните 1 КБ флэш-памяти на sprintf, @Juraj

@Юрай, Юрай, я могу сделать лучше. Прочитав ваш ответ здесь: https://arduinoprosto.ru/q/62783/create-new-serial-class-inheriting-from-stream, я попробовал фиктивный класс. К моему удивлению, это сработало., @Jot


1

Вот скетч, в котором используется другой подход, чем Джот в своем ответе. Нет сомнений в том, что ответ Джота превосходен и требует всего лишь нескольких строк кода.

Я подумал, что было бы неплохо, если бы необработанное значение, целое число, располагалось по центру столбца «Необработанное значение», когда оно имело максимальное значение 1023. Значение 1 было бы выровнено по правому краю, но при этом было бы выровнено. имея в виду центр.

Я подумал, что числа с плавающей запятой, которые могут быть положительными или отрицательными, должны быть выровнены по правому краю, поэтому я написал вторую функцию для работы с этими числами.

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; //аналоговое чтение(аналоговый вход0);
  Voltage0 = 11.0; //(RawValue0 / 1023.0) * 5000; // 5000, чтобы получить милливоты.
  tempC0 = -100.0; //(Напряжение0-500) * 0,1; // 500 — это смещение
  tempF0 = 1212.0; //(tempC0 * 1,8) + 32; // конвертируем в F
}

void loop(){

  // Увеличиваем переменные для имитации тестовых данных.
  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;}

  // Распечатываем данные в столбцах.
  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);
}

Когда я компилирую скетч Джота, его размер составляет 6640 байт. Если вы удалите его «причудливый» заголовок, он упадет до 6414 байт. Мой скетч весит 5124 байта. При использовании sprintf() возникают определенные «накладные расходы».

Вам следует задать себе вопрос: «Имеет ли значение экономия 1000 байт?».

,