嵌入式C-UART协议
我需要关于如何正确处理UART通信的建议。我觉得我已经很好地处理了通过UART发送串行命令,但我不知道解析响应或接收串行数据的方式是否是最好的方式非常感谢您提供的任何提示,但我只想知道是否有更好、更优雅的方法来解析UART RX。 这是一个MSP430 uC的方式 首先,我在头文件中声明了这些内容:嵌入式C-UART协议,c,embedded,firmware,msp430,C,Embedded,Firmware,Msp430,我需要关于如何正确处理UART通信的建议。我觉得我已经很好地处理了通过UART发送串行命令,但我不知道解析响应或接收串行数据的方式是否是最好的方式非常感谢您提供的任何提示,但我只想知道是否有更好、更优雅的方法来解析UART RX。 这是一个MSP430 uC的方式 首先,我在头文件中声明了这些内容: const unsigned char *UART_TX_Buffer; unsigned char UART_TX_Index; unsigned char UART_TX_Length; uns
const unsigned char *UART_TX_Buffer;
unsigned char UART_TX_Index;
unsigned char UART_TX_Length;
unsigned char UART_TX_Pkt_Complete;
unsigned char UART_RX_Buffer[25];
unsigned char UART_RX_Pkt_Complete;
unsigned char UART_RX_Index;
void Receive_Resp()
{
switch (UART_RX_Buffer[UART_RX_Index - 3])
{
case 0x4B:
break;
case 0x56:
P1OUT &= ~(tos_sel0 + tos_sel1);
break;
case 0x43:
P1OUT |= tos_sel0;
P1OUT &= ~tos_sel1;
break;
case 0x34:
P1OUT |= tos_sel1;
P1OUT &= ~tos_sel0;
break;
case 0x33:
P1OUT |= tos_sel0 + tos_sel1;
break;
default:
break;
}
UART_RX_Pkt_Complete = 0;
UART_RX_Index = 0;
}
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCIA0RX_ISR(void)
{
UART_RX_Buffer[UART_RX_Index++] = UCA0RXBUF;
if (UART_RX_Buffer[UART_RX_Index - 1] == 0x0A)
{
UART_RX_Pkt_Complete = 1;
_BIC_SR_IRQ(LPM3_bits);
}
IFG2 &= ~UCA0RXIFG;
}
if (UART_TX_Index < UART_TX_Length) // Check if there are more bytes to be sent
{
UCA0TXBUF = UART_TX_Buffer[UART_TX_Index++];
}
else // Last byte has been sent
{
UART_TX_Pkt_Complete = 1; // Set flag to show last byte was sent
_BIC_SR_IRQ(LPM3_bits);
}
IFG2 &= ~UCA0TXIFG;
void Send_CMD (const unsigned char *Data, const unsigned char Length)
{
UART_TX_Buffer = Data; // Move into global variables
UART_TX_Length = Length;
UART_TX_Pkt_Complete = 0; // Starting values
UART_RX_Pkt_Complete = 0;
UART_TX_Index = 0;
UCA0TXBUF = UART_TX_Buffer[UART_TX_Index++];
while(!UART_TX_Pkt_Complete)
{
Delay(5,'u');
}
while(!UART_RX_Pkt_Complete)
{
Delay(5,'u');
}
}
以下是在ISR中设置标志UART\U RX\U Pkt\U Complete后调用的函数:
const unsigned char *UART_TX_Buffer;
unsigned char UART_TX_Index;
unsigned char UART_TX_Length;
unsigned char UART_TX_Pkt_Complete;
unsigned char UART_RX_Buffer[25];
unsigned char UART_RX_Pkt_Complete;
unsigned char UART_RX_Index;
void Receive_Resp()
{
switch (UART_RX_Buffer[UART_RX_Index - 3])
{
case 0x4B:
break;
case 0x56:
P1OUT &= ~(tos_sel0 + tos_sel1);
break;
case 0x43:
P1OUT |= tos_sel0;
P1OUT &= ~tos_sel1;
break;
case 0x34:
P1OUT |= tos_sel1;
P1OUT &= ~tos_sel0;
break;
case 0x33:
P1OUT |= tos_sel0 + tos_sel1;
break;
default:
break;
}
UART_RX_Pkt_Complete = 0;
UART_RX_Index = 0;
}
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCIA0RX_ISR(void)
{
UART_RX_Buffer[UART_RX_Index++] = UCA0RXBUF;
if (UART_RX_Buffer[UART_RX_Index - 1] == 0x0A)
{
UART_RX_Pkt_Complete = 1;
_BIC_SR_IRQ(LPM3_bits);
}
IFG2 &= ~UCA0RXIFG;
}
if (UART_TX_Index < UART_TX_Length) // Check if there are more bytes to be sent
{
UCA0TXBUF = UART_TX_Buffer[UART_TX_Index++];
}
else // Last byte has been sent
{
UART_TX_Pkt_Complete = 1; // Set flag to show last byte was sent
_BIC_SR_IRQ(LPM3_bits);
}
IFG2 &= ~UCA0TXIFG;
void Send_CMD (const unsigned char *Data, const unsigned char Length)
{
UART_TX_Buffer = Data; // Move into global variables
UART_TX_Length = Length;
UART_TX_Pkt_Complete = 0; // Starting values
UART_RX_Pkt_Complete = 0;
UART_TX_Index = 0;
UCA0TXBUF = UART_TX_Buffer[UART_TX_Index++];
while(!UART_TX_Pkt_Complete)
{
Delay(5,'u');
}
while(!UART_RX_Pkt_Complete)
{
Delay(5,'u');
}
}
以下是RX ISR供参考:
const unsigned char *UART_TX_Buffer;
unsigned char UART_TX_Index;
unsigned char UART_TX_Length;
unsigned char UART_TX_Pkt_Complete;
unsigned char UART_RX_Buffer[25];
unsigned char UART_RX_Pkt_Complete;
unsigned char UART_RX_Index;
void Receive_Resp()
{
switch (UART_RX_Buffer[UART_RX_Index - 3])
{
case 0x4B:
break;
case 0x56:
P1OUT &= ~(tos_sel0 + tos_sel1);
break;
case 0x43:
P1OUT |= tos_sel0;
P1OUT &= ~tos_sel1;
break;
case 0x34:
P1OUT |= tos_sel1;
P1OUT &= ~tos_sel0;
break;
case 0x33:
P1OUT |= tos_sel0 + tos_sel1;
break;
default:
break;
}
UART_RX_Pkt_Complete = 0;
UART_RX_Index = 0;
}
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCIA0RX_ISR(void)
{
UART_RX_Buffer[UART_RX_Index++] = UCA0RXBUF;
if (UART_RX_Buffer[UART_RX_Index - 1] == 0x0A)
{
UART_RX_Pkt_Complete = 1;
_BIC_SR_IRQ(LPM3_bits);
}
IFG2 &= ~UCA0RXIFG;
}
if (UART_TX_Index < UART_TX_Length) // Check if there are more bytes to be sent
{
UCA0TXBUF = UART_TX_Buffer[UART_TX_Index++];
}
else // Last byte has been sent
{
UART_TX_Pkt_Complete = 1; // Set flag to show last byte was sent
_BIC_SR_IRQ(LPM3_bits);
}
IFG2 &= ~UCA0TXIFG;
void Send_CMD (const unsigned char *Data, const unsigned char Length)
{
UART_TX_Buffer = Data; // Move into global variables
UART_TX_Length = Length;
UART_TX_Pkt_Complete = 0; // Starting values
UART_RX_Pkt_Complete = 0;
UART_TX_Index = 0;
UCA0TXBUF = UART_TX_Buffer[UART_TX_Index++];
while(!UART_TX_Pkt_Complete)
{
Delay(5,'u');
}
while(!UART_RX_Pkt_Complete)
{
Delay(5,'u');
}
}
这里还有发送ISR和发送UART命令例程:
const unsigned char *UART_TX_Buffer;
unsigned char UART_TX_Index;
unsigned char UART_TX_Length;
unsigned char UART_TX_Pkt_Complete;
unsigned char UART_RX_Buffer[25];
unsigned char UART_RX_Pkt_Complete;
unsigned char UART_RX_Index;
void Receive_Resp()
{
switch (UART_RX_Buffer[UART_RX_Index - 3])
{
case 0x4B:
break;
case 0x56:
P1OUT &= ~(tos_sel0 + tos_sel1);
break;
case 0x43:
P1OUT |= tos_sel0;
P1OUT &= ~tos_sel1;
break;
case 0x34:
P1OUT |= tos_sel1;
P1OUT &= ~tos_sel0;
break;
case 0x33:
P1OUT |= tos_sel0 + tos_sel1;
break;
default:
break;
}
UART_RX_Pkt_Complete = 0;
UART_RX_Index = 0;
}
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCIA0RX_ISR(void)
{
UART_RX_Buffer[UART_RX_Index++] = UCA0RXBUF;
if (UART_RX_Buffer[UART_RX_Index - 1] == 0x0A)
{
UART_RX_Pkt_Complete = 1;
_BIC_SR_IRQ(LPM3_bits);
}
IFG2 &= ~UCA0RXIFG;
}
if (UART_TX_Index < UART_TX_Length) // Check if there are more bytes to be sent
{
UCA0TXBUF = UART_TX_Buffer[UART_TX_Index++];
}
else // Last byte has been sent
{
UART_TX_Pkt_Complete = 1; // Set flag to show last byte was sent
_BIC_SR_IRQ(LPM3_bits);
}
IFG2 &= ~UCA0TXIFG;
void Send_CMD (const unsigned char *Data, const unsigned char Length)
{
UART_TX_Buffer = Data; // Move into global variables
UART_TX_Length = Length;
UART_TX_Pkt_Complete = 0; // Starting values
UART_RX_Pkt_Complete = 0;
UART_TX_Index = 0;
UCA0TXBUF = UART_TX_Buffer[UART_TX_Index++];
while(!UART_TX_Pkt_Complete)
{
Delay(5,'u');
}
while(!UART_RX_Pkt_Complete)
{
Delay(5,'u');
}
}
if(UART\u TX\u Index
如果这可以工作并且满足您的系统要求,那么就可以了。但有几种方法可以改进
和Receive_Resp()
紧密耦合,这是不可取的。它们都为另一个操作USCIA0RX_ISR()
(UART\u RX\u索引
递增它,并USCIA0RX\u ISR()
清除它),并且它们都依赖另一个作为每个消息帧的一部分(Receive\u Resp()
在USCIA0RX\u ISR()
为下一帧进行解释和重置)。如果将这些例程解耦,效果会更好Receive\u Resp()时查找帧的结尾)
- 字符缓冲区应该是一个循环缓冲区,带有头指针(添加字符的位置)和尾指针(删除字符的位置)。ISR只应将字符添加到循环缓冲区中,并前进头部指针。ISR还应该处理将头指针包装回循环缓冲区的开头。ISR应该通过确保头指针不超过尾指针来防止溢出
- 接收例程应负责对消息进行帧处理。这包括从尾部指针中提取字符以及标识消息的开头和结尾。接收例程递增并包装尾部指针。通常,接收例程被实现为一个状态机,其状态用于识别帧的开始、主体和结束
- 对于更少的耦合,您可能有一个单独的函数来解释消息的内容(即,将框架与消息的解释分开)李>
- 您的
例程不会处理任何错误,例如删除字符。它假定所有三个字符都正确接收。也许这对您的应用程序和需求来说是很好的。但是这里通常会执行一些错误检查。在从中减去3之前,至少应该确保ReceiveResp()
。换句话说,确保消息长度是合理的。一个更健壮的串行协议在每个帧中都有一个校验和或CRC,以确保正确地接收到该帧,但这对于您的应用程序来说可能是过分的UART\u RX\u Index>=3
- 您的传输端可以通过一些相同的建议进行改进。通常有一个用于传输字符的循环缓冲区。传输例程向缓冲区添加字符并管理头指针。TX ISR将字符从缓冲区复制到UART,并管理尾部指针
在
Send_CMD()
中调用Delay
是否意味着应用程序在等待完成传输时完全停止?同样,对于您的应用程序来说,这可能是可以的,但通常这是不可取的。通常,您希望应用程序在等待UART准备好传输时仍能继续运行。通过使用循环传输缓冲区,可以让多条消息在传输缓冲区中排队,而无需等待前一条消息完成后再排队。但是,您应该为缓冲区溢出添加保护,这可能会使事情变得不必要的复杂。这让我回到了我的第一点,如果您所拥有的能够工作并满足您的需求,那么它就很好了。就我个人而言,我会编写一个完全独立的UART模块,其中包含用于写操作和读操作的方法。在引擎盖下,我会创建两个循环缓冲区(无论大小合适),并在数据进出时使用它们来存储字节。这将允许使用缓冲区的中断驱动解决方案
例如,我的接收中断将执行以下操作:
#pragma vector=USCIAB0RX_VECTOR
__interrupt void UartRxIsr()
{
...
// Add new byte to my receive buffer.
...
}
然后我可以调用我的Uart.read()
方法来读取那个字节。read
方法可能如下所示:
char read()
{
if (Uart.rxBuffer.length > 0)
{
return Uart.rxBuffer.buffer[Uart.rxBuffer.write++];
}
}
这是假设您已经使用指针实现了循环缓冲区
我有一个解决办法。我会设法找到它并将其张贴。谢谢您的回答!我将致力于所有这些改进。