嵌入式C UART约定

use*_*581 2 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;
Run Code Online (Sandbox Code Playgroud)

这是在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;
}
Run Code Online (Sandbox Code Playgroud)

这里是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;
 }
Run Code Online (Sandbox Code Playgroud)

这里还有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');
    }
}
Run Code Online (Sandbox Code Playgroud)

kkr*_*mbo 5

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

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

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