Вопрос вывода символов на дисплей. Знатоки, подскажите !

Sikorskiy
Offline
Зарегистрирован: 25.04.2016

Дисплей двухстрочный подключаю через I2C
[​IMG]
Имею код (представлен ниже) просто беру инфу с сенсора и отображаю на дисплей.

если значения с сенсора двух значное, то выглядит это примерно так:
СО 41
СН4 16
если трех значное то единицы уползают вправо примерно так:
СО 418
СН4 16
а нужно мне сделать чтобы было так:
СО 418
СН4 16
а именно единицы должны стоять в одном столбце и если появляются сотни то они ставятся в столбец слева а не двигают единицы направо.

Знатоки, подскажите кто знает как это сделать?
[​IMG]

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);

#define sens A0
#define sensmq A1

void setup() {
Serial.begin(9600);
lcd.init();
lcd.init();
lcd.backlight();
pinMode(sens, INPUT);
pinMode(sensmq, INPUT);

}

void loop() {

int data = analogRead(sens);
int data1 = analogRead(sensmq);

Serial.print("CO ");
Serial.print(data);
lcd.setCursor(0,0);
lcd.print(F("CO "));
lcd.setCursor(4,0);
lcd.print(data);
Serial.print(" CH4 ");
Serial.println(data1);
lcd.setCursor(0,1);
lcd.print(F("CH4 "));
lcd.setCursor(4,1);
lcd.print(data1);
delay(1000);
}

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Если надо попроще, в две строки, то можно вот так:

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

void setup(void) {
	Serial.begin(115200);
	char szBuffer[5];
 	int n = 432;
 	sprintf(szBuffer,"%4d",n); // ширина поля 4 символа, прижато вправо
 	Serial << "===" << szBuffer << "===\n";
}

void loop(void) {}

Запустите, посмотрите. szBuffer будет всегда содержать число n шириной в 4 символа, прижатое вправо. Это же то, что Вам нужно?

Если хотите слева дозаполнить незначащими нулями, просто вместо "%4d" напишите "%04d"

Sikorskiy
Offline
Зарегистрирован: 25.04.2016

честно сказать я не понял как это должно работать

решил вопрос одной строчкой

я просто переношу курсор в другой столбей если он ставится трехзначным

lcd.setCursor(data < 100 ? 4 : 3, 0);

Ваш вариант возможно более универсален

Буду благодарен за разяснения по пердложенному код,

а именно первые две строчки ? что там за магия такая?

что куда возвращаем?

где посмотреть что значат эти операторы?

что значит szBuffer[5];? int n = 432;?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Строка №1 - не берите в голову, она не относится к примеру. Она нужна для того, чтобы строку 8 можно было записать кратко, как она записана, а не в три оператора ( Serial.print("==="); Serial.print(szBuffer); Serial.println("===\n"); )

Строки 2-4 - не берите в голову, они стандартные - всегда такие.

Строка 5 - заводим буфер размером в 5 символов

Строка 6 - заводим целую переменную n и что-нибудь ей присваиваем

Строка 7 - преобразем n в символьный вид, при этом требуем, чтобы она занимала 4 символа и сели надо, дополнялась слева пробелами

Строка 8 - печатаем для проверки

Так как Вы сделали - хорошо при условии, что 

1) там всегда три или четыре, и никогда не может быть, например, два

2) если сначала было 4-значное число, а потом стало 3-значное, Вы сместите курсор, но не сотрёте уже ненужную крайнюю левую цифру и она так там и останется.

Sikorskiy
Offline
Зарегистрирован: 25.04.2016

у меня бывают и двух значные

Пробелы после СО стирают старые значения количество пробелов перекрывает область в котором выводятся значения

после чего я пишу на них новые

 

lcd.print("CO       ");
lcd.setCursor(data < 100 ? 6 : 5, 0);
lcd.print(data);

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, вот я и говорю, что Вам проще сформировать печатаемую строку целиком одним вызовом sprintf а потом одним махом всё и вывести и не париться.

