“传输缓冲区”是什么意思?和“接收缓冲器”在 UART 上下文中意味着什么?
我对发送/接收缓冲区的理解很大程度上与以太网系统有关,在以太网系统中,在传输整个数据之前,一些数据存储在缓冲区中。这与 UART 是否相同,其中一些数据存储在 UART 发送/接收缓冲区中,直到有 8 位(从而填满 UART 容量)或当系统被命令从缓冲区发送数据时?
我问这个问题的原因是因为我正在查看 MSP430FR5994 MCU涉及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;
}
}
My understanding of what a transmit/receive buffer is largely related to ethernet systems, where some data is stored in the buffer before the whole data is transmitted. 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?
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. 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.
#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;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
有软件缓冲区和硬件缓冲区。
UART 硬件外设具有硬件缓冲区、接收数据等待程序处理的接收缓冲区和数据等待 MCU 发送的发送缓冲区(将设置发送完成标志)。在某些 MCU 中,每个只有 1 字节大。其他的则遵循 FIFO 原则,具有更大的接收缓冲区。
您的示例中的 UCA0TXBUF 似乎是这个 tx 缓冲区/数据寄存器,显然它只有 1 个字节大。
USCI_UART_UCTXIFG
似乎是传输完成时设置的标志,并且设置为在完成时生成中断。示例中的 RXbuffer 是 UART 驱动程序使用的软件缓冲区。
与您的问题无关,此代码有几个问题和潜在的错误正在等待爆发:
使用
char
作为原始数据总是不正确的,因为char
具有实现定义的签名如果将原始数据存储在 MSB 中,则可能会变成负数。它不是可移植类型,除了文本字符串之外不应该用于任何其他类型。请改用unsigned char
或uint8_t
。代码中没有针对竞争条件的保护,因此,如果主程序在 ISR 写入时访问
RXbuffer
,您将遇到各种奇怪的错误。无法防止错误的编译器优化。如果您的编译器没有意识到 ISR 从来不是由软件调用而是由硬件调用,则优化器可能会破坏代码。为了防止这种情况,所有共享变量都应该声明为
易失性
(如果您使用 DMA 缓冲区,情况也是如此)。查看:
微控制器系统不会从 main() 返回,因此
int main (void)
总是错误的。您应该使用实现定义的形式void main (void)
(如果使用 gcc 编译,请使用-ffreestand
)并结束main()
函数使用for(;;) {}
循环。您可能想要处理 UART 帧错误 = 数据损坏或错误波特率,以及 UART 溢出错误 = 硬件缓冲区在 MCU 清空之前被覆盖。这些通常也可以通过中断标志来获得。
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). In some MCUs these are just 1 byte large each. Others have a larger rx buffers following a FIFO principle.
UCA0TXBUF
in your example appears to be this tx buffer/data register and apparently it is just 1 byte large.USCI_UART_UCTXIFG
appears to be the flag set upon transmission complete and it's set to generate an interrupt when done.The
RXbuffer
in your example is a software buffer used by the UART driver.Unrelated to your question, this code has several problems and latent bugs waiting to explode:
Using
char
for raw data is always incorrect, sincechar
has implementation-defined signedness and might turn into negative number if you store raw data in the MSB. It is not a portable type and shouldn't be used for anything but text strings. Useunsigned char
oruint8_t
instead.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.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. To prevent this all shared variables should be declared
volatile
(same goes in case you would use DMA buffers instead).Check out:
Microcontroller systems do not return from main() so
int main (void)
is always wrong. You should use the implementation-defined formvoid main (void)
(use-ffreestanding
if compiling with gcc) and end themain()
function with afor(;;) {}
loop.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. These are typically available through interrupt flags too.