概述:我想使用Visual Studio(用C语言)通过串行COM端口从传感器读取24字节数据包的低端十六进制HEX值。每当新数据发送到端口时,我都需要更新串行读取,并将数据的某些字节解释为浮点值。当串行数据可用时,如何从COM端口读取信息,组织字节并将其转换为浮点/有用信息?
详细信息:传入数据包的长度为24字节,以已知字符(“ {”和“}”)开头/结尾,因此有助于了解要捕获的字节数以及如何捕获分解它们。字节7-10包含little-endian Hex格式的气体1浓度数据,字节11-14包含little-endian Hex格式的气体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数组的假设(也许需要逐个字符读取并缝合在一起而不是在一个数组块中将其缝合在一起)的假设非常不正确,然后将其转换(调用a char字符串为十六进制值,然后将该十六进制值转换为浮点数?)-这是我的知识和经验非常有限的地方,将非常感谢实现建议。
答案 0 :(得分:0)
好的,不用担心,这不太困难。
我对您的伪代码进行了重新设计,因此可以将其编译为C代码段。我相信您的问题的主要部分是关于如何提取和组合一个多字节值。在下面的代码块中,这是decode
函数。
像处理二进制数据包一样,最好使用unsigned char
而不是仅仅使用char
。这使换挡更容易/更正确。
您说数据包是 newline 终止的,但是在图中没有显示。并且,由于我们正在处理 binary 数据(如您在顶部注释中所确认的),因此数据包数据部分中的任何有效字节都可以为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();
}
}