Страница 1 из 1
UART прием пачки(посылки) WinAVR C
Добавлено: Чт ноя 11, 2010 11:04:04
Ярослав
Доброго времени суток.
Помогите решить задачу.
Исходные данные: ATmega32, UART (19200 бод), PC, WinAVR, C
Требуется принимать посылки вида
(начало посылки (буква B))
(переменные, по одному байту - нное количество)
(конец посылки (буква E))
Т.е. если принятый символ является началом посылки, то следующие скажем 8 переменных я принимаю циклом, и если конец посылки является самим собой - то завершаю прием и выполняю одно действие.
Проблема в том, что я не понимаю как это сделать адекватно и быстро, к томуже надо ждать (как мне объяснили) готов ли УАРТ.
Код: Выделить всё
unsigned char usart_rx (void) {
while ( !(UCSRA & (1<<7)) ); //ждём очистки регистра данных USART
return UDR; //читаем данные
}
void Accept (void) { //Принятие посылки
u08 i;
if (usart_rx == 'B' )
{
for (i=1;i<8;i++)
{
Servo[i].Position = usart_rx;
}
if (usart_rx == 'E' )
{
Servo_sort();
Servo_upd();
}
}
}
Помогите пожалуйста, кто чем может =)
ЗЫ Еще может быть проблемой в решении быстрого приема - на базе таймера Т0 работает ШИМ с периодом 50Гц и 255 градациями, на 8 каналов. Т.е. пректически постоянно МК на что-то прерывается. Как тут быть?
Re: UART прием пачки(посылки) WinAVR C
Добавлено: Чт ноя 11, 2010 12:02:33
Liv
А почему нельзя использовать прерывание по приему байта UART?
Re: UART прием пачки(посылки) WinAVR C
Добавлено: Чт ноя 11, 2010 18:53:58
Ярослав
А ведь надо принять минимум 10 байт. Всё в одно прерывание - или как?
Re: UART прием пачки(посылки) WinAVR C
Добавлено: Чт ноя 11, 2010 19:14:58
Rimsky
Все зависит от тактовой частоты МК и распределением ресурсов, если есть возможность во время приема байт ничего не делать, только следить за флажками юарта, то тогда можно обойтись и без прерываний. А лучше сделать так: завести буфер байт на 16, назначить программные флаги и инициализировать прерывания (там уже и забивать буфер). Далее по мере надбности щупать флажек, прилетела или нет команда в буфер. прилетела, считали, инициализировали все и опять по кругу
Re: UART прием пачки(посылки) WinAVR C
Добавлено: Чт ноя 11, 2010 19:46:08
lix
Servo
.Position = usart_rx; не правильно, правильно usart_rx();
я бы сделал так
Код: Выделить всё
#define SERVO_NUM 8
volatile unsigned char servo_pwm[SERVO_NUM];
main()
{
...
while(1)
{
// важно чтобы главный цикл выполнялся быстро, иначе будут потери чтения из usart
// можно перевести на прерывания с кольцевыми буферами
if(UCSRA&_BV(RXC))
{
//есть данные в usart
usart_data = UDR;
switch(state) // автомат с 2 состояниями
{
case 0: // принимаем коды команд
switch(usart_data)
{
case 'E': Servo_add_upd(); break; // конец посылки, обновление серв
case 'B': state = 1; break; // переход в другое состояние, будем принимать параментры команды B
}
break;
case 1: // обработка параметров команды B
servo_pwm[curr_pwm++] = usart_data; // кладем в массив аргумент команды
if(curr_pwm == SERVO_NUM) // повторять будем, сколько у нас серв
{
curr_pwm = 0; // обнуление счетчика, для следующего раза
state = 0; // будем ожидать команды
}
break;
}
}
... //тут остальной код главного цикла
}
}
вот как-то так. можно легко добавить новые команды.
Re: UART прием пачки(посылки) WinAVR C
Добавлено: Чт ноя 11, 2010 23:22:45
Ярослав
Сделал вот так
Код: Выделить всё
void Accept (void) { //Принятие посылки
unsigned char curr_serv,usart_data,state;
state=0; curr_serv=0;
if(UCSRA&_BV(RXC)) { //есть данные в usart
usart_data = UDR;
switch(state) { // автомат с 2 состояниями
case 0: // принимаем коды команд
switch(usart_data)
{
case 'E': Servo_sort(); Servo_upd(); break; // конец посылки, обновление серв
case 'B': state = 1; break; // переход в другое состояние, будем принимать параментры команды B
}
break;
case 1: // обработка параметров команды B
Servo[curr_serv].Position = usart_data; // кладем в массив аргумент команды
curr_serv++;
if(curr_serv == 8) // повторять будем, сколько у нас серв
{
curr_serv = 0; // обнуление счетчика, для следующего раза
state = 0; // будем ожидать команды
}
break;
}
}}
В железе не работает, дебаггер доходит до проверки наличия чего-то в UDR - прыгает к первому switch и начинает все сначала =(
ЗЫ Извините за кодировку комментов. Но там ничего нового.
ЗЫЫ Частота МК 12МГц , бодрейт поднял до 38400
ЗЫЫЫ Спасибо за совет по кодировке!
Re: UART прием пачки(посылки) WinAVR C
Добавлено: Пт ноя 12, 2010 00:36:58
Goodefine
Чтобы кодировка была нормальной, перед копированием меняйте раскладку клавиатуры на русскую...
Re: UART прием пачки(посылки) WinAVR C
Добавлено: Пт ноя 12, 2010 10:06:10
lix
если код вынести в отдельную функцию, то переменные state и curr_serv должны быть static. функцию accept нужно постоянно вызывать (чем чаще, тем меньше вероятность потерять какой-нибуть символ из usart). можешь весь код выложить?
Re: UART прием пачки(посылки) WinAVR C
Добавлено: Пт ноя 12, 2010 10:57:44
Ярослав
УРа! Заработало! Всем СПАСИБО!
Вот код этого участка. Функция - она и только она вызывается в главном цикле.
Весь код смысла не несет особого(там сама работа серв на таймере, немного для ЖКИ, ну и ...пока всё., мега32 - но это отладочная плата.)
Еще есть мелкие проблемы по настройке уже самого ШИМ и проблема с реакцией в 60% заполнения на команду в 0hFF (т.е. практически единица). Но с этим я справлюсь сам.
Код: Выделить всё
void Accept (void) { //Принятие посылки
static unsigned char curr_serv,usart_data,state;
if(UCSRA&_BV(RXC)) { //есть данные в usart
usart_data = UDR;
switch(state) { // автомат с 2 состояниями
case 0: // принимаем коды команд
switch(usart_data)
{
case 'E': Servo_sort(); Servo_upd(); break; // конец посылки, обновление серв
case 'B': state = 1; break; // переход в другое состояние, будем принимать параментры команды B
}
break;
case 1: // обработка параметров команды B
Servo[curr_serv].Position = usart_data; // кладем в массив аргумент команды
curr_serv++;
if(curr_serv == 8) // повторять будем, сколько у нас серв
{
curr_serv = 0; // обнуление счетчика, для следующего раза
state = 0; // будем ожидать команды
}
break;
}
}}