我目前正在编程ATmega32u4。我已经实现了串行通信,它是使用内置中断实现的,每次在Rx引脚上接收到一个字节时执行。 Rx引脚上的字节放在一个字节缓冲区中,当Rx引脚上接收到另一个字节时,该缓冲区被替换。这是atmel的内置库。
ISR(USART1_RX_vect, ISR_BLOCK)
{
RingBuffer_Insert(&usart_rx_buffer,UDR1);
}
我的代码在Rx引脚上接收到一个字节时执行中断。当接收到一个字节时,该字节被输入我的环形缓冲区uart_rx_buffer,稍后对其进行解码。
如果正在执行中断并且这导致在执行UART中断之前替换一个字节缓冲区,则该字节将丢失。
这样做的结果是其他中断的执行时间不能超过波特率,否则会丢失串行字节。有什么方法可以避免这个问题吗?
答案 0 :(得分:2)
解决此问题的一种方法是在所有占用时间超过波特率的中断中使用属性 ISR_NOBLOCK ,从而使编译器尽可能早地激活中断启用标志ISR并允许 USART1_RX_vect 在其他中断内执行。但是,“应注意避免堆栈溢出,或避免在进入ISR之前AVR硬件未清除相应中断标志的情况下无限进入ISR”。
我遇到了同样的问题,到目前为止这是我能想到的最好的解决方案。 我没有使用它,也没有测试过它。
编辑:请记住,所有其他中断也可以在使用属性 ISR_NOBLOCK 声明的中断内执行,而不仅仅是您想要的中断。所以你基本上允许所有中断都嵌套在所有中断中,除了 USART1_RX_vect (以及用 ISR_BLOCK 声明的那些)。这是此解决方案的主要问题(除了堆栈溢出问题)。
答案 1 :(得分:1)
这样做的结果是其他中断的执行时间不能超过波特率,否则会丢失串行字节。有什么方法可以避免这个问题吗?
你的所有观察都是正确的。虽然允许Nuno的答案中建议的嵌套中断可以工作,但通常是你应该/应该想要避免的。允许嵌套中断到处都会使代码变得不可预测。
我首先尝试优化阻止UART接收ISR的中断的执行时间。看看中断优先级。如果有几个中断待处理,它们将根据此优先级执行。这可能导致饥饿"较低级别的中断,如果有"总是"更高级别的中断待处理。
你的波特率是多少?即使在115200 bit / s,您也可以每个字节执行大约700条指令(假设为8MHz)。 ISR应尽可能短。如果有一个ISR需要很长时间并且您无法以任何理由对其进行优化,那么您可以考虑在此单个ISR中仅允许嵌套中断(这仅在执行不重要时才可行)。
如果您使用高波特率,请考虑减少它。 9600波特通常就足够了,但可能需要异步发送以防止阻塞代码。