四轴飞行器1.7 NRF24L01P无线通讯和改进型环形缓冲

原创文章,欢迎转载,转载请注明出处

这次花了10多天了才再次写blog,一是中秋优点小活动,二是这次完成了不少东西。。

终于接近完成了,这次完成了NRF的通讯,并且用了改进的环形缓冲和简单的通讯协议规划

看着做的东西挺少,实际工作量不小。。哈。。我们先要在遥控上写个简易的UI,显示一些数据,然后读取手柄数据,通过NRF传给飞控,看看数据是否正确传输,而且还要解决数据传输中的各种问题,虽然以前用过NRF905,但是NRF24L01是没有用过的,不过大同小异。

1:NRF24L01P模块的使用

2:改进型环形缓冲的实现方法

3:通讯协议

1:NRF24L01P模块

       NRF24L01的资料很多了,就不细说了,怎么配置,看看手册就好了,对了,关于手册,网上很多,中文版的也各种各样,但是最好的还是官方的原版英文的,不会有歧义,很多细节你都能在这个手册上找到。我们使用的是Enhanced ShockBurst模式,可以自动ACK,ACK带payload模式没有使用,是用了ACK模式,因为ACK带payload模式的花,PRX端(接收端)发送数据是被动发送了,只有对方发送数据来了,我们在ACK的包里面将我们要的数据顺带发给对方,如果对方没数据来,我们就无法将ACK里面的payload发过去了,这种只能在某些特定场合。那我们发送数据就需要自己控制NRF转换为TX模式了,发送完数据马上回到RX模式。。各个模式的转化如下图所示,摘自英文原版手册

可以看到TX Mode和RX Mode之间转换需要经过StandBy-1模式,中间需要让CE=0回到StandBy-1模式,然后在通过PRIM位来控制RX和TX模式,再置CE=1,虽然我们直接改变PRIM能到TX模式,但是还是按照手册上面执行比较安全靠谱。

讲到Enhanced ShockBurst下的ACK,不得不再上一张图,图下图:

其实上图的英文部分对于ACK和地址的设置已经比较清楚了哈。。不过我们这里还是稍微说下,PRX接收端收数据有6个通道,但是通道0比较特殊,是用来接收ACK包的数据。

对于这个图我看了下,很多人都有不同的理解。。。不同的理解对TX_ADDR和RX_ADDR的理解会完全不一样。先讲解下上面的图,再讲讲网上的对TX_ADDR、RX_ADDR一两种理解和我们自己的理解。

对于发送端:发送的时候需要设置两个地址,一个是TX_ADDR,还有一个是RX_ADDR_P0,这两个设定程一样的地址,我们假设为地址1,

对于接收端:需要设定一个RX_ADDR,而这个RX_ADDR地址需要和上面设定的地址一样,就是地址1,P0还是P几无所谓,接收端会根据监测到的空中的数据包中的Address和自己的RX_ADDR对比,如果哪个对上了,就会接收数据,空中数据发送的数据格式(可以理解为链路层的数据,物理层就是空气,哈,这样理解不知道对不对)如图:

发送端接收到数据后,会发送ACK数据包,这个数据包发给谁呢?发给地址1,对,这就是为什么发送端需要把RX_ADDR_P0设置为地址1的原因,这个就是用来接收ACK包的,接收到ACK包后,会产生TX_DS中断,通知MCU发送完成。

对这个地址可能会有点混,怎么发送接收都是地址1。。。。。。对,开始我也优点晕。。我们下面来看看对这两个地址的理解

网上的理解:大概意思是信息是在空中传播的,NRF会监测到在频道上的所有信息,NRF的RX_ADDR的意义是要接收的目标的地址,返回的时候也通过这个地址返回ACK,TX_ADDR是自己的地址,标志自己,好像我看到一个理解是这样说的,这怎么说呢,点对点没问题,多对多那就是错误了。。这样理解多对多会发生非常混乱的情况。

