CRSF 协议 RC 通道接收解析模块设计

CRSF 协议 RC 通道数据接收解析模块详细设计文档

文档信息

项目 内容
设计目标 指导实现 CRSF 协议 0x16 类型帧解析,输出 16 路 RC 通道数值
协议依据 CRSF Protocol Rev07
适用场景 无人机飞控 / 遥控设备的 CRSF RC 数据接收解析

一、文档概述

1.1 设计目标

本文档定义 CRSF 协议中0x16类型帧(RC通道打包数据)的接收解析模块设计逻辑,需实现以下核心目标:

  1. 遵循 CRSF 协议 Rev07 的 RC 通道数据打包规则,将 22 字节负载解析为 16 个 11 位的 RC 通道数值;

  2. 提供标准化的宏定义、数据结构和函数接口,保障代码可维护性;

  3. 适配中断接收场景,确保数据读取的实时性和准确性;

  4. 具备基础的容错能力(如帧长度校验),过滤无效数据。

1.2 核心约束

  1. 协议约束:严格遵循 CRSF 0x16 帧结构(总长度 26 字节,负载 22 字节,16 通道 ×11 位);

  2. 硬件约束:适配 UART 中断接收场景,数据读取需避免编译器优化;

  3. 数值约束:RC 通道数值业务范围为 191~1792(原生协议 0~2047,业务层裁剪)。

二、需求分析

2.1 功能需求

需求 ID 需求描述 优先级
F01 定义 CRSF RC 通道相关常量(帧长度、数值范围)
F02 定义 16 路 RC 通道索引枚举,提升代码可读性
F03 声明 / 初始化全局 RC 通道数值数组
F04 实现 0x16 帧解析函数,提取 16 路 RC 通道值
F05 预留 0x14 帧处理接口,便于扩展
F06 帧长度校验,过滤无效 0x16 帧

2.2 性能需求

  1. 解析效率:单帧解析耗时≤10μs(适配 4ms / 帧的 RC 数据更新率);

  2. 数据准确性:解析后的 RC 通道值与协议打包值完全一致;

  3. 中断安全:全局数据在中断 / 主循环交互时无数据不一致问题。

三、总体设计

3.1 模块架构

模块分为 “定义层” 和 “实现层”,分层设计如下:

┌─────────────────┐  头文件(crsf_RecvPro.h)

│  宏定义         │  - CRSF协议常量、RC数值范围

│  枚举定义       │  - 16通道索引枚举

│  全局变量声明   │  - RC通道数值数组声明

│  函数声明       │  - 0x14/0x16帧处理函数声明

└─────────────────┘

      ↓

┌─────────────────┐  源文件(crsf_RecvPro.c)

│  全局变量初始化 │  - RC数组默认值(中位值)

│  函数实现       │  - 0x16帧解析核心逻辑

│                 │  - 0x14帧预留空实现

└─────────────────┘

3.2 数据流程

UART中断接收CRSF帧 → 判断帧类型为0x16 → 调用0x16解析函数 → 帧长度校验 → 负载字节拼接为位流 → 按11位拆分通道值 → 存储到全局数组 → 主循环读取数组使用

四、详细设计

4.1 宏定义设计

4.1.1 设计思路

基于 CRSF 协议规则和业务需求,定义以下核心宏,需满足 “可读性 + 可维护性”,避免硬编码。

4.1.2 具体宏定义

宏名 设计值 设计依据 代码实现示例
CRSF_PAYLOAD_SIZE_RC_CHANNELS 22 CRSF 协议:16 通道 ×11 位 = 176 位 = 22 字节 #define CRSF_PAYLOAD_SIZE_RC_CHANNELS 22
CRSF_MAX_CHANNEL 16 CRSF 协议标准 RC 通道数 #define CRSF_MAX_CHANNEL 16
CRSF_0X16_FRAME_SIZE 26 0x16 帧总长度 = 同步字节 1 + 长度 1 + 类型 1 + 负载 22+CRC1 #define CRSF_0X16_FRAME_SIZE 26
CRSF_RC_MIN_VALUE 191 业务层裁剪:原生 0~2047,取 191 作为最小有效值 #define CRSF_RC_MIN_VALUE 191
CRSF_RC_MAX_VALUE 1792 业务层裁剪:原生 0~2047,取 1792 作为最大有效值 #define CRSF_RC_MAX_VALUE 1792
CRSF_RC_MID_VALUE (191+1792)/2 通道中位值(摇杆居中时的默认值) #define CRSF_RC_MID_VALUE ((CRSF_RC_MAX_VALUE + CRSF_RC_MIN_VALUE) / 2)
CRSF_RC_VALUE_SCALE 1792-191 通道有效行程范围(用于后续量程转换) #define CRSF_RC_VALUE_SCALE (CRSF_RC_MAX_VALUE - CRSF_RC_MIN_VALUE)

