Обработка потока в UART, управляемом прерываниями - ATMEGA328P

Я пытаюсь реализовать связь UART, управляемую прерываниями, с ATMEGA328P. Мне нужно отправить команды (массивы символов) через UART, чтобы извлечь значения в мои переменные в подпрограмме main, чтобы я мог запрограммировать поведение в своей схеме.

Данные, которые я отправляю, имеют следующий формат: 2 255 0 255 0 0 255 1000 (это для светодиодной лампы RGB). Здесь описаны long int значения для mode, 2 цветов RGB и duration.

Пока это то, что у меня есть в main:

while(1)
{
    if(rxFlag==1){
        char * pEnd;
        mode = strtol(buffer,&pEnd,10);
        Ri = strtol (pEnd, &pEnd,10);
        Gi = strtol (pEnd, &pEnd,10);
        Bi = strtol (pEnd, &pEnd,10);
        Rf = strtol (pEnd, &pEnd,10);
        Gf = strtol (pEnd, &pEnd,10);
        Bf = strtol (pEnd, &pEnd,10);
        duration = strtol (pEnd,NULL,10);
        rxFlag=0;
    }

    switch(mode){
        case 1: // fixed color
            fixed(Rf, Gf, Bf);
            break;
        case 2: // yoyo pulse
            yoyo(Ri,Gi,Bi,Rf,Gf,Bf,duration);
            break;
        default:// red blinky
            fixed(0,255,255);
            _delay_ms(500);
            fixed(255,255,255);
            _delay_ms(500);
            break;

    }
}

И ISR (процедура обслуживания прерывания), которая обрабатывает прием:

ISR(USART_RX_vect)
{   
   while ( !(UCSR0A & (1<<RXC0)) );
   if (rxn==80){ // if BUFFER_SIZE is reached, reset to start of buffer.
       rxn=0;
   }
   buffer[rxn++] = UDR0; // increment rxn and return new value.
   if(buffer[rxn]=='\0'){
    rxFlag=1; // notify main of receipt of data.
   }
}

Как видите, я пытаюсь обновить значения переменных только тогда, когда обнаруживаю \0 в конце потока.

Это что-то вроде (в ISR):

  • Прочитать входящий байт и сохранить его в буфере длиной не более 80 байт.
  • Если приходит \0, сообщите главному узлу, что у него есть новые данные для обработки.

In main:

  • Если есть новые данные, разбейте буфер на long int и сохраните значения
  • сбросить флаг новых данных
  • действовать согласно новым ценностям.

Проблема в том, что все идет не так, как я хотел, и я вроде как потерялся. Я знаю, что мой оператор switch работает правильно, если у переменных есть правильные значения. Я сузил проблему до прерывания фазы связи / заполнения буфера ИЛИ извлечения значений переменных, которые были нарушены, но не уверен, что или и то, и другое.

Кто-нибудь может поделиться своими мыслями?


person Joum    schedule 23.06.2014    source источник


Ответы (1)


Изменить: было еще время подумать об этом. Игнорируйте мой предыдущий ответ.

Убедитесь, что ваш буфер объявлен с ключевым словом volatile.

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

#define BUFF_MAX_BYTES 80

#define TRUE 1
#define FALSE 0

typedef unsigned char boolean;

static volatile unsigned char buff[BUFF_MAX_BYTES];

static volatile unsigned char buffHead = 0;
static volatile unsigned char buffTail = 0;
static volatile unsigned char buffSize = 0;

boolean store_byte(unsigned char b)
{
    boolean success = TRUE;

    if(buffSize < BUFF_MAX_BYTES){
        buff[buffTail] = b;
        buffSize++;
        buffTail = (buffTail + 1) % BUFF_MAX_BYTES;
    } else{
        success = FALSE;
    }

    return success;
}

boolean eol_received(void)
{
    unsigned char prev_index = (buffTail == 0) ? BUFF_MAX_BYTES - 1 : buffTail - 1;
    boolean eol = FALSE;

    if(buff[prev_index] == '\0'){
        eol = TRUE;
    }

    return eol;
}

// Because strtol has no conception of where the buffer ends and wraps, you
// will have to create a modified version that can handle this case.
//
// A simple approach would be to calculate the length of your message, copy
// it to another buffer for parsing (advancing buffHead as you read bytes),
// and then call strtol on this new buffer.

ISR(USART_RX_vect)
{   
    while ( !(UCSR0A & (1<<RXC0)) );

    if(!store_byte(UDR0)){
        // Use a flag to inform main() of overflow, handle as appropriate
    }

    rxFlag = eol_received() ? 1 : 0;
}
person Community    schedule 23.06.2014