Подскажите по разборке строки
- Войдите на сайт для отправки комментариев
Добрый день. Ребята подскажите деревенскому пенсионеру по такому вопросу.
У меня есть устройство на ESP8266, которое отправляет на народный мониторинг 9 параметров системы отопления: 4 температуры, 4 напряжения и давление в СО. Это всё я могу просматривать на телефоне. Но решил добавить индикацию на TFT экране от UNO, благо и то и другое имелось в наличие. Передачу параметров решил сделать на 433 МГц с помощью библиотеки VirtualWire. Данные отправляю пакетами по три параметра.
Вот кусок скетча передатчика
#include <VirtualWire.h>
int msgSet = 1; //Отправку начать с первого массива
void setup(){
//настройка virtualWire
vw_set_tx_pin(12);//пин передачи
vw_set_rx_pin(11);//пин приема
vw_set_ptt_inverted(true);
vw_setup(2000);//скорость передачи данных
Serial.begin(9600);
}
void loop(){
float Press = 2.0; //A
float Temp0 = 60.5; //B
float Temp1 = 55.5; //C
float Temp2 = 30.5; //A
float Temp3 = 25.5; //B
int Volt0 = 220; //C
int Volt1 = 220; //A
float Volt2 = 13.5; //B
float Volt3 = 13.5; //C
char msg[255];
String strMsgX = "X";
strMsgX = strMsgX + ",";
strMsgX = strMsgX + "A";
strMsgX = strMsgX + ",";
strMsgX = strMsgX + Press;
strMsgX = strMsgX + ",";
strMsgX = strMsgX + "B";
strMsgX = strMsgX + ",";
strMsgX = strMsgX + Temp0;
strMsgX = strMsgX + ",";
strMsgX = strMsgX + "C";
strMsgX = strMsgX + ",";
strMsgX = strMsgX + Temp1;
String strMsgY = "Y";
strMsgY = strMsgY + ",";
strMsgY = strMsgY + "A";
strMsgY = strMsgY + ",";
strMsgY = strMsgY + Temp2;
strMsgY = strMsgY + ",";
strMsgY = strMsgY + "B";
strMsgY = strMsgY + ",";
strMsgY = strMsgY + Temp3;
strMsgY = strMsgY + ",";
strMsgY = strMsgY + "C";
strMsgY = strMsgY + ",";
strMsgY = strMsgY + Volt0;
String strMsgZ = "Z";
strMsgZ = strMsgZ + ",";
strMsgZ = strMsgZ + "A";
strMsgZ = strMsgZ + ",";
strMsgZ = strMsgZ + Volt1;
strMsgZ = strMsgZ + ",";
strMsgZ = strMsgZ + "B";
strMsgZ = strMsgZ + ",";
strMsgZ = strMsgZ + Volt2;
strMsgZ = strMsgZ + ",";
strMsgZ = strMsgZ + "C";
strMsgZ = strMsgZ + ",";
strMsgZ = strMsgZ + Volt3;
if(msgSet == 1){
strMsgX.toCharArray(msg,255);
msgSet = 2;
}
else if(msgSet == 2){
strMsgY.toCharArray(msg,255);
msgSet = 3;
}
else {
strMsgZ.toCharArray(msg,255);
msgSet = 1;
}
Serial.println(msg);
vw_send((uint8_t*)msg, strlen(msg));
vw_wait_tx(); // Ждем пока передача будет окончена
delay(200);
}
Вот пакеты которые он отправляет
X,A,2.00,B,60.50,C,55.50 Y,A,30.50,B,25.50,C,220 Z,A,220,B,13.50,C,13.50
Вот кусок кода приемника
#include <VirtualWire.h>
#define displayInterval1 1000 // интервал между показаниями
uint8_t buf[VW_MAX_MESSAGE_LEN]; // Буфер для сообщения
uint8_t buflen = VW_MAX_MESSAGE_LEN; // Длина буфера
long lastdisplayTime = 0; // время последнего отображения данных
const int transmit_pin = 12;
const int receive_pin = 11;
char data[100];
char mode[2];
char paramA[2];
char paramB[2];
char paramC[2];
char valueA[6];
char valueB[6];
char valueC[6];
float Press; //AX
float Temp0; //BX
float Temp1; //CX
float Temp2; //AY
float Temp3; //BY
int Volt0; //CY
int Volt1; //AZ
float Volt2; //BZ
float Volt3; //CZ
int i;
void setup() {
Serial.begin(9600);
vw_set_tx_pin(transmit_pin);
vw_set_rx_pin(receive_pin);
vw_set_ptt_inverted(true);
vw_setup(2000);
vw_rx_start(); // Начинаем мониторинг эфира
}
void loop(){
if (vw_get_message(buf, &buflen)){ // Если принято сообщение
if (buf[0] == 'X'){ // Если сообщение адресовано нам
for (i = 0; i < buflen; i++){
data[i] = buf[i];
}
sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s",
&mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC);
Press = atof(valueA);
Temp0 = atof(valueB);
Temp1 = atof(valueC);
}
if (buf[0] == 'Y'){ // Если сообщение адресовано нам
for (i = 0; i < buflen; i++){
data[i] = buf[i];
}
sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s",
&mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC);
Temp2 = atof(valueA);
Temp3 = atof(valueB);
Volt0 = atoi(valueC);
}
if (buf[0] == 'Z'){ // Если сообщение адресовано нам
for (i = 0; i < buflen; i++){
data[i] = buf[i];
}
sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s",
&mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC);
Volt1 = atoi(valueA);
Volt2 = atof(valueB);
Volt3 = atof(valueC);
}
}
unsigned long currentMillis = millis(); // текущее время в миллисекундах
if(currentMillis - lastdisplayTime >= displayInterval1) {
Serial.print("Press");
Serial.print(",");
Serial.print(Press,1);
Serial.print(" ");
Serial.print("Temp0");
Serial.print(",");
Serial.print(Temp0,1);
Serial.print(" ");
Serial.print("Temp1");
Serial.print(",");
Serial.println(Temp1,1);
Serial.print("Temp2");
Serial.print(",");
Serial.print(Temp2,1);
Serial.print(" ");
Serial.print("Temp3");
Serial.print(",");
Serial.print(Temp3,1);
Serial.print(" ");
Serial.print("Volt0");
Serial.print(",");
Serial.println(Volt0);
Serial.print("Volt1");
Serial.print(",");
Serial.print(Volt1);
Serial.print(",");
Serial.print("Volt2");
Serial.print(",");
Serial.print(Volt2,1);
Serial.print(",");
Serial.print("Volt3");
Serial.print(",");
Serial.println(Volt3,1);
Serial.println("");
lastdisplayTime = currentMillis; // запоминаем момент времени
}
}
Вот такие пакеты приходят
Press,2.0 Temp0,60.5 Temp1,55.5 Temp2,30.5 Temp3,25.5 Volt0,220 Volt1,220,Volt2,13.5,Volt3,13.5
Устройство собрано и работает, правда на пока без корпуса, на макете

