Как выйти из USART ISR с помощью atmega? - PullRequest
0 голосов
/ 08 октября 2019

У меня проблема с Atmega 1284p, я написал этот ISR для получения команд через последовательный порт. Если я отправляю CR или LF в конец команды, программа работает правильно, но если я не отправляю ни одну из них, программа остается в ISR, блокируя мою программу.

Поскольку ISR отключает менявсе прерывания я не знаю как из этого выбраться!

Может кто-нибудь мне помочь?

void USART_init(void)
{   
UCSR0B |= (1<<RXEN0) | (1<<TXEN0);
UCSR0C &= ~(1<<USBS0);                  //Stop bits 1
UCSR0C &= ~((1<<UPM00) | (1<<UPM01));   //Parity check disabled

UCSR0C |= (1<<UCSZ00) | (1<<UCSZ01);    //8 bit data
UCSR0B &= ~(1<<UCSZ02);             //8 bit data continue

UCSR0B |= (1 << RXCIE0);

UBRR0H = 0;
UBRR0L = 64; //9600 baud for a 16MHz Clock.
}


unsigned char USART_receive(void)
{
while(!(UCSR0A & (1<<RXC0)));
return UDR0;
}


ISR(USART0_RX_vect)
{
clean_variables();

do {
    cmd[inc] = USART_receive();
    inc++;
} while ((cmd[inc - 1] != '\n') && (command[inc - 1] != '\r'));
inc = 0;                            
comd = 1;
split();
}

Ответы [ 3 ]

2 голосов
/ 08 октября 2019

Эта программа побеждает саму цель использования прерываний. Вы запускаете прерывание после первого полученного символа, а затем проводите опрос. Вместо этого вам следует инициировать прерывание один раз для каждого символа, а затем как можно скорее покинуть ISR.

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

0 голосов
/ 08 октября 2019

Хорошей практикой будет ограничение кода в ISR до минимума (и неблокирование!). Вам нужно только прочитать новый символ из UDR0 в буфер. Выполните всю остальную обработку в основном цикле.

ISR(USART0_RX_vect) {
    // no need to check RXC0, the byte is available when the ISR is called
    cmd[inc] = UDR0;
    inc++;        
}

main() {
    if ((cmd[inc - 1] == '\n') || (cmd[inc - 1] == '\r')) {
        // process...
    }
}

Некоторые думают указать

  • Могут быть синтаксические ошибки, я просто записал это
  • Вы должны справиться с потенциальным переполнением буфера, когда inc становится большим
  • Объявите inc и cmd как volatile, поскольку они доступны из ISR и основного контекста
  • Комуизбегайте возможных условий гонки, которые вам понадобятся, чтобы сделать эту «безопасную нить». Например, отключив прерывания (как можно более короткие) при доступе к cmd и inc в основном цикле. Что-то вроде отключения-> копирования значений-> повторного включения-> работа с копиями-> повтор.
0 голосов
/ 08 октября 2019

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

Тогда в вашем обработчике прерываний вы не только проверяете свое завершениесимволов, но также запускают цикл while, пока USART_receive возвращает значение true.

Необходимо учитывать тот факт, что прерывание может сработать до того, как будет получено полное сообщение, т. е. нет перевода строки или возврата каретки.

...