Построчный парсинг и SerialEvent
- Войдите на сайт для отправки комментариев
Еще раз доброе время суток всем!
Решил вынести свою проблему описанную здесь в отдельную тему, т.к. понял что чем дальше в лес тем толще партизаны. Вобщем, третий код, который казалось бы хоть как-то удовлетворяет мою хотелку, тоже работает через раз - то выдает нормально, то какую-то абракадабру, потом опять нормально и т.д.
Решил использовать прерывания в виде serialEvent(). Посмотрев пример вот что у меня получилось:
#include <SoftwareSerial.h>
int sinhro = 0;
String bufer = "";
String string2 = "ADSL link down\n";
String stringOne = "ADSL2/ADSL2+ connection\n";
char* AT_command_string = "admin"; //логин и пароль
char* AT_command_string2 = "adsl info --show"; // команда
String inputString = "";
boolean stringComplete = false;
SoftwareSerial mySerial(10, 11); // RX, TX
void setup() {
Serial.begin(115200);
mySerial.begin(9600);
pinMode(8, INPUT_PULLUP);
}
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
// mySerial.println(inputString);
}
}
}
void loop() {
// read_serial();
if (digitalRead(8) == LOW) {
digitalWrite(13, HIGH);
sinhro = 1;
}
if (sinhro == 1) {
delay(1000);
Serial.write(0x0A); // переход на новую строку (в некоторых модемах можно не выполнять)
delay(2000); // ждем 2 сек.
Serial.write(AT_command_string);// отправляем логин
Serial.write(0x0A); // переход на новую строку
delay(2000); // ждем
Serial.write('\n');// отправляем пароль
// Serial.write(0x0A); // переход на новую строку
delay(2000); // ждем
Serial.flush(); // очищаем буфер
Serial.write(AT_command_string2); // отправляем команду
Serial.write(0x0A); // переход на новую строку
sinhro = 0;
if (stringComplete) {
mySerial.println(inputString);
// очищаем строку:
inputString = "";
stringComplete = false;
}
serialEvent();
}
}
Пока пытаюсь просто разобрать прилетающую от модема в Serial информацию по строкам и вывести все это в softSerial. Моделирую в Proteuse через подключенный к com-порту ПК модем.
При нажатии кнопки вижу в виртуальном терминале Протеуса информацию которую выдает модем, а вот в виртуальном терминале "подключенном" к softSerial в это время пусто. Нажимаю второй раз кнопку, вижу опять инфу от модема и ... о чудо в softSerial выводится информация, но ... полученная при предыдущем нажатии кнопки. Нажимаю третий раз и стуация опять повторяется - в softSerial почему-то приходит инфа полученная в результате предыдущего запроса. Причем может выдать как нормально так и какие-то обрывки или через раз - то есть, то пусто, потом опять нормальная (полная).
Помогите разобраться где я накосячил
Вы не задумывались, что с модема может прилетать '\n' не вконце строки, а в начале ?
Вы не задумывались, что с модема может прилетать '\n' не вконце строки, а в начале ?
я запретил думать
О, великий Клапауций, прости засранца , но я не знал о твоем запрете и случайно взял и подумал. Вот лог снятый в Putty и открытый в Notepad++ с отображением всех символов
каждая строка у тебя оканчивается двумя символами - '\r', '\n'
в каждой строке '\n' идет последним? Так ведь и в коде идет проверка
if (inChar == '\n') { stringComplete = true;}и если условие выполняется то считается что строка принята. А '\r' , если я правильно понимаю, просто дописывается к содержимому строки. Но пока не пойму как это влияет на описанные косяки?
После небольшого перерыва опять достал с полки свой скетч и поэксперементирорав переделал его в очередной раз
#include <SoftwareSerial.h> int i=0; int s=0; int sinhro = 0; String bufer = ""; String string2 = "ADSL link down\n"; String stringOne = "ADSL2/ADSL2+ connection\n"; char* AT_command_string = "admin"; //логин и пароль char* AT_command_string2 = "adsl info --show"; // команда String inputString = ""; boolean stringComplete = false; SoftwareSerial mySerial(10, 11); // RX, TX void setup() { Serial.begin(115200); mySerial.begin(9600); pinMode(13, OUTPUT); pinMode(8, INPUT_PULLUP); } void serialEvent() { while (Serial.available()) { // get the new byte: char inChar = (char)Serial.read();//delayMicroseconds(100); if (inChar == '\n') { i++; //считаем строки } if ((i>=15 && i<=16) || (i>=18 && i<=20) ||(i>=34&&i<=39)|| i==59) // пишем строки 13-20,34-39 и 59 { inputString += inChar; if (inChar == '\n') { stringComplete = true; } } } } void loop() { if (digitalRead(8) == LOW) { digitalWrite(13, HIGH); sinhro = 1; } if (sinhro == 1) { delay(1000); Serial.write(0x0A); // переход на новую строку (в некоторых модемах можно не выполнять) delay(2000); // ждем 2 сек. Serial.write(AT_command_string);// отправляем логин Serial.write(0x0A); // переход на новую строку delay(2000); // ждем секунду Serial.write('\n');// отправляем пароль // Serial.write(0x0A); // переход на новую строку delay(1000); // ждем секунду Serial.flush(); // очищаем буфер Serial.write(AT_command_string2); // отправляем команду Serial.write(0x0A); // переход на новую строку sinhro = 0; serialEvent(); if (stringComplete) { mySerial.println(inputString); mySerial.print("inputString length=");mySerial.println(inputString.length()); // очищаем строку: inputString = ""; stringComplete = false; i=0; while(Serial.available()) // очищаем буфер { delay(2); Serial.read(); } } } }Помогите все-таки разобраться почему
1. inputString выводится не построчно, а одной строкой. Вот результат вывода inputString.length()
2. Почему возникает задержка с выводом (такое впечатление что при первом нажатии кнопки инфа пишется в буфер, и только при втором нажатии считывается из него)
советую попробовать все это принять не софтверсериалом, а хардварным, и о результате собщите.
мне кажется софтвер и может косячить, то успевает то не успевает все принять.
и кстати скетч сколько памяти занимает? и поместится ли в буфер все, может банально не помещается?
А почему не использовать это?
if (Serial.available()) { String buffer; buffer = Serial.readString(); }А почему не использовать это?
if (Serial.available()) { String buffer; buffer = Serial.readString(); }кстати, еси бы кто подробно обьяснил недостатки такого способа вывоад инфы из стринг? с чем можно столкнуться?
Ребят, подскажите пожалуйста:
Будет ли работать функция SerialEvent с софтовым сериалом?
Аппаратный порт занят приемом данных с GPS, и использует эту (SerialEvent) функцию. А софтовым надо просто слушать другой порт и если придет команда (2 байта) = выполнить ряд действий (временно забив на данные с GPS) и все. Главное, не пропустить эту команду. Вот, думаю попробовать тоже использовать SerialEvent, для этой задачи.
Нет, не будет.
А софтовым надо просто слушать другой порт и если придет команда (2 байта) = выполнить ряд действий (временно забив на данные с GPS) и все.
а зачем обязательно SerialEvent ? - эта функция не делает ничего, что нельзя было бы сделать самому просто в loop()
Если вы принимаете данные с GPS постоянно, без перерывов - даже с функцией SerialEvent вы можете пропустить команду с другого Сериала, эта функция ничего не гарантирует
http://arduiniana.org/libraries/newsoftserial/
И нахрена эту какашку сюда притянул. А самому глянуть на то дерьмо что у них кодом зовется не? Просто людям советуем? Ну смотрим
void NewSoftSerial::write(uint8_t b) { if (_tx_delay == 0) return; uint8_t oldSREG = SREG; cli(); // turn off interrupts for a clean txmit // Write the start bit tx_pin_write(_inverse_logic ? HIGH : LOW); tunedDelay(_tx_delay + XMIT_START_ADJUSTMENT); // Write each of the 8 bits if (_inverse_logic) { for (byte mask = 0x01; mask; mask <<= 1) { if (b & mask) // choose bit tx_pin_write(LOW); // send 1 else tx_pin_write(HIGH); // send 0 tunedDelay(_tx_delay); }И шо? А вот шо. Пока идет write прерывания cli(); - запрещены, а значить прием данных не производится. И если на Rx в этот момент начнет поступать нечто то оно будет пропущено или искажено. Каким образом внешнее устройство должно заподозрить что именно сейчас такое произойдет и не передавать что либо во избежании потерь? Правильный софтсириал должен уметь принять переданное им же. Т.е соединяем у контроллера Tx и Rx и приняли то что отправили. Сразу скажу - это возможно, но то дерьмо что ардуине суют такое не умеет.
Спасибо!
Да, тоже пришел к таким мыслям. Программа Принимает пакеты с GPS, снимает показания с датчиков, обрабатывает их и выплевывает в сериал вместе с данными GPS. Долго пытался отладить, чтобы не было пропусков, но получилось. Именно SerialEvent помог и более высокие скорости ком-порта.
Для софтового сделаю отдельную функцию, по типу SerialEvent.
Да, тоже пришел к таким мыслям. .............
SerialEvent помог и более высокие скорости ком-порта.
Не знаю, кому вы тут пишете, что "пришли к тем же мыслям" - но я-то вам написал совсем обратное - не нужен вам SerialEvent от слова "совсем" Вы явно заблуждаетесь насчет того, как работает эта функция - похоже вы думаете, что она выполняется в бекграунде, независимо от основной программы. Это абсолютная чушь. Обычный Serial.available() , размещенный в loop() - делает то же самое.
Вы не там ищете решение ваших проблем. Главное, что может помочь не терять ничего от входящего потока - это избавится от всез задержек в основном цикле программы. А если у вас основной код сидит в процедурах и функциях сотни миллисекунд - никакой SerialEvent вам не поможет И кстати, "более высокие скорости компорта" - это абсолютно неверно, на самом деле если вы не успеваете с обработкой - скорость порта надо снижать, а не повышать, это ж очевидно....
не знаю советовать или нет, классика из интернетов на кружевных Стрингах
#include <SoftwareSerial.h> SoftwareSerial MODEM (10, 11); // RX, TX #define STRING_LENGTH 55 // максимальная длина строки (количество символов) от модема String currStr = ""; void readMODEM() { if (!MODEM.available()) return; char currSymb = MODEM.read(); static bool stringEnd = 0; // Serial.write(currSymb); // раскоментировать, если нужна отладка в Serial if ('\r' == currSymb || stringEnd == 1) // если строка принята - парсим её. { if (currStr.indexOf(F("YA MODEM")) > -1) {тут что-то делаем, если в строке от модема есть такой текст "YA MODEM"} currStr = ""; stringEnd = 0; } else if ('\n' != currSymb) currStr += String(currSymb); if (currStr.length()>STRING_LENGTH) stringEnd = 1; } void setup() { MODEM.begin (19200); Serial.begin (19200); } void loop() { readMODEM(); // тут остальная программа, без delay-ев }