Форум программистов, компьютерный форум, киберфорум
Arduino
Войти
Регистрация
Восстановить пароль
 
2 / 2 / 0
Регистрация: 19.08.2016
Сообщений: 43
1

Проблема с чтением из SoftwareSerial

22.02.2021, 11:54. Просмотров 381. Ответов 4

Добрый день, коллеги!
Занялся сборкой устройства для дистанционного управления обогревателем в гараже. Для реализации использую клон Arduino Nano на 168 микросхеме, связь обеспечивает модуль Neoway M590, далее нагрузкой управляет реле. Данные отправляю на сервер народного мониторинга, откуда отправляю и команду на включение или выключение нагревателя.

С контролем температуры реализовать передачу данных на narodmon труда не составило, в интернете полно примеров реализации. А вот с тем, чтобы встретить команду от сервера возникла проблема.

Для работы с модулем в него надо в определенной последовательности вбить последовательность строк для подготовки модуля для передачи данных по GPRS. Далее необходимо отправить данные для сервера, это тоже определенная последовательность, содержащая индивидуальный номер прибора, показания с датчиков и два символа завершения передачи ##. После чего с сервера мы получаем ОК, или команду управления вместо ОК.

Когда я вручную ввожу данные используя такую конструкцию в скетче:
C++
1
2
3
4
5
6
void bypass(){  //передает ответы модема напрямую в serial
  if (gsm.available())
      Serial.write(gsm.read());
    if (Serial.available())
      gsm.write(Serial.read())
 }
То после того, как я передаю данные на сервер, то всегда получаю команду управления от сервера в виде:

+TCPRECV:0,Х#ИМЯ_КОМАНДЫ", где X - длина имени команды

Однако когда я записываю свои действия следующим образом:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <SoftwareSerial.h>
SoftwareSerial gsm(8, 7); // RX, TX
 
void gprssend(){
DHT11.read(DHT11PIN); // читаем данные с градусника
char val[61];
snprintf(val, sizeof(val), "#ХХХХХХХХХХХХХХХХ#akotb\n#H1DHT11#%d\n#T1DHT11#%d\n#V1VCC10#%d\n##",
DHT11.humidity, DHT11.temperature, 5);
gsm.println("AT+TCPCLOSE=0"); // закрываем соединение, на всякий случай
 
while(1){ // в цикле соединяемся с сервером народмон
gsm.println("AT+TCPSETUP=0,185.245.187.136,8283");
delay(2500);
if (gsm.find("+TCPSETUP:0,OK")) break; // если соединились, выходим из цикла
Serial.println("tcp_err");
// если нет, проверяем соединины ли с интернетом
gsm.flush();
gsm.println("at+xiic?");
delay(100);
if (gsm.find("0.0.0.0")){
gprsconnect(); // если нет, то подключаемся
delay(2000);
}
}
// отправляем 60 байт
gsm.println("at+tcpsend=0,60");
delay(100);
Serial.available();
gsm.println(val);
//delay(2500);
Serial.println("sendOK");
if (gsm.find("+TCPRECV:0,7,#warm1")){ Serial.println("WARM1"); W1 = !W1;}
else if (gsm.find("+TCPRECV:0,7,#warm2")){ Serial.println("WARM2"); W2 = !W2;}
else if (gsm.find("+TCPRECV:0,6,#ref1")) TIME = 5;
else if (gsm.find("+TCPRECV:0,6,#ref2")) TIME = 30;
}
digitalWrite(IN1, W1);
digitalWrite(IN2, W2);
Serial.println(TIME);
Serial.println(W1);
Serial.println(W2);
gsm.println("AT+TCPCLOSE=0"); // закрываем соединение
Serial.print("!!!");
}
То по какой-то причине ардуинка в упор не видит команды от сервера. К примеру при ручной передаче я четко вижу, что сервер передал "+TCPRECV:0,7,#warm1", однако когда я пишу
C++
1
if (gsm.find("+TCPRECV:0,7,#warm1")){ Serial.println("WARM1"); W1 = !W1;}
то ничего не происходит, как будто такая строка в порт не заходит.

Я пробовал укоротить проводник между модулем и ардуиной до 1см, не помогло. Пробовал вместо "+TCPRECV:0,7,#warm1" писать только первый элемент строки "+", в этом случае срабатывало, однако оно срабатывало даже если команду с народмона я не направлял. Пробовал уменьшать длину команды, пробовал изменять имя команды на числовое значение, не помогло.

Я совершенно не понимаю как это работает. Когда я делаю gsm.find, то я ищу в конкретной строке в конкретный момент времени или вообще во всем, что зашло в порт с момента его инициализации?