我们的理解:TX_ADDR就是目标地址,和TCP/IP里面一样,就是目标的地址,而RX_ADDR就是我自己的地址。会理解混的主要原因在于ACK返回的时候是通过自己的RX_ADDR_P0这个地址返回(我们可以把P0到P5理解为TCP/IP里面的端口,实际上用的时候P1到P5的前四个地址要求是一样的,只有最后一个自己可以改,这样理解为端口也更合情合理)。不是有六个接收地址么,我们用P0不干其他事情,就只用来接收ACK包,用P1来接收数据。这样就好理解了,RX就是本机地址,放在P1里面,TX就是目标地址,放在TX里面和P0里面。

如果需要开通更多的接收地址或者收端口,再开RX_ADDR,每个RX_ADDR给不同的线程处理,不就实现了类似余TCP/IP里面的端口功能了么。

发送端的发送流程这样的,发送数据,然后等待,等待TX_DS或者MAX_TX,TX_DS说明发送完成,并且收到了ACK数据,MAT_TX说明发送了设定的重发次数后还是没有收到ACK包,那就是发送失败了意味着。

接收端当监测到RX_DR信息的时候,说明接受到数据,我们读取数据处理数据就行了。

将上面的都实现了,其实我们的通讯已经完成了, 调用发送命令发送数据,发送完转换到RX模式,等待接收数据,有数据就接收,没有一直等,如果有数据要发送,转换到发送模式发送数据,发送完再转换到RX模式,等待接收数据,如此无限循环下去。

没错,我们的通讯完成了,但是这是极其不稳定不可靠的。一个完整的系统我想通讯也不会做到这里为止的,必须有个高速缓存,为什么要高速缓存?想象一下:当发送数据的频率非常多非常快的时候会出现什么情况,接收端收到RX_DR然后读取信息,然后处理,处理的过程是要时间的,当我们还没处理完,又一个RX_DR来了怎么办,这时候就会丢包,并且如果我们是收到RX_DR然后处理数据,然后再清楚RX_DR标志,这时候就不是丢包问题了,而是直接漏了一个RX_DR信号,也就是说有个包在RX_BUFF里面,我们根本就不知道,就算收到RX_DR立马清掉,然后处理数据,这时候不丢第二个RX_DR,但是第三个第四个RX_DR呢?虽然我们可以在每次RX_DR都判断status寄存器,看RX_BUFF里面有没有数据,有就读出来,全部读出来在清,但是处理时间在那,跟不上的话RX_BUFFER会满(我们用的动态数据长度模式),满了就没办法接收新的数据,发送端就会收到MAX_TX信号,表示数据没有发送成功。。这一切的根源就在于我们收到数据要处理,处理需要时间,当大量的数据高频率的过来的时候,我们无法保证数据处理的速度足够快来保证每个接收到的包能的到即时的响应。这时候要怎么解决?没错,需要一个高速缓存。有了高速缓存就好说了,来了数据就放入缓存,放入缓存不管了,让其他任务去处理,这样能够最大限度的保证处理数据的时间很短,能够尽可能快的响应到来的数据包。下面讲讲缓存的那些事。

2:改进型环形缓冲的实现方法

     看下面之前,可以先看看维基百科上对环形缓冲的讲解:http://zh.wikipedia.org/wiki/環形緩衝區

     我们使用的是环形缓存,这里主要讲讲改进型环形缓冲到底改进了哪些东西

传统环形缓冲一种是字节字节压入的,一种是块数据压入的,块数据就是固定长度的数据,例如每次都压入八个字节。

字节压入型的环形缓存应用在,例如串口。这是数据流方式的输入,来一个字节就写一个字节,来一个字节就写一个字节,读的时候根据头指针和尾指针,从头读到为,碰到尾部调头就是了,是个很简单的环形缓存形式,注意,读数据的时候外面需要一个内存空间来存这些数据,每次读数据,都需要从缓存中将数据复制到一个连续的内存空间去,要复制一次,然后再处理,很多串口都是这样实现的。对,问题处在这,处理的时候需要复制出去,要多复制一次,这就浪费时间了,要怎么处理呢?下面的块字节压入方式的环形缓冲就解决了这个问题。

