0 / 0 / 0
Регистрация: 08.01.2012
Сообщений: 151
|
|
1 | |
Передача и сортировка разнотипных данных по UART05.04.2015, 07:15. Показов 19232. Ответов 19
Метки нет (Все метки)
Всем привет. Возникла такая проблема за неопытностью, разрабатываю устройство на двух микроконтроллерах связываются между собой UART-RS232. Прочитал про кольцевой буфер, подключил библиотеки к обоим проектам, с этим всё понятно всё работает. А вот потом как разобраться где что в этом буфере я не пойму, т.е. я допустим передаю с одного МК на другой значение нескольких АЦП, цифрового датчика, и несколько дискретных значений (вкл/кыкл). Как потом понять где что? Все примеры что нашёл, на передачу одного значения. Заранее спасибо!
0
|
05.04.2015, 07:15 | |
Ответы с готовыми решениями:
19
передача разнотипных данных из Exel в Access передача разнотипных данных из Excel в Access Передача данных по UART Передача данных в мобилку по UART Передача данных по UART из stm на ПК |
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
05.04.2015, 07:25 | 2 |
делайте уникальный идентификатор начала пакета
0
|
0 / 0 / 0
Регистрация: 08.01.2012
Сообщений: 151
|
|
05.04.2015, 07:31 | 3 |
Сообщение от Hotd
0
|
0 / 0 / 0
Регистрация: 06.10.2013
Сообщений: 170
|
|
05.04.2015, 07:50 | 4 |
Да как угодно! По сути надо самому с собой договориться, как и на каком языке общаться.
Можно взять готовые протоколы обмена данными или свой изобрести. Базовая основа в любом протоколе будет стартовый маркер и (опционально) стоповый маркер. Маркер - это последовательность символов (байт), которые обязательно идут в каждой посылке. А дальше за этим маркером уже начинаем развлекаться - длина пакета, контрольная сумма, адрес источника/приемника, тип пакета.... В общем все что угодно! Остается только в кольцевом буфере дождаться стартовый маркер и попытаться разобрать пакет по своей принятой нотации. Что-то пошло не так - отрезать маркер и опять начать сначала отбрасывая все те символы, которые не являются этим самым стартовым маркером. Вот к примеру протокол общения с WiFi-модулем по UART: 1) Запрос к модулю 1.1) должен начинаться с символов "AT" 1.2) далее идут собственно команды и возможно ее параметры 1.3) запрос завершается символом \r 2) Ответ от модуля 2.1) начинается символами "\r\n" 2.2) символы "OK" - команда выполнена. Символы "ERROR" - ошибка выполнения команды 2.3) опциональная расшифровка ошибки 2.4) терминируется символами "\r\n" Вот уже исходя из этого формального описания можно рисовать алгоритм: Код
while( <длина буфера> > 0 ){ if( <первые 2 символа> == "\r\n" ){ // Маркер ответа. Начинаем проверку if( <2 последних байта> == "\r\n" ){ // Это точно ответ! Начинаем парсить его } else { // Либо что-то еще не пришло, либо это явная ошибка - не терминированный ответ. } } else { // Сдвинуть буфер на 1 символ влево. (Стереть 1-й байт) } }
0
|
Sptymtir
|
|
05.04.2015, 16:58 | 5 |
Не советую использовать маркерный метод определения начала пакета. При использовании маркера Вам требуется обеспечить уникальность этого маркера в пределах посылки, т.е. если в теле посылки у вас данные совпадут с маркером, то ваш алгоритм разобьет посылку на две - данные будут искажены. Так же не советуют использовать избыточные текстовые протоколы (типа АТ-команда). От кольцевого буфера толку мало, если только у Вас не высокозагруженный МК не успевающий обработать принятые посылки и Вам приходится хранить их в принятом буфере.
Лучше сделать так. Использовать пакетный принцип передачи данных. В простейшем случае пакет может содержать только полезные данные. Но лучше как минимум в конце пакета добавить CRC. Если требуется адресация устройств, то в начале пакета можно добавить адрес. Если данные разных пакетов имеют разный смысл, то нужно добавить поле типа данных или команды, можно также добавить сведения о длине пакета. Итого как то так: ADDR|LEN|CMD|DATA|CRC Такие пакеты удобно обрабатывать на си, т.к. по сути они уже являются структурой. И самое главное - как это принимать. Тут нет никаких маркеров, здесь передача ведется по таймаутам. Т.е. передающая сторона делает паузу перед передачей нового пакета. Длину этой паузы выбираете самостоятельно, обычно не менее времени необходимого для передачи нескольких байт на данной скорости. На приемной стороне выделяете буфер, размер которого равен максимально возможной длине пакета. По прерыванию складываете каждый принятый байт в этот буфер. После принятия первого байта заводите таймер на величину выбранного таймаута и каждый раз в прерывании от принятого байта сбрасываете этот таймер. После приема последнего байта пакета и истечению таймаута у Вас сработает прерывание от таймера. Попадание в это прерывание будет означать что пакет полностью принят - здесь вы его обрабатываете и очищаете приемный буфер. Плюс такого метода: минимальная избыточность (поле CRC обычно 2 байта, ADDR, LEN, CMD - по 1 байту), надежность (за счет использования CRC). Минус: обязательный таймаут в конце пакета - на множестве мелких пакетов реальная скорость в канале связи падает, но с ростом размера пакета этот минус практически исчезает. Для избавления от этого минуса можно ввести также маркер начала и конца пакета, но тогда как и раньше придется принять меры для того чтобы в пакете не появились символы равные маркеру. Яркий пример протоколов такого типа: SLIP. |
0 / 0 / 0
Регистрация: 12.08.2012
Сообщений: 1,217
|
|
05.04.2015, 17:52 | 6 |
Да не обязательно вырезать маркер из передаваемых данных.
Например: [маркер] [адрес] [длинна пакета] [данные] [контрольная сумма] Если пакеты фиксированной длинны то соответствующее поле выкидываем, также с адресом если не нужен. Алгоритм: 1. если буфер не пустой то вычитываем байт из буфера, если совпадает с маркером то п.2 иначе п.1 2. ждём пока в буфере не появятся адрес и длинна пакета, проверяем их корректность, если корректны то п.3, иначе п.1. 3. ждём пока буфер заполнится данными в соответствии с полем [длинна пакета] попутно вычисляя crc, если пакет принят полностью то п.4 4. сравниваем вычисленную crc с принятой, если не совпадает то п.1 иначе п.5. 5. в буфере у нас лежит корректный пакет, берём из него нужные данные, после чего перемещаем маркер начала буфера на следующий после crc байт, тем самым удаляем пакет из буфера, и переходим к п.1 Если внутри пакета будут данные совпадающие с маркером то на работу это никак не повлияет.
0
|
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
|
|
05.04.2015, 18:06 | 7 |
Как передаешь , в разнобой или всё что надо одной кучей?
0
|
0 / 0 / 0
Регистрация: 08.01.2012
Сообщений: 151
|
|
05.04.2015, 18:08 | 8 |
Сообщение от YTYOUT
0
|
Sptymtir
|
|
05.04.2015, 20:43 | 9 |
Сообщение от mShit
Собственно вывод: нужно либо исключить появление символов равных маркеру внутри пакета, либо производить замену таких символов по определенному алгоритму, либо не париться со всей этой ерундой и разделять пакеты по таймауту. Можно конечно стабилизировать и описанный алгоритм с маркерами и допустимым символом равным маркеру внутри пакета, но это будут те еще костыли и не факт что что-то не забудете предусмотреть. Например достаточно изменить пункт 4, переходя при ошибке CRC не к следующему байту в буфере, а к следующему байту после мнимого маркера. Но тогда буфер приема должен быть равен минимум двум максимальным длинам пакета. |
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
|
|
05.04.2015, 21:06 | 10 |
0
|
Sptymtir
|
|
05.04.2015, 21:07 | 11 |
Сообщение от ORV
Так как у вас RS232 то поле адрес Вам не нужно. Принимаете такую структуру пакета TYPE|DATA|CRC - если источник данных по своей инициативе асинхронно шлет данные Если данные запрашивает мастер: CMD|ARG|CRC - пакет запрос данных TYPE|DATA|CRC - пакет ответ с данными где: TYPE - условный тип данных (например, 0 - температура, 1 - давление.....) DATA - данные определенного типа (температура, давление....) CMD - команда запроса определенного типа данных (температуры, давления....) ARG - аргумент команды, если требуется, (например температура 2-го датчика) CRC - контрольная сумма Пакеты шлете с интервалом не менее например 3-х байт (для скорости 9600 бит/с примерно 3,5 мс). На приеме организуете буфер длиной равной максимальной длине пакета. Помещаете в него все принятые байты. По таймауту в 3 мс обрабатываете данные в буфере как пакет и очищаете буфер. В плане нагрузки на МК это работает очень быстро т.к. во время приема пакета МК по прерыванию только кладет принятый байт в буфер и инкриментирует указатель буфера. А признаком приема пакета является прерывание от таймера и тут мы быстренько обрабатываем принятый пакет. Т.е. до момента начала обработки пакета мы выполняем практически все аппаратно. |
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
|
|
05.04.2015, 21:29 | 12 |
А ещё лучше откажись от кольца. Сделай для каждого свой маленький буфер и передавай address+ data. Где адрес константа ( смещение ) для буфера приемника. Т.е АдресBUF + address ( полученный) +N (счетчик заполнения буфера от 0 до N)
0
|
1 / 1 / 0
Регистрация: 16.12.2016
|
|
06.04.2015, 05:01 | 13 |
Сообщение от mShit
https://ru.wikipedia.org/wiki/Modbus#.D ... 1.80.D1.8B Проще его реализовать, все-таки промышленный стандарт, на будущее будет возможность работать с промышленным оборудованием, а не тупиковый код.
0
|
0 / 0 / 0
Регистрация: 08.01.2012
Сообщений: 151
|
|
06.04.2015, 05:05 | 14 |
Сообщение от sym
0
|
1 / 1 / 0
Регистрация: 16.12.2016
|
|
06.04.2015, 06:13 | 15 |
Сообщение от Sptymtir
0
|
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
06.04.2015, 07:29 | 16 |
аналогично у себя используем допиленный модбас, передача по таймаутам. Оказалось удобно.
Сообщение от sym
Код
09:49:20-> 30 40 10 50 03 0C <- 30 40 10 50 01 00 01 65 09:49:24-> 30 40 10 59 C3 0A <- 30 40 10 59 01 00 D1 67 09:51:45-> 30 40 10 50 03 0C <- 30 40 10 50 01 00 01 65 09:51:49-> 30 40 10 59 C3 0A <- 30 40 10 59 01 00 D1 67 09:51:53-> 30 40 10 60 03 18 <- 30 40 10 60 08 00 00 00 03 A7 B8 00 00 94 CB 09:52:51-> 30 40 10 60 03 18 <- 30 40 10 60 08 00 00 00 03 A7 B8 00 00 94 CB 09:52:58-> 30 40 10 61 C2 D8 <- 30 40 10 61 08 00 00 00 03 A7 B7 A0 00 8D 0D
0
|
0 / 0 / 0
Регистрация: 08.01.2012
Сообщений: 151
|
|
06.04.2015, 11:32 | 17 |
Ну представление теперь есть в каком направлении двигаться, буду пробовать.
0
|
Sptymtir
|
|
06.04.2015, 12:00 | 18 |
Про ModBus правильно сказали. Лучше разобраться с ним и дальше использовать в своих проектах. Протокол очень простой, промышленный, стандартный. На его основе реализовано много проприентарных протоколов. Есть ASCII режим и бинарный (RTU). Есть и расширение для TCP.
Вот реализация под разное железо, в том числе под AVR. http://www.freemodbus.org/index.php?idx=5 Заводится легко и быстро, есть примеры. Здесь ModBus Tistir - отличный ModBus терминал для отладки http://www.agrostroy.ru/index.php?page=4 |
1 / 1 / 0
Регистрация: 16.12.2016
|
|
06.04.2015, 15:49 | 19 |
Сообщение от Sptymtir
http://www.lectussoft.com/opcserver.html Бесплатной версии как-раз хватит. Особо порадовал режми Modbus через TCP (не Modbus TCP), когда сервер шлет Modbus RTU/Asci данные через Ethernet на простой преобразователь Ethernet/RS232 или GPRS модем, работающий в прозрачном режиме, и далее на ваше устройство.
0
|
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
06.04.2015, 15:59 | 20 |
Для обычного RTU (по UART) использовали Modbus Poll.
0
|
06.04.2015, 15:59 | |
06.04.2015, 15:59 | |
Помогаю со студенческими работами здесь
20
Stm32 передача данных по UART Передача данных через UART посредством Python AVR, mega32, cvavr, uart, передача данных Передача данных c МК51 по UART и вывод в терминал Посимвольный передача данных по UART через прерывание PIC16F876 передача данных с arduino uno на компьютер по UART через с++ Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |