[英]Embedded C UART conventions
I need advice on proper way of handling UART communication. 我需要有关处理UART通信的正确方法的建议。 I feel like I've done handling sending serial commands over UART well but I don't know if the way I'm parsing the response or receiving serial data is the best way to do it.
我觉得我已经很好地处理了通过UART发送串行命令的过程,但是我不知道解析响应或接收串行数据的方法是否是最好的方法。 Any tips are appreciated but I just want to know if there's a better more and elegant way to parse UART RX.
任何提示都值得赞赏,但我只是想知道是否有更好的,更优雅的方式来解析UART RX。
This is for an MSP430 uC by the way... 顺便说一下,这是针对MSP430 uC的...
First I have these declared in the header file: 首先,我在头文件中声明了这些:
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;
Here is the function that is called once the flag UART_RX_Pkt_Complete is set in the ISR: 在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;
}
For reference here's the RX ISR: 作为参考,这里是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;
}
Also here's the TX ISR and send UART command routine: 这也是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');
}
}
If this works and meets your system's requirements then it's fine. 如果此方法有效并且满足您系统的要求,那就很好。 But there are several ways it could be improved.
但是有几种方法可以改进它。
Receive_Resp()
and USCIA0RX_ISR()
are tightly coupled, which is undesirable. Receive_Resp()
和USCIA0RX_ISR()
紧密耦合,这是不希望的。 They both manipulate UART_RX_Index
for the other ( USCIA0RX_ISR()
increments it and Receive_Resp()
clears it) and they both rely on the other for part of the framing of each message ( USCIA0RX_ISR()
finds the end of the frame while Receive_Resp()
interprets and resets for the next frame). UART_RX_Index
( USCIA0RX_ISR()
递增,而Receive_Resp()
清除),并且它们在每个消息的成帧过程中都依赖于另一个( USCIA0RX_ISR()
找到帧的结尾,而Receive_Resp()
解释并为下一帧重置)。 It would be better if these routines were decoupled. ReceiveResp()
routine doesn't handle any errors such as a dropped character. ReceiveResp()
例程不处理任何错误,例如字符丢失。 It assumes that all three characters were received correctly. UART_RX_Index >= 3
before you subtract 3 from it. UART_RX_Index >= 3
减去3之前,至少应确保UART_RX_Index >= 3
。 In other words, make sure the message length is sane. Do the calls to Delay
in Send_CMD()
mean that your application is totally stalled while it's waiting to finish the transmission? 在
Send_CMD()
对Delay
的调用是否意味着您的应用程序在等待完成传输时完全停止了? Again, maybe that's OK for your application but typically that is undesirable. 同样,对于您的应用程序可能没问题,但是通常这是不希望的。 Typically you want the application to continue to function even while it's waiting for the UART to be ready to transmit.
通常,您希望应用程序即使在等待UART准备发送时也能继续运行。 By using a circular transmit buffer, it would be possible for multiple messages to queue up in the transmit buffer and you wouldn't have to wait for the previous message to finish before queuing up another.
通过使用循环传输缓冲区,可能有多个消息在传输缓冲区中排队,并且您不必等待上一条消息完成就可以排队另一条消息。 But then you should add protection for a buffer overrun and this may complicate things unnecessarily for you.
但是,然后您应该为缓冲区溢出添加保护,这可能会使您不必要地复杂化。 Which brings me back to my first point, if what you have works and meets your requirements then it is fine.
这使我回到我的第一点,如果您的工作可以满足您的要求,那很好。
Personally, I'd write a completely separate UART module that contained methods for write
and read
operations. 就个人而言,我将编写一个完全独立的UART模块,其中包含用于
write
和read
操作的方法。 Under the hood I'd create two circular buffers (of whatever the appropriate size may be) and use those for storing bytes as data comes in or goes out. 在后台,我将创建两个循环缓冲区(大小合适的缓冲区),并使用它们在数据进出时存储字节。 This would allow an interrupt driven solution with buffers.
这将允许具有缓冲区的中断驱动解决方案。
For instance, my interrupt for receive would do something like: 例如,我的接收中断将执行以下操作:
#pragma vector=USCIAB0RX_VECTOR
__interrupt void UartRxIsr()
{
...
// Add new byte to my receive buffer.
...
}
Then I can call my Uart.read()
method to read out that byte. 然后,我可以调用
Uart.read()
方法来读取该字节。 The read
method might look something like the following: read
方法可能类似于以下内容:
char read()
{
if (Uart.rxBuffer.length > 0)
{
return Uart.rxBuffer.buffer[Uart.rxBuffer.write++];
}
}
This is assuming that you've implemented circular buffers using pointers. 假设您已经使用指针实现了循环缓冲区。
I have a solution lying around somewhere. 我有个解决方案。 I'll try to find it and post it.
我将尝试查找并将其发布。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.