0

一个外部模块通过中断一次一个字符地向我的程序发送字符串“CMD\n”。重要的是要知道模块在序列中的位置,以便我可以进行故障排除。这是我目前处理模块跟踪的方式:

// Enumeration describing the different states
typedef enum {
    BTSTATE_ENTERING_CMD_C, // awaiting "C"
    BTSTATE_ENTERING_CMD_M,
    BTSTATE_ENTERING_CMD_D,
    BTSTATE_ENTERING_CMD_EOL,
    BTSTATE_CMD
} btstate_t;

// State variable
btstate_t btstate = BTSTATE_ENTERING_CMD_C;

// function called every time a new character is sent
ISR(USART_RX_vect) {
    uint8_t rcv = UDR0; // the received character 
    if (        btstate == BTSTATE_ENTERING_CMD_C   && rcv == 'C') {
        btstate = BTSTATE_ENTERING_CMD_M;
    } else if ( btstate == BTSTATE_ENTERING_CMD_M   && rcv == 'M') {
        btstate = BTSTATE_ENTERING_CMD_D;
    } else if ( btstate == BTSTATE_ENTERING_CMD_D   && rcv == 'D') {
        btstate = BTSTATE_ENTERING_CMD_EOL;
    } else if ( btstate == BTSTATE_ENTERING_CMD_EOL && rcv == '\n') {
        btstate = BTSTATE_CMD;
    } else {
        // error handling here
    }
}

直觉上,代码中似乎有很多冗余。是否有更好或更规范的方法来实现相同的结果?

4

2 回答 2

1

类似以下内容将测试传入流以确认它与字符串匹配:

static const char leader[] = "CMD\n";
uint8_t btstate = 0;

ISR(USART_RX_vect) {
    uint8_t rcv = UDR0;
    if (btstate < 4)
    {
        if (rcv == leader[btstate])
            btstate++;
        else
        {
             // error handling here
             btstate = 0;
        }
    }
}

(显然未经测试)

如果(btstate == 4)那时你有你的领导字符串,现在正在接收后面的任何内容。

此处未妥善处理的错误情况可能会影响设计,即您在正确字符串之前收到一些前导垃圾。按照目前的情况,我们将进入// error handling here并重置btstate,但如果rcv现在等于'C'发送者真正想要的第一个,那么我们就错过了,下一次我们会期待'C'但会收到'M' 并引发另一个错误并完全错过正确的字符串。

在这里,您有两个选择。一种是通知发送方重置自身(这在高延迟链接上可能会很麻烦),另一种是重新检查 (rcv == 'C')错误处理程序。

如果您的命令字符串是"GABBAGABBAHEY",而您期待的是 ,'H' 但您却得到了'G',则可能所有前面的字符都被错误发送,或者某些字符被故意作为另一个字符串(或当前字符串)的前缀发送.

处理这种情况,以及处理存在多个可能字符串的情况,需要一个可以根据接收到的字符采用不同路径的结构。在您确实希望容忍前导垃圾的情况下,该结构可以自行循环 - 指向与当前状态匹配的最长前缀 - 在这种情况下,您真的不想手动构建表.

你已经说过你知道你期待什么字符串,所以我不会深入讨论,但我认为为了完整起见值得一提。

于 2013-07-09T09:24:39.663 回答
1

那这个呢 ?它非常易读且易于修改。

// Enumeration describing the different states
typedef enum {
    BTSTATE_ENTERING_CMD_C, // awaiting "C"
    BTSTATE_ENTERING_CMD_M,
    BTSTATE_ENTERING_CMD_D,
    BTSTATE_ENTERING_CMD_EOL,
    BTSTATE_CMD
} btstate_t;

// State variable
btstate_t btstate = BTSTATE_ENTERING_CMD_C;

struct       cmp
{
   btstate_t state;
   btstate_t next_state;
   uint8_t   c;
}            t_cmp;

ISR(USART_RX_vect) {
    static t_cmp cmp_array[] = {
      {BTSTATE_ENTERING_CMD_C, BTSTATE_ENTERING_CMD_M, 'C'},
      {BTSTATE_ENTERING_CMD_M, BTSTATE_ENTERING_CMD_D, 'M'},
      {BTSTATE_ENTERING_CMD_D, BTSTATE_ENTERING_CMD_EOL, 'D'},
      {BTSTATE_ENTERING_CMD_EOL, BTSTATE_CMD, '\n'}
    };
    static int array_size = sizeof(cmp_array) / sizeof(cmp_array[0]);

    uint8_t rcv = UDR0; // the received character
    int     i; 
    for (i = 0; i < array_size; ++i)
    {
        if (btstate == cmp_array[i].state && rcv == cmp_array[i].c)
        {
             btstate = cmp_array[i].next_state;
             break ;
        }
    }
    if (i == array_size)
        // error handling here
}
于 2013-07-09T09:32:43.043 回答