基于无人机边沿相关 ------- IBUS、SBUS协议和PPM信号

文章目录

  • 一、IBUS协议
  • 二、SBUS协议
  • 三、PPM信号


一、IBUS协议

IBUS(Intelligent Bus)是一种用于电子设备之间通信的协议,采用串行通信方式,允许多设备通过单一数据线通信,较低延迟,支持多主机和从机结构,常用于遥控器与天空端之间,富斯官网已公开协议,协议格式如下可见:
在这里插入图片描述
一共32字节,2 字节帧头+28字节数据位 + 2字节校验位组成

解码如下:

#define IBUS_USER_CHANNELS		10		
#define IBUS_LENGTH				0x20	
#define IBUS_COMMAND40			0x40	
#define IBUS_MAX_CHANNLES		14uint8_t rx_buffer[32] = {0};
uint16_t channel[IBUS_USER_CHANNELS] = {0};
uint16_t checksum_cal, checksum_ibus;void IBUS_READ_CHANNEL(uint8_t user_channels)
{uint16_t channel_buffer[IBUS_MAX_CHANNLES] = {0};if(rx_buffer[0] == IBUS_LENGTH && rx_buffer[1] == IBUS_COMMAND40){checksum_cal = 0xffff - rx_buffer[0] - rx_buffer[1];for(int i = 0; i < IBUS_MAX_CHANNLES; i++){channel_buffer[i] = (uint16_t)(rx_buffer[i * 2 + 3] << 8 | rx_buffer[i * 2 + 2]);checksum_cal = checksum_cal - rx_buffer[i * 2 + 3] - rx_buffer[i * 2 + 2];}checksum_ibus = rx_buffer[31] << 8 | rx_buffer[30];if(checksum_cal == checksum_ibus){for(int j = 0; j < user_channels; j++){channel[j] = channel_buffer[j];}}}HAL_UART_Receive_IT(IBUS_UART, rx_buffer, 32);
}

二、SBUS协议

SBUS(Serial Bus)也是一种用于遥控模型、无人机和其他应用程序中的串行通信协议,特别是在飞控系统和遥控设备之间,以实现高效的数据传输。

采用串行通信,单线信号传输,支持最多16个通道的控制,实时性强,可反向兼容PWM,设计考虑冗余性。

协议格式共有25字节数据,由首部(1字节)+ 数据(22字节)+ 标志位(1字节)+ 结束符(1字节)组成

  • 帧头: 0x0F
  • 数据: 22 字节的数据,分别代表16个通道的数据,也即是每个通道的值用了 11 位来表示,22x8/16 = 11,每个通道的取值范围为 0~2047,低位在前、高位在后
  • 标志位: 1字节,高四位从高到低依次表示:
    bit7:CH17数字通道
    bit6:CH16数字通道
    bit5:帧丢失(Frame lost)
    bit4:安全保护(Failsafe):失控保护激活位(0x10)判断飞机是否失控
    bit3~bit0:低四位不用
  • 结束符: 0x00

通道解析:
在这里插入图片描述
解码如下:

