简体   繁体   English

UART 上下文中的“发送缓冲区”和“接收缓冲区”是什么意思?

[英]What does "transmit buffer" and "receive buffer" mean in the UART context?

My understanding of what a transmit/receive buffer is largely related to ethe.net systems, where some data is stored in the buffer before the whole data is transmitted.我对什么是传输/接收缓冲区的理解主要与 ethe.net 系统有关,其中一些数据在传输整个数据之前存储在缓冲区中。 Is this the same with UART, where some data is stored in a UART transmit/receive buffer until there are 8 bits (thus filling up the UART capacity) or when the system is ordered to send the data from the buffer?这与 UART 是否相同,其中一些数据存储在 UART 发送/接收缓冲区中,直到有 8 位(从而填满 UART 容量)或当系统被命令从缓冲区发送数据时?

The reason I am asking this is because I am looking at some C code for the MSP430FR5994 MCU involving UART and I'd like to fully understand the code.我问这个的原因是因为我正在查看一些涉及 UART 的 MSP430FR5994 MCU的 C 代码,我想完全理解这些代码。 Please let me know if more info is needed to answer my question.如果需要更多信息来回答我的问题,请告诉我。

The code in question, if anyone's interested.有问题的代码,如果有人感兴趣的话。 The code runs fine, I just want to know what the buffer does in UART.代码运行良好,我只想知道缓冲区在 UART 中的作用。

#include <msp430.h>

char RXbuffer[32];
const unsigned char maxRXbytes = sizeof(RXbuffer);
unsigned char RXbytes = 0;

const char message[] = "ok\n";
const unsigned char messageLength = sizeof(message);
unsigned char TXbytes = 0;

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;               // Stop Watchdog


    // Configure GPIO
    P2SEL0 &= ~(BIT0 | BIT1);
    P2SEL1 |= (BIT0 | BIT1);                // USCI_A0 UART operation (p93_s)

    // Disable the GPIO power-on default high-impedance mode to activate
    // previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;

    // Startup clock system with max DCO setting ~8MHz
    CSCTL0_H = CSKEY_H;                       // Unlock CS registers
    CSCTL1 = DCOFSEL_3 | DCORSEL;             // Set DCO to 8MHz
    CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
    CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;     // Set all dividers
    CSCTL0_H = 0;                             // Lock CS registers

    // Configure USCI_A0 for UART mode
    UCA0CTLW0 = UCSWRST;                    // Put eUSCI in reset (p788)
    UCA0CTLW0 |= UCSSEL__SMCLK;             // CLK = SMCLK
    // Baud Rate calculation for 19200
    // 8000000/(16*19200) = 26.042
    // Fractional portion = 0.042
    // User's Guide Table 21-4: UCBRSx = 0xD6
    // UCBRFx = int ( (52.083-52)*16) = 1
    UCA0BRW = 26;                           // 8000000/16/19200, p789
    UCA0MCTLW |= UCOS16 | UCBRF_1 | 0xD600; // UCOS16 = Oversampling enable, used when high frequency clk is used, probably divides everything by 16, UCBRF = fine turner when UCOS16 is active
                                            // 0xD600 is for first 8 bits,
    UCA0CTLW0 &= ~UCSWRST;                  // Initialize eUSCI
    UCA0IE |= UCRXIE;                       // Enable USCI_A0 RX interrupt

    __bis_SR_register(LPM3_bits | GIE);       // Enter LPM3, interrupts enabled
    __no_operation();                         // For debugger
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=EUSCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(EUSCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
    switch(__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG))
    {
      case USCI_NONE: break;
      case USCI_UART_UCRXIFG:

          if(RXbytes < maxRXbytes)
          {
              // Get the byte
              RXbuffer[RXbytes] = UCA0RXBUF;

              // Check for either ASCII carriage return '\r', or linefeed '\n' character.
              // If true enable the TX interrupt to send response message
              if((RXbuffer[RXbytes] == '\r') || (RXbuffer[RXbytes] ==  '\n'))
              {
                  // Start message transmission
                  UCA0IE |= UCTXIE;

                  // Reset receive buffer index
                  RXbytes = 0;
              }
              else
                  RXbytes++;

          }
          break;

      case USCI_UART_UCTXIFG:

          // Transmit the byte
          UCA0TXBUF = message[TXbytes++];

          // If last byte sent, disable the interrupt
          if(TXbytes == messageLength)
          {
              UCA0IE &= ~UCTXIE;
              TXbytes = 0;
          }
          break;

      case USCI_UART_UCSTTIFG: break;
      case USCI_UART_UCTXCPTIFG: break;
      default: break;
    }
}