Если у кого есть идеи, почему ардуино может слепо игнорировать мои команды, прошу помочь, у меня идеи закончились.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
22.02.2021, 11:54
Ответы с готовыми решениями:

Проблема с чтением из com порта
Товарищи, здравствуйте! У меня какой то глюк на компе и не срабатывает сигнал readyRead(), когда...

Проблема с чтением строки
Добрый день, есть следующая строка (классическое определение системы координат, заданное в...

Проблема с чтением файла
При открытии файла функцией fopen и выводе на консоль отображается только первая строчка. Я так...

Проблема с чтением из файла!
Проблема такая: у меня есть текстовый файл, в котором на каждой новой строке написано число. Я хочу...

4
2720 / 1235 / 166
Регистрация: 28.10.2011
Сообщений: 4,571
Записей в блоге: 6
22.02.2021, 12:01 2
Цитата Сообщение от AKOTb Посмотреть сообщение
Я совершенно не понимаю как это работает.
Знаете что такое Software? Это программа. SoftwareSerial это программный uart.Чтобы прием стабильно работал нужно непрерывно выполнять if (Serial.available()) и как только условие выполнено сразу же прочитать gsm.read() При этом по желательно отключить все прерывания и не выполнять никакой другой код.
0
2 / 2 / 0
Регистрация: 19.08.2016
Сообщений: 43
22.02.2021, 12:30  [ТС] 3
locm, спасибо. Сейчас попробую. Поставить find в условие if available

Добавлено через 25 минут
Цитата Сообщение от locm Посмотреть сообщение
Знаете что такое Software? Это программа. SoftwareSerial это программный uart.Чтобы прием стабильно работал нужно непрерывно выполнять if (Serial.available()) и как только условие выполнено сразу же прочитать gsm.read() При этом по желательно отключить все прерывания и не выполнять никакой другой код.
Реализовал следующим образом:
C++
1
2
3
if (gsm.available()){
      if (gsm.find("+TCPRECV:0,6,#ref1")) TIME = 5; 
    }
Программа доходит до этого места, видит что программный uart занят и бежит дальше, попробовал заставить её там задержаться следующим образом:
C++
1
2
3
4
5
6
7
8
9
    while (!gsm.available()){    //ждём пока программный uart не освободится
      Serial.print(".");
    }
    if (gsm.available()){    // для полной уверенности что он все ещё свободен повторно проверяем это
      Serial.print("GSM_AVAILABLE");   //отправляем запись в консоль, чтобы понять что мы действительно сюда попадаем
      if (gsm.find("+TCPRECV:0,6,#ref1")){    // ищем команду, которая 100% пришла в порт (я проверял это)
        TIME = 5; 
      }
    }
После выполнения этой части кода в порт приходит запись:
GSM_AVAILABLE
Далее команда присвоения TIME = 5 не выполняется. значение переменной TIME остается 30.
То есть порт не занят, но при этом искомой строки в нём нет.
Может кто подскажет, как узнать, какая именно строка приходит в порт в текущий момент времени?
Я пробовал вставить сюда
C++
1
2
if (gsm.available())
      Serial.write(gsm.read());
Но он не отражает информации почему-то. Как будто в порт ничего и не приходит
0
2720 / 1235 / 166
Регистрация: 28.10.2011
Сообщений: 4,571
Записей в блоге: 6
22.02.2021, 13:14 4
Надеюсь delay убрали потому что если ответ придет во время паузы, он не будет получен.
0
2 / 2 / 0
Регистрация: 19.08.2016
Сообщений: 43
23.02.2021, 00:01  [ТС] 5
Цитата Сообщение от locm Посмотреть сообщение
Надеюсь delay убрали потому что если ответ придет во время паузы, он не будет получен.
Понимаю, delay закоменчен. На всякий случай сейчас убрал и вывод Serial.println("sendOK");, чтобы ничего не мешало поймать команду. Но он её не видит все равно. Причем конструкция gsm.find применяется мной в других местах кода, вот например:

C++
1
2
while(!gsm.find("+PBREADY")){             // при включении ждем отклик от модема        
    Serial.print(". ");
Самой первой командой от модема я получаю +PBREADY, и именно этого слова жду, чтобы понять что он включился.
Эта часть выполняется корректно, также вот тут:

C++
1
if (gsm.find("RING")) gprssend();
Если я позвоню на модем, то в порт передается строка "RING", и я запускаю процесс обмена данных с сервером, и это тоже работает корректно.

Мистика какая-то...

Добавлено через 1 час 21 минуту
Сейчас дополнительно решил зафиксировать как выглядит передача при ручном вводе команд.

После выполнения всех процедур по подключению и авторизации в сети я отправляю модему следующие команды:

AT+TCPSETUP=0,185.245.187.136,8283

после чего в мониторе порта вижу следующее

OK

+TCPSETUP:0,OK

далее команда: at+tcpsend=0,60, в мониторе появляется символ готовности принять строку:

OK

+TCPSETUP:0,OK

>

далее ввожу строку из 60 символов для отправки на народмон, в мониторе вижу следующее:
OK

+TCPSEND:0,60

+TCPRECV:0,6,#ref1


+TCPCLOSE:0,Link Closed


в ручном режиме все ок

Добавлено через 3 часа 34 минуты
Ох, ребята, это такая жесть, два дня потратил на очевидно простое решение...
Сейчас все протестирую до конца, и отпишусь как удалось решить.

Добавлено через 3 часа 6 минут
Имело дело сразу несколько факторов, которые в целом сильно затрудняли поиск проблемы.
Для начала я переписал функцию, для работы с командами програмvного uart напрямую:
C++
1
2
3
4
5
6
7
8
void bypass(){  //передает ответы модема напрямую в serial
  while(true) {
  if (gsm.available())
      Serial.write(gsm.read());
  if (Serial.available())
      gsm.write(Serial.read());
 }
}
Просто закольцевал функцию в бесконечном цикле, далее я вызвал её аккурат после передачи параметров на сервер народмон: gsm.println(val);

После чего я увидел, что программа ожидает от меня команды, как-будто строка не была передана.
В результате оказалось, что требовалось после строки передать символ перевода каретки, что я и сделал:

C++
1
2
3
4
5
gsm.println("at+tcpsend=0,60");
  delay(100); 
  gsm.println(val);  
  gsm.println("/n");
  delay(250);
После чего строки стали определяться, но когда я добавил одну строку к коду, то определяться они перестали снова.
Оказалось, что для 168 микросхемы объем памяти для глобальных переменных увеличился настолько, что она стала работать нестабильно (об этом сообщает Arduino IDE, но я не обращал на это внимания). Решил найти способ уменьшить программу и для начала во всех строках с конструкциями
C++
1
Serial.println(TEXT);
заменил текст на число, и это помогло. Как я выяснил по опыту, если объем глобальных переменных превышает 67%, то программа перестает работать, сейчас у меня :
Код
Скетч использует 7248 байт (50%) памяти устройства. Всего доступно 14336 байт.
Глобальные переменные используют 669 байт (65%) динамической памяти, оставляя 355 байт для локальных переменных. Максимум: 1024 байт.
Пробую применить макросы F() к текстовым строкам

Добавлено через 1 час 56 минут
Посоветуйте по примененной мною конструкции:

C++
1
2
3
if (gsm.find("+TCPRECV:0,7,#warm1")){Serial.println(F("WARM1")); W1 = !W1;}
else if (gsm.find("+TCPRECV:0,7,#warm2")){Serial.print(F("WARM2")); W2 = !W2;}
else if (gsm.find("+TCPRECV:0,6,#ref1")){Serial.print(F("TCPRCV_REF1")); TIME = 5;}
Мне кажется, что она не рациональная, когда я хочу найти строку "+TCPRECV:0,6,#ref1", то никогда её не нахожу, так как она стоит далеко. Я полагаю, что тут оптимальнее было бы записывать в строку то, что находится между +TCPRECV:0 и концом строки, и уже в дальнейшем работать с этим. Но как это записать не знаю пока. Можно конечно просто попробовать String = gsm.read(), ну туда может и пустая запись попасть. Буду думать.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
23.02.2021, 00:01

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Проблема с чтением файла
Всем здорова) Хочу написать код который читает xml и другие файлы на java Так почему он у меня не...

Проблема с чтением файла
не пойму, почему так работает var Reader, Writer : TFileStream; SizeofFile : Uint64; ...

Проблема с чтением из файла
Подскажите пожалуйста в чем ошибка? Чтения не происходит. Нули в массиве как были, так и остаются....

Проблема С Чтением Аттача
Здравствуйте. Необходимо сохранить аттач с почты. При чтении имени аттача получаю строку типа типа...

syslog проблема со чтением логов
Не мог бы кто-то подсказать, возможно ли прочитать логи syslog за прошедший период времени, и если...

Проблема с чтением двоичных файлов
Добрый день! Если быть точным, то проблема с обнаружением конца двоичного файла. Данные в файле...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.