sprintf - ща бошка лопнет!

5N62V
Offline
Зарегистрирован: 25.02.2016

кризис мысли, ребята, выручайте!

int xx = 87;
void setup {}

void loop{
Serial.print("xx=");   Serial.print(xx);.   //  просто мониторю
print_lcd();
}

void print_lcd(){
Serial.print("xx=");   Serial.print(xx);.  //  просто мониторю
.......
// вывод других переменных на дисплей

...............
Serial.print("xx=");   Serial.print(xx);.  //  опять просто мониторю

lcd.setCursor(0, 2);
sprintf(temp, "my_rssi%3d AtmH%4d", xx, atm_altitude/10); 
lcd.print(temp);
Serial.print("my_rssi=");Serial.print(xx);     //  опять просто мониторю
}

в лупе выводится хх = 87,   в начале функции вывода на дисплей выводится хх = 87,  непосредственно перед выводом переменной хх выводится выводится хх = 87, а на дисплей выводится 0, и последний вывод на монитор тоже выводится 0.       Ваще мыслей не осталось. :))))

9 переменных на дисплей вывел как надо, а с этой уже пол дня бьюсь.  Кто что подскажет?

_kp
Offline
Зарегистрирован: 07.10.2016

1.
Если xx не константа, замените в первой же строке
int xx = 87;
на
volatile int xx = 87;

2.
LCD через какую библиотеку подключен ?

3.
Получается портится переменная на участке
 sprintf(temp, "my_rssi%3d AtmH%4d", xx, atm_altitude/10);
 lcd.print(temp);

По идее портиться переменная не должна, если ОЗУ не жмёт.
sprintf выделяет временную память из кучи, и если ОЗУ мало, он, испортит чужие данные.
Более того, сторока "my_rssi%3d AtmH%4d", хранится и в ОЗУ и во флеш. (Так уж криво gcc поддерживает AVR, и ARDUINO соответственно)

Поэтому сразу вопрос, а почему вообще на AVR используется sprintf() а не sprintf_p()?
Думаю, учитывая отладочный вывод, слишком много ОЗУ понапрасну занято строковыми константами, которые лучше поместить во флеш.

Рекомендую заменить все sprintf в программе на sprintf_p так.
sprintf_P(temp, PSTR("my_rssi%3d AtmH%4d"), xx, atm_altitude/10);

и заодно строковые константы в отладочном выводе
Serial.print("xx=");
на
Serial.print(F("xx="));

И в начале файла добавить
#include <avr/pgmspace.h>

Так освободится значительное(по меркам AVR) количество ОЗУ.

5N62V
Offline
Зарегистрирован: 25.02.2016

спасибо за совет!

Попробовал - не помогло. Изменений не замечено, увы. 

Действительно затирается переменная. У меня другой версии нет.   Взял, объявил другую переменную ккк, тоже глобальную,  и в лупе, где шло присваивание значения переменной хх ( в приведенном мною коде не так, просто я для наглядности писал, имхо это ничего не меняет), так вот в лупе, где до этого было хх = (функция)   я прописал 

ккк = хх = функция;

и потом в функции вывода данных на дисплей уже использовал ккк.    И заработало! Быдлячество полное, но непонимание сути проблемы не дает шанса на более изящное решение этой проблемы.

Со свободной  памятью проблем нет, Мега используется, если верить IDE , то использовано только 15% динамической памяти.

LCD подключен через <LiquidCrystal_I2C.h>

Тот факт, что с 9тью выводимыми переменными проблем не было ( не, вру, с одной было: sprintf  с float не хотел работать, пришлось врукопашную расставить знаки , цифры и точку)  , а с этой хх убил пол дня, ставит меня в тупик.

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

5N62V, ты бы выложил скетч, а не фрагмент. Как там у тебя объявлена переменная temp...?

5N62V
Offline
Зарегистрирован: 25.02.2016

Andy пишет:

5N62V, ты бы выложил скетч, а не фрагмент. Как там у тебя объявлена переменная temp...?

byte kkk;
char temp[20];  // дисплей 2004  - сразу целую строку делаю
byte xx;

void setup{}

void loop{
.......
kkk = xx = (функция);
........
print_lcd();
}

void print_lcd{
.......
lcd.setCursor(0, 2);
sprintf(temp, "my_rssi%3d AtmH%4d", kkk, atm_altitude/10); 
lcd.print(temp);
.........
}

Вот ккк работает как надо, а хх - выводит ноль.   

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Я полагаю temp[30] решит проблему

Hot Rod
Offline
Зарегистрирован: 27.06.2017

