首页 > 解决方案 > 是否可以在不检查 AVR ATMega32 中的 UDRE 标志的情况下将 UDR 写入 USART_RXC 中断处理程序中?

问题描述

我一直试图理解这段代码,它应该使用中断回显在 AVR 的 USART 接口上接收到的每个字节。

#include 
#include 

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

int main (void)
{
   UCSRB = (1 << RXEN) | (1 << TXEN);   // Turn on the transmission and reception circuitry
   UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes

   UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
   UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register

   UCSRB |= (1 << RCXIE); // Enable the USART Recieve Complete interrupt (USART_RXC)
   sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed

   for (;;) // Loop forever
   {
         // Do nothing - echoing is handled by the ISR instead of in the main loop
   }   
}

ISR(USART_RXC_vect)
{
   char ReceivedByte;
   ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"
   UDR = ReceivedByte; // Echo back the received byte back to the computer
}

我无法理解这部分

ISR(USART_RXC_vect)
    {
       char ReceivedByte;
       ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"
       UDR = ReceivedByte; // Echo back the received byte back to the computer
    }

为什么这里不检查 UDRE 标志以查看是否确实可以写入新数据,而不会覆盖以前的数据?由于我们在相应的轮询方法中做同样的事情:

while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"

while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ReceivedByte; // Echo back the received byte back to the computer

不应该在UDR = ReceivedByte;里面的行之前检查UDRE标志ISR吗?任何见解将不胜感激。

标签: serial-portmicrocontrolleravrusartatmega16

解决方案


简短的回答是 -的:您可以在任何时候编写 UDR,而无需事先进行任何检查。

但是,如果输出缓冲区已满(UCSRA 中的 UDRE 标志未设置),则发送器将忽略写入的数据,或者换句话说,它将丢失。

USART 模块有一个双输出缓冲器。这意味着可以提前写入两个字节:一个正在传输,一个在缓冲区中将稍后传输。UDRE 标志在缓冲区字节为空时显示,而 TXC 标志在发送字节被拉出时显示。

因此,如果您有办法确保发送器缓冲区不会溢出,则可以根本不检查该标志。由于接收字节需要与发送完全相同的时间,您可以确定 RXC 中断不会比发送字节更频繁,因此,如果 UDR 没有写入其他位置,则可以假设输出缓冲区当 RXC 中断发生时,总是可以接受至少一个字节。

尽管如此,如果 UDR 被写入其他地方,输出缓冲区可能不会为空,当发生 RXC 中断时,传输的回显字节将丢失。

At the other hand, the good programming practice is to leave interrupt handlers as soon as possible. Putting wait loops in the interrupt handler routine is a bad idea. In that case, if you can not be sure the output buffer will be empty on the RXC event, better to either have some kind of output buffer in RAM, which will be processed in UDRE interrupt, or to perform echo outside the RXC interrupt.


推荐阅读