Страница 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;
    				}
}}