С Новым годом! Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.82/93: Рейтинг темы: голосов - 93, средняя оценка - 4.82
0 / 0 / 0
Регистрация: 08.01.2012
Сообщений: 151
1

Передача и сортировка разнотипных данных по UART

05.04.2015, 07:15. Показов 19232. Ответов 19
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем привет. Возникла такая проблема за неопытностью, разрабатываю устройство на двух микроконтроллерах связываются между собой UART-RS232. Прочитал про кольцевой буфер, подключил библиотеки к обоим проектам, с этим всё понятно всё работает. А вот потом как разобраться где что в этом буфере я не пойму, т.е. я допустим передаю с одного МК на другой значение нескольких АЦП, цифрового датчика, и несколько дискретных значений (вкл/кыкл). Как потом понять где что? Все примеры что нашёл, на передачу одного значения. Заранее спасибо!
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
05.04.2015, 07:15
Ответы с готовыми решениями:

передача разнотипных данных из Exel в Access
Здравствуйте! помогите мне, пожалуйста! Имеется таблица в EXEL с разными типами данных. Данные...

передача разнотипных данных из Excel в Access
Здравствуйте! помогите мне, пожалуйста! Имеется таблица в EXEL с разными типами данных. Данные...

Передача данных по UART
Здравствуйте, форумчане! Не могу понять, почему при передаче числа в hex по UART на контроллер...

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

Передача данных по UART из stm на ПК
Здравствуйте, имеется задача передачи данных от stm32 на ПК и от ПК в stm по UART. Имеется...

19
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
делайте уникальный идентификатор начала пакета
Т.е. например передаю температуру: "t" "значение температуры" "$", гду t и $ начала и конец пакета соответственно?
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
Да не обязательно вырезать маркер из передаваемых данных.
...
Алгоритм:
1. если буфер не пустой то вычитываем байт из буфера, если совпадает с маркером то п.2 иначе п.1
2. ждём пока в буфере не появятся адрес и длинна пакета, проверяем их корректность, если корректны то п.3, иначе п.1.
3. ждём пока буфер заполнится данными в соответствии с полем [длинна пакета] попутно вычисляя crc, если пакет принят полностью то п.4
4. сравниваем вычисленную crc с принятой, если не совпадает то п.1 иначе п.5.
5. в буфере у нас лежит корректный пакет, берём из него нужные данные, после чего перемещаем маркер начала буфера на следующий после crc байт, тем самым удаляем пакет из буфера, и переходим к п.1
Если внутри пакета будут данные совпадающие с маркером то на работу это никак не повлияет.
Если Вы работаете с буфером приема в произвольный момент времени (когда МК освободился от основной программы и решил поработать с буфером UART), то может произойти переполнение буфера. Для кольцевого буфера при этом затрется часть от одного или нескольких первых помещенных в буфер пакетов. Тоже самое может произойти в случае неполного/искаженного пакета. Допустим в первом искаженном пакете (начало которого было затерто) присутствует символ равный маркеру, тогда мы считаем что следующим идет адрес и далее длина пакета. По этой мнимой длине пакета мы нарезаем пакет и считаем его CRC и сравниваем его с мнимым CRC - они естественно не совпадают. Отбрасываем пакет как искаженный. И фиг бы с ним он итак искажен т.к. часть его была затерта. Но если значение мнимой длины кадра позволило нам залезть на следующий пакет, то мы съели у него кусок. Т.о. следующий валидный маркер будет только у третьего пакета и то если в остатках второго пакета не попадется символ равный маркеру, а в этом случае все повторится по кругу. Т.о. время синхронизации указателя на начало реального пакета в буфере не детерминировано, т.е. фиг знает сколько пакетов Вы потеряете пока не найдете реальный маркер. А если поле длины двухбайтное и на мнимую длину выпало значение 0xffff - сидите и ждите 64 кБ данных :) Понятно конечно что Вы заранее знаете максимальную длину пакета и посчитаете такую длину ошибочной. В этот момент Вам уже нужно изменить алгоритм и не ждать конца пакета а искать следующий маркер. Но если мнимая длина пакета меньше максимально допустимой, а поток по UART иссяк, а вам еще не хватает по мнимой длине еще несколько символов, то Вам все равно придется вводить таймаут поступления данных или будете сидеть ждать вечно.
Собственно вывод: нужно либо исключить появление символов равных маркеру внутри пакета, либо производить замену таких символов по определенному алгоритму, либо не париться со всей этой ерундой и разделять пакеты по таймауту.
Можно конечно стабилизировать и описанный алгоритм с маркерами и допустимым символом равным маркеру внутри пакета, но это будут те еще костыли и не факт что что-то не забудете предусмотреть. Например достаточно изменить пункт 4, переходя при ошибке CRC не к следующему байту в буфере, а к следующему байту после мнимого маркера. Но тогда буфер приема должен быть равен минимум двум максимальным длинам пакета.
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
05.04.2015, 21:06 10
В разнобой
Да , это хреново. Как не крути , а идентификатор нужен. ( HOLD) Все остальные преамбулы (описанные выше) , нужны для помехозащиты не более. Если у Вас процы в пределах стандартного кабеля RS232 , то идентификатор самое милое дело. Обозначьте например ADC1 = 0хA1 ADC2=0xA2 - это идентификаторы - В буфере всегда будут расположены по чётным адресам , если старт адреса буфера привязан к 0. (0х100, 0х110 ...) Все нечётные это данные/ Посылка 2 байта .
0
Sptymtir
05.04.2015, 21:07 11
Цитата Сообщение от ORV
Цитата Сообщение от YTYOUT
Как передаешь , в разнобой или всё что надо одной кучей?
В разнобой
Так как у вас 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
Да не обязательно вырезать маркер из передаваемых данных.
Например: [маркер] [адрес] [длинна пакета] [данные] [контрольная сумма]
Это вы описали протокол Modbus 1979 года выпуска. Маркер есть в Modbus asci.

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
Плюс такого метода: минимальная избыточность (поле CRC обычно 2 байта, ADDR, LEN, CMD - по 1 байту), надежность (за счет использования CRC). Минус: обязательный таймаут в конце пакета - на множестве мелких пакетов реальная скорость в канале связи падает, но с ростом размера пакета этот минус практически исчезает
Еще минус - нечитаемые логи, если нужно проанализировать диалог, придется писать и задержки, что усложняет программу, стандартные логгеры не подойдут.
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
Здесь ModBus Tistir - отличный ModBus терминал для отладки
http://www.agrostroy.ru/index.php?page=4
Для отладки использую Лектус, первое что было под рукой
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
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
06.04.2015, 15:59
Помогаю со студенческими работами здесь

Stm32 передача данных по UART
Здравствуйте, начинаю разбираться с библиотекой HAL. МК Stm32f407ig, IDE SW4STM32 Создала в кубе...

Передача данных через UART посредством Python
Программа должна передавать число от 00 до FF, но получается передавать только коды символов....

AVR, mega32, cvavr, uart, передача данных
Добрый вечер, господа. Имею вопрос к вам. Накидал uart на меге, и все вроде бы работает, но мк...

Передача данных c МК51 по UART и вывод в терминал
Нужно передать 2-х байтовое число через UART по каналу RS-485 на терминал.

Посимвольный передача данных по UART через прерывание PIC16F876
Добрый время суток, я новичок в программирование на мк в семейсте PIC. Установил и настроил MPLAB X...

передача данных с arduino uno на компьютер по UART через с++
Приветствую всех. Стоит следующая задача. На с++ разработать программу которая принимает данные с...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru