"transmit buffer" 和 "receive buffer" 在 UART 上下文中是什么意思?
What does "transmit buffer" and "receive buffer" mean in the UART context?
我对什么是 transmit/receive 缓冲区的理解主要与以太网系统有关,在以太网系统中,一些数据在传输整个数据之前存储在缓冲区中。这与 UART 是否相同,其中一些数据存储在 UART transmit/receive 缓冲区中,直到有 8 位(从而填满 UART 容量)或当系统被命令从缓冲区发送数据时?
我问这个问题的原因是因为我正在查看一些涉及 UART 的 MSP430FR5994 MCU 的 C 代码,我想完全理解这些代码。如果需要更多信息来回答我的问题,请告诉我。
有问题的代码,如果有人感兴趣的话。代码运行正常,我只想知道缓冲区在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;
}
}
有软件缓冲区和硬件缓冲区。
UART 硬件外设有硬件缓冲区,接收数据等待程序处理的 rx 缓冲区,以及数据等待 MCU 传输的 tx 缓冲区(tx 完成标志将被设置).在某些 MCU 中,每个只有 1 个字节大。其他人有更大的 rx 缓冲区遵循 FIFO 原则。
UCA0TXBUF
在您的示例中似乎是这个 tx buffer/data 寄存器,显然它只有 1 个字节大。 USCI_UART_UCTXIFG
似乎是在传输完成时设置的标志,它设置为在完成时生成中断。
您的示例中的RXbuffer
是UART驱动程序使用的软件缓冲区。
与你的问题无关,这段代码有几个问题和潜在的错误等待爆发:
对原始数据使用 char
总是不正确的,因为 char
具有 implementation-defined 符号并且如果将原始数据存储在 MSB 中可能会变成负数.它不是可移植类型,除了文本字符串外,不应该用于任何其他用途。请改用 unsigned char
或 uint8_t
。
您的代码中没有针对竞争条件的保护,因此如果主程序正在访问 RXbuffer
而 ISR 正在写入它,您将遇到各种奇怪的错误.
没有针对不正确的编译器优化的保护。如果您的编译器没有意识到 ISR 永远不会被软件调用,而是由硬件调用,则优化器可能会破坏代码。为防止出现这种情况,应声明所有共享变量 volatile
(如果您改用 DMA 缓冲区也是如此)。
查看:
微控制器系统不从 main() return 所以 int main (void)
总是错误的。您应该使用 implementation-defined 形式 void main (void)
(如果使用 gcc 编译则使用 -ffreestanding
)并使用 for(;;) {}
循环结束 main()
函数。
您可能想要处理 UART 帧错误 = 数据损坏或波特率错误,以及 UART 溢出错误 = 硬件缓冲区在 MCU 清空之前被覆盖。这些通常也可以通过中断标志获得。
我对什么是 transmit/receive 缓冲区的理解主要与以太网系统有关,在以太网系统中,一些数据在传输整个数据之前存储在缓冲区中。这与 UART 是否相同,其中一些数据存储在 UART transmit/receive 缓冲区中,直到有 8 位(从而填满 UART 容量)或当系统被命令从缓冲区发送数据时?
我问这个问题的原因是因为我正在查看一些涉及 UART 的 MSP430FR5994 MCU 的 C 代码,我想完全理解这些代码。如果需要更多信息来回答我的问题,请告诉我。
有问题的代码,如果有人感兴趣的话。代码运行正常,我只想知道缓冲区在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;
}
}
有软件缓冲区和硬件缓冲区。
UART 硬件外设有硬件缓冲区,接收数据等待程序处理的 rx 缓冲区,以及数据等待 MCU 传输的 tx 缓冲区(tx 完成标志将被设置).在某些 MCU 中,每个只有 1 个字节大。其他人有更大的 rx 缓冲区遵循 FIFO 原则。
UCA0TXBUF
在您的示例中似乎是这个 tx buffer/data 寄存器,显然它只有 1 个字节大。 USCI_UART_UCTXIFG
似乎是在传输完成时设置的标志,它设置为在完成时生成中断。
您的示例中的RXbuffer
是UART驱动程序使用的软件缓冲区。
与你的问题无关,这段代码有几个问题和潜在的错误等待爆发:
对原始数据使用
char
总是不正确的,因为char
具有 implementation-defined 符号并且如果将原始数据存储在 MSB 中可能会变成负数.它不是可移植类型,除了文本字符串外,不应该用于任何其他用途。请改用unsigned char
或uint8_t
。您的代码中没有针对竞争条件的保护,因此如果主程序正在访问
RXbuffer
而 ISR 正在写入它,您将遇到各种奇怪的错误.没有针对不正确的编译器优化的保护。如果您的编译器没有意识到 ISR 永远不会被软件调用,而是由硬件调用,则优化器可能会破坏代码。为防止出现这种情况,应声明所有共享变量
volatile
(如果您改用 DMA 缓冲区也是如此)。查看:
微控制器系统不从 main() return 所以
int main (void)
总是错误的。您应该使用 implementation-defined 形式void main (void)
(如果使用 gcc 编译则使用-ffreestanding
)并使用for(;;) {}
循环结束main()
函数。您可能想要处理 UART 帧错误 = 数据损坏或波特率错误,以及 UART 溢出错误 = 硬件缓冲区在 MCU 清空之前被覆盖。这些通常也可以通过中断标志获得。