#define USART_BUF_SIZE      8       
#define SBUS_DATA_SIZE      25      
struct SBUS_t{uint8_t head;                   // 1字节帧头uint16_t ch[16];                // 16个通道数据uint8_t flag;                   // 1字节标志位uint8_t end;                    // 1字节结束
};uint8_t usart_buf[USART_BUF_SIZE];
uint8_t sbus_rx_head = 0;               // 发现起始字节 0x0F
uint8_t sbus_rx_sta = 0;                // sbus 接收状态,0:未完成,1:已完成一帧接收
uint8_t sbus_rx_index;                  // 接收字节计数
uint8_t sbus_rx_buf[SBUS_DATA_SIZE];    // 接收sbus数据缓冲区struct SBUS_t sbus;                     // SBUS 结构体实例化void USART2_IRQHandler(void)                                            //中断函数
{uint8_t chr;if ((__HAL_UART_GET_FLAG(&UART2_Handler, UART_FLAG_RXNE) != RESET)) // 接收中断{HAL_UART_Receive(&UART2_Handler, &chr, 1, 1000);                // 接收一个字符if (sbus_rx_sta == 0)                                           // 接收未完成{if ((chr == 0x0F) || sbus_rx_head)                          // 找到首字节或已经找到首字节{sbus_rx_head = 1;                                       // 标明已经找到首字母if (sbus_rx_index < SBUS_DATA_SIZE)                     // 未接收到25个字符{sbus_rx_buf[sbus_rx_index] = chr;                   // 不断接收sbus_rx_index ++;}else                                                    // 接收到25个字符了{sbus_rx_sta = 1;                                    // 接收完成sbus_rx_head = 0;                                   // 清零,准备下一次接收sbus_rx_index = 0;}}}}HAL_UART_IRQHandler(&UART2_Handler);
}/* 对SBUS协议数据进行解析                                                      */
/* 实现对S.BUS协议缓存,头部为 0x0F,结尾为 0x00, 中间22Bytes16通道数据,1Byte标志符 */
void SbusParseTask(void *arg)
{while (1){if(sbus_rx_sta==1)                          // 接收完一帧{NVIC_DisableIRQ(USART2_IRQn);           // 要关闭中断,防止读写混乱sbus.head = sbus_rx_buf[0];             // 首部sbus.flag = sbus_rx_buf[23];            // 标志符sbus.end  = sbus_rx_buf[24];            // 结尾sbus.ch[0] =((sbus_rx_buf[2]<<8)  + (sbus_rx_buf[1])) & 0x07ff;          sbus.ch[1] =((sbus_rx_buf[3]<<5)  + (sbus_rx_buf[2]>>3)) & 0x07ff;sbus.ch[2] =((sbus_rx_buf[5]<<10) + (sbus_rx_buf[4]<<2) + (sbus_rx_buf[3]>>6)) & 0x07ff;sbus.ch[3] =((sbus_rx_buf[6]<<7)  + (sbus_rx_buf[5]>>1)) & 0x07ff;sbus.ch[4] =((sbus_rx_buf[7]<<4)  + (sbus_rx_buf[6]>>4)) & 0x07ff;sbus.ch[5] =((sbus_rx_buf[9]<<9)  + (sbus_rx_buf[8]<<1) + (sbus_rx_buf[7]>>7)) & 0x07ff;  sbus.ch[6] =((sbus_rx_buf[10]<<6) + (sbus_rx_buf[9]>>2)) & 0x07ff;sbus.ch[7] =((sbus_rx_buf[11]<<3) + (sbus_rx_buf[10]>>5)) & 0x07ff;sbus.ch[8] =((sbus_rx_buf[13]<<8)  + sbus_rx_buf[12]) & 0x07ff;sbus.ch[9] =((sbus_rx_buf[14]<<5)  + (sbus_rx_buf[13]>>3)) & 0x07ff;sbus.ch[10]=((sbus_rx_buf[16]<<10) + (sbus_rx_buf[15]<<2) + (sbus_rx_buf[14]>>6)) & 0x07ff;sbus.ch[11]=((sbus_rx_buf[17]<<7)  + (sbus_rx_buf[16]>>1)) & 0x07ff;sbus.ch[12]=((sbus_rx_buf[18]<<4)  + (sbus_rx_buf[17]>>4)) & 0x07ff;sbus.ch[13]=((sbus_rx_buf[20]<<9)  + (sbus_rx_buf[19]<<1) + (sbus_rx_buf[18]>>7)) & 0x07ff;sbus.ch[14]=((sbus_rx_buf[21]<<6) + (sbus_rx_buf[20]>>2)) & 0x07ff;sbus.ch[15]=((sbus_rx_buf[22]<<3) + (sbus_rx_buf[21]>>5)) & 0x07ff;delay_ms(500);                          // 先做完延时再开启中断与下一次捕获,否则延时期间中断到来,没有达到预期效果NVIC_EnableIRQ(USART2_IRQn);            // 打开串口中断sbus_rx_sta = 0;                        // 准备下一次接收   }else{delay_ms(500);                          // 免得异常时,到此处使得低优先级任务无法执行}}
}

三、PPM信号

PPM(Pulse Position Modulation,脉冲位置调制)信号是一种用于传输控制信号的调制方式,尤其在遥控系统中非常常见。PPM信号通过改变脉冲在时间上的位置来代表不同的信息,在遥控模型、无人机和一些工业控制系统中被广泛应用。

采用串行通信,信号频率只有50Hz,略逊于ibus和sbus,对于一些高精度仪器不可用。

这里提一下,PWM表示脉冲宽度调制,也就是高电平维持的时间,而PPM实质上就是将多个通道的PWM放到“一根线”上进行传输,一个完整的PPM信号帧包含了多个通道的PWM值。
在这里插入图片描述
PPM信号一帧数据分为低电平(0.5ms)+高电平(0.5ms-1.5ms),高电平长度与PWM占空比成正比。因为一帧信号最多要2ms,信号周期为20ms,所以理论一次PPM信号可以发送10帧数据,但是由于要确定帧头信号,所以要加入同步帧,真正的PPM信号里面最多有9帧数据帧。

解析方式:①外部中断 ②定时器输入捕获

考虑安全条件下,建议使用定时器输入捕获方式进行解码,具体解码参考如下:

uint16_t PPM_Sample_Cnt=0;
uint32_t PPM_Time=0;
uint16_t PPM_Okay=0;
uint16_t PPM_Databuf[8]={0};   //PPM信号存储
uint8_t TIM2_CH2_CAPTURE_STA=0;void TIM2_IRQHandler(void)
{if(TIM_GetITStatus(TIM2,TIM_IT_CC2)==!RESET)//捕获中断{if(TIM2_CH2_CAPTURE_STA&0x01)//符合条件的话说明上次捕获了高电平,那么这次捕获的一定是低电平{PPM_Time=TIM_GetCapture2(TIM2);if(PPM_Time>0)PPM_Time++;			if(PPM_Okay==1){PPM_Databuf[PPM_Sample_Cnt]=PPM_Time;PPM_Sample_Cnt++;if(PPM_Sample_Cnt>8)PPM_Okay=0;}if(PPM_Time>7000)//识别到帧尾{PPM_Okay=1;PPM_Sample_Cnt=0;}    TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);TIM2_CH2_CAPTURE_STA=0;//清掉标志位准备开始下一次上升沿和下降沿检测}else{TIM_SetCounter(TIM2,0);//以上为清零            TIM2_CH2_CAPTURE_STA|=0x01;//高电平指示被赋值TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //当捕获上升沿后改为捕获下降沿}        }TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位,一定不要忘,要不然下次进不了中断    
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/52409.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot集成kafka-监听器注解

SpringBoot集成kafka-监听器注解 1、application.yml2、生产者3、消费者4、测试类5、测试 1、application.yml #自定义配置 kafka:topic:name: helloTopicconsumer:group: helloGroup2、生产者 package com.power.producer;import com.power.model.User; import com.power.uti…

C++11详解 (右值引用、可变参数模板、emplace_back、lambda表达式、function、bind)

目录 简介 左值引用与右值引用 左值引用与右值引用是什么 左值引用与右值引用的比较 右值引用的使用场景与C11中STL的新变化 完美转发 新的类功能 可变参数模板 可变参数模板的应用——emplace_back lambda表达式 包装器 function bind 结语 简介 在过往&#xf…

基于vue框架的毕业设计选题系统bqx47(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;学生,指导老师,课题信息,类型,选题信息 开题报告内容 基于Vue框架的毕业设计选题系统 开题报告 一、引言 毕业设计选题是高等教育中极为关键的一环&#xff0c;它不仅关乎学生未来研究的方向与深度&#xff0c;也是培养其创新思维和实…

SSRF漏洞与redis未授权访问的共同利用

1.利用靶场Pikachu来认识SSRF漏洞 1.什么是SSRF SSRF漏洞允许攻击者通过向服务器发起请求来伪造请求。这种漏洞的核心在于攻击者能够控制服务器向任意目标地址发起请求&#xff0c;而这些请求通常是攻击者无法直接从客户端发起的。 简单来说&#xff0c;假设你的网站有一个功能…

rk3568 npu opencv 怎么联系起来

问题&#xff1a; 客户一直再问 关于 3568 npu opencv 的编译内容。 大致了解一些 &#xff0c;这方面的内容。 网上的资料。 也许这个基本上就是他的逻辑了&#xff0c; 首先界面使用QT来写。 然后&#xff0c;使用 opencv 去读取摄像头。 然后拿到一帧图像之后&#xff…

IO进程线程8月26ri

1&#xff0c;思维导图 2&#xff0c;用两个进程分别复制文件的上下两部分到另一个文件 #include<myhead.h> int main(int argc, const char *argv[]) {int fpopen("./1.txt",O_RDONLY);if(fp-1){perror("open");return -1;}int countlseek(fp,0,SE…

电脑U口管理软件分享|U口管理软件哪个好?

电脑U口&#xff08;即USB端口&#xff09;管理软件是保护电脑安全、防止数据泄露和恶意软件入侵的重要工具。 在选择U口管理软件时&#xff0c;需要考虑其功能、易用性、安全性以及是否满足个人或企业的具体需求。以下是一些值得推荐的电脑U口管理软件及其特点&#xff1a; 1…

基本数据类型及命令

String String 是Redis最基本的类型&#xff0c;Redis所有的数据结构都是以唯一的key字符串作为名称&#xff0c;然后通过这个唯一的key值获取相应的value数据。不同的类型的数据结构差异就在于value的结构不同。 String类型是二进制安全的。意思是string可以包含任何数据&…

Linux:Linux线程池

目录 线程池的概念 线程池的优点 线程池的应用场景 线程池的实现 线程池演示 线程池的概念 线程池是一种线程使用模式。 线程过多会带来调度开销&#xff0c;进而影响缓存局部和整体性能&#xff0c;而线程池维护着多个线程&#xff0c;等待着监督管理者分配可并发执行的…

每日OJ_牛客_剪花布条(string内置函数)

目录 牛客_剪花布条&#xff08;string内置函数&#xff09; 解析代码 牛客_剪花布条&#xff08;string内置函数&#xff09; 剪花布条__牛客网 解析代码 题意就是在S串中&#xff0c;T串整体出现了多少次。C语言可以通过strstr函数找&#xff0c;用STL的string库可以通过f…

mysql练习5

数据准备 创建两张表:部门(dept)和员工(emp)&#xff0c;并插入数据&#xff0c;代码如下 create table dept( dept id int primary key auto increment comment部门编号, dept_name char(20)comment部门名称 ); insert into d…

排序1

一、概述 直接插入排序 是稳定排序 二、插入排序 1&#xff09;直接插入排序 2&#xff09;折半插入排序 3)希尔排序 、 三、交换排序 1&#xff09;冒泡排序 2&#xff09;快速排序

Redis计数器:数字的秘密

文章目录 Redis计数器incr 指令用户计数统计用户统计信息查询缓存一致性 小结 技术派项目源码地址 : Gitee :技术派 - https://gitee.com/itwanger/paicodingGithub :技术派 - https://github.com/itwanger/paicoding 用户的相关统计信息 文章数&#xff0c;文章总阅读数&am…

绿洲乐队重组?加拉格尔兄弟重组音乐会的猜测越来越多

据报道&#xff0c;这支英国传奇摇滚乐队计划于 2025 年夏天在曼彻斯特和伦敦举办一系列大型演出。 加拉格尔兄弟终于和解了吗&#xff1f;越来越多的猜测认为&#xff0c;利亚姆和诺埃尔已经放下他们之间的传奇分歧&#xff0c;重新组建绿洲乐队&#xff0c;并举办一场必定是几…

6.Linux_服务器搭建

TFTP服务器 1、概述 什么是TFTP服务器&#xff1a; TFTP&#xff08;Trivial File Transfer Protocol&#xff09;即简单文件传输协议是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议&#xff0c;提供不复杂、开销不大的文件传输服务。端口号为69 介…

编程示例:汉字生成盲文的翻译器

1 翻译器的意义 我国有视障人士2000多万人&#xff0c;需要把大量的文章与书籍转换成盲文书。 2 翻译器的开发原理 根据汉语与盲文符号的对照表&#xff0c;以此为基础&#xff0c;进行汉字与盲文之间的转换。 如下的两个图片是汉语与盲文符号的对照表。 3 翻译器的开发示例…

【计算机网络】mini HTTP服务器框架与代码

注注注&#xff1a;本篇博文都是代码实现细节&#xff0c;但不会进行演示&#xff0c;演示看孪生篇 另外&#xff0c;由于tcp套接字部分本质都是套路&#xff0c;所以就不再进行赘述。 目录 1 请求反序列化2 读取url文件内容3 构建响应 1 请求反序列化 我们肯定会先收到请求&…

HandBrakeCLI 压缩工具的简单实用

HandBrakeCLI -i input.mp4 -o output.mp4 --encoder qsv_h264 -b 500k --preset "Android 576p25" --width 320 --height 576 --quiet--encoder qsv_h264 意思代表inter的gpu编码 -b 500k 设置比特率 --preset "Android 576p25" 设置预设 --width 320 --…

MySQL索引失效的场景

创建一个名为test_db的数据库&#xff0c;并在其中创建一个名为test_table的表。该表包含多个字段&#xff0c;并在某些字段上创建索引。 CREATE DATABASE IF NOT EXISTS test_db;USE test_db;CREATE TABLE IF NOT EXISTS test_table (id INT PRIMARY KEY AUTO_INCREMENT,name…

什么样的条件才会造就这样疯狂的末日期权?

今天带你了解什么样的条件才会造就这样疯狂的末日期权&#xff1f;末日期权一般是指期权合约快到期的一周或者最后三天&#xff0c;当然最后一天就是末日期权的疯狂。 末日期权是指那些接近到期日的期权。 由于剩余时间较短&#xff0c;这些期权的时间价值通常非常低&#xf…