4.2 枚举设计

4.2.1 设计思路

将 16 路 RC 通道编号(1~16)映射为数组索引(0~15),提升代码可读性(如RC_CHANNELS_5直接对应第 5 通道)。

4.2.2 代码实现示例

enum

{

      RC_CHANNELS_1 = 0,  // 通道1 → 数组索引0

      RC_CHANNELS_2,      // 通道2 → 数组索引1

      RC_CHANNELS_3,

      RC_CHANNELS_4,

      RC_CHANNELS_5,

      RC_CHANNELS_6,

      RC_CHANNELS_7,

      RC_CHANNELS_8,

      RC_CHANNELS_9,

      RC_CHANNELS_10,

      RC_CHANNELS_11,

      RC_CHANNELS_12,

      RC_CHANNELS_13,

      RC_CHANNELS_14,

      RC_CHANNELS_15,

      RC_CHANNELS_16,     // 通道16 → 数组索引15

};

4.3 全局变量设计

4.3.1 设计思路

  1. 定义全局数组存储 16 路 RC 通道值,需加volatile修饰(中断中修改,主循环读取,避免编译器优化);

  2. 初始化值为中位值(CRSF_RC_MID_VALUE),避免上电未接收数据时出现无效值。

4.3.2 代码实现示例

// 头文件声明(供外部调用)

extern volatile uint16_t rcChannelValues[CRSF_MAX_CHANNEL];

// 源文件初始化

volatile uint16_t rcChannelValues[CRSF_MAX_CHANNEL]  = {

      CRSF_RC_MID_VALUE,

      CRSF_RC_MID_VALUE,

      // ... 共16个元素,均初始化为中位值

      CRSF_RC_MID_VALUE

};

4.4 函数设计

4.4.1 函数列表

函数名 输入参数 输出参数 功能说明
CRSF_TYPE_0x14_REC ptr:帧数据首地址len:帧长度 预留接口,处理 0x14 类型帧
CRSF_TYPE_0x16_REC ptr:帧数据首地址len:帧长度 解析 0x16 帧,提取 RC 通道值到全局数组

4.4.2 CRSF_TYPE_0x14_REC 设计

  • 设计思路:预留接口,暂不实现逻辑,仅定义函数体;

  • 代码实现示例:

void CRSF_TYPE_0x14_REC(uint8_t *ptr, uint8_t len)

{

      // 空实现,后续扩展0x14帧解析时补充

}

4.4.3 CRSF_TYPE_0x16_REC 设计(核心)

1. 设计思路
步骤 设计逻辑
1 定义局部变量:64 位位缓冲区(存储拼接的字节流)、有效位数计数器、通道索引
2 帧长度校验:仅处理长度为 26 的 0x16 帧,过滤无效数据
3 遍历负载字节:从帧第 3 字节(负载起始位)开始,拼接 22 字节负载为连续位流
4 提取通道值:每累计 11 位,提取低 11 位作为 1 个通道值,存储到全局数组
5 位缓冲区清理:提取后右移 11 位,继续处理剩余位流
2. 关键变量设计
变量名 类型 设计值 设计依据
bitBuffer uint64_t 初始 0 64 位足够容纳拼接的位流(单次最多拼接 2 字节 = 16 位),避免溢出
bitsInBuffer int 初始 0 记录位缓冲区中已拼接的有效位数,用于判断是否可提取 11 位通道值
channelIndex int 初始 0 记录当前解析的通道索引,范围 0~15
3. 核心算法设计(位拼接与提取)

CRSF 协议中,16 个 11 位通道值会被连续拼接为 176 位流,按 8 位 / 字节拆分为 22 字节负载(存储顺序:先低字节后高字节,先低 11 位后高 11 位)。

  • 拼接逻辑:将每个负载字节左移bitsInBuffer位后拼接到bitBuffer,并累加有效位数;

  • 提取逻辑:当有效位数≥11 时,用0x7FF(11 位全 1)掩码提取低 11 位,右移 11 位清理已提取位。

