在C中解析和读取数据帧?

时间:2010-03-23 14:14:04

标签: c linux serial-port frame

我正在编写一个从Linux上的串口读取数据的程序。 数据由具有以下帧格式的其他设备发送:

|start | Command | Data               | CRC  | End |
|0x02  | 0x41    | (0-127 octets)     |      | 0x03|
----------------------------------------------------

数据字段包含127个八位字节,如图所示,八位字节1,2包含一种数据类型;八位位组3,4包含另一个数据。我需要获取这些数据

我知道如何在Linux中从串口写入和读取数据,但只是编写和读取一个简单的字符串(如“ABD”)

我的问题是我不知道如何解析上面格式化的数据框,以便我可以:

  • 获取数据字段
  • 中八位字节1,2的数据
  • 获取数据字段
  • 中八位字节3,4的数据
  • 获取CRC字段中的值以检查数据的一致性

这里是从Linux读取和写入一个简单字符串的示例剪辑代码:

int writeport(int fd, char *chars) {
    int len = strlen(chars);
    chars[len] = 0x0d; // stick a <CR> after the command
    chars[len+1] = 0x00; // terminate the string properly
    int n = write(fd, chars, strlen(chars));
    if (n < 0) {
        fputs("write failed!\n", stderr);
        return 0;
    }
    return 1;                                                                                                           
}

int readport(int fd, char *result) {
    int iIn = read(fd, result, 254);
    result[iIn-1] = 0x00;
    if (iIn < 0) {
        if (errno == EAGAIN) {
            printf("SERIAL EAGAIN ERROR\n");
            return 0;
        } else {
            printf("SERIAL read error %d %s\n", errno, strerror(errno));
            return 0;
        }
    }                    
    return 1;
}

有没有人请一些想法?

2 个答案:

答案 0 :(得分:5)

result是一个char的数组,宽度为1个八位字节。

读取八位字节 n 使用:

char octet_n = result[n];

所以做你想要的你需要的东西:

// skip the start and command fields
char *data_field = result + 2; 

int octet_1_2 = data_field[1] | (data_field[2] << 8);
int octet_3_4 = data_field[3] | (data_field[4] << 8);

// crc is at byte 128 + 2 = 130
int crc = result[130];

修改:此行的说明:

int octet_1_2 = data_field[1] | (data_field[2] << 8);

您希望将两个连续的八位字节读取为一个16位字:

            1
       bits 5        8 7       0
            --------------------
octet_1_2 = | octet 2 | octet 1|
            --------------------

所以你想把8位的比特7:0放在octet_1_2的7:0位:

octet_1_2 = data_field[1];

然后你想取八位字节2的7:0位并将它们放在octet_1_2的15:8位。你可以通过向左移八位字节8位,并将结果OR变为octet_1_2来实现这一点:

octet_1_2 |= data_field[2] << 8;

这两行可以像我上面那样合并为一行。

答案 1 :(得分:0)

在C中读取格式化数据的最好方法是读取结构。 鉴于您拥有的帧格式,我将执行以下操作。


typedef struct special_data
{
    char first_data[2];
    char second data[2];
} special_data_t;

union data_u
{
    special_data_t my_special_data;
    char           whole_data[128];
};

typedef struct data_frame
{
    unsigned char start;
    unsigned char cmd;
    union data_u  data;
    unsigned char crc;
    unsigned char end;
} data_frame_t;

void func_read(int fd)
{
    data_frame_t my_data;

    if (read(fd, &my_data, sizeof(my_data)) != -1)
    {
        // Do something
    }
    return;
}

这样您就可以通过结构字段访问所需的数据。第一个结构和联合只是帮助在框架的数据字段中访问所需的字节。