Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Работа с обоими USART в ATMega64
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
UniBomb
Добрый день. У меня есть девайс на 64-ой меге, в которой задействованы оба усарта. Реализован протокол ModBus RTU (самолично).

По описанию протокола все посылки данных начинаются и оканчиваются интервалом времени, равное времени приёма 3,5 символов. Не мудрствуя лукаво я реализовал это условие в лоб - при приёме первого символа мк уходит в прерывание и не выходит из него до тех пор, пока не примет всю посылку. До недавнего времени использовался только один усарт и всё было хорошо. Но вот буквально вчера возникла необходимость использования и второго усарта. Естетсвенно вышеописанный подход неверен, т.к. из-за большой частоты посыла запроса и соответсвенно получения ответа два прерывания по приёму данных мешают друг другу. Т.е. если в данный момент уже идёт приём данных по первому усарту и в это время начали приходить данные на второй усарт, то часть посылки со второго усарта просто теряется. Такого быть недолжно.... Сократил об прерывания до самого минимума:

Код
uint8_t data_recv0[128];
uint8_t cur_data_recv0;
/*...*/
ISR(SIG_UART0_RECV)
{
  data_recv1[cur_usart1_recv] = UDR0;
  cur_data_recv++;
}


Но я никак немогу сообразить, как же в этом случае вести отсчёт времени, как отделять посылки друг от друга и вообще как определить конец посылки. Пробовал через таймер, но что то невыходит. Получается либо слишком большой промежуток времени, либо приходится делать период срабаотывания таймера настолько маленьким, что одна посылка разбивается на несколько.


Какие ещё есть решения? Кто как обходил эту ситуацию?

MrYuran
Цитата(UniBomb @ May 21 2009, 11:32) *
По описанию протокола все посылки данных начинаются и оканчиваются интервалом времени, равное времени приёма 3,5 символов. Не мудрствуя лукаво я реализовал это условие в лоб - при приёме первого символа мк уходит в прерывание и не выходит из него до тех пор, пока не примет всю посылку.

Посмотрите реализацию FreeModbus.(berlios.de)
По прерыванию от УАРТа байт просто кидается в буфер и обнуляется таймер таймаута (предварительно настроенный на 3,5 символа)
А вот по прерыванию таймера уже запускается первичная разборка пакета - CRC, адрес и т.д.
И вот если всё нормально (адрес соответствует, CRC в норме и т.д.), тогда выставляется флаг принятого пакета и функция ModPoll() в основном потоке анализирует пакет, запускает колбэк-функции и формирует ответ.

И вообще: ждать чего-то в прерывании - это не просто дурной тон, а ламерство в чистом виде.
В прерывании нужно делать самые неотложные вещи и выскакивать как можно скорее.
UniBomb
MrYuran, я думал так сделать, но у меня всего один свободный таймер остался. А с одним таймер на два усарта не очень то и получается...
MrYuran
Цитата(UniBomb @ May 21 2009, 11:56) *
MrYuran, я думал так сделать, но у меня всего один свободный таймер остался. А с одним таймер на два усарта не очень то и получается...

Наверняка есть "непрерывный" режим работы таймера, правда в АВР-ах таймеры вообще куцые и ублюдочные...
Таймер крутится по кругу, а в защёлках хранятся значения для разных событий. По прерыванию "передвигаете" значение в защёлке на дельтаТ и обрабатываете событие.
Сколько защёлок в таймере, столько разных событий можно на него повесить.
fantex
Алгоритм работы следующий:

Обработчику прерывания задается указатель на буфер приема и размер буфера.
С каждым принятым байтом указатель инкрементируестя, резмер буфера уменьшается.

В основном цикле программы проверяется изменение размера буфера. При каждом изменении запоминается время в миллисекундах. При отсутсвии изменений в течении заданного времени (3.5 символа) фиксируется окончание пакета, и дальше идет его обработка.
UniBomb
Да, насчёт таймера я был неправ... Сейчас попробую)))


зы: кстате, бонус вопрос. Если скорость обмена 38400Кбод/сек, то время приёма 3,5 символов будет (1/38400)*3,5 ?
fantex
В описании протокола Modbus написано, что при скоростях >= 19200 можно задать фиксированое время равное 1.75мс, то есть 1/19200*(кол-во бит в символе)*3.5
ReAl
Цитата(UniBomb @ May 21 2009, 10:56) *
MrYuran, я думал так сделать, но у меня всего один свободный таймер остался. А с одним таймер на два усарта не очень то и получается...

Так нужен не таймер, а output compare модули с на таймере с подходящей ценой кванта (чтобы 3,5символа были короче периода переполнения и длинее хотя бы десяти квантов, а это 6000 крат диапазон). Причём для разных UART это могут быть OCR на разных таймерах.
"Все таймеры заняты" у меня бывало, но пару свободных OCR в меге64 обычно оставалось.
_Pasha
Можно использовать пустые посылки (драйвер передатчика RS-485 выключен), в прерывании TXC считаете до 4-х.

Кстати, 3,5 символа это 3,5*(число бит в кадре)/(скорость)

Тут еще подумал - можно подпрячь на TxD прерывание по изменению уровня, или (не  в 64-й) PCNx. Тогда, выдавая при 11 битах значение 0xC0, получим более точный тайминг, почти нужные 0,5 символа. Надо запомнить.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.