There are software buffers and hardware buffers.有软件缓冲区和硬件缓冲区。

The UART hardware peripheral has hardware buffers, a rx buffer where received data is waiting to get handled by the program, and a tx buffer where data is waiting for the MCU to transmit it (a tx complete flag will get set). UART 硬件外设具有硬件缓冲区、接收数据等待程序处理的 rx 缓冲区和数据等待 MCU 传输的 tx 缓冲区(将设置 tx 完成标志)。 In some MCUs these are just 1 byte large each.在某些 MCU 中,每个只有 1 个字节大。 Others have a larger rx buffers following a FIFO principle.其他人有更大的 rx 缓冲区遵循 FIFO 原则。

UCA0TXBUF in your example appears to be this tx buffer/data register and apparently it is just 1 byte large.您的示例中的UCA0TXBUF似乎是这个 tx 缓冲区/数据寄存器,显然它只有 1 个字节大。 USCI_UART_UCTXIFG appears to be the flag set upon transmission complete and it's set to generate an interrupt when done. USCI_UART_UCTXIFG似乎是传输完成时设置的标志,它设置为在完成时生成中断。

The RXbuffer in your example is a software buffer used by the UART driver.示例中的RXbuffer是 UART 驱动程序使用的软件缓冲区。


Unrelated to your question, this code has several problems and latent bugs waiting to explode:与您的问题无关,这段代码有几个问题和潜在的错误等待爆发:

  • Using char for raw data is always incorrect, since char has implementation-defined signedness and might turn into negative number if you store raw data in the MSB.char用于原始数据总是不正确的,因为char具有实现定义的符号,如果将原始数据存储在 MSB 中,则可能会变成负数。 It is not a portable type and shouldn't be used for anything but text strings.它不是可移植类型,除了文本字符串外,不应该用于任何其他用途。 Use unsigned char or uint8_t instead.请改用unsigned charuint8_t

  • There is no protection from race conditions in your code, so in case the main program is accessing RXbuffer while the ISR is writing to it, you will get all manner of weird bugs.您的代码中没有针对竞争条件的保护,因此如果主程序在 ISR 写入RXbuffer时访问它,您将遇到各种奇怪的错误。

  • There is no protection against incorrect compiler optimizations.没有针对不正确的编译器优化的保护。 In case your compiler doesn't realize that an ISR is never called by software but by hardware, the optimizer might break the code.如果您的编译器没有意识到 ISR 永远不会被软件调用,而是由硬件调用,则优化器可能会破坏代码。 To prevent this all shared variables should be declared volatile (same goes in case you would use DMA buffers instead).为防止这种情况,所有共享变量都应声明为volatile的(如果您改用 DMA 缓冲区,情况也是如此)。

    Check out:查看:

  • Microcontroller systems do not return from main() so int main (void) is always wrong.微控制器系统不会从 main() 返回,因此int main (void)总是错误的。 You should use the implementation-defined form void main (void) (use -ffreestanding if compiling with gcc) and end the main() function with a for(;;) {} loop.您应该使用实现定义的形式void main (void) (如果使用 gcc 编译则使用-ffreestanding )并使用for(;;) {}循环结束main() function。

  • You probably want to handle UART framing errors = data corruption or wrong baudrate, as well as UART overrun errors = hardware buffers were overwritten before MCU emptied them.您可能想要处理 UART 帧错误 = 数据损坏或波特率错误,以及 UART 溢出错误 = 硬件缓冲区在 MCU 清空之前被覆盖。 These are typically available through interrupt flags too.这些通常也可以通过中断标志获得。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM