Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как грамотные люди делают прием пакетов по USART
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
TamTam
Ну написал с горем пополам обработку прирывания по окончанию приема байта, процедурку копирования из буфера в eeprom, но вот вопрос ???

Данные приходят всегда по разному иногда в нужной мне строке символ 0х0d и 0х0а встречаються несколько раз значит обработка пришедших данныш по окончанию строки мне не подходит, думаю так
после окончания приема запускать таймер и если за отведенное время не поступит следующий байт тогда начинать обработку данных а если данные еще идут то складываем их в еепром.

Правильно ли я мыслю или может есть способ по приличней, ведь таймер нужная и без этого весчь.
TamTam
Цитата(kertis @ Jun 5 2006, 05:48) *
не очень понял ваше изложение.

Может вам просто буфер создать и спокойно обрабатывать данные когда МК "свооден" ? Буфер нужного размера вам автоматически нарисует CVAVR и пример есть в задаче 5 запрещенного курса.


я конечно наченающий но немного соображаю,

Буфер у меня 32 байта а информации иной раз и все 200 приходит, поэтому в обработке прерывания по приему байта я делаю так

Код
interrupt [UART_RXC] void uart_rx_isr(void)
{
char status,data;
int i=2;
status=USR;
data=UDR;
if (data != 0x0A)
   {
      if (data != 0x0d)
         {
            if ((status & (FRAMING_ERROR | DATA_OVERRUN))==0)
               {
                  rx_buffer[rx_wr_index]=data;
                  if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
                  if (++rx_counter == RX_BUFFER_SIZE)
                     {
                        rx_counter=0;
                        rx_buffer_overflow=1;
                     };
               };
         }
   }      
   else;
   {
      while(rx_counter != 0x00)
      {
      i++;
      fraza[i]==ReceiveByte();
      }
   }
}


где fraza переменная в еепроме, но из затого что размер полезных данных может меняться от 4 до 190 байт мне както нужно организовать обработку этих данных, когда начать ??? данные могут идти с разной интенсивностью.
rat
Принимаемый поток организуете Вы же? Если так, то можно в сообщении передавать длину посылки, тогда и конец строки не понадобиться. Еще полезно передавать CRC, чтобы ошибки отлавливать.
TamTam
Цитата(rat @ Jun 5 2006, 06:36) *
Принимаемый поток организуете Вы же? Если так, то можно в сообщении передавать длительность посылки, тогда и конец строки не понадобиться. Еще полезно передавать CRC, чтобы ошибки отлавливать.


к сожалению не я.

Цитата(kertis @ Jun 5 2006, 06:40) *
Щас наверно более опытные товарищи подскажут, но я б сделал буфер на 200 символов во-первых.


Вы меня натолкнули на мысль что нужно добавить выгрузку и при переполнении буфера.
на 200 не могу поскольку 2313 столько не имеет.
haker_fox
Может быть эта ссылка Вам поможет?
TamTam
Цитата(haker_fox @ Jun 5 2006, 07:04) *
Может быть эта ссылка Вам поможет?


Да нет спасибо, протокол не я делаю, есть готовое устройство с которым надо общаться, а вейк я както давно под дельфи реализовывал.
beer_warrior
Идея правильная, вот пример кода который кочует из проекта в проект:

Код
struct {
        volatile    BYTE    mode;
        volatile    WORD  timeout;
        volatile    BYTE    errc;
        
        volatile    WORD    tx_cnt;
        volatile    WORD    tx_len;
        BYTE*               tx_buf;
        
        volatile    WORD    rx_cnt;
        volatile    WORD    rx_len;
        BYTE*                   rx_buf;
        } UCB; //UART control block

SIGNAL(SIG_UART_RECV)
{
//wdt_reset();
SET_RX_BUSY;

UCB.timeout = 0;
UCB.rx_buf[UCB.rx_cnt] = UDR;

if(hRxProc) hRxProc();

UCB.rx_cnt++;

if(UCB.rx_cnt >= UCB.rx_len)
    {
    CLR_RX_BUSY;
    if(hRxEnd) hRxEnd();    
    UCB.rx_cnt = 0;
    }
}


Здесь:
SET_RX_BUSY - установка флажка занятости UART (пакет в процессе приема)
hRxProc() вызов функции для анализа пришедшего байта проинициализиоравна как NULL
hRxEnd() вызов функции обработки заполненного буфера.
BYTE* tx_buf,rx_buf указатели на объявленные глобально буфера.

