树莓派3b接收USB串口数据并解析处理

通过树莓派3b使用wiringPi接收串口数据,并对帧头帧尾进行判断,解析出符合帧协议的数据。

 

1. 帧头、帧尾、帧长度定义

我们在这里定义串口数据的帧头为 0x3A 0x3B,帧尾为 0x7E 0x7F一帧最大的长度为 10个字节

帧头帧尾格式可自行更改。

// 最大帧长度
#define MaxFrameLength	10			// 对最大帧长度加以限定,防止接收到过长的帧数据
// 完整的帧头,2个字节
#define Frame_Header1   0x3A                    // 串口接收消息包的帧头的第1个字节
#define Frame_Header2   0x3B                    // 串口接收消息包的帧头的第2个字节
// 完整的帧尾,2个字节
#define Frame_Tail1     0x7E                    // 串口接收消息包的帧尾的第1个字节
#define Frame_Tail2     0x7F                    // 串口接收消息包的帧尾的第2个字节

 

2. 用户处理代码

接收到符合帧协议的数据,用户处理在这里定义。

其中 /* */ 分割的地方为用户处理代码。

我写的是将接收到的数据发回去,并重新等待接收下一帧。用户可根据需求自行更改。

                        /* 用户处理代码 */
                        /* 将接收到符合帧定义的帧,原路发送回去 */
                        int i = 0;
                        for (i = 0; i < (tnum + 1); i++)
                        {
                            serialPutchar(hs1, chrtmp[i]);	// 通过串口发送字节
                        }

                        /*  处理完用户代码,重新接收计数 */
                        tnum = 0;

 

3. 串口选择、波特率

这里对自己使用的串口进行更改,我使用的是USB串口,波特率115200,CP2102免驱。

    //hs1 = serialOpen("/dev/ttyS0", 115200);     // 打开 /dev/ttyS0 串口设备,波特率115200
    hs1 = serialOpen("/dev/ttyUSB0", 115200);     // 打开 /dev/ttyUSB0 串口设备,波特率115200

树莓派使用USB串口教程:树莓派使用USB串口

 

4. 完整c代码

GitHub仓库:树莓派-串口解析代码

#include <stdio.h>
#include <wiringPi.h>
#include <wiringSerial.h>

// 最大帧长度
#define MaxFrameLength	10			// 对最大帧长度加以限定,防止接收到过长的帧数据
// 完整的帧头,2个字节
#define Frame_Header1   0x3A                    // 串口接收消息包的帧头的第1个字节
#define Frame_Header2   0x3B                    // 串口接收消息包的帧头的第2个字节
// 完整的帧尾,2个字节
#define Frame_Tail1     0x7E                    // 串口接收消息包的帧尾的第1个字节
#define Frame_Tail2     0x7F                    // 串口接收消息包的帧尾的第2个字节

int main(void)
{
    int hs1;
    int snum = 0;                               // 系统串口接收缓存区的可用字节数
    int tnum = 0;                               // 用户串口接收区的数目
    unsigned char chrtmp[100];                  // 用户串口接收区,将缓存的数据放入这里处理
    int f_h1_flag = 0;                          // 接收到帧头的第一个字节标志位
    int f_h_flag = 0;                           // 接收到帧头标志位
    int f_t1_flag = 0;                          // 接收到帧尾的第一个字节标志位


    wiringPiSetup();                            // 使用wiring编码去初始化GPIO序号
    //hs1 = serialOpen("/dev/ttyS0", 115200);     // 打开 /dev/ttyS0 串口设备,波特率115200
    hs1 = serialOpen("/dev/ttyUSB0", 115200);     // 打开 /dev/ttyUSB0 串口设备,波特率115200


    /*printf("ttyS0 uart test2:\n");              // 终端打印
    serialPrintf(hs1, "Hello World!\r\n");      // 串口打印
    serialPrintf(hs1, "Enter a paragraph and end with Enter:\r\n");*/

    while (1)
    {
        snum = serialDataAvail(hs1);                	// 获取串口接收缓存区的可用字节数
        if(snum > 0)
        {
            chrtmp[tnum] = serialGetchar(hs1);  		// 从接收缓存区读取一个字节

            if (f_h_flag == 1)  // 有帧头,判断帧尾,接收消息
            {
                if (f_t1_flag == 1) //有帧头,有帧尾1
                {
                    if (chrtmp[tnum] == Frame_Tail2)
                    {
                        /* 用户处理代码 */
                        /* 将接收到符合帧定义的帧,原路发送回去 */
                        int i = 0;
                        for (i = 0; i < (tnum + 1); i++)
                        {
                            serialPutchar(hs1, chrtmp[i]);	// 通过串口发送字节
                        }

                        /*  处理完用户代码,重新接收计数 */
                        tnum = 0;
                    }
                    else
                    {
                        f_t1_flag = 0;
                        tnum ++;
                    }
                }
                else						// 有帧头,无帧尾1
                {
                    if (chrtmp[tnum] == Frame_Tail1)
                    {
                        f_t1_flag = 1;
                        tnum ++;
                    }
                    else					// 接收消息包中间内容
                    {
                        tnum ++;
                    }
                }
            }
            else						// 没有接收到帧头
            {
                if (f_h1_flag == 1)			        //没有帧头,有帧头1。下一步判断是否为第2个字节
                {
                    if (chrtmp[tnum] == Frame_Header2)          // 如果为帧头的第2个字节,接收到帧头标志位标志位置1,tnum自增
                    {
                        f_h_flag = 1;
                        tnum ++;
                    }
                    else
                    {
                        f_h1_flag = 0;
                        tnum = 0;
                    }
                }
                else						//没有帧头,没有有帧头1。下一步判断,是否为帧头的第1个字节
                {
                    if (chrtmp[tnum] == Frame_Header1)  // 如果为帧头的第1个字节,标志位置1,tnum自增
                    {
                        f_h1_flag = 1;
                        tnum ++;
                    }
                    else                                // 否则,标志位清0,tnum清0
                    {
                        tnum = 0;
                    }
                }
            }

            // 大于MaxFrameLength个字节的帧不接收
            if (tnum > (MaxFrameLength - 1) )
            {
                tnum = 0;
                f_h1_flag = 0;
                f_h_flag = 0;
                f_t1_flag = 0;
                continue;
            }

        }
    }

    return 0;
}

 

5. 运行现象

使用ftp发送到树莓派中,编译、运行:

pi@raspberrypi:~/demo/serial/c_demo $ gcc serial.c -o serial -l wiringPi
pi@raspberrypi:~/demo/serial/c_demo $ ./serial 

 

打开串口调试助手,波特率115200,收发均为16进制显示。

发送 3A 3B 11 12 12 20 7E 7F。只要是帧头为 3A 3B,帧尾为7E 7F都可以。要跟自定义的帧协议一致。

之后接收到相同的数据。现象正确。帧头帧尾解析正确

 

将帧尾改一下,使其不符合帧格式,发送后无返回。现象正确。帧头帧尾解析正确

 

发送一个11字节长度的数据,验证最大帧长度的判断是否有用。

下方的收发记录显示,发送了11字节数据,并没有返回。最大帧长度的判断有效

 

帧长度为10时,收发一致,现象正确。最大帧长度的判断有效

 

6. 串口通信,控制树莓派播放视频

串口通信,控制树莓派HDMI播放视频

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值