块数据压入能够很好的解决上面读数据的时候需要复制出来的问题,其实我们需要读数据的时候,只需要返回数据的指针,然后我们去读就可以了,上面需要赋值出来再处理的最根本原因就是,数据存在缓存中没有保证是连续的。例如一个数据包来了,10个字节长,前5个字节存在尾部,后5个字节存在头部,那么如果你返回数据头指针,读到的前5个数据是对的,后5个数据已经越界,读到的不知道什么数据,所以需要读出来到另外内存中(可以理解为我们的变量中或者数组中),读出来后就可以保证数据是连续的,之后才可以处理。而块数据压入方式就不存在这样的问题了,例如我们设定了每次都是压入10个字节,那我们缓冲区的大小设定为10的倍数,这样就绝对不回出现数据一部分在尾部一部分在头部的情况,就可以通过返回数据指针来操作数据了,操作完成后,再POP掉就解决了,这样节省了内存空间,而且还少复制了一次,提升了处理速度,唯一的缺陷就是压入的数据长度必须一样,这个让我们有点小完美主义也可以说有点小强迫症的用起来觉得是非常的不爽。于是我们就自己动工,写两个个可以压入任意,并且读的时候只要返回指针,不需要复制数据的环形缓冲。

改进型环形缓冲:简单的说一下实现的思路,需要实现压入任意长度并且读数据只需要返回指针的环形缓冲需要解决两个问题,一个是你压入任意长度,假如里面有好几个包,你怎么直到读出来怎么读?第一个数据包多长?第二个数据包多长?二就是保证单个数据包在缓存中的数据在内存中是连续存放的。第一个问题:每个数据包的前面我们加一个长度信息,用来标识接下来多长为一个数据包。第二个问题就是我们监测当尾部不能够容下这个数据包的时候,我们就开启跳列模式,跳到头部,从头部再写,这样就可以保证数据在内存中存取是连续的,读取的时候需要判断跳列标志,并且需要直到跳到哪里去了。具体细节就不多说了,大体上实现方式就是这样的。这个也有缺点,就是每个包我都会占用一定的空间用来存取长度信息,然后当最后长度不够放的时候,我会跳到前面去,后面的空间就浪费掉了。这个没有办法。。哈。。有利有弊。。不过这种更通用的环形缓冲方式,我等有小强迫症的还是比较喜欢的。

3:通讯协议

待续。。。明天加上。。

时间: 2024-10-27 13:57:42

四轴飞行器1.7 NRF24L01P无线通讯和改进型环形缓冲的相关文章

四轴飞行器1.3 MPU6050(大端)和M4的FPU开启方法

 原创文章,欢迎转载,转载请注明出处      最近时间花在最多的地方就是STM32的I2C上了.之前就知道STM32的I2C并不好用,因为之前用过模拟的I2C,也写过AVR的I2C也就是TWI的硬件驱动,所以想试试写STM32的硬件I2C...为了避免库带来的麻烦,之前和特意将STM32F4的标准库升级到了1.3.0,但是貌似问题依旧.于是在网上找到了ST转为I2C写的CPAL的库,拿着它的英文手册和例子看了下,觉得很不错,功能相当的齐全,按照手册配置用起来应该不错,于是开始加载到自己的项目中

四轴飞行器1.4 姿态解算和Matlab实时姿态显示

原创文章,欢迎转载,转载请注明出处 MPU6050数据读取出来后,经过一个星期的努力,姿态解算和在matlab上的实时显示姿态终于完成了. 1:完成matlab的串口,并且实时通过波形显示数据 2:添加RTT查看CPU使用率的扩展功能,MPU6050读取数据的优化 3:四元素表示的坐标变化,四元素与欧拉角的关系和Madgwick的IMUupdate算法 4:飞控数据采集线程和数据处理线程的安排,类似于生产者与消费者的关系. 先放个效果视频... 如果看不了视频,请打开视屏网址:http://v.

四轴飞行器飞行原理与双闭环PID控制

四轴轴飞行器是微型飞行器的其中一种,相对于固定翼飞行器,它的方向控制灵活.抗干扰能力强.飞行稳定,能够携带一定的负载和有悬停功能,因此能够很好地进行空中拍摄.监视.侦查等功能,在军事和民用上具备广泛的运用前景. 四轴飞行器关键技术在于控制策略.由于智能控制算法在运行复杂的浮点型运算以及矩阵运算时,微处理器计算能力受限,难以达到飞行控制实时性的要求:而PID控制简单,易于实现,且技术成熟,因此目前主流的控制策略主要是围绕传统的PID控制展开. 1 四轴飞行器的结构与基本飞行原理 四轴飞行器结构主要

