【通知帖】裁判系统用户数据读取
![robomaster](https://hz-rm-bbs-web-prod.oss-cn-hangzhou.aliyuncs.com/avatar/pre/v1/000000014_avatar_big.jpg)
用户数据协议说明
1、帧头数据
/**
* @brief frame header structure definition
*/
typedef __packed struct
{
uint8_t sof;
uint16_t data_length;
uint8_t seq;
uint8_t crc8;
} frame_header_t;
2、命令码
3、数据
4、帧尾数据
数据发送和接收
1、数据发送
/**
* @brief pack data to bottom device
* @param[in] cmd_id: command id of data
* @param[in] *p_data: pointer to the data to be sent
* @param[in] len: the data length
*/
void data_pack_handle(uint16_t cmd_id, uint8_t *p_data, uint16_t len)
{
memset(computer_tx_buf, 0, COMPUTER_FRAME_BUFLEN);
frame_header_t *p_header = (frame_header_t*)computer_tx_buf;
p_header->sof = UP_REG_ID;
p_header->data_length = len;
memcpy(&computer_tx_buf[HEADER_LEN], (uint8_t*)&cmd_id, CMD_LEN);
append_crc8_check_sum(computer_tx_buf, HEADER_LEN);
memcpy(&computer_tx_buf[HEADER_LEN + CMD_LEN], p_data, len);
append_crc16_check_sum(computer_tx_buf, HEADER_LEN + CMD_LEN + len + CRC_LEN);
}
2、数据接收
2.1 串口不定长数据接收
2.2 数据储存
2.3 数据解析
3、示例代码
裁判系统的学生接口外发的数据一帧分为 4 个部分,分别是帧头数据、命令码 ID、数据、帧尾校验数据。
1、帧头数据
/**
* @brief frame header structure definition
*/
typedef __packed struct
{
uint8_t sof;
uint16_t data_length;
uint8_t seq;
uint8_t crc8;
} frame_header_t;
帧头数据 | 占用字节 | 详细描述 |
sof | 1 | 数据的域ID,学生接口域:0xA5 |
data_length | 2 | 每帧内数据data的长度 |
seq | 1 | 包序号 |
crc8 | 1 | 帧头的crc校验结果 |
2、命令码
一个命令码对应一帧包含具体信息的数据。
命令码 | 占用字节 |
cmdid | 2 |
3、数据
为命令码 ID 对应的数据结构,数据长度即这个结构体的大小。
数据 | 占用字节 |
data | data_length |
4、帧尾数据
每帧数据的crc16校验结果存储在这个位置。
帧尾数据 | 占用字节 |
crc16 | 2 |
数据发送和接收
1、数据发送
数据发送部分比较简单,数据打包好后,其实就是正常的数据加上了帧头帧尾和校验数据,这个时候我们只需要把打包好的数据的数组直接通过串口发送出去即可。不管是使用串口进行普通的移位发送,还是使用 DMA 发送,都可以很容易的实现。
使用如下函数打包要发送的数据:
* @brief pack data to bottom device
* @param[in] cmd_id: command id of data
* @param[in] *p_data: pointer to the data to be sent
* @param[in] len: the data length
*/
void data_pack_handle(uint16_t cmd_id, uint8_t *p_data, uint16_t len)
{
memset(computer_tx_buf, 0, COMPUTER_FRAME_BUFLEN);
frame_header_t *p_header = (frame_header_t*)computer_tx_buf;
p_header->sof = UP_REG_ID;
p_header->data_length = len;
memcpy(&computer_tx_buf[HEADER_LEN], (uint8_t*)&cmd_id, CMD_LEN);
append_crc8_check_sum(computer_tx_buf, HEADER_LEN);
memcpy(&computer_tx_buf[HEADER_LEN + CMD_LEN], p_data, len);
append_crc16_check_sum(computer_tx_buf, HEADER_LEN + CMD_LEN + len + CRC_LEN);
}
2、数据接收
裁判系统的数据发送出来时不同的帧数据长度是不定的,而且可能会有连续帧或者断帧的情况出现,这个时候使用接收遥控器数据的方法来接收就会出现问题。下面给大家提供接收裁判系统数据的具体思路,主要包含串口不定长数据的接收,以及接收到的数据的存储和解析。
2.1 串口不定长数据接收
首先解决不定长数据的问题,因为数据不定长度,所以不能只靠一个固定长度的缓冲和空闲中断来接收数据,缓冲可能有溢出的情况,而且单片机的资源有限,也不可能使用很大的内存空间一次性接收完每次裁判系统发送过来的数据。
使用串口空闲中断,加 DMA 满中断来接收和存储串口数据。下面是两种中断配合使用时的具体情况:
- 在串口空闲中断时,读取 DMA 缓冲中的所有数据并储存,然后重启 DMA,让 DMA 重新开始接收数据;
- 在 DMA 缓冲满中断时,读取 DMA 缓冲中的所有数据并储存,然后让 DMA 重新开始接收数据。在这里可以使用 DMA 双缓冲,既提高效率,也不用使用程序来复位 DMA 接收缓冲;
使用空闲中断处理数据的时候需要注意,要记录此时 DMA 缓冲中的数据位数,然后作为缓冲的读写指针,下一次 DMA 满中断或者空闲中断时从这个位置开始读取。
裁判系统的有些数据是固定频率发送的,但有些是随机发送的,比如伤害信息这种类型的数据,装甲受到打击后才会发送,而且只发送一次。为了防止有漏接的数据,可以使用队列来储存串口接收到的原始数据。
这个队列是存储串口接收数据的,可以自己实现队列的数据结构,如果是带操作系统的话,也可以使用其中自带的队列结构 api。需要注意的是进行队列读写操作时,队列为空或者满时尽量直接返回,不要阻塞程序。
2.3 数据解析
按照裁判系统的协议格式,如果要解析出有效数据,我们就需要在存储数据的队列中从帧头开始,分别通过帧头、命令码和数据长度、CRC8,以及最终的 CRC16 这些校验之后,才能认为这帧数据是有效的,也就解析出了有效的裁判系统数据。
3、示例代码
在 robomaster 的官方 GitHub 中,有开源的 ICRA 比赛使用的步兵固件,大家可以参考其中的一些代码来实现对裁判系统的数据接收。RoboRTS-Firmware 地址是:https://github.com/RoboMaster/RoboRTS-Firmware
下面是具体功能实现的位置:
请问这篇文章对你有用吗?
【通知帖】裁判系统用户数据读取