如何摆脱带有atmega的USART ISR?

问题描述 投票:0回答:3

我对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();
}
c avr atmega
3个回答
0
投票

您的问题是,即使没有任何数据,也将继续检查UART的数据。我可以建议您更改USART_receive,以便它返回成功/失败标志,并使用传递该指针的指针将数据写入缓冲区。

然后,在中断处理程序中,您不仅要检查终止字符,而且还只在USART_receive返回true时运行while循环。

[您需要考虑到可能在收到完整消息之前即没有换行符或回车符的情况下触发中断的事实。


0
投票

该程序无法达到使用中断的目的。您在收到第一个字符时触发中断,然后从那里开始轮询。相反,您应该每个字符触发一次中断,然后尽快离开ISR。

基于中断的UART接收的常用技术是使用环形缓冲区,您可以从ISR中填充环形缓冲区,而从调用方中将其清空。还请记住重新进入!始终,对于您编写的每个中断,都不会例外。


0
投票

优良作法是将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变大时,您应该处理潜在的缓冲区溢出
  • inccmd声明为volatile,因为它们是从ISR和主上下文访问的
  • 为了避免潜在的竞争状况,您需要使此“线程安全”。例如,通过在主循环中访问cmdinc时禁用中断(尽可能短)。类似于禁用->复制提示->重新启用->处理副本->重复。
© www.soinside.com 2019 - 2024. All rights reserved.