嵌入式C UART约定

时间:2013-11-22 11:10:10

标签: 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;
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');
    }
}

2 个答案:

答案 0 :(得分:5)

如果这样可以满足您的系统要求,那就没关系。但有几种方法可以改进。

  • Receive_Resp()USCIA0RX_ISR()紧密耦合,这是不可取的。他们都为其他人操纵UART_RX_IndexUSCIA0RX_ISR()递增它并Receive_Resp()清除它)并且他们都依赖另一个来构成每条消息的部分框架(USCIA0RX_ISR()找到当Receive_Resp()解释并重置下一帧时帧的结束)。如果将这些例程解耦,那就更好了。
  • 字符缓冲区应该是一个循环缓冲区,带有一个头指针(添加了字符)和一个尾指针(字符被删除)。 ISR应该只将chars添加到循环缓冲区并推进头指针。 ISR还应该处理将头指针包装回循环缓冲区的开头。并且ISR应该通过确保头指针不通过尾指针来防止超出。
  • 接收例程应负责构建消息。这包括从尾指针中拉出字符并识别消息的开头和结尾。 Receive例程递增并包装尾指针。通常,接收例程实现为状态机,其状态用于标识帧的开始,正文和结尾。
  • 对于更少的耦合,您可能有一个单独的函数来解释消息的内容(即,将框架与消息的解释分开)。
  • 您的ReceiveResp()例程不会处理任何错误,例如丢弃的字符。它假定所有三个字符都被正确接收。也许这对您的应用和要求很好。但通常应该在这里执行一些错误检查。至少你应该在从它中减去3之前确保UART_RX_Index >= 3。换句话说,确保消息长度合理。更健壮的串行协议将在每个帧中具有校验和或CRC,以确保正确接收帧,但这可能对您的应用程序而言过度。
  • 您可以通过一些相同的建议改进您的传输方面。通常,存在用于传输字符的循环缓冲区。 Transmit例程将chars添加到缓冲区并管理头指针。 TX ISR将字符从缓冲区复制到UART并管理尾指针。

Delay中对Send_CMD()的调用是否意味着您的应用程序在等待完成传输时完全失效?再一次,也许这对你的应用来说没问题,但通常这是不可取的。通常,您希望应用程序即使在等待UART准备好传输时也能继续运行。通过使用循环发送缓冲区,可以在发送缓冲区中排队多个消息,并且在排队另一个消息之前不必等待先前的消息完成。但是,您应该为缓冲区溢出添加保护,这可能会使您不必要地复杂化。这让我回到了我的第一点,如果你有什么工作并满足你的要求,那就没关系了。

答案 1 :(得分:0)

就个人而言,我会编写一个完全独立的UART模块,其中包含writeread操作的方法。在引擎盖下我会创建两个循环缓冲区(无论适当的大小),并在数据进入或退出时使用它们存储字节。这将允许带缓冲区的中断驱动解决方案。

例如,我的接收中断会执行以下操作:

#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++];
    }
}

这假设你已经使用指针实现了循环缓冲区。

我在某处有一个解决方案。我会尝试找到并张贴它。