Теперь самое интересное- UCB.timeout. Один из таймеров умеющий работать в режиме CTC,
настроен на генерацию миллисекунд, в его прерывании ин(де)крементируются счетчики задержек,
счетчики секунд и UCB.timeout который проверяеться либо в основном контексте либо в hRxProc(),
смотря по протоколу.

И последнее не надо складывать данные сразу в EEPPROM - он не вечен.
WHALE
Судя по 0A,0D-это модем.Действительн,в eeprom зачем постоянно складывать-рано илипоздно откажет.
А если нужно энергозависимое с большим обьемом-можно 537ру10 с развязкой по питанию и cs на диодах,а в качесте резервного источника можно конденсатор или аккумулятор-потребление минимально и количество циклов записи неограниченно.
kertisДостал,зараза sad.gif
vet
Цитата(TamTam @ Jun 5 2006, 05:11) *
Ну написал с горем пополам обработку прирывания по окончанию приема байта, процедурку копирования из буфера в eeprom


В курсе, что ресурс EEPROM AVR - 100 тыс. записей?

Цитата(TamTam @ Jun 5 2006, 05:11) *
Правильно ли я мыслю или может есть способ по приличней, ведь таймер нужная и без этого весчь.


Трех стандартных AVR таймеров вполне хватит для чего угодно.
Nanobyte
Лучше применять не RAM со всеми его недостатками, а FRAM от Ramtron. Они теперь и с параллельным интерфейсом есть. При 3.3в питания число перезаписей неограничено (у них так написано в DS).
WHALE
а почем нынче fram ?
beer_warrior
Насколько я понял человек пишет во внутреннюю EEPROM, так-что FRAM в данном случае отдыхает. Я так понял речь идет о записии каких-то параметров или лога, 100 000 циклов за глаза хватит.Поэтому просто надо убедится, что да, данные заехали правильные, в полном объеме, а потом сбрасывать в EEPROM.
И еще один нюанс - писать, что во внешнюю, что во внутреннюю память надо вне прерывания - это же время.
Вот так вот выходит боком пресловутый "курс".
otrog
Цитата(WHALE @ Jun 5 2006, 11:56) *
а почем нынче fram ?

Пару месяцев назад FM24CL64-S мне привезли по 81.81р.
вообщем:
http://www.efind.ru/icsearch/?search=FM24
defunct
Цитата(kertis @ Jun 5 2006, 12:16) *
Да курс то причем тут ?

в запрещенном курсе на стр 03.htm ясно написано
...

На пачках сигарет тоже пишут "курение опасно для здоровья". Много вы встретили курильщиков, которые бросили курить из-за этой надписи?
TamTam
Цитата(WHALE @ Jun 5 2006, 09:44) *
Судя по 0A,0D-это модем.Действительн,в eeprom зачем постоянно складывать-рано илипоздно откажет.
А если нужно энергозависимое с большим обьемом-можно 537ру10 с развязкой по питанию и cs на диодах,а в качесте резервного источника можно конденсатор или аккумулятор-потребление минимально и количество циклов записи неограниченно.
kertisДостал,зараза sad.gif


Да имено модем. Почему именно eeprom ??? да только лиш по тому что ситуация при котором может что то появиться крайне редко может возникнуть, да и лучшебы ей вовсе не возникать, а то люди потеряют баксы, а баксы это для людей святое :-))))
vesago
Мне понравилось как у Атмела сделано. Я такую конструкцию не только для уарта применяю, но и вообще где надо стыковать асинхронные процессы. Также в примерах исходников prottos привел классный драйверок - аналог. На прием естественно надо таймаут ставить - после приема каждого байта заряжать таймер. Если нет данных в течение опеределенного времени - сбрасываем стэк. Кроме кольцевого буфера нужен буфер для сборки принимаемых пакетов и буфер для сборки отправляемых пакетов. А на будущее - haker_fox далл ссылку на прекрасный на мой субъективный взгляд протокол. Сам его повсеместно использую. Четко и стабильно работает. Програмная реализация тоже есть в исходниках.
TamTam
Цитата(vesago @ Jun 6 2006, 12:08) *
Мне понравилось как у Атмела сделано. Я такую конструкцию не только для уарта применяю, но и вообще где надо стыковать асинхронные процессы. Также в примерах исходников prottos привел классный драйверок - аналог. На прием естественно надо таймаут ставить - после приема каждого байта заряжать таймер. Если нет данных в течение опеределенного времени - сбрасываем стэк. Кроме кольцевого буфера нужен буфер для сборки принимаемых пакетов и буфер для сборки отправляемых пакетов. А на будущее - haker_fox далл ссылку на прекрасный на мой субъективный взгляд протокол. Сам его повсеместно использую. Четко и стабильно работает. Програмная реализация тоже есть в исходниках.