Вы не знаете что такое sprintf и как записывать формат строки? Так в сети полно примеров. Поищите по названию функции.

А то Вот Вы проверяеете на <100. А если она >999 - так может быть? если может, то у Вас опять проблема.

Sikorskiy
Offline
Зарегистрирован: 25.04.2016

Согласен, пойду дальше учится)

arduinec
Offline
Зарегистрирован: 01.09.2015

ЕвгенийП пишет:

Строка №1 - не берите в голову, она не относится к примеру. Она нужна для того, чтобы строку 8 можно было записать кратко, как она записана, а не в три оператора ( Serial.print("==="); Serial.print(szBuffer); Serial.println("===\n"); )

В данном случае я предпочитаю использовать макросы типа:

#define sp1(a) Serial.println(a)
#define sp2(a,b) Serial.print(a); Serial.println(b)
#define sp3(a,b,c) Serial.print(a); Serial.print(b); Serial.println(c)
Пример:
sp3("N = ", 123, " ye");

 

Sikorskiy
Offline
Зарегистрирован: 25.04.2016

Это получается мы создаем функцию sp3, вызываем ее и даем ей значения?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, если только для печати, то разницы-то никакой абсолютно, используйте на здоровье. Разница проявляется, если это надо использовать с разными переменными типа Stream (несколько сериалов, софтверный сериал и т.п.) - моё определение работает на всё сразу, а макросы надо писать отдельно для каждой потоковой переменной.

Только, надеюсь, Вы не так "в лоб" пишете, а то так, как у Вас написано могут возникнуть проблемы, например, if (a>b) sp3("a=", a, "\n"); сработает неадекватно.

arduinec
Offline
Зарегистрирован: 01.09.2015

Sikorskiy пишет:

Это получается мы создаем функцию sp3, вызываем ее и даем ей значения?

Мы не создаём функцию. При компиляции макрос sp3 просто заменяется на 3 отдельных Serial.print, и поэтому в приведённом примере с if нужно использовать фигурные скобки:
if (a>b) { sp3("a= ", a, " >b"); }

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

arduinec пишет:

поэтому в приведённом примере с if нужно использовать фигурные скобки:

if (a>b) { sp3("a= ", a, " >b"); }

Да, лучше уж сразу в #define определить это блоком, обычно пишут 

#define sp3(a,b,c) do { Serial.print(a); Serial.print(b); Serial.println(c); } while (false);

Приличный компилятор никаких глупых проверок не вставит, зато то, что это единое целое, поймёт.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Sikorskiy пишет:

первые две строчки ? что там за магия такая?

Кстати, вся магия подробно разбирается вот здесь.

Sikorskiy
Offline
Зарегистрирован: 25.04.2016
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }
#define co A0
void setup(void) {
  Serial.begin(115200);
  pinMode(co, INPUT);
  
  }

void loop(void) {
  float n = analogRead(co);
  
  char szBuffer[4];
  sprintf(szBuffer,"%5d",n); // ширина поля 4 символа, прижато вправо
  Serial << "===" << szBuffer << "===\n";}

Почему если переменная n - int все работает а если float то вот так?

мне просто очень нужно дробное выражение с 3 знаками после запятой

===   0===

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

В 13 строке напишите

sprintf(szBuffer,"%5.2f",n);

Только, сейчас мне не на чем проверить, написал по памяти. Если лажанулся, посмотрите сами, пожалуйста форматы функции printf

Но так "по памяти" то, что я написал должно означать, что будет число ширной пять символов с двумя знаками после точки (т.е. XX.YY - где XX - целая часть, а YY - дробная). Если для целой части надо 3 знака, а не 2, то укажите 6 после %

Да, кстати, если надо, чтобы по-прежнему было прижато вправо, а не влево, то перед шириной поля поставьте 0 (т.е. не "%5.2f", а "%05.2f".