CEM5861G-M11雷达模块通过串口读写数据,上位机与模块之间的应用层协议定义如下:
1)帧头,2字节
上位机→雷达: 0x55 0x5A
上位机←雷达: 0x55 0xA5
2)数据长度,2字节
采用大端序,包含: 功能码 、命令码 、数据、校验和
3)功能码,1字节
读: 0x0
写: 0x1
被动上报: 0x2
主动上报: 0x3
4)命令码 ,2字节
命令码1 为功能分类, 命令码2 表示具体功能。
5)数据
6)校验和,1字节
之前所有数据按uint8_t格式相加之和的低8位。
默认情况下,模块上电就开始主动上报数据,按照手册,也可以通过配置,采取请求应答机制。
在树莓派4B上编写代码,使用串口读取主动上报的数据并解析。
解析代码如下:
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <cstdint>
// 定义帧头
const uint8_t FRAME_HEADER_TX[2] = {0x55, 0x5A}; // 上位机发送帧头
const uint8_t FRAME_HEADER_RX[2] = {0x55, 0xA5}; // 上位机接收帧头
// 打开串口
int openSerialPort(const char* portName)
{
int fd = open(portName, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
perror("Failed to open serial port");
return -1;
}
struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_cflag &= ~PARENB; // 无奇偶校验
options.c_cflag &= ~CSTOPB; // 1位停止位
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8; // 8位数据位
options.c_cflag |= (CLOCAL | CREAD);
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始模式
options.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用流控
options.c_oflag &= ~OPOST; // 原始输出
if (tcsetattr(fd, TCSANOW, &options) != 0)
{
perror("Failed to condiv serial port");
close(fd);
return -1;
}
return fd;
}
void receiveData(int fd)
{
char buf[128];
int n = read(fd, buf, sizeof(buf));
if (buf[0] != FRAME_HEADER_RX[0] || buf[1] != FRAME_HEADER_RX[1])
{
return;
}
// 读取数据长度(大端格式)
uint16_t length = (buf[2] << 8) | buf[3];
printf("length: %d\n", length);
printf("id= %d, status=%d, distance=%ucm\n", buf[7], buf[8], ((buf[9] << 8) | buf[10]));
return;
}
int main()
{
int fd = openSerialPort("/dev/ttyS0");
if (fd == -1)
{
return 1;
}
while(1)
{
receiveData(fd);
usleep(10000);
}
return 0;
}
运行结果如下图所示:
全部评论