Алгоритм приема пакета по UART.ATmega16.IAR AVR.
Добавлено: Ср июн 08, 2011 10:12:15
Доброго времени суток уважаемые форумчане. В общем стоит задача безошибочно принимать каждые 30мс пакет данных (время передачи одного пакета = 0,1мс, байты идут друг за другом),
состоящий из 10 байт, по UART(115200 бит/с) и, в случае приема правильного пакета, ответить в обратном канале. Если не проходит несколько пакетов подряд, вывести флаг ошибки соединения,
при восстановлении связи, очистить флаг и продолжать прием в штатном режиме.
Ошибочным считается пакет в котором находится меньше байт, чем должно быть (10).
Написал кое-какой код, вроде даже работает, но по прошествии некоторого времени перестает распознавать ошибку соединения (не выставляет флаг). JTAG отладчика и возможности подключиться к
контроллеру по JTAG, к сожалению нет (ножки заняты).
расскажу как работает мой алгоритм.
в инициализации заводится таймер на 35мс в течение которого ожидается прием безошибочного пакета.
в основном цикле проверяется состояние этого таймера, если время прошло, таймер сбрасывается и инкрементируется счетчик ошибочных пакетов. Если пришел хотя бы один байт в прерывании
сбрасывается таймер 35мс (но продолжает считать), заводится таймер на 5мс, отлавливающий окончание пакета, считается кол-во пришедших байт. При получении последующих байт сбрасываются
оба таймера. При получении последнего байта, в прерывании сбрасывается и выключается таймер 5мс, поскольку пакет пришел и выставляется флаг прихода пакета. Если произошел таймаут 5мс или
выставлен флаг прихода пакета, таймер сбрасывается, приемник выключается. Проверяется кол-во пришедших байт, если оно не равно необходимому кол-ву байт, пакет игнорируется. Если кол-во
байт равно необходимому, пакет обрабатывается. Включается передатчик и передается байт обратно. (В прерывании по окончании передачи передатчик выключается) после обработки пакета кол-во
пришедших байт сбрасывается, приемник включается. Укажите ошибку в алгоритме, либо подскажите как правильно реализовать.
вот код прерывания по окончанию передачи
вот код прерывания по окончанию приема
вот код основного цикла
в общем жду помощи. повторяю вопрос: почему после некоторого времени работы алгоритм перестает определять ошибку соединения. (Flag.DownCommErr)
состоящий из 10 байт, по UART(115200 бит/с) и, в случае приема правильного пакета, ответить в обратном канале. Если не проходит несколько пакетов подряд, вывести флаг ошибки соединения,
при восстановлении связи, очистить флаг и продолжать прием в штатном режиме.
Ошибочным считается пакет в котором находится меньше байт, чем должно быть (10).
Написал кое-какой код, вроде даже работает, но по прошествии некоторого времени перестает распознавать ошибку соединения (не выставляет флаг). JTAG отладчика и возможности подключиться к
контроллеру по JTAG, к сожалению нет (ножки заняты).
расскажу как работает мой алгоритм.
в инициализации заводится таймер на 35мс в течение которого ожидается прием безошибочного пакета.
в основном цикле проверяется состояние этого таймера, если время прошло, таймер сбрасывается и инкрементируется счетчик ошибочных пакетов. Если пришел хотя бы один байт в прерывании
сбрасывается таймер 35мс (но продолжает считать), заводится таймер на 5мс, отлавливающий окончание пакета, считается кол-во пришедших байт. При получении последующих байт сбрасываются
оба таймера. При получении последнего байта, в прерывании сбрасывается и выключается таймер 5мс, поскольку пакет пришел и выставляется флаг прихода пакета. Если произошел таймаут 5мс или
выставлен флаг прихода пакета, таймер сбрасывается, приемник выключается. Проверяется кол-во пришедших байт, если оно не равно необходимому кол-ву байт, пакет игнорируется. Если кол-во
байт равно необходимому, пакет обрабатывается. Включается передатчик и передается байт обратно. (В прерывании по окончании передачи передатчик выключается) после обработки пакета кол-во
пришедших байт сбрасывается, приемник включается. Укажите ошибку в алгоритме, либо подскажите как правильно реализовать.
вот код прерывания по окончанию передачи
Код: Выделить всё
#pragma vector=USART_TXC_vect
__interrupt void TX_COMPLETE()
{
UCSRB&=~((1<<TXCIE)|(1<<TXEN)); // Запрет прерывания по окончании передачи|выключение передатчика
}Код: Выделить всё
#pragma vector=USART_RXC_vect
__interrupt void RX_COMPLETE()
{
v *var=&Variables; //указатель на глобальную структуру
var->PacketToutCnt=0; //обнуляем счетчик 5мс
var->LongToutCnt=0; //обнуляем счетчик 35мс
Flag.PacketTout=0; //очищаем флаг окончания таймаута 5мс
Flag.LongTout=0; //очищаем флаг окончания таймаута 35мс
var->WrongPacketCnt=0; //обнуляем кол-во неправильных пакетов
Flag.DownCommErr=0; //очищаем флаг ошибки соединения (down поскольку приемное устройство является подчиненным)
Flag.PacketToutEn=1; //"выключатель" таймаута 5мс (1-вкл, 0-выкл)
if(++var->BytesReceived<=BYTES_IN_PACKET) //проверка кол-ва пришедших байт (предв. инкремент)
{
if (UCSRA&((1<<FE)|(1<<DOR)|(1<<PE))) /*это я не стал описывать текстк, здесь проверяются биты ошибок приемника UART(FrameError,DataOverRun,ParityError)*/
var->ByteErrorFlags|=(1<<(var->BytesReceived-1)); //если есть ошибка, в переменной выставляется соответствующий бит
data.InputBuf[(var->BytesReceived-1)]=UDR; //входной буфер данных (массив InputBuf)
if (var->BytesReceived==BYTES_IN_PACKET) //если кол-во пришедших байт совпадает с кол-вом необходимых в пакете
{
Flag.PacketTout=1; //выставляем флаг окончания пакета
Flag.PacketToutEn=0; //выключаем таймер 5мс
var->PacketToutCnt=0; //сбрасываем таймер 5мс (его счетчик)
}
}
}Код: Выделить всё
__C_task void main(void)
{
...............//тут инициализация данных
UBRRH=(unsigned char)(CUR_UBRR>>8); //установка скорости UART
UBRRL=(unsigned char)(CUR_UBRR&0x00FF);
#ifdef DOUBLE_SPEED
UCSRA|=(1<<U2X);
#endif
UCSRC=(1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)|(1<<UPM1); // Выбор UCSRC регистра|Включение проверки четности|8-битная посылка
UCSRB=(1<<RXCIE)|(1<<RXEN); // Разрешение прерывания по приему|включение приемника
for (;;)
{
if(Flag.LongTout)
{
//в течение LongTimeout не пришло ни одного правильного пакета
Flag.LongToutEn=1; //включение таймаута 35мс (в обработчике этого таймера он автоматом выключается)
Flag.LongTout=0; //сброс флага таймаута 35мс
if(var->WrongPacketCnt<MAX_WRONG_PACKETS) //если кол-во неправильных пакетов еще не достигло макс значения
{
var->WrongPacketCnt++; //то инкрементируем значение
}
else
{
Flag.DownCommErr=1; //иначе выставляем флаг ошибки соединения
}
}
else //в случае если не было срабатывания таймера 35мс
{
if (Flag.PacketTout) //проверяем флаг таймаута 5мс (таймаут прихода правильного пакета)
{
UCSRB&=(~((1<<RXCIE)|(1<<RXEN))); //выключаем приемник
Flag.PacketTout=0; //очищаем флаг таймаута 5мс
var->LongToutCnt=0; //обнуляем счетчик таймаута 35мс
if(var->BytesReceived==BYTES_IN_PACKET) //если кол-во байт равно кол-ву необходимых байт
{
if(var->ByteErrorFlags!=0)//обработка переменной флагов ошибок байтов пакета
{
var->ByteErrorFlags=0; //если есть ошибки приема данных (Parity,Frame,OverRun) здесь можно их обработать (я их тупо сбрасываю)
}
else
{
........//здесь идет долгая обработка пакета данных (около 3мс)
UCSRB|=(1<<TXCIE)|(1<<TXEN);// Разрешение прерывания по окончании передачи|включение передатчика
UDR=var->TrData; // Передаем ответные данные (1 байт)
}
}
UCSRB|=(1<<RXCIE)|(1<<RXEN); // Разрешение прерывания по окончании приема|включение приемника
var->BytesReceived=0; //обнуление счетчика кол-ва пришедших байт в пакете
}
}
}
}