Но заметил, что в пакете Y последний параметр Volt0 выскакивает 2200 вместо 220
Temp2,30.5 Temp3,25.5 Volt0,2200
Разбор пакета Y происходит в строке 58
sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", |
058 |
&mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); |
В чем может быть причина?
Я ни разу не программист, просто зимой в деревне работы не много, вот и ардуиню по маленьку. Так что если что не судите строго.
Добавлю, вернее после строки 58 получается
А уже после обработки данных получается
После строки 46 приёмника добавьте
data[i] = 0;
После строки 46 приёмника добавьте
data[i] = 0;
Спасибо. Вы наверное имели ввиду после 47. Я вставил после 48. Вроде пока работает. Может поставить после всех функций sscanf ?
Я имел в виду именно после строки 46. Но сейчас посмотрел код внимательнее и увидел, что Вы зачем-то одно и тоже разместили в трёх местах. Потому, "правильно" - после 46, 56 и 66.
Но это именно "правильно". Потому, что правильно будет не размещать одно и тоже в трёх местах, а просто
1. Строки 44-46 перенести после строки 42 (и сразу после них (после бывшей строки 46) вставить то, что я говорил)
2. Строки 54-56 и 64-66 просто выбросить за ненадобностью.
Я имел в виду именно после строки 46. Но сейчас посмотрел код внимательнее и увидел, что Вы зачем-то одно и тоже разместили в трёх местах. Потому, "правильно" - после 46, 56 и 66.
Вставил после 46 строки перед функцией sscanf тоже работает. Не понимаю почему. В строках 44-46 буфер переписывается в массив data. И после этого этот массив обнуляю. Как же тогда работает функция sscanf ?
Библиотека VirtualWire имеет ограничения по размеру отправляемого пакета. Поэтому в передатчике я отправляю три пакета X, Y, Z. А потом в строках 43,53,63 я определяю какой пакет был получен и с помощью функции sscanf каждый из этих пакетов анализирую, поэтому она в трех местах.
P.S. Вставил data[i] = 0; перед функцией sscanf, после строк 46, 56, 66 и прием пакетов сбился, гонит белеберду. Вставил data[i] = 0; после функции sscanf, после 48, 58 и 68, прием пакетов возобновился и всё заработало.
Не понимаю почему.
В строках 44-46 Вы переписываете буфер в массив data, БЕЗ хвостового нуля (который служит признаком конца строки). Поэтому, если там что-то до Вас было, оно остаётся и "приклеивается" в Вашим данным из буффера. Вот лишний нолик и вылазит.
Еще раз, Вы копируете строковый буфер без завершающего нуля. А я лишь добавил этот ноль в конец и всё заработало.
В строках 44-46 Вы переписываете буфер в массив data, БЕЗ хвостового нуля (который служит признаком конца строки). Поэтому, если там что-то до Вас было, оно остаётся и "приклеивается" в Вашим данным из буффера. Вот лишний нолик и вылазит.
Насколько я знаю признаком конца строки является '\0'. Тогда почему не его добавляем? Или может в передатчике его поставить в конце каждого пакета. А в приемнике в строках 44,54,64 цикл
for(i = 0; i < buflen; i++)переделать таким образомfor(i = 0; i < '\0'; i++)Еще раз, Вы копируете строковый буфер без завершающего нуля. А я лишь добавил этот ноль в конец и всё заработало.
Тогда почему, когда вставил data[i] = 0; перед функцией sscanf, после строк 46, 56, 66 прием пакетов сбился, а когда вставил data[i] = 0; после функции sscanf, после 48, 58 и 68, прием пакетов возобновился и всё заработало.
Насколько я знаю признаком конца строки является '\0'. Тогда почему не его добавляем?
Открою маленький секрет: '\0' и 0 - одно и то же для типа char.
Насколько я знаю признаком конца строки является '\0'. Тогда почему не его добавляем?
Ну, добавляйте его. Так будет "методологически" правильнее. На физическом уровне разницы нет, а на логическом - да, '\0' - более кошерно.
Тогда почему, когда вставил data[i] = 0; перед функцией sscanf, после строк 46, 56, 66 прием пакетов сбился, а когда вставил data[i] = 0; после функции sscanf, после 48, 58 и 68, прием пакетов возобновился и всё заработало.
Я не знаю, что, куда, и как Вы добавляли, Вы же не показываете код с добавлениями. То, что Вы в цикле копирования не вставляете 0 - это точно. А остальное - откуда мне знать.
Первый эксперимент
Вот так парсит белеберду, это когда data[i] = 0; вставил после 46 строки перед функцией sscanf
if (buf[0] == 'X'){ // Если сообщение адресовано нам for (i = 0; i < buflen; i++){ data[i] = buf[i]; } data[i] = 0; sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", &mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); Press = atof(valueA); Temp0 = atof(valueB); Temp1 = atof(valueC);Вот так работает прекрасно, гонял пол дня, data[i] = 0; вставил после 48 строки после функции sscanf
if (buf[0] == 'X'){ // Если сообщение адресовано нам for (i = 0; i < buflen; i++){ data[i] = buf[i]; } sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", &mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); data[i] = 0; Press = atof(valueA); Temp0 = atof(valueB); Temp1 = atof(valueC);Второй эксперимент
Добавил в передатчике в конце каждого пакета strMsg = strMsg + "\0";
И в приемнике везде убрал data[i] = 0; и переделал цикл for (i = 0; i < '\0'; i++) Не работает вообще. На выходе одни нули. Что не так?
Вот так парсит белеберду, это когда data[i] = 0; вставил после 46 строки перед функцией sscanf
Ну, я же написал позже, что надо после всех Ваших копирований, а не только после 44
Добавил в передатчике в конце каждого пакета strMsg = strMsg + "\0";
И в приемнике везде убрал data[i] = 0; и переделал цикл for (i = 0; i < '\0'; i++) Не работает вообще. На выходе одни нули. Что не так?
Цикл-то чем винован, верните длину сообщения на место.
Добавил в передатчике в конце каждого пакета strMsg = strMsg + "\0"; и в приемнике везде убрал data[i] = 0; и вернул цикл for назад. Все равно появляется лишний ноль.
Буду использовать предущий вариант с data[i] = 0; Большое спасибо.
Добавил в передатчике в конце каждого пакета strMsg = strMsg + "\0"; и в приемнике везде убрал data[i] = 0; и вернул цикл for назад. Все равно появляется лишний ноль.
так и будет появляться, Вы принципа не поняли.
Чтобы не появлялся, можно, например,
1. В передатчике передавать 0
2. Выбросить Ваш цикл копирования буфера, заменив его на вызов функции strcpy. Она и скопирует и 0 вставит.
1. В передатчике передавать 0
Добавил в передатчике в конце каждого пакета strMsg = strMsg + "\0"; Все равно появляется лишний ноль.
2. Выбросить Ваш цикл копирования буфера, заменив его на вызов функции strcpy. Она и скопирует и 0 вставит.
Выбросил цикл копирования буфера, заменил его на функцию strcpy. Пока работает, посмотрим насколько устойчиво.
P.S. Сбивается и не восстановливается. Предущий вариант с data[i] = 0; работает более стабильно и если сбивается то восстанавливается.
Ну, Вы знаете, так не бывает. Чтобы strcpy "сбивалась" - это Вы где-то тщательно постарались её сбить. Я Вам в 9-ом посте писал - покажите код. Вы показали какой-то огрызок. Ну, так и будем тут фигнёй страдать. Нужна помощь - выкладывайте код (целиком!), не нужна - дело Ваше.
Я показал полный код приема и парсинга пакетов. Вот он с функцией strcpy. Здесь он в виде отдельной фукции receiver(); потом её всавляю в код TFT экрана.
#include <VirtualWire.h> #define displayInterval1 1000 // интервал между показаниями uint8_t buf[VW_MAX_MESSAGE_LEN]; // Буфер для сообщения uint8_t buflen = VW_MAX_MESSAGE_LEN; // Длина буфера long lastdisplayTime = 0; // время последнего отображения данных const int transmit_pin = 12; const int receive_pin = 11; char data[100]; char mode[2]; char paramA[2]; char paramB[2]; char paramC[2]; char valueA[6]; char valueB[6]; char valueC[6]; float Press; //AX float Temp0; //BX float Temp1; //CX float Temp2; //AY float Temp3; //BY int Volt0; //CY int Volt1; //AZ float Volt2; //BZ float Volt3; //CZ int i; void setup() { Serial.begin(9600); vw_set_tx_pin(transmit_pin); vw_set_rx_pin(receive_pin); vw_set_ptt_inverted(true); vw_setup(2000); vw_rx_start(); // Начинаем мониторинг эфира } void loop(){ receiver(); unsigned long currentMillis = millis(); // текущее время в миллисекундах if(currentMillis - lastdisplayTime >= displayInterval1) { Serial.print("Press"); Serial.print(","); Serial.print(Press,1); Serial.print(" "); Serial.print("Temp0"); Serial.print(","); Serial.print(Temp0,1); Serial.print(" "); Serial.print("Temp1"); Serial.print(","); Serial.println(Temp1,1); Serial.print("Temp2"); Serial.print(","); Serial.print(Temp2,1); Serial.print(" "); Serial.print("Temp3"); Serial.print(","); Serial.print(Temp3,1); Serial.print(" "); Serial.print("Volt0"); Serial.print(","); Serial.println(Volt0); Serial.print("Volt1"); Serial.print(","); Serial.print(Volt1); Serial.print(","); Serial.print("Volt2"); Serial.print(","); Serial.print(Volt2,1); Serial.print(","); Serial.print("Volt3"); Serial.print(","); Serial.println(Volt3,1); Serial.println(""); lastdisplayTime = currentMillis; // запоминаем момент времени } } void receiver(){ if (vw_get_message(buf, &buflen)){ // Если принято сообщение if (buf[0] == 'X'){ // Если сообщение X for (i = 0; i < buflen; i++){ strcpy(data,buf); //data[i] = buf[i]; } sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", &mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); //data[i] = 0; Press = atof(valueA); Temp0 = atof(valueB); Temp1 = atof(valueC); } if (buf[0] == 'Y'){ // Если сообщение Y for (i = 0; i < buflen; i++){ strcpy(data,buf); //data[i] = buf[i]; } sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", &mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); //data[i] = 0; Temp2 = atof(valueA); Temp3 = atof(valueB); Volt0 = atoi(valueC); } if (buf[0] == 'Z'){ // Если сообщение Z for (i = 0; i < buflen; i++){ strcpy(data,buf); //data[i] = buf[i]; } sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", &mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); //data[i] = 0; Volt1 = atoi(valueA); Volt2 = atof(valueB); Volt3 = atof(valueC); } } }Код передатчика тот же, только в конце каждого пакета strMsg = strMsg + "\0"; Передатчик передает каждый пакет через 200мС.
Прием идет каждую секунду.
вы хотя бы попытались прочитать описание функции strcpy() ?
Зачем вы этот бред пишете:
for (i = 0; i < buflen; i++){ strcpy(data,buf); }вы хотя бы попытались прочитать описание функции strcpy() ?
Зачем вы этот бред пишете:
for (i = 0; i < buflen; i++){ strcpy(data,buf); }Из этого следует что цикл for лишний. Попробую без него.
Из этого следует что цикл for лишний. Попробую без него.
неужели дошло? :)
Попробуйте понять, зачем вообще нужен ноль в конце данных. По вашим сообшениям мне кажется. что у вас понимания нет.
Я показал полный код приема
В стартовом посте. А после моей просьбы показать изменения, Вы показали огрызок в посте №10.
Поймите, Вам кажется, что Вы правильно вставляете изменения, а мне - что нет. Так показывайте же полностью как Вы их вставляете, дайте посмотреть-то!
Вы смысл слова "полностью" пнимаете? Это как было в стартовом посте или как код приёмника сейчас.
Ну, блин, я хочу Вам помочь, но не создавайте же мне проблем в этом! Вы что, место на сервере экономите?
for (i = 0; i < buflen; i++){ strcpy(data,buf); //data[i] = buf[i]; }Вот, тот самый случай о котором я говорил (когда Вы считаете, что правильно вставили).
Я Вам что писал?
2. Выбросить Ваш цикл копирования буфера, заменив его на вызов функции strcpy. Она и скопирует и 0 вставит.
А Вы что сделали? Зачем цикл оставили? Отвсего приведённого кусочка должна остаться ТОЛЬКО строка 2 - ничего другого!
Код передатчика тот же, только в конце каждого пакета strMsg = strMsg + "\0"; Передатчик передает каждый пакет через 200мС.
Скорее всего, это опять тот самый случай о котором я говорил (когда Вы считаете, что правильно вставили)
Давайте всё же договримся так. После каждого изменения, Вы выкладываете коды передатчика и приёмника. Иначе я просто прекращаю работать в этой теме. Просто тупо выкладываете после любого изменения.
Вот сейчас,
1. Вы прикажете мне догадываться в какое место Вы это вставили?
2 (и главное) Я должен угадывать, поменяли Вы строчку 84
в передатчике или оставили как была? А если Вы её не поменяли, Вы туда хоть десять нулей дописывайте, всё равно передатчик их передавать не будет!
В общем, если ноль Вы добавили правильно, то эта строка должна выгладеть как
+1 нужна, чтобы этот Ваш ноль учесть. Иначе никто его передавать и не подумает! И, кстати, эта +1 гораздо Важнее Вашей попытки дописать 0 (скорее всего неудачной), т.к. ноль в кончце строки и без Вас есть, не надо его туда дописывать, а вот чтобы он передался нужна эта +1
----------
В общем правьте и выкладывайте коды и приёмника и передатчика. Если по каким-то причинам, Вам этого делать не хочется, то простите, я прекращаю это занятие. Ну, правда, надоело Вас умолять.
Из этого следует что цикл for лишний. Попробую без него.
неужели дошло? :)
Попробуйте понять, зачем вообще нужен ноль в конце данных. По вашим сообшениям мне кажется. что у вас понимания нет.
Ещё раз повторяю, я крестьянин, а не программист. Я занимаюсю пчелами, курями и т.д. И как старый радиолюбитель зимой немного ардуиню. Мне уже трудно разбираться во всех этих функция, поэтому я опираюсь на примеры. Мне Вашего уровня не достичь, да я и не стараюсь. Я уже много чего сделал и оно работает. Поэтому прошу немного снисходительности.
Теперь по теме: убрал цикл - работает, но лишний ноль не пропал. Volt0 получает 2200
----------
В общем правьте и выкладывайте коды и приёмника и передатчика. Если по каким-то причинам, Вам этого делать не хочется, то простите, я прекращаю это занятие. Ну, правда, надоело Вас умолять.
Ещё раз извините, я только учусь, хотя уже поздно наверное.
Ещё раз повторяю, я крестьянин, а не программист.
Так и выкладывайте код, когда Вас просят! Не считайте, что Вы вставили всё правильно!
Вот окончательный код передатчика
#include <VirtualWire.h> int msgSet = 1; //Отправку начать с первого массива void setup(){ //настройка virtualWire vw_set_tx_pin(12);//пин передачи vw_set_rx_pin(11);//пин приема vw_set_ptt_inverted(true); vw_setup(2000);//скорость передачи данных Serial.begin(9600); } void loop(){ float Press = 2.0; //AX float Temp0 = 60.5; //BX float Temp1 = 55.5; //CX float Temp2 = 30.5; //AY float Temp3 = 25.5; //BY int Volt0 = 220; //CY int Volt1 = 220; //AZ float Volt2 = 13.5; //BZ float Volt3 = 13.5; //CZ char msg[255]; String strMsgX = "X"; strMsgX = strMsgX + ","; strMsgX = strMsgX + "A"; strMsgX = strMsgX + ","; strMsgX = strMsgX + Press; strMsgX = strMsgX + ","; strMsgX = strMsgX + "B"; strMsgX = strMsgX + ","; strMsgX = strMsgX + Temp0; strMsgX = strMsgX + ","; strMsgX = strMsgX + "C"; strMsgX = strMsgX + ","; strMsgX = strMsgX + Temp1; strMsgX = strMsgX + "\0"; String strMsgY = "Y"; strMsgY = strMsgY + ","; strMsgY = strMsgY + "A"; strMsgY = strMsgY + ","; strMsgY = strMsgY + Temp2; strMsgY = strMsgY + ","; strMsgY = strMsgY + "B"; strMsgY = strMsgY + ","; strMsgY = strMsgY + Temp3; strMsgY = strMsgY + ","; strMsgY = strMsgY + "C"; strMsgY = strMsgY + ","; strMsgY = strMsgY + Volt0; strMsgY = strMsgY + "\0"; String strMsgZ = "Z"; strMsgZ = strMsgZ + ","; strMsgZ = strMsgZ + "A"; strMsgZ = strMsgZ + ","; strMsgZ = strMsgZ + Volt1; strMsgZ = strMsgZ + ","; strMsgZ = strMsgZ + "B"; strMsgZ = strMsgZ + ","; strMsgZ = strMsgZ + Volt2; strMsgZ = strMsgZ + ","; strMsgZ = strMsgZ + "C"; strMsgZ = strMsgZ + ","; strMsgZ = strMsgZ + Volt3; strMsgZ = strMsgZ + "\0"; if(msgSet == 1){ strMsgX.toCharArray(msg,255); msgSet = 2; } else if(msgSet == 2){ strMsgY.toCharArray(msg,255); msgSet = 3; } else { strMsgZ.toCharArray(msg,255); msgSet = 1; } Serial.println(msg); vw_send((uint8_t*)msg, strlen(msg)+1); vw_wait_tx(); // Ждем пока передача будет окончена delay(200); }Окончательный код приемника
#include <VirtualWire.h> #define displayInterval1 1000 // интервал между показаниями uint8_t buf[VW_MAX_MESSAGE_LEN]; // Буфер для сообщения uint8_t buflen = VW_MAX_MESSAGE_LEN; // Длина буфера long lastdisplayTime = 0; // время последнего отображения данных const int transmit_pin = 12; const int receive_pin = 11; char data[100]; char mode[2]; char paramA[2]; char paramB[2]; char paramC[2]; char valueA[6]; char valueB[6]; char valueC[6]; float Press; //AX float Temp0; //BX float Temp1; //CX float Temp2; //AY float Temp3; //BY int Volt0; //CY int Volt1; //AZ float Volt2; //BZ float Volt3; //CZ int i; void setup() { Serial.begin(9600); vw_set_tx_pin(transmit_pin); vw_set_rx_pin(receive_pin); vw_set_ptt_inverted(true); vw_setup(2000); vw_rx_start(); // Начинаем мониторинг эфира } void loop(){ receiver(); unsigned long currentMillis = millis(); // текущее время в миллисекундах if(currentMillis - lastdisplayTime >= displayInterval1) { Serial.print("Press"); Serial.print(","); Serial.print(Press,1); Serial.print(" "); Serial.print("Temp0"); Serial.print(","); Serial.print(Temp0,1); Serial.print(" "); Serial.print("Temp1"); Serial.print(","); Serial.println(Temp1,1); Serial.print("Temp2"); Serial.print(","); Serial.print(Temp2,1); Serial.print(" "); Serial.print("Temp3"); Serial.print(","); Serial.print(Temp3,1); Serial.print(" "); Serial.print("Volt0"); Serial.print(","); Serial.println(Volt0); Serial.print("Volt1"); Serial.print(","); Serial.print(Volt1); Serial.print(","); Serial.print("Volt2"); Serial.print(","); Serial.print(Volt2,1); Serial.print(","); Serial.print("Volt3"); Serial.print(","); Serial.println(Volt3,1); Serial.println(""); lastdisplayTime = currentMillis; // запоминаем момент времени } } void receiver(){ if (vw_get_message(buf, &buflen)){ // Если принято сообщение if (buf[0] == 'X'){ // Если сообщение адресовано нам //for (i = 0; i < buflen; i++){ strcpy(data,buf); //data[i] = buf[i]; //} sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", &mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); //data[i] = 0; Press = atof(valueA); Temp0 = atof(valueB); Temp1 = atof(valueC); } if (buf[0] == 'Y'){ // Если сообщение адресовано нам //for (i = 0; i < buflen; i++){ strcpy(data,buf); //data[i] = buf[i]; //} sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", &mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); //data[i] = 0; Temp2 = atof(valueA); Temp3 = atof(valueB); Volt0 = atoi(valueC); } if (buf[0] == 'Z'){ // Если сообщение адресовано нам //for (i = 0; i < buflen; i++){ strcpy(data,buf); //data[i] = buf[i]; //} sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", &mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); //data[i] = 0; Volt1 = atoi(valueA); Volt2 = atof(valueB); Volt3 = atof(valueC); } } }Вроде сейчас всё учел
Вот так-то лучше.
Ну, строки 41, 56 и 71 в передатчике - лишние. Они ничего не делают (но и не мешают).
И что, всё равно 0 появляется? На первый взгляд, вроде не должен. Исчез или смотреть внимательнее?
Вопрос 1: Как я понял, strlen(msg) + 1 и есть добавка символа конца строки, и
strMsgZ = strMsgZ +"\0";не требуется.Вопрос2: А функция strcpy() так же добавит конец строки, он не будет лишним?
Вопрос3. У меня обновление экрана через 10 сек. Передатчик передает за раз 1 пакет, у меня три пакета. С каким периодом передавать пакеты и с каким периодом их опрашивать?
Вопрос 1: Как я понял, strlen(msg) + 1 и есть добавка символа конца строки, и
strMsgZ = strMsgZ +"\0";не требуется.0 в конце строки уже есть. Его не надо добавлять. strlen(msg) + 1 - задаёт количество передаваемых символов и означает "передать всю строку и ещё один символ после неё". Вот это ещё один символ и есть тот самый 0, который там уже есть и без нас. Т.е. это не добавление (он уже есть), а лишь указание. что его надо передать.
Вопрос2: А функция strcpy() так же добавит конец строки, он не будет лишним?
Она ничего никуда не добавляет. Она копирует строку, считая, что в её конце есть 0 (именно так она и опредеяет где конец). При копировании строки она этот конечный ноль ТОЖЕ копирует.
Вопрос3. У меня обновление экрана через 10 сек. Передатчик передает за раз 1 пакет, у меня три пакета. С каким периодом передавать пакеты и с каким периодом их опрашивать?
Это вопрос по сути Вашей задачи, о которой я ничего не знаю.
Ещё раз огромное спасибо, за то что уделили мне время и всё разжевали.
Пока всё работает нормально.
Проработало три часа и начало сбиваться.
У меня обновление экрана через 10 сек. Опрос приемника тоже раз в 10 сек. Передатчик передает каждую секунду 1 пакет, у меня три пакета. Значит до следующего опроса передается каждый пакет 3 раза. Это потому, что заметил не все пакеты определяются одинаково. Некоторые обновились по 2 раза, некоторые ни разу.
Ещё заметил, что чем чаще делаю опрос тем быстрее начинает сбиваться. Как будто в буфер попадает сторонняя информация. Но почему это происходит непонятно, ведь будер обновляется с каждым пакетом.
Проработало три часа и начало сбиваться. ... Ещё заметил, что чем чаще делаю опрос тем быстрее начинает сбиваться
По симптомам похоже на распашку памяти, но так сразу я не вижу где она.
У меня обновление экрана через 10 сек. Опрос приемника тоже раз в 10 сек. Передатчик передает каждую секунду 1 пакет, у меня три пакета.
А, так Вы гоняете не тот код, что выложен здесь? Потому как в здешнем коде никакого экрана нет, а в сериал выводится раз в секунду, а не в десять.
Похоже, Вы утром ничего не поняли. Я сейчас потратил минут тридцать в поисках где может быть распашка в Вашем коде, подключил монитор памяти, изучал его логи, а оказалось, что я смотрю не тот код в котором проблема. Честно говоря, после моих утренних объяснений, не ожидал. Похоже, Вы просто издеваетесь.
Ещё раз прошу извинить, что так получилось. Я конечно не ожидал, что Вы так тчательно к этому отнесетесь. У меня проблема была в коде приемника и я поэтому только его выложил. Я же сразу написал и фотку приложил, что это был только кусок кода для приемника. А весь код отображает информацию на экран. Я и сам не знал что приемник с кодом экрана будут давать ошибку и только сейчас в этом убедился. Вот весь код для экрана, только в него вставлен вывод в сериал для контроля.
//----------------------------------------------------------- #include <VirtualWire.h> #include <utf8rus.h> // Функция русских букв #include <Adafruit_GFX.h> // Libreria de graficos #include <Adafruit_TFTLCD.h> // Libreria de LCD //----------------------------------------------------------- // Pines de conexion del LCD #define LCD_CS A3 // Chip Select - Pin analogico 3 #define LCD_CD A2 // Command/Data - Pin Analogico 2 #define LCD_WR A1 // LCD Write - Pin Analogico 1 #define LCD_RD A0 // LCD Read - Pin Analogico 0 #define LCD_RESET 13 // LCD Reset - Pin 13 #define displayInterval1 5000 // интервал между показаниями Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); // Instancia del LCD char buf[VW_MAX_MESSAGE_LEN]; // Буфер для сообщения char buflen = VW_MAX_MESSAGE_LEN; // Длина буфера const int transmit_pin = 12; //пин передачи const int receive_pin = 11; //пин приема char data[100]; char mode[2]; char paramA[2]; char paramB[2]; char paramC[2]; char valueA[6]; char valueB[6]; char valueC[6]; float Press; //AX float Temp0; //BX float Temp1; //CX float Temp2; //AY float Temp3; //BY int Volt0; //CY int Volt1; //AZ float Volt2; //BZ float Volt3; //CZ int i; long lastdisplayTime = 0; // время последнего отображения данных int displaySet = 2; // номер включеного дисплея //----------------------------------------------------------- #define BLACK 0x0000 // Определим цвета, чтобы обращаться к ним по имени #define RED 0xF800 // вместо использования шестнадцатеричного кода #define GREEN 0x07E0 #define WHITE 0xFFFF #define BLUE 0x001F #define CYAN 0x07FF #define YELLOW 0xFFE0 #define MAGENTA 0xF81F #define LINECOLOR1 0xFFFF //WHITE #define TEXTCOLOR1 0x07FF //CYAN #define TEXTCOLOR2 0x07FA #define DATACOLOR1 0x07E0 //GREEN #define DATACOLOR2 0xFFE0 //YELLOW #define DATACOLOR3 0xF800 //RED //----------------------------------------------------------- void setup(void){ Serial.begin(9600); //настройка Adafruit_TFTLCD tft.begin(0x9325); // Нициализация адреса контроллера tft.setRotation(3); //поворачиваем дисплей tft.fillScreen(BLACK); // Очистка в черный цвет экран //настройка virtualWire vw_set_tx_pin(transmit_pin); //пин передачи vw_set_rx_pin(receive_pin); //пин приема vw_set_ptt_inverted(true); vw_setup(2000); //скорость приема vw_rx_start(); // Включаем мониторинг эфира } //----------------------------------------------------------- void loop(){ // Начинаем вывод на экран unsigned long currentMillis = millis(); // текущее время в миллисекундах if((displaySet > 1) && (currentMillis - lastdisplayTime >= displayInterval1)) { if(displaySet > 2) tft.fillScreen(BLACK); displaySet = 1; // включаем 1 экран receiver(); table(); Temperature(); Voltage(); lastdisplayTime = currentMillis; // запоминаем момент времени } if((displaySet == 1) && (currentMillis - lastdisplayTime >= displayInterval1)) { displaySet = 2; // включаем 2 экран receiver(); Pressure(); lastdisplayTime = currentMillis; // запоминаем момент времени } } //----------------------------------------------------------- void receiver(){ if (vw_get_message(buf, &buflen)){ // Если принято сообщение if (buf[0] == 'X'){ // Если сообщение адресовано нам Serial.println(buf); strcpy(data,buf); sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", &mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); Press = atof(valueA); Temp0 = atof(valueB); Temp1 = atof(valueC); serprn(); } if (buf[0] == 'Y'){ // Если сообщение адресовано нам Serial.println(buf); strcpy(data,buf); sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", &mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); Temp2 = atof(valueA); Temp3 = atof(valueB); Volt0 = atoi(valueC); serprn(); } if (buf[0] == 'Z'){ // Если сообщение адресовано нам Serial.println(buf); strcpy(data,buf); sscanf(data, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s", &mode, ¶mA, &valueA, ¶mB, &valueB, ¶mC, &valueC); Volt1 = atoi(valueA); Volt2 = atof(valueB); Volt3 = atof(valueC); serprn(); } } } //----------------------------------------------------------- void table() { // Делаем большой толстый прямоугольник tft.drawRect (0, 0, 320, 240, LINECOLOR1); tft.drawRect (1, 1, 318, 238, LINECOLOR1); tft.drawRect (2, 2, 316, 236, LINECOLOR1); // Делаем правый толстый прямоугольник tft.drawRect (0, 3, 100, 234, LINECOLOR1); tft.drawRect (0, 3, 99, 234, LINECOLOR1); tft.drawRect (0, 3, 98, 234, LINECOLOR1); // Делаем левый толстый прямоугольник tft.drawRect (0, 3, 220, 234, LINECOLOR1); tft.drawRect (0, 3, 221, 234, LINECOLOR1); tft.drawRect (0, 3, 222, 234, LINECOLOR1); // Делаем правый горизонтальный толстый прямоугольник tft.drawRect (220, 120, 320, 120, LINECOLOR1); tft.drawRect (220, 121, 220, 120, LINECOLOR1); tft.drawRect (220, 122, 220, 120, LINECOLOR1); // Делаем левый горизонтальный толстый прямоугольник tft.drawRect (0, 0, 100, 120, LINECOLOR1); tft.drawRect (0, 1, 100, 120, LINECOLOR1); tft.drawRect (0, 2, 100, 120, LINECOLOR1); } //----------------------------------------------------------- void Voltage() { tft.fillRect(102, 5, 115, 230, BLACK); //квадрат 115 на 230 tft.setTextSize(2); tft.setTextColor(TEXTCOLOR1); tft.setCursor(135, 10); tft.println(utf8rus("СЕТЬ")); tft.setCursor(140, 65); tft.println(utf8rus("UPS")); tft.setCursor(130, 125); tft.println(utf8rus("АКБ 1")); tft.setCursor(130, 180); tft.println(utf8rus("АКБ 2")); tft.setTextSize(4); tft.setCursor(125, 30); tft.setTextColor(DATACOLOR2); if (Volt0 < 210 || Volt0 > 230) tft.setTextColor(DATACOLOR3); tft.println(Volt0); tft.setCursor(125, 85); tft.setTextColor(DATACOLOR2); if (Volt1 < 210 || Volt1 > 230) tft.setTextColor(DATACOLOR3); tft.println(Volt1); tft.setCursor(115, 145); tft.setTextColor(DATACOLOR2); if (Volt2 < 13 || Volt2 > 14) tft.setTextColor(DATACOLOR3); tft.println(Volt2,1); //1 знак после запятой tft.setCursor(115, 200); tft.setTextColor(DATACOLOR2); if (Volt3 < 13 || Volt3 > 14) tft.setTextColor(DATACOLOR3); tft.println(Volt3,1); //1 знак после запятой } //----------------------------------------------------------- void Pressure() { tft.fillRect(102, 5, 115, 230, BLACK); //квадрат 115 на 230 tft.setCursor(115, 35); tft.setTextSize(2); tft.setTextColor(TEXTCOLOR1); tft.println(utf8rus("ДАВЛЕНИЕ")); tft.setCursor(108, 65); tft.println(utf8rus("В СИСТЕМЕ")); tft.setCursor(108, 100); tft.setTextSize(6); tft.setTextColor(DATACOLOR2); if (Press < 1.6 || Press > 2.2) tft.setTextColor(DATACOLOR3); tft.println(Press,1); tft.setCursor(140, 160); tft.setTextSize(2); tft.setTextColor(TEXTCOLOR1); tft.println(utf8rus("АТМ")); } //----------------------------------------------------------- void Temperature() { tft.setTextSize(2); tft.setTextColor(TEXTCOLOR2); tft.setCursor(20, 10); tft.println(utf8rus("КОТЕЛ")); tft.setCursor(15, 30); tft.println(utf8rus("ПОДАЧА")); tft.setCursor(240, 10); tft.println(utf8rus("КОТЕЛ")); tft.setCursor(230, 30); tft.println(utf8rus("ОБРАТКА")); tft.setCursor(20, 130); tft.println(utf8rus("Т.ПОЛ")); tft.setCursor(15, 150); tft.println(utf8rus("ПОДАЧА")); tft.setCursor(240, 130); tft.println(utf8rus("Т.ПОЛ")); tft.setCursor(230, 150); tft.println(utf8rus("ОБРАТКА")); tft.setTextSize(5); tft.fillRect(240, 60, 60, 50, BLACK); //квадрат 50 на 60 tft.setCursor(242, 65); tft.setTextColor(DATACOLOR2); if (Temp0 < 50 || Temp0 > 80) tft.setTextColor(DATACOLOR3); tft.println(Temp0,0); tft.fillRect(20, 60, 60, 50, BLACK); //квадрат 50 на 60 tft.setCursor(22, 65); tft.setTextColor(DATACOLOR2); if (Temp1 < 40 || Temp1 > 70) tft.setTextColor(DATACOLOR3); tft.println(Temp1,0); tft.fillRect(20, 175, 60, 50, BLACK); //квадрат 50 на 60 tft.setCursor(22, 180); tft.setTextColor(DATACOLOR2); if (Temp2 < 25 || Temp2 > 35) tft.setTextColor(DATACOLOR3); tft.println(Temp2,0); tft.fillRect(240, 175, 60, 50, BLACK); //квадрат 50 на 60 tft.setCursor(242, 180); tft.setTextColor(DATACOLOR2); if (Temp3 < 20 ||Temp3 > 30) tft.setTextColor(DATACOLOR3); tft.println(Temp3,0); } //----------------------------------------------------------- void serprn() { Serial.print(mode); Serial.print(","); Serial.print(paramA); Serial.print(","); Serial.print(valueA); Serial.print(","); Serial.print(paramB); Serial.print(","); Serial.print(valueB); Serial.print(","); Serial.print(paramC); Serial.print(","); Serial.println(valueC); Serial.println(); }Не знаю, как остальным, а мне не нравится, что проверка буфера при асинхронном режиме приема производится с приличной паузой, а sscanf лупит прямо по указателю без контроля длины выделенного фрагмента. Да и вообще никаких проверок нет, в принципе - после 'X' может прилететь любая хрень на 79 байт, которая будет вгружена, как я понимаю, в двухбайтовый массив с известным нам всем результатом.