四轴飞行器1.2.2 RT-Thread 串口

本来是打算说根据RT-Thread的设备管理提供的驱动接口些串口驱动的,但是仔细一看,我去,串口驱动写好了,只需要调用就可以了.下面我们说说具体怎么使用的.      首先在rt_hw_board_init()函数里面有个rt_hw_usart_init(),这个就是串口初始化的函数了,而且RTT已经写好了三个串口的初始化,只需要修改下宏定义就可以使用,RTT实在用心良苦啊,这都帮我们写好了.      个人的一点看法,可能不是很全面,能力有限.其实我对函数rt_hw_usart_init()的

四轴飞行器设计报告

单片机应用技术实训设计报告(四轴飞行器) 所属系部: 电气信息工程系 班 级: (2014)通信技术1班 姓 名: 彭世秋 指导老师: 施 芸 摘 要 为了满足四轴飞行器的设计要求,设计了以微控制器为核心的控制系统和算法.首先进行了各单元电路方案的比较论证,确定了硬件设计方案.四轴飞行器采用了固连在刚性十字架交叉结构上的4个无刷电机驱动的一种飞行器,以ARM公司的Context-M3 CPU內核为基础,围绕新的Context-M3 CPU內核演化而来的意法半导体公司的STM32F103高容量单片

四轴飞行器1.2.3 STM32F407时钟配置和升级标准库文件

原创文章,欢迎转载,转载请注明出处 这个星期进度比较慢哈,只有周末和晚上下班回来才能做,事件不连续,琐碎的事情又比较多,挺烦的,有多琐碎呢?           1.本人有点小强迫症哈,虽然RTT将文件夹已经分类的很好了,但是在一个项目跟目录下这样放着看起来还是很不舒服的哈,于是强迫症范了,要整理下它.按照以前做项目的习惯,将程序分为四个层次,硬件层,驱动层,系统层和应用层,我们就整理下,对三个文件夹,其中硬件层和驱动层放在BSP文件夹里面,BSP文件里面再分硬件和驱动的文件夹,同时添加一个库文

四轴飞行器1.1 Matlab 姿态显示

四轴飞行器1.1 Matlab 姿态显示 开始做四轴了,一步一步来,东西实在很多,比较杂.先做matlab上位机,主要用来做数据分析,等板子到了可以写飞控的程序了,从底层一层一层开始写..希望能好好的完成它...关于matlab上位机,首先做个姿态显示,然后等板子来了,把板子底层程序写好后,加上matlab的串口接收部分,基本的环境就算搭建好了.... 这个代码写了一天,写到最后出现戏剧性的一幕,实在是太恶心了哈..开始自己的想法就是通过输入pitch roll yaw三个欧拉角,然后在空间中现

四轴飞行器1.2.1 RT-Thread 环境搭建

买的飞控板到了,开始写下位机的程序了,本来打算用UCOS的,因为以前用过,比较熟悉,可以很快上手,不过板子的卖家推荐了RT-Thread,以前虽然有接触过,但是没用过,于是去官网看了下,感觉还不错.其一这是咱们国人写的,其二USOS有的基本任务调度功能它都有了,其三它的GUI貌似原生支持中文(不确定),其四他有很多的附加组件,虽然这些组建大部分在以前做项目的时候都自己完成过,并且我并不怎么喜欢集成度太高的RTOS,但是这次可以尝试看看.还有它有些好的环形buffer,可以用来做串口的缓冲,哈,这

PLC无线通讯方案,支持西门子,三菱,欧姆龙,台达等各品牌PLC

在实际项目中,经常有多台PLC之间需要通讯,距离可能从几十米到几千米,也有的客户需要通过互联网来远距离监控PLC的状态. 在这里介绍一种PLC无线通讯的实现方法,采用巨控GRM200系列PLC专用无线通讯模块,支持通过PPI协议连接西门子S7200 PLC和通过MPI协议连接西门子S7300 /400 PLC, PLC侧都不需要编程,同时巨控PLC专用无线通讯模块还可直接支持的PLC包括三菱 PLC,,欧姆龙PLC,台达PLC,也可以通过modbus通讯连接松下PLC,永宏PLC,施耐德PLC,