Да WAKE штука хорошая. Я его тоже однажды применял. но железо не моё было я токо под дельфю переписывал. Хотел библу с исходником выложить да так и потерял сурц а библа гдето лежит.
Sergiy
Да, обратите внимание на фразу, что в обработчиках прерывания должны быть краткие функции, и не в коем случае писать незя в ЕЕПРОМ, потому что процесс достаточно длителен (мс на байт), выставьте битовую переменную, что нужный пакет в буфере обмена и готовьте следующее окно (я использую двухоконные буфера), когда один заполняется, второй готов и константен для целевой функции - все довольны, а оперирую двумя битовыми флагами, один показывает, что новый буфер подготовлен и ожидает, а второй что какое окно надо пользовать в данный момент целевой функцией, первое может менять в активное состояние прерывание приемника, в пассивное возвращает целевая функция, а окна переключаются в инверсии, да два буфера хватит если есть простой в конце заполнения второго буфера и ждать пока не будет сброшен обработки первого буфера в целевой функции.

Когда позволяет выбрать протокол - выбор вообще делаю в пользу битовой синхронизации начала пакета, работает не просто железно, а супержелезно. По таймауту тоже применяю, когда надо минимальная длина пакета с простой упаковкой. Применять шапочную синхронизацию по голове и-или хвосту без таймаутной проверки не стал бы - рискуете потерять часть пакетов и рассинхронизироваться, когда в секторе данных будут шапки - поймете их за служебные - а это только данные на самом деле. Но когда нить конечно синхронизация будет восстановлено, но пакеты патеряны для вас. Можно синхронизировать тройками, когда в секторе данных есть синхросимволы, то повторять их подряд три раза, это знак что это данные. Но это немного увеличит трафик и распаковку пакетов. Да, при таймаутах учитывайте особенности программирования под винду. Обрамляйте процесс передачи пакета в Делфи или Билдере где вы там пишете в РиалТайм процесс, это делается парой строчкой на Делфи но значительно понижает вероятность ложного таймаута внутри пакета. Хотя шанс маленький все равно остается, иногда больший (на раком установленных операционках, высокоприоритетных задачах, выполняемых одновременно с вашим приложением - запись, форматирование дисков smile.gif.
TamTam
Цитата(Sergiy @ Jun 6 2006, 13:15) *
Да, обратите внимание на фразу, что в обработчиках прерывания должны быть краткие функции, и не в коем случае писать незя в ЕЕПРОМ, потому что процесс достаточно длителен (мс на байт), выставьте битовую переменную, что нужный пакет в буфере обмена и готовьте следующее окно (я использую двухоконные буфера), когда один заполняется, второй готов и константен для целевой функции - все довольны, а оперирую двумя битовыми флагами, один показывает, что новый буфер подготовлен и ожидает, а второй что какое окно надо пользовать в данный момент целевой функцией, первое может менять в активное состояние прерывание приемника, в пассивное возвращает целевая функция, а окна переключаются в инверсии, да два буфера хватит если есть простой в конце заполнения второго буфера и ждать пока не будет сброшен обработки первого буфера в целевой функции.


Советик дельный, а вот что делать с размерностью буферов, ведь как известно памяти в AT90S2313
всего 128 байт надеюсь 2Х32 мне хватит через глаза.
Sergiy
Цитата(TamTam @ Jun 6 2006, 11:38) *
Цитата(Sergiy @ Jun 6 2006, 13:15) *

Да, обратите внимание на фразу, что в обработчиках прерывания должны быть краткие функции, и не в коем случае писать незя в ЕЕПРОМ, потому что процесс достаточно длителен (мс на байт), выставьте битовую переменную, что нужный пакет в буфере обмена и готовьте следующее окно (я использую двухоконные буфера), когда один заполняется, второй готов и константен для целевой функции - все довольны, а оперирую двумя битовыми флагами, один показывает, что новый буфер подготовлен и ожидает, а второй что какое окно надо пользовать в данный момент целевой функцией, первое может менять в активное состояние прерывание приемника, в пассивное возвращает целевая функция, а окна переключаются в инверсии, да два буфера хватит если есть простой в конце заполнения второго буфера и ждать пока не будет сброшен обработки первого буфера в целевой функции.


Советик дельный, а вот что делать с размерностью буферов, ведь как известно памяти в AT90S2313
всего 128 байт надеюсь 2Х32 мне хватит через глаза.


Вообще все просто - надо брать размер буфера не менее чем максимальная длина пакета (он у вас наверное переменно
Sergiy
Цитата(TamTam @ Jun 6 2006, 11:38) *
Цитата(Sergiy @ Jun 6 2006, 13:15) *

Да, обратите внимание на фразу, что в обработчиках прерывания должны быть краткие функции, и не в коем случае писать незя в ЕЕПРОМ, потому что процесс достаточно длителен (мс на байт), выставьте битовую переменную, что нужный пакет в буфере обмена и готовьте следующее окно (я использую двухоконные буфера), когда один заполняется, второй готов и константен для целевой функции - все довольны, а оперирую двумя битовыми флагами, один показывает, что новый буфер подготовлен и ожидает, а второй что какое окно надо пользовать в данный момент целевой функцией, первое может менять в активное состояние прерывание приемника, в пассивное возвращает целевая функция, а окна переключаются в инверсии, да два буфера хватит если есть простой в конце заполнения второго буфера и ждать пока не будет сброшен обработки первого буфера в целевой функции.


Советик дельный, а вот что делать с размерностью буферов, ведь как известно памяти в AT90S2313
всего 128 байт надеюсь 2Х32 мне хватит через глаза.


Вообще все просто - надо брать размер буфера не менее чем максимальная длина пакета (он у вас наверное переменной длины - выберите максимальный вариант) - если же пакет больше, то такая буферизация вам не подходит. Странный выбор контроллера на 2006 год, надеюсь что выбор продиктован только тем, что у вас есть какая то готовая плата пятилетней давности, и вы ее хотите использовать. Потому что щас можно дешевле купить то, что получше, например Атмега8 - стоит в Украине чуть больше евро - интересно сколько стоит ваш кристалл.

Так вот если все таки максимально длинная команда больше размера того, что вы ей можете предложить, то замедляйте обмен (скорость, интервалы между байтами в одном пакете), используйте буферизацию, но выполнение выгрузки из буфера прийдется начинать тогда, когда вы не дошли до конца пакета. В основном цикле сканируйте флаг наличия нового байта в буфере (буфер должен быть кольцевой), если есть - делайте выемку байта - сдвиг указателя кольцевого буфера на -1 и запись в ЕЕПРОМ, и так постоянно. Выбор невелик. Пример реализации кольцевого буфера на cvavr:

#define RX_BUFFER_SIZE1 32 //size of rx buffer

unsigned char rx_buffer[RX_BUFFER_SIZE1+1];
register unsigned char rxr_pntr=0, rxw_pntr = 0;


// UART Receiver interrupt service routine
//--------------------------------------------------------------------------
// Procedure of RXD interrupt processing
//--------------------------------------------------------------------------
interrupt [USART_RXC] void uart_rx_isr(void)
{
unsigned char temp_byte;

temp_byte=UDR;
rx_buffer[rxw_pntr]=temp_byte;
if (rxw_pntr < RX_BUFFER_SIZE1-1)
rxw_pntr++;
else rxw_pntr=0;
}

//--------------------------------------------------------------------------
// Extract a byte from rx-buffer if buffer isn't empty
//--------------------------------------------------------------------------
void check_rx_buffer()
{
unsigned char current_byte_from_buffer;

if (rxr_pntr != rxw_pntr)
{
#asm("cli");
current_byte_from_buffer=rx_buffer[rxr_pntr];
if (rxr_pntr < RX_BUFFER_SIZE1-1)
rxr_pntr++;
else rxr_pntr=0;
#asm("sei");
rx_buffer_processor(current_byte_from_buffer); <- ваша целевая функция над текущем байтом
}
}


Удачи
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.