概述:我想使用Visual Studio (C语言)通过串行COM端口从传感器读取24字节数据包的小端十六进制值。每当有新数据发送到端口时,我都需要更新串行读取,并将数据的一些字节解释为浮点值。当串行数据可用时,我如何开始从COM端口读取数据,组织字节,并将它们转换为浮点数/有用的信息?
详细信息:传入的数据包是已知的24字节长度,并以已知字符("{“和"}")开始/结束,因此这有助于了解要捕获的字节数以及如何分解它们。字节7-10包含小端十六进制格式的气体1浓度数据,字节11-14包含小端十六进制格式的气体2浓度数据。示例数据包如下所示:
类似数据包的另一个示例(由传感器的数据表提供)如下所示:
我为整个操作绘制的伪代码概述如下:
If serial data is available{
//read serial packet into char array
Char serialString[24] = read serial until newline character ()
startBracketHexChar = serialString[0] //”{“ part of packet
Gas1HexChar= serialString[6-9] //gas measurement 1 data from packet
Gas2HexChar = serialString[10-13] //gas measurement 2 data from packet
tempHexChar = serialString[14-17] //temp measurement from packet
endBracketHexChar = serialString[23] //”}” part of bracket
//if packet is as expected…
if (startBracketHexChar == ‘{‘ && endBrackHexChar == ‘}’){
Gas1Float = char.to.float(Gas1HexChar) //convert char to float type
Gas2Float = char.to.float(Gas2HexChar) //convert char to float type
tempFloat = char.to.float(tempHexChar) //convert char to float type
gas1textBox.Text = Gas1Float; //display gas 1 reading
gas2textBox.Text = Gas2Float; //display gas 2 reading
temptextBox.Text = tempFloat; //display temp reading
}
else {
ErrortextBox.Text = “Packet error”; //unexpected packet error
}
}
我认为我在伪代码中关于读取Gas1HexChar数组的假设是非常错误的(也许它需要一个字符一个字符地读取并拼接在一起,而不是在一个数组块中?)和转换它(在调用一个字符字符串一个十六进制值,然后将该十六进制值转换为浮点数?)-这是我的知识和经验非常有限的地方,实现建议将非常感谢。
发布于 2018-10-26 02:26:10
好的,不用担心,这并不是很难。
我重新编写了您的伪代码,以便将其编译为C代码片段。我相信你问题的主要部分是关于如何引入和组装一个多字节的值。在下面的代码块中,这是decode
函数。
在处理像您这样的二进制数据包时,比起仅仅使用char
,使用unsigned char
要好得多。这使得转换更容易/更正确。
您说数据包以换行符终止,但这并未显示在图中。而且,由于我们处理的是二进制数据,正如您在顶部注释中确认的那样,数据包的数据部分中的任何有效字节都可能是0x0A (即换行符),因此在看到换行符之前,我们不能逐个读取字符。
如果在最后确实有换行符,我们可能需要读取25个字节,并只检查最后一个字符。
我不做windows :-),所以我不知道访问COM端口的细节,但我已经编写了你可以填充的函数。
无论如何,代码如下,请原谅不必要的样式清理
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
typedef struct {
char Text[100];
} TextBox_t;
FILE *stream;
TextBox_t gas1textBox;
TextBox_t gas2textBox;
TextBox_t temptextBox;
TextBox_t ErrortextBox;
// serial_data_is_available -- check for data ready
int
serial_data_is_available(void)
{
return 1;
}
// serial_get -- get single byte from device
unsigned char
serial_get(void)
{
return rand();
}
// serial_buf -- assemble packet buffer
int
serial_buf(unsigned char *buf,int buflen)
{
int idx;
for (idx = 0; idx < buflen; ++idx)
buf[idx] = serial_get();
return idx;
}
// decode -- get a binary value
uint32_t
decode(unsigned char *buf,int beg,int end)
{
uint32_t acc = 0;
for (int idx = end; idx >= beg; --idx) {
acc <<= 8;
acc |= buf[idx];
}
return acc;
}
// floatget -- get a float value
float
floatget(unsigned char *buf,int beg,int end)
{
union {
float fval;
uint32_t val;
} join;
join.val = decode(buf,beg,end);
return join.fval;
}
// process_packet -- process a single packet
void
process_packet(void)
{
// for raw binary data, unsigned is better
unsigned char buf[24];
// read serial packet into char array
serial_buf(buf,sizeof(buf));
// "{" part of packet
char start = buf[0];
// "}" part of bracket
char end = buf[23];
//if packet is as expected…
if ((start == '{') && (end == '}')){
// gas measurement 1 data from packet
float Gas1Float = floatget(buf,6,9);
// gas measurement 2 data from packet
float Gas2Float = floatget(buf,10,13);
// temp measurement from packet
float tempFloat = floatget(buf,14,17);
sprintf(gas1textBox.Text,"%f",Gas1Float);
sprintf(gas2textBox.Text,"%f",Gas2Float);
sprintf(temptextBox.Text,"%f",tempFloat);
}
else {
strcpy(ErrortextBox.Text,"Packet error"); //unexpected packet error
}
}
void
loop(void)
{
while (1) {
if (serial_data_is_available())
process_packet();
}
}
https://stackoverflow.com/questions/52993785
复制相似问题