Помогите разобраться с приемом по UART
- Войдите на сайт для отправки комментариев
Добрый день!
помогите пожалуйста разобраться с приемом данных по UART на Arduino Nano
суть такая - по UART идет прием данных (например с GPS, но его использую для примера), когда принимаем /CR, всю собранную в буфер ерунду передаем по радио (передача по радио занимает довольно много времени, секунд 10)
обработка (в немного обрезанном виде) выглядит вот так:
unsigned char track[654];
unsigned char serial_buffer[622];
void setup(){
Serial.begin(9600);
}
void loop(){
if (Read_UART(Serial.read(), serial_buffer, sizeof(serial_buffer)) >0) {
memcpy(track +31, serial_buffer, sizeof(serial_buffer)); //данные добавляем к заголовку пакета
radio(); //Функция передачи по радио
memset(serial_buffer,0,sizeof(serial_buffer));
}
}
int Read_UART(int source, unsigned char *buffer, unsigned int len)
{
static unsigned int pos = 0;
unsigned int rpos;
if (source > 0) {
switch (source) {
case '\n':
break;
case '\r':
rpos = pos;
pos = 0;
return rpos;
default:
if (pos < len-1) {
buffer[pos++] = source;
buffer[pos] = 0;
}
}
}
return -1;
}
Проблема вот в чем.
если я подцепляю usb-com и передаю данные на ардуинку вручную, то все отрабатывает хорошо, передается ровно та строка данных которую я туда и загоняю, завершая ее CR-ом.
но вот если прицепить модуль gps, которые генерирует строку $GPGGA вида:
$GPGGA,,,,,,0,00,99.99,,,,,,*48
каждую секунду (остальные строки выключены), то все начинает работать очень странно. Постоянно передается смесь из двух строк.
$GPGGA,,,,,,0,00,99$GPGGA,,,,,,0,00,99.99,,,,,,*48
по какой-то причине не обнаруживается завершение первой строки и в буфер попадает часть первой и вторая строки.
Подскажите пожалуйста почему такое может происходить? Может кто сталкивался или это очевидно, а я не понимаю?
Спасибо!
serial_buffer - это указатель на массив.
sizeof(serial_buffer) это размер указателя.
Объяви #define SIZE_OF_SERIAL_BUFFER 622 и используй его везде, в том числе и при объявлении самого массива.
сделал, но дело ведь не в этом..
я так понимаю что дело какраз в том, что передавая данные в UART вручную, буфер UART успевает и наполниться данными и опустошиться при чтении оттуда. А при передаче в UART с модуля GPS т.к. он отправляет туда строку каждую секунду, буфер захлебывается и отдельные строки "слипаются".
Но я всегда считал, что буфер UART кольцевой и я в любом случае наткнусь на CR и сформирую свою телеграмму.
а тут выходит, что CR кудато теряется, если GPS грузит в буфер постоянно, а считывание из него (в момент работы функции radio()) не происходит.
Подскажите пожалуста как можно решить это проблему?
Предлагаю подумать, что будет, если:
1. В момент вызова radio() во внутренний буфер UART будут поступать данные;
2. Что произойдёт, когда пойдут дальнейшие вызовы Read_UART.
Код - неправильный: во-первых, вы обнуляете содержимое массива неправильно. Во-вторых, поскольку вы отбрасываете \n - то по причине неправильного обнуления массива после первой отработки radio() вы получите слипшиеся две строки в буфере.
Вопросы?
Мне казалось, что в момент вызова radio(), поскольку буфер кольцевой новые данные будут как им и следует приходить в него.
а в момент очередного чтения из него, это чтение произойдет в некий произвольный момент, не обязательно попадающий на начало необходимой мне строки, массив будет заполняться снова.
memset-ом я записываю нули во все ячейки массива, и вроде в нем не должно оставаться ничего от предыдущей строки.
вы имеете ввиду что неправильно обнулять массив memset-ом?
честно говоря я пока не понял ошибку, не могли бы вы подсказать что неправильно в этом?
Поторопился я - с обнулением массива всё норм. Но проблему склеивания строк это не снимает, как понимаете. Попробуйте, во-первых, переместить memset выше radio(), и, во-вторых - проанализируйте, как ведёт себя переменная pos - чой-то подозрения у меня на неё :)
Убрал все до минимума, решил поиграться без лишних функций, оставив вместо radio() просто задержку.
#include <SoftwareSerial.h> #define RXD 2 #define TXD 3 SoftwareSerial soft_serial(RXD, TXD); unsigned char serial_buffer[200]; void setup(){ Serial.begin(9600); soft_serial.begin(9600); } void loop(){ if (Read_UART(soft_serial.read(), serial_buffer, 200) >0) { Serial.write(serial_buffer,200); Serial.println(); memset(serial_buffer,0,200); delay(1000); } } int Read_UART(int source, unsigned char *buffer, unsigned int len) { static unsigned int pos = 0; unsigned int rpos; if (source > 0) { switch (source) { case '\n': break; case '\r': rpos = pos; pos = 0; return rpos; default: if (pos < len-1) { buffer[pos++] = source; buffer[pos] = 0; } } } return -1; }И даже с задержкой в 1 секунду всеравно время от времени в выдаче проскакивали слипшиеся строки..
Проблема решается, если перед задержкой закрывать порт, а после нее опять открывать:
Или если опустошать буфер вот так:
for(;soft_serial.available();){soft_serial.read();}Но если честно, я всеравно не понимаю почему так происходит :(
Эммм. Смотрите, что увидел: if(Read_UART, когда вы возвращаете -1 - тоже true, т.к. всё, что отлично от нуля - интерпретируется булевой логикой как true. Ферштейн?
ферштейн то ферштейн, но Read_UART имеет тип integer, а условие if проверяется на >0...
ферштейн то ферштейн, но Read_UART имеет тип integer, а условие if проверяется на >0...
Млять, старею, не заметил > 0 :))
Короче, надо делать отладочный вывод в Serial, и смотреть, при каких условиях слипаются строки. В чудеса я не верю, значит, код работает не так, как надо. В таких случаях у меня всегда на подозрении статические локальные переменные - первым делом, так сказать.
Плюс - кмк, буфер может успеть протухнуть, т.к. читаем его не в цикле, пока available, а тупо побайтово, по байту за каждый вызов loop. Следовательно, если вновь поступившие данные успеют в кольцевом буфере затереть \r\n - получим слипшуюся строку.
Вывод: попробовать переписать код, читая Read_UART до тех пор, пока available().
Помогите и мне пожалуйста.
К ардуино uno будет подключено много много датчиков. Nodemcu будет эти датчики считывать по uart.
С чтением/записью в Ардуино мне помогли разобраться, спасибо.
http://arduino.ru/forum/programmirovanie/kak-sobrat-string-ot-com-porta#comment-293939
Для ардуино я написала следующий код:
//Device Address: 281398D70200005D //Device Address: 28FF57A3811603C0 #include <OneWire.h> #include <DallasTemperature.h> #define ONE_WIRE_BUS 2 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress Thermometer1 = {0x28, 0x13, 0x98, 0xD7, 0x02, 0x00, 0x00, 0x5D }; DeviceAddress Thermometer2 = {0x28, 0xFF, 0x57, 0xA3, 0x81, 0x16, 0x03, 0xC0 }; String inString; void setup() { sensors.begin(); sensors.setResolution(Thermometer1, 10); sensors.setResolution(Thermometer2, 10); Serial.begin(115200); } void printTemperature(DeviceAddress deviceAddress) { float tempC = sensors.getTempC(deviceAddress); Serial.println(tempC); } void loop() { while (Serial.available()) { char inChar = Serial.read(); inString += inChar; if (inChar == '#') { if (inString.indexOf("sensor1#")>0) { sensors.requestTemperatures(); Serial.print("Sensor1 "); printTemperature(Thermometer1); } else if (inString.indexOf("sensor2#")>0) { sensors.requestTemperatures(); Serial.print("Sensor2 "); printTemperature(Thermometer2); } else { Serial.println("Net komandy"); } inString=""; } } }Т.е. будут считываться два датчика температуры.
Теперь что качается Nodemcu
Т.е. отправить команду я умею.
Чтобы считать датчики нужно выполнить следующее:
print("sensor1#")
print("sensor2#")
Соответственно в ответ я получаю:
Sensor1 27.50
Sensor1 27.50
Почему данные такие? РАзбитые
pin=4 gpio.mode(pin, gpio.OUTPUT) tmr.alarm(0, 3000, 1, function() print("sensor2#") gpio.write(pin, gpio.HIGH) end ) uart.on("data", &, function(data) print("Text: "..data) gpio.write(pin, gpio.LOW) end, 0)Разобралась, добавила символ после которого получаю температуру
Скажите,
RX -D9
TX -D10
Есть ещё,
RXD2 -D7
TXD2 -D8
Как использовать вторые? Чтобы не мешать процессу заливки lua кода
Перелопатив форум вот что у меня получилось.
Ввожу в браузер адрес:
192.168.0.11/sensor1
Получаю:
Sensor1=25.33&
Всё как мне и надо
Далее ввожу 192.168.0.11/sensor2
А получаю Sensor1=25.33&
А если повторно нажать 192.168.0.11/sensor2
Тогда получаю то что надо Sensor2=26.00&
Почему мне нужно делать два запроса из браузера чтобы обновить текст
(в мониторе порта ардуино и ноде команды получаю как в запросе, так же ардуино отвечает правильно)
Код ардуино:
//Device Address: 281398D70200005D //Device Address: 28FF57A3811603C0 #include <OneWire.h> #include <DallasTemperature.h> #define ONE_WIRE_BUS 2 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress Thermometer1 = {0x28, 0x13, 0x98, 0xD7, 0x02, 0x00, 0x00, 0x5D }; DeviceAddress Thermometer2 = {0x28, 0xFF, 0x57, 0xA3, 0x81, 0x16, 0x03, 0xC0 }; String inString; String b; void setup() { sensors.begin(); sensors.setResolution(Thermometer1, 10); sensors.setResolution(Thermometer2, 10); Serial.begin(115200); } void printTemperature(DeviceAddress deviceAddress) { float tempC = sensors.getTempC(deviceAddress); b = String(tempC)+"&"; Serial.println(b); } void loop() { while (Serial.available()) { char inChar = Serial.read(); inString += inChar; if (inChar == '#') { if (inString.indexOf("sensor1#")>0) { sensors.requestTemperatures(); Serial.print("Sensor1="); printTemperature(Thermometer1); } else if (inString.indexOf("sensor2#")>0) { sensors.requestTemperatures(); Serial.print("Sensor2="); printTemperature(Thermometer2); } else { Serial.println("Net komandy&"); } inString=""; } } }Код ноде:
-- main.lua -- tmr.alarm(0, 1000, 1, function() if wifi.sta.getip() == nil then print("Connecting to AP...\n") else ip, nm, gw=wifi.sta.getip() print("IP Info: \nIP Address: ",ip) print("Netmask: ",nm) print("Gateway Addr: ",gw,'\n') tmr.stop(0) end end) otvet='pusto' -- a simple http server srv = net.createServer(net.TCP, 30) srv:listen(80,function(conn) conn:on("receive",function(conn,get) nac=string.find(get,"/"); uart.on("data",'&', function(data) otvet=data end, 0) function zapr() kon=string.find(get,"HTTP"); zap=string.sub(get, nac,kon-2); if zap == "/sensor1" then print("sensor1#") elseif zap== "/sensor2" then print("sensor2#") else otvet="error" end end if nac~=nil then zapr() end conn:send('HTTP/1.1 200 OK\n') conn:send('Access-Control-Allow-Origin:*\n\n') conn:send(otvet) conn:on("sent", function(conn) conn:close() end) end) end)