我需要有关处理UART通信的正确方法的建议。我觉得我已经完成了通过UART发送串行命令的处理,但我不知道我解析响应或接收串行数据的方式是否是最好的方法。 任何提示都很受欢迎,但我只是想知道是否有更好,更优雅的解析UART RX的方式。
这是针对MSP430 uC的方式......
首先我在头文件中声明了这些:
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;
这是在ISR中设置标志UART_RX_Pkt_Complete后调用的函数:
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;
}
供参考,这里是RX ISR:
#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;
}
此处还有TX ISR并发送UART命令例程:
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');
}
}
答案 0 :(得分:5)
如果这样可以满足您的系统要求,那就没关系。但有几种方法可以改进。
Receive_Resp()
和USCIA0RX_ISR()
紧密耦合,这是不可取的。他们都为其他人操纵UART_RX_Index
(USCIA0RX_ISR()
递增它并Receive_Resp()
清除它)并且他们都依赖另一个来构成每条消息的部分框架(USCIA0RX_ISR()
找到当Receive_Resp()
解释并重置下一帧时帧的结束)。如果将这些例程解耦,那就更好了。ReceiveResp()
例程不会处理任何错误,例如丢弃的字符。它假定所有三个字符都被正确接收。也许这对您的应用和要求很好。但通常应该在这里执行一些错误检查。至少你应该在从它中减去3之前确保UART_RX_Index >= 3
。换句话说,确保消息长度合理。更健壮的串行协议将在每个帧中具有校验和或CRC,以确保正确接收帧,但这可能对您的应用程序而言过度。 Delay
中对Send_CMD()
的调用是否意味着您的应用程序在等待完成传输时完全失效?再一次,也许这对你的应用来说没问题,但通常这是不可取的。通常,您希望应用程序即使在等待UART准备好传输时也能继续运行。通过使用循环发送缓冲区,可以在发送缓冲区中排队多个消息,并且在排队另一个消息之前不必等待先前的消息完成。但是,您应该为缓冲区溢出添加保护,这可能会使您不必要地复杂化。这让我回到了我的第一点,如果你有什么工作并满足你的要求,那就没关系了。
答案 1 :(得分:0)
就个人而言,我会编写一个完全独立的UART模块,其中包含write
和read
操作的方法。在引擎盖下我会创建两个循环缓冲区(无论适当的大小),并在数据进入或退出时使用它们存储字节。这将允许带缓冲区的中断驱动解决方案。
例如,我的接收中断会执行以下操作:
#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++];
}
}
这假设你已经使用指针实现了循环缓冲区。
我在某处有一个解决方案。我会尝试找到并张贴它。