首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在UART上下文中,“传输缓冲区”和“接收缓冲区”意味着什么?

在UART上下文中,“传输缓冲区”和“接收缓冲区”意味着什么?
EN

Stack Overflow用户
提问于 2022-04-08 13:30:45
回答 1查看 992关注 0票数 0

我对什么是发送/接收缓冲器的理解主要与以太网系统有关,在整个数据传输之前,有些数据被存储在缓冲区中。在UART中,某些数据存储在UART发送/接收缓冲区中,直到有8位(从而填补了UART容量),或者当系统被命令从缓冲区发送数据时,这种情况是否相同?

我之所以问这个问题,是因为我看到了一些涉及UART的MSP430FR5994单片机的C代码,我想完全理解这些代码。如果需要更多的信息来回答我的问题,请告诉我。

如果有人感兴趣的话。代码运行良好,我只想知道缓冲区在UART中的作用。

代码语言:javascript
复制
#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;
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-08 13:53:45

有软件缓冲区和硬件缓冲区。

UART硬件外设具有硬件缓冲区、rx缓冲器(接收到的数据等待程序处理)和tx缓冲区(数据等待MCU发送)(设置tx完整标志)。在一些MCU中,每个MCU只有1字节大。其他的有一个更大的rx缓冲器遵循FIFO原理。

在您的示例中,UCA0TXBUF似乎是这个tx缓冲区/数据寄存器,显然它只有一个字节大。USCI_UART_UCTXIFG似乎是在传输完成时设置的标志,并且设置为在完成时生成一个中断。

您的示例中的RXbuffer是UART驱动程序使用的软件缓冲区。

与您的问题无关,这段代码有几个问题和潜在的bug等待爆炸:

  • 对原始数据使用char总是不正确的,因为char具有实现定义的签名性,如果将原始数据存储在MSB中,则可能会变成负数。它不是一个可移植的类型,不应该用于任何东西,除了文本字符串。使用unsigned charuint8_t代替。
  • 在您的代码中没有针对竞争条件的保护,因此,如果在RXbuffer编写时,主程序正在访问它,那么您将得到各种奇怪的bug。
  • 没有针对不正确的编译器优化的保护。如果您的编译器没有意识到ISR从来不被软件调用,而是通过硬件调用,优化器可能会破坏代码。为了防止这种情况,所有共享变量都应该声明为volatile (如果使用DMA缓冲区,情况也是一样)。 查看:
代码语言:javascript
复制
- [Avoiding global variables when using interrupts in embedded systems](https://electronics.stackexchange.com/questions/329339/avoiding-global-variables-when-using-interrupts-in-embedded-systems/329961#329961)
- [Using volatile in embedded C development](https://electronics.stackexchange.com/a/409570/6102)
  • 微控制器系统不会从main()返回,因此int main (void)总是错误的。您应该使用实现定义的表单void main (void) (如果与gcc一起编译,则使用-ffreestanding ),并使用for(;;) {}循环结束main()函数。
  • 您可能希望处理UART帧错误=数据损坏或错误的波德率,以及UART溢出错误=硬件缓冲区在MCU清空它们之前被覆盖。这些通常也可以通过中断标志获得。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71797942

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档