如何设计一个函数来识别“+IPD”何时从UART 到达?
How to design a function which identifies when "+IPD," is arrived from UART?
我正在使用 Tiva Launchpad EK-TM4C123GXL 和 ESP8266 WIFI 模块。
本模块收到wifi包后,通过UART口发送给单片机
ESP8266发送数据包(通过UART到uC)使用的格式是:
+IPD,n:xxxxx\r\nOK\r\n
其中:
n
为数据包的长度(字节)
:
表示下一个字节为第一个数据字节
xxxxx
是数据包
\r\nOK\r\n
是6个字节,对我没用。
例如:
+IPD,5:hello\r\nOK\r\n
这是我的情况:
我正在处理现有项目,我无法更改以下两点:
1- UART 模块已配置为在其接收 FIFO(16 字节)为 half-full 时生成中断。
2- 处理此中断的 ISR(中断服务程序):
只从UARTDR(UART数据寄存器)读取一个字节
保存到一个变量
调用一个函数(称为 rx_data())来处理该字节。
现在,我必须用 C 语言编写这个名为 rx_data() 的函数。
所以,来自 ESP8266 模块的消息被传递给这个函数,rx_data(),一次一个字节,这个函数必须能够至:
识别 header +IPD,
读取数据包的长度n
将数据包xxxxx
(位于:
字符之后,第一个\r
字符之前)保存到缓冲区
丢弃最后的字节\r\nOK\r\n
(这6个字节对我来说没用,但是,无论如何,我必须读取它们以将它们从接收FIFO中移除)
我想按部就班,所以现在我在推理:
如何识别 +IPD,
,考虑到 一次只有一个字节 被传递给这个函数?
是时候制作状态机了。每次调用 rx_data
时,您都会更新状态机的状态,最终在某个时候您会知道您收到了字符串“+IPD”。
假设将从 UART 接收的字节作为参数传递给 rx_data
:
void rx_data(uint8_t byte)
{
static uint8_t state = 0;
if (byte == '+') { state = 1; }
else if (state == 1 && byte == 'I') { state = 2; }
else if (state == 2 && byte == 'P') { state = 3; }
else if (state == 3 && byte == 'D') { state = 4; }
else if (state == 4 && byte == ',') {
state = 0;
handleIPDMessage(); // we received "+IPD,"
}
else { state = 0; }
}
您可以看到当且仅当最后收到的字符是“+IPD”时才会调用 handleIPDMessage()
。
但是,您应该考虑编写一个更通用的状态机,它可以对行进行操作,而不是仅仅查找这个字符串。这可能会更容易编写并且更健壮。当接收到完整的行时,您将调用名为 handleLineReceived()
的函数来处理该行。该函数可以访问包含整行的缓冲区,并且可以以任何它想要的方式解析它。 (请注意,您永远不要写入超出该缓冲区末尾的内容。)
顺便说一下,我不会在 ISR 中加入那样的逻辑。通常最好保持 ISR 简单快速。如果您还没有这样做,请将字节存储到 ISR 中的循环缓冲区,然后在主循环中从循环缓冲区中读取,每次从循环缓冲区中读取一个字节,然后调用 [=11 之类的函数=] 上面描述的函数来处理字节。
我正在使用 Tiva Launchpad EK-TM4C123GXL 和 ESP8266 WIFI 模块。
本模块收到wifi包后,通过UART口发送给单片机
ESP8266发送数据包(通过UART到uC)使用的格式是:
+IPD,n:xxxxx\r\nOK\r\n
其中:
n
为数据包的长度(字节):
表示下一个字节为第一个数据字节xxxxx
是数据包\r\nOK\r\n
是6个字节,对我没用。
例如:
+IPD,5:hello\r\nOK\r\n
这是我的情况:
我正在处理现有项目,我无法更改以下两点:
1- UART 模块已配置为在其接收 FIFO(16 字节)为 half-full 时生成中断。
2- 处理此中断的 ISR(中断服务程序):
只从UARTDR(UART数据寄存器)读取一个字节
保存到一个变量
调用一个函数(称为 rx_data())来处理该字节。
现在,我必须用 C 语言编写这个名为 rx_data() 的函数。
所以,来自 ESP8266 模块的消息被传递给这个函数,rx_data(),一次一个字节,这个函数必须能够至:
识别 header
+IPD,
读取数据包的长度
n
将数据包
xxxxx
(位于:
字符之后,第一个\r
字符之前)保存到缓冲区丢弃最后的字节
\r\nOK\r\n
(这6个字节对我来说没用,但是,无论如何,我必须读取它们以将它们从接收FIFO中移除)
我想按部就班,所以现在我在推理:
如何识别 +IPD,
,考虑到 一次只有一个字节 被传递给这个函数?
是时候制作状态机了。每次调用 rx_data
时,您都会更新状态机的状态,最终在某个时候您会知道您收到了字符串“+IPD”。
假设将从 UART 接收的字节作为参数传递给 rx_data
:
void rx_data(uint8_t byte)
{
static uint8_t state = 0;
if (byte == '+') { state = 1; }
else if (state == 1 && byte == 'I') { state = 2; }
else if (state == 2 && byte == 'P') { state = 3; }
else if (state == 3 && byte == 'D') { state = 4; }
else if (state == 4 && byte == ',') {
state = 0;
handleIPDMessage(); // we received "+IPD,"
}
else { state = 0; }
}
您可以看到当且仅当最后收到的字符是“+IPD”时才会调用 handleIPDMessage()
。
但是,您应该考虑编写一个更通用的状态机,它可以对行进行操作,而不是仅仅查找这个字符串。这可能会更容易编写并且更健壮。当接收到完整的行时,您将调用名为 handleLineReceived()
的函数来处理该行。该函数可以访问包含整行的缓冲区,并且可以以任何它想要的方式解析它。 (请注意,您永远不要写入超出该缓冲区末尾的内容。)
顺便说一下,我不会在 ISR 中加入那样的逻辑。通常最好保持 ISR 简单快速。如果您还没有这样做,请将字节存储到 ISR 中的循环缓冲区,然后在主循环中从循环缓冲区中读取,每次从循环缓冲区中读取一个字节,然后调用 [=11 之类的函数=] 上面描述的函数来处理字节。