4. 代码实现模板
void CRSF_TYPE_0x16_REC(uint8_t *ptr, uint8_t len)

{

      // 步骤1:定义局部变量

      uint64_t bitBuffer = 0;    // 临时位缓冲区

      int bitsInBuffer = 0;      // 缓冲区有效位数

      int channelIndex = 0;      // 通道索引

      int i;

      // 步骤2:帧长度校验(容错设计)

      if (len != CRSF_0X16_FRAME_SIZE)

      {

              return;

      }

      // 步骤3:遍历22字节负载(帧索引3\~24)

      for (i = 3; i < CRSF_PAYLOAD_SIZE_RC_CHANNELS + 3; ++i)

      {

              // 3.1 拼接当前字节到位缓冲区(低位在前)

              bitBuffer |= (ptr[i]) << bitsInBuffer;

              bitsInBuffer += 8;

              // 3.2 累计≥11位时,提取通道值

              while (bitsInBuffer >= 11 && channelIndex < CRSF_MAX_CHANNEL)

              {

                      // 提取低11位(0x7FF为11位掩码)

                      rcChannelValues[channelIndex] = (bitBuffer & 0x7FF);

                      // 清理已提取的11位

                      bitBuffer >>= 11;

                      bitsInBuffer -= 11;

                      // 解析下一个通道

                      channelIndex++;

              }

      }

}

五、实现步骤(按此步骤编写代码)

步骤 1:创建头文件(crsf_RecvPro.h)

  1. 引入工程核心头文件main.h

  2. 定义 4.1.2 节的所有宏;

  3. 定义 4.2.2 节的通道索引枚举;

  4. 声明全局变量rcChannelValues

  5. 声明CRSF_TYPE_0x14_RECCRSF_TYPE_0x16_REC函数。

步骤 2:创建源文件(crsf_RecvPro.c)

  1. 包含头文件crsf_RecvPro.h

  2. 初始化全局数组rcChannelValues(16 个元素均为CRSF_RC_MID_VALUE);

  3. 实现CRSF_TYPE_0x14_REC空函数;

  4. 按 4.4.3 节的设计实现CRSF_TYPE_0x16_REC函数。

步骤 3:代码验证(关键检查点)

  1. 宏定义数值是否与设计一致;

  2. volatile修饰符是否添加;

  3. 0x16 帧解析中,负载遍历范围是否为i=3i=24

  4. 位提取时是否使用0x7FF掩码;

  5. 通道索引是否限制在 0~15 范围内。

六、测试验证设计

6.1 功能测试

测试项 测试步骤 预期结果
帧长度校验 传入长度≠26 的 0x16 帧,调用解析函数 函数直接返回,全局数组值不变
通道值解析准确性 构造已知负载的 0x16 帧(如通道 1=191,通道 2=1792),调用解析函数 全局数组对应位置值与构造值一致
中位值初始化 上电后未接收任何帧,读取全局数组 所有元素均为CRSF_RC_MID_VALUE(991)

6.2 中断安全测试

测试项 测试步骤 预期结果
中断 / 主循环数据一致性 在 UART 中断中调用解析函数,主循环每秒读取 1000 次全局数组 读取值与中断解析值一致,无数据错乱

七、设计扩展建议

7.1 容错能力扩展

  1. 增加 CRC 校验:解析帧最后 1 字节的 CRC 值(多项式 0xD5),验证帧完整性;

  2. 通道值范围校验:解析后判断值是否在 191~1792 范围内,超出则重置为中位值;

  3. 通道数校验:解析完成后检查channelIndex是否为 16,不足则补中位值。

7.2 功能扩展

  1. 实现CRSF_TYPE_0x14_REC函数,支持 0x14 帧(遥测数据)解析;

  2. 增加 RC 通道值量程转换函数(如将 191~1792 映射为 0~1000);

  3. 增加数据更新标志位,主循环仅在数据更新时读取。

八、设计约束与注意事项

  1. 字节序约束:CRSF 协议为大端序,但 RC 通道负载为连续位流,解析时无需字节序转换;

  2. 中断约束:解析函数需在 UART 接收完成中断中调用,确保帧数据完整;

  3. 性能约束:位操作需简洁,避免嵌套循环过多导致解析耗时超标;

  4. 维护约束:宏定义集中在头文件,后续修改协议参数仅需调整宏值。

posted @ 2025-12-04 13:20  Afangdong  阅读(127)  评论(0)    收藏  举报