Ребят, подскажите по sprintf, никак сам не осилю:

// упрощенный вариант 
int temp1; 
char strbuf[20]; 
sprintf(strbuf, "%2d,%d", temp1 / 10, abs(temp1 % 10)); 
Serial.print(strbuf);

temp1 - температура, умноженная на 10. При выводе делю на десять и после запятой абсолютное значение остатка от дел на 10.

Проблема при выводе temp1, если она в диапазоне от -1 до -9 (то есть реальная температура  от -0.1 до -0.9), - выводится без знака минус. Логично, конечно, но подскажите как написать, чтобы выводилось и в этом диапазоне со знаком минус? (Нужно именно строкой, там будет еще несколько других значений)

Заранее благодарю.

5N62V
Offline
Зарегистрирован: 25.02.2016

Hot Rod пишет:

Ребят, подскажите по sprintf, никак сам не осилю:

// упрощенный вариант 
int temp1; 
char strbuf[20]; 
sprintf(strbuf, "%2d,%d", temp1 / 10, abs(temp1 % 10)); 
Serial.print(strbuf);

temp1 - температура, умноженная на 10. При выводе делю на десять и после запятой абсолютное значение остатка от дел на 10.

Проблема при выводе temp1, если она в диапазоне от -1 до -9 (то есть реальная температура  от -0.1 до -0.9), - выводится без знака минус. Логично, конечно, но подскажите как написать, чтобы выводилось и в этом диапазоне со знаком минус? (Нужно именно строкой, там будет еще несколько других значений)

Заранее благодарю.

Наверное надо под знак отвести место в строке, а выводить только положительные значения. Например так:

sprintf(strbuf, "%с%2d,%d", temp<0?"-":" ",abs(temp1 / 10), abs(temp1 % 10));

Не компилировал, но по идее должно работать.

 

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

 

Hot Rod
Offline
Зарегистрирован: 27.06.2017

5N62V, благодарю, работает.

sprintf(strbuf, "%c%2d,%d ", temp1 < 0 ? '-' : ' ', abs(temp1 / 10), abs(temp1 % 10));

Только теперь если значение температуры отрицательное однозначное, то между знаком "-" и числом есть лишний пробел.

ch-1: -12,3°;
ch-2: - 1,2°;
ch-3: - 0,7°;
ch-4:  12,3°;

Я все же надеялся, что есть возможность не усложнять и обойтись без сравнения, просто я не мог сообразить как. ))

5N62V
Offline
Зарегистрирован: 25.02.2016

Hot Rod пишет:

5N62V, благодарю, работает.

sprintf(strbuf, "%c%2d,%d ", temp1 < 0 ? '-' : ' ', abs(temp1 / 10), abs(temp1 % 10));

Только теперь если значение температуры отрицательное однозначное, то между знаком "-" и числом есть лишний пробел.

ну попробуйте вместо пробела пустые кавычки оставить. 

sprintf(strbuf, "%c%2d,%d ", temp1 < 0 ? '-' : '', abs(temp1 / 10), abs(temp1 % 10));

 

 

Hot Rod
Offline
Зарегистрирован: 27.06.2017

Да нет, с положительной t все в порядке, там же знака нет. Проблема только у отрицательной до -10 (в моем примере это строки 2 и 3), лишний пробел между знаком "-" и значением.

5N62V
Offline
Зарегистрирован: 25.02.2016

Hot Rod пишет:

Да нет, с положительной t все в порядке, там же знака нет. Проблема только у отрицательной до -10 (в моем примере это строки 2 и 3), лишний пробел между знаком "-" и значением.

попробуйте двойку убрать в 

%c%2d,%d

Hot Rod
Offline
Зарегистрирован: 27.06.2017

Это было первое, что я попробовал. )) Но тогда сдвигаются значения однозначных относительно двузначных 

ch-1: -12,3°;
ch-2: -1,2°;
ch-3: -0,7°;

Задавать еще одно условие совсем не хочется

Hot Rod
Offline
Зарегистрирован: 27.06.2017

дубликат, del 

5N62V
Offline
Зарегистрирован: 25.02.2016

Hot Rod пишет:

Это было первое, что я попробовал. )) Но тогда сдвигаются значения однозначных относительно двузначных 

ну тогда заполните пробел нулем ))

 

Hot Rod
Offline
Зарегистрирован: 27.06.2017

Спасибо за мысли и предложения  ))

sadman41
Offline
Зарегистрирован: 19.10.2016

Я тоже как-то страдал фигней такой. Терпения не хватило - забил на десятые доли градуса. Все равно они особой точности не добавляют температуре на улице.