Официальный сайт компании Arduino по адресу arduino.cc
Проблема с чтением из SoftwareSerial
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Добрый день, уважаемые форумчане.
Занялся сборкой устройства для дистанционного управления обогревателем в гараже. Для реализации использую клон Arduino Nano на 168 микросхеме, связь обеспечивает модуль Neoway M590, далее нагрузкой управляет реле. Данные отправляю на сервер народного мониторинга, откуда отправляю и команду на включение или выключение нагревателя.
С контролем температуры реализовать передачу данных на narodmon труда не составило, в интернете полно примеров реализации. А вот с тем, чтобы встретить команду от сервера возникла проблема.
Для работы с модулем в него надо в определенной последовательности вбить последовательность строк для подготовки модуля для передачи данных по GPRS. Далее необходимо отправить данные для сервера, это тоже определенная последовательность, содержащая индивидуальный номер прибора, показания с датчиков и два символа завершения передачи ##. После чего с сервера мы получаем ОК, или команду управления вместо ОК.
Когда я вручную ввожу данные используя такую конструкцию в скетче:
void bypass(){ //передает ответы модема напрямую в serial if (gsm.available()) Serial.write(gsm.read()); if (Serial.available()) gsm.write(Serial.read()) }
То после того, как я передаю данные на сервер, то всегда получаю команду управления от сервера в виде:
+TCPRECV:0,Х#ИМЯ_КОМАНДЫ", где X - длина имени команды
Однако когда я записываю свои действия следующим образом:
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", однако когда я пишу if (gsm.find("+TCPRECV:0,7,#warm1")){ Serial.println("WARM1"); W1 = !W1;}, то ничего не происходит, как будто такая строка в порт не заходит.
Я пробовал укоротить проводник между модулем и ардуиной до 1см, не помогло. Пробовал вместо "+TCPRECV:0,7,#warm1" писать только первый элемент строки "+", в этом случае срабатывало, однако оно срабатывало даже если команду с народмона я не направлял. Пробовал уменьшать длину команды, пробовал изменять имя команды на числовое значение, не помогло.
Добрый день.
Спасибо за совет. Возможно вы подскажете как можно определить пришла в порт искомая строка или нет?
Самый простой способ - выводить все, что приходит, в консоль и там проверять глазками.
Вы невнимательно читали первое сообщение в теме.
Первое сообщение в теме читать внимательно опасно для здоровья глаз
Первое сообщение в теме читать внимательно опасно для здоровья глаз
Я понимаю что оформление следует поправить, но на этом форуме править сообщения нельзя, или я не нашел как это делать
Да, в общем-то, у меня нет такой обязанности внимательно читать все сообщения. Если бы Вы хотели, чтобы на что-то было обращено особое внимание, вполне можно было на этом акцентировать.
Также я не обязан помнить все темы с начала до последнего сообщения. Поэтому я могу отвечать буквально на заданный вопрос, не сверяясь с тем, что было написано ранее. А следить за темой - это уже обязанность ТС. В частности, формулировать новые вопросы так, чтобы они содержали достаточную информацию, не надеясь, что отвечающий вспомнит, что было в начале обсуждения.
Ну и еще одно замечание: IMHO 168 содержит слишком мало памяти, чтобы полноценно работать со строками. Поэтому было бы целесообразно сначала отладить весь скетч на Меге, и только потом пытаться упихать его в 168.
PS. И - да, требовать внимательного прочтения от так оформленного текста IMHO выходит за рамки разумного.
AKOTb - выложите код, во-первых, по правилам форума. Во-вторых - целиком. В нынешнем обрывке мне совершенно непонятно, откуда берется функция gsm.find(). gsm - это экземпляр класса SoftwareSerial, у которого, насколько мне известно, нет метода find()
ТС - и в принципе. Заставьте программу работать без сети, а уж потом добавьте сеть.
Проблему решил установив в конце строки передачи данных символ перевода каретки. Теперь возник вопрос оптимизации кода.
Для 168 микросхемы сообщение об объеме занимаемой скетчем программы выглядит так:
АКОТ, похоже вы не мастер отвечать на вопросы. Так откуда все-таки берется метод gsm.find() ?
А на тему оптимизации - начните с применения макроса F() - с вашими строчками должны выиграть байтов двести оперативки
Ну для экономии ОЗУ можно воспользоваться макросом F() к текстовым строкам.
АКОТ, похоже вы не мастер отвечать на вопросы. Так откуда все-таки берется метод gsm.find() ?
стандартный метод, я ничего не изобретал, вот у гайвера про него нашел информацию
https://alexgyver.ru/lessons/serial/
Serial.find(target), Serial.find(target, length)
за совет спасибо. Буду изучать
Ух как это круто!
126
if
((millis() - LT) > (TIME*60000))
127
{
128
gprssend();
129
LT = millis();
130
}
Здесь путаница с типами.
LT у вас зачем то float. После 60000 надо дописать UL т.е. 60000UL
LT у вас зачем то float. После 60000 надо дописать UL т.е. 60000UL
Спасибо, исправил.
Посоветуйте по примененной мною конструкции:
Мне кажется, что она не рациональная, когда я хочу найти строку "+TCPRECV:0,6,#ref1", то никогда её не нахожу, так как она стоит далеко. Я полагаю, что тут оптимальнее было бы записывать в строку то, что находится между +TCPRECV:0 и концом строки, и уже в дальнейшем работать с этим. Но как это записать не знаю пока. Можно конечно просто попробовать String = gsm.read(), ну туда может и пустая запись попасть. Буду думать.
Посоветуйте по примененной мною конструкции:
Мне кажется, что она не рациональная, когда я хочу найти строку "+TCPRECV:0,6,#ref1", то никогда её не нахожу, так как она стоит далеко.
Абсолютно верно вам кажется, использовать find таким образом нельзя. Эта функция ищет строку во входных данных Сериал, то есть читает приходящие в порт символы и сравнивает их со строкой в первом if(). Функция работает до тех пор, пока не найдет строку или данные в Сериал не кончатся. Только после этого программа перейдет к условию во втором if(), однако не будет искать вторую строчку в уже принятых данных, а будет ждать новых. Таким образом, если в Сериал приходит только одна строка из трех - строки во втором и последующих elseif() не будут найдены никогда.
да, в вашем случае правильнее СНАЧАЛА принять данные, сохранить куда-то, а уже потом в этих данных искать нужные строки. Символы "+TCPRECV:0", однаковые во всех строках - можно использовать как маркер для определения, что именно сохранять
Посоветуйте по примененной мною конструкции:
На днях здесь было обсуждение по похожей теме. http://arduino.ru/forum/programmirovanie/nuzhna-pomoshch-s-uart#comment-589960 Без изменений вам не подходит, но как пример посмотрите.
стандартный метод, я ничего не изобретал, вот у гайвера про него нашел информацию
https://alexgyver.ru/lessons/serial/
Serial.find(target), Serial.find(target, length)
Upd:
Посоветуйте по примененной мною конструкции:
Мне кажется, что она не рациональная, когда я хочу найти строку "+TCPRECV:0,6,#ref1", то никогда её не нахожу, так как она стоит далеко.
Всем спасибо, с Вашими советами удалось реализовать стабильную работу.
Написал следующую функцию, которую вызываю сразу после передачи данных с датчиков температуры
Благодаря такому способу реализации, я могу считать с отправленной команды данные, к примеру ранее я создавал команду ref1 чтобы обновление данных шло раз в 5 минут, а команду ref2 ,чтобы раз в 30 минут. Теперь же я реализовал чтение числа после ref, и стало гораздо удобнее. Также вызов нагревателя я организовал одним If, возможно это не имело смысла, ещё подумаю над этим.
Рассмотрел также ситуацию, когда вместо команды придёт абракадабра, программа нормально на это реагирует, и игнорирует такие запросы. Сейчас ещё реализую обратную связь, чтобы быть уверенным, что нагреватель включен/выключен, и думаю это победа.
Всем спасибо)
победой можно считать избавление от String (что еще более важно для атмеги 168) и неблокирующее чтение из Serial без delay и while
здесь более подходящая для ТС тема и код. Почитайте внимательно ту тему сначла
да макрос F() еще недоиспользован )
Макрос F как оказалось с операторами сравнения работает нестабильно. Через раз, а иногда и вовсе не срабатывает. Вынужденная мера убрать макросы Эф из while и if.
По вопросу избавления от string спасибо за совет. Как посетит вдохновение, обязательно займусь усовершенствованием кода. Тут другая задача появилась. В течении длительного теста что-то в связке ардуина+модем стало зависать. Вот думаю над организацией какого-то аналога watchdog'а. Хотя возможно стоит внимательнее почитать в мониторе порта, что там а это время происходит. Сложность в том что проблема вылезла пока что единожды, а плавающие ошибки ловить сложнее всего.
Нестабильно может работать программа. Но тогда - все вопросы к программисту.
Нестабильно? Возможно, вы имели ввиду, что макросы могут иметь скрытые эффекты?
Нестабильно может работать программа. Но тогда - все вопросы к программисту.
Безусловно моей компетенции в этом вопросе недостаточно, но по своим наблюдениям заметил, что при введении в скетч этой конструкции появляются проблемы, убрал, стало лучше.
Всю ночь тестировал на стабильность устройство, пока работает.
Нестабильно? Возможно, вы имели ввиду, что макросы могут иметь скрытые эффекты?
Да, я пока не набрал опыта в использовании этой новой для меня конструкции, но первое впечатление оказалось неоднозначным, памяти сэкономил здорово, но встретился с некоторыми особенностями
...но по своим наблюдениям заметил, что при введении в скетч этой конструкции появляются проблемы, убрал, стало лучше.
Почему-то начинающие программисты винят в неустойчивости работы программы что угодно: компилятор, макросы, библиотеки, но никогда не себя любимого.
Написал следующую функцию, которую вызываю сразу после передачи данных с датчиков температуры
К вопросу о стабильности. Замечания ниже возможно не критичны в вашем случае, но в общем случае могут пригодится.
strData лучше объявить внутри функции SSRead(). Тогда будет меньше вероятность утечки памяти. См. http://arduino.ru/forum/programmirovanie/etyudy-dlya-nachinayushchikh-pamyat-3-dinamicheskie-i-avtomaticheskie-peremen параграфы про String
При заполнении strData желательно ограничить (контролировать) ее длину.
дак задача может это вовсе и не другая. String-и любят пожирать ресурсы МК, особенно у начинающих юзеров, не умеющих эти трусы готовить. И уж тем более это актуально для атмеги 168. А когда заканчивается ОЗУ, чудеса бывают самые разные и естественно их сложно локализовать и отловить. Так что я не зря вам даже ссылку с примером дал. тот пример поправить под ваши нужды было не трудно, ну как хотите
Макс, вот тебе в копилку: есть такая штука для хранения строк, называется PROGMEM. И всякие к ней функции имеются в avr lib: https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html#ga... -очень полезные.
прогмем то я пользуюсь когда надо, но все равно пасиб, посмотрю
Спасибо, ребят! Вот реально приятно, когда людям не безразличен твой проект. Протестирую обновление, обязательно отпишусь!
типа так?