当前位置: 首页 > news >正文

51单片机使用NRF24L01进行2.4G无线通信

本文并不打算详细介绍NRF24L01的各个功能寄存器及指令的详细用法,因为网上都可以搜到很多非常详细的教程文档,这里只是介绍一些基本概念、用法以及代码的解释,旨在帮助新手能够快速上手调通快速使用。

基础概念

该模块使用的是SPI协议,SPI协议的具体内容可以参考我的上一篇博文(https://www.chengpei.top/archives/spi-xie-yi-jian-jie),当然不太了解SPI协议的具体内容也没关系,后面的实现代码里已经封装了现成的SPI协议收发数据逻辑。SPI协议只是定义了mcu和NRF24L01模块之间的通信方法,模块的具体使用方法还得看它本身定义的指令以及寄存器的配置。

指令

指令是定义的一些模块可以执行的动作,比如:读寄存器、写寄存器、写数据到空中等等

所有的指令在源码头文件中有定义:

// SPI(nRF24L01) commands
#define READ_REG    0x00  // Define read command to register
#define WRITE_REG   0x20  // Define write command to register
#define RD_RX_PLOAD 0x61  // Define RX payload register address
#define WR_TX_PLOAD 0xA0  // Define TX payload register address
#define FLUSH_TX    0xE1  // Define flush TX register command
#define FLUSH_RX    0xE2  // Define flush RX register command
#define REUSE_TX_PL 0xE3  // Define reuse TX payload register command
#define NOP         0xFF  // Define No Operation, might be used to read status register

寄存器

相当于模块中的配置项,可以通过发送指令及内容修改读取模块中的寄存器值,来完成对模块的功能配置

所有的寄存器地址在源码头文件中有定义:

// SPI(nRF24L01) registers(addresses)
#define CONFIG      0x00  // 'Config' register address
#define EN_AA       0x01  // 'Enable Auto Acknowledgment' register address
#define EN_RXADDR   0x02  // 'Enabled RX addresses' register address
#define SETUP_AW    0x03  // 'Setup address width' register address
#define SETUP_RETR  0x04  // 'Setup Auto. Retrans' register address
#define RF_CH       0x05  // 'RF channel' register address
#define RF_SETUP    0x06  // 'RF setup' register address
#define STATUS      0x07  // 'Status' register address
#define OBSERVE_TX  0x08  // 'Observe TX' register address
#define CD          0x09  // 'Carrier Detect' register address
#define RX_ADDR_P0  0x0A  // 'RX address pipe0' register address
#define RX_ADDR_P1  0x0B  // 'RX address pipe1' register address
#define RX_ADDR_P2  0x0C  // 'RX address pipe2' register address
#define RX_ADDR_P3  0x0D  // 'RX address pipe3' register address
#define RX_ADDR_P4  0x0E  // 'RX address pipe4' register address
#define RX_ADDR_P5  0x0F  // 'RX address pipe5' register address
#define TX_ADDR     0x10  // 'TX address' register address
#define RX_PW_P0    0x11  // 'RX payload width, pipe0' register address
#define RX_PW_P1    0x12  // 'RX payload width, pipe1' register address
#define RX_PW_P2    0x13  // 'RX payload width, pipe2' register address
#define RX_PW_P3    0x14  // 'RX payload width, pipe3' register address
#define RX_PW_P4    0x15  // 'RX payload width, pipe4' register address
#define RX_PW_P5    0x16  // 'RX payload width, pipe5' register address
#define FIFO_STATUS 0x17  // 'FIFO Status Register' register address

引脚定义

模块有8个引脚,定义如下:
CSN:芯片的片选线,CSN 为低电平芯片工作。

SCK:芯片控制的时钟线(SPI 时钟)

MISO:芯片控制数据线(Master input slave output)

MOSI:芯片控制数据线(Master output slave input)

IRQ:中断信号。无线通信过程中 MCU 主要是通过 IRQ 与 NRF24L01 进行通信。

CE: 芯片的模式控制线。 在 CSN 为低的情况下,CE 协同 NRF24L01 的 CONFIG 寄存器共同决定 NRF24L01 的状态(参照 NRF24L01 的状态机)

VCC:供电

GND:接地

前4个引脚是SPI协议的引脚,测试代码是基于51单片机的硬件连接方式

// Define SPI pins
sbit CE   = P1^3;  // Chip Enable pin signal (output)
sbit CSN  = P1^4;  // Slave Select pin, (output to CSN, nRF24L01)
sbit IRQ  = P3^3;  // Interrupt signal, from nRF24L01 (input)
sbit MISO = P1^6;  // Master In, Slave Out pin (input)
sbit MOSI = P1^5;  // Serial Clock pin, (output)
sbit SCK  = P1^7;  // Master Out, Slave In pin (output)

关键函数

SPI读写函数

该函数使用代码模拟的SPI通信协议,传入一个字节,函数会将该字节循环输出到MOSI,并且从MISO读取一个字节返回

uchar SPI_RW(uchar byte)
{uchar i;for(i=0; i<8; i++)          // 循环8次{MOSI = (byte & 0x80);   // byte最高位输出到MOSIbyte <<= 1;             // 低一位移位到最高位SCK = 1;                // 拉高SCK,nRF24L01从MOSI读入1位数据,同时从MISO输出1位数据byte |= MISO;          // 读MISO到byte最低位SCK = 0;               // SCK置低}return(byte);               // 返回读出的一字节
}

写寄存器

该函数是给指定寄存器写入数据,第一个参数是写指令+寄存器地址,第二个参数是一个字节的值

uchar SPI_RW_Reg(uchar reg, uchar value)
{uchar status;CSN = 0;                   // CSN置低,开始传输数据status = SPI_RW(reg);      // 选择寄存器,同时返回状态字SPI_RW(value);             // 然后写数据到该寄存器CSN = 1;                   // CSN拉高,结束数据传输return(status);            // 返回状态寄存器
}

写多个字节到寄存器

其实就是写寄存器函数的多字节版本,通过调用循环调用SPI_RW实现多字节的写入,第一个参数是写指令+寄存器地址,第二个参数是字节数组,第三个参数是写入长度

uchar SPI_Write_Buf(uchar reg, uchar * pBuf, uchar bytes)
{uchar status, i;CSN = 0;                    // CSN置低,开始传输数据status = SPI_RW(reg);       // 选择寄存器,同时返回状态字for(i=0; i<bytes; i++)SPI_RW(pBuf[i]);        // 逐个字节写入nRF24L01CSN = 1;                    // CSN拉高,结束数据传输return(status);             // 返回状态寄存器
}

设置为接收模式

该函数是设置模块为接收模式

void RX_Mode(void)
{CE = 0;SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);  // 接收设备接收通道0使用和发送设备相同的发送地址SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);               // 使能接收通道0自动应答SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);           // 使能接收通道0SPI_RW_Reg(WRITE_REG + RF_CH, 40);                 // NRF24L01使用文档.pdf选择射频通道0x40SPI_RW_Reg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH);  // 接收通道0选择和发送通道相同有效数据宽度SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0f);            // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);              // CRC使能,16位CRC校验,上电,接收模式CE = 1;                                            // 拉高CE启动接收设备
}

设置发送模式

该函数设置模块为发送模式,并且发送数据

void TX_Mode(uchar * BUF)
{CE = 0;SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);     // 写入发送地址SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);  // 为了应答接收设备,接收通道0地址和发送地址相同SPI_Write_Buf(WR_TX_PLOAD, BUF, TX_PLOAD_WIDTH);                  // 写数据包到TX FIFOSPI_RW_Reg(WRITE_REG + EN_AA, 0x01);       // 使能接收通道0自动应答SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);   // 使能接收通道0SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1a);  // 自动重发延时等待250us+86us,自动重发10次SPI_RW_Reg(WRITE_REG + RF_CH, 40);         // 选择射频通道0x40SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0f);    // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);      // CRC使能,16位CRC校验,上电CE = 1;
}

设置接收/发送模式的流程也可以参考下模块的使用文档的七八两页,文档可以去我的博客页下载:https://www.chengpei.top/archives/51-nrf24l01

完整的示例代码主要逻辑是初始化,设置为接收模式,循环读状态寄存器判断是否可读,读出数据到读缓冲区,如果按钮P3^5被按下,则设置发送模式发送0x31,然后切回接收模式,如果你有两套51单片机加NRF24L01可以烧录进去进行读写测试

完整代码:https://github.com/chengpei/2.4g-51-test

相关文章:

51单片机使用NRF24L01进行2.4G无线通信

本文并不打算详细介绍NRF24L01的各个功能寄存器及指令的详细用法&#xff0c;因为网上都可以搜到很多非常详细的教程文档&#xff0c;这里只是介绍一些基本概念、用法以及代码的解释&#xff0c;旨在帮助新手能够快速上手调通快速使用。 基础概念 该模块使用的是SPI协议&…...

HelloMeme 上手即用教程

HelloMeme是一个集成空间编织注意力的扩散模型&#xff0c;用于生成高保真图像和视频。它提供了一个代码库&#xff0c;包含实验代码和预训练模型&#xff0c;支持PyTorch和FFmpeg。用户可以通过简单的命令行操作来生成图像和视频。 本文将详细介绍&#xff0c;如何在GPU算力租…...

自定义call方法和apply方法

自定义call方法 //Fn:要执行的函数&#xff0c;obj&#xff1a;函数中this的指向&#xff0c;args:剩余参数function call(Fn, obj, ...args) {//判断if (obj undefined || obj null) {obj globalThis; //全局对象 globalThis&#xff1a;es11新增的特性&#xff0c;用来指向…...

typescript中为js文件提供类型声明

案例&#xff1a;为JS文件提供类型声明 场景描述 假设我们有一个JavaScript文件 utils.js&#xff0c;其中包含一些实用工具函数和变量。为了在TypeScript中使用这些函数和变量并获得类型提示&#xff0c;我们可以使用 declare 关键词为它们提供类型声明。 1. 创建 JavaScri…...

ETH挖矿显卡超频信息汇总

NVIDIA 显卡 显卡型号 核心频率增减量 内存频率增减量 功耗墙(W) 预估算力(ethash算法) RTX 3090-3001000285W / 80%120 MH/sRTX 3080-150900220W / 68%98 MH/sRTX 3070-5001100130W / 60%60 MH/sRTX 3060 Ti-5001200130W / 65%60 MH/sRTX 2080 Ti-2001100150W /…...

调用 Xinference OpenAI接口时报错 Model not found in the model list, uid

错误如下, 请不要被错误吓住或蒙蔽双眼, 自己看最下面的报错内容 Traceback (most recent call last): File "C:\Users\HW\.conda\envs\aibot\Lib\site-packages\starlette\responses.py", line 259, in __call__ await wrap(partial(self.listen_for_disconn…...

一文说清:C静态库与动态库的区别

一 前言 大家在用C语言编程时&#xff0c;一定会遇到各种库&#xff0c;它们为开发者提供了大量的预编译函数和数据结构&#xff0c;从而极大地提高了软件开发的效率。 在C语言中&#xff0c;库主要分为两种类型&#xff1a; 静态库&#xff08;Static Library&#xff09;&…...

Mysql 5.7.6以上版本怎样关闭GTID(由GTID改为基于file,position方式)

平时不建议关闭GTID&#xff0c;假如开启GTID遇到问题&#xff0c;需要回退到基于file,position方式&#xff0c;则可以执行如下步骤&#xff1a; 1.在从库停止主从复制&#xff1a; STOP SLAVE; CHANGE MASTER TO MASTER_AUTO_POSITION 0; START SLAVE; SHOW SLAVE STAT…...

MATLAB常见数学运算函数

MATLAB中含有许多有用的函数,可以随时调用。 a b s abs abs函数 a b s abs abs函数在MATLAB中可以求绝对值,也可以求复数的模长:c e i l ceil ceil函数 向正无穷四舍五入(如果有小数,就向正方向进一)f l o o r floor floor函数 向负无穷四舍五入(如果有小数,就向负方向…...

设置Fusion360 - Prusa slicer -octoprint 一键打印流程

此流程可以直接从fusion360导出文件到prusa slicer切片&#xff0c;切片后可以一键上传并开始打印。以下操作在MacOS中进行&#xff0c;Windows也可以参考。 Fusion360中点击文件-3D打印 弹出对话框中点击应用程序&#xff0c;并在从我的计算机选择中选取Prusa Slicer的可执行…...

IO流实用案例:用字节流--输入流(Inpustream)、输出流(OutputStream)写一个拷贝图片的案例--超简单!

案例背景&#xff1a; 我的电脑桌面有一张白敬亭的照片&#xff0c;我们需要把这张照片拷贝到我的电脑D:\学习软件\copyBJT目录下&#xff0c;当前我们这个目录是没有东西的。 代码演示以及注释&#xff1a; ublic class StreamCopy {public static void main(String[] args)…...

Tensorflow基本概念

简介&#xff1a;本文从Graph讲到Session&#xff0c;同时讲解了tf.constant创建tensor的用法和variable需要初始化的知识点&#xff0c;可以给你打好一个学习Tensorflow的基础。本文都是基于TensorFlow1.14.0的版本下运行。 本专栏将会系统的讲解TensorFlow在1.14.0版本下的各…...

游戏引擎学习第九天

视频参考:https://www.bilibili.com/video/BV1ouUPYAErK/ 修改之前的方波数据&#xff0c;改播放正弦波 下面主要讲关于浮点数 1. char&#xff08;字符类型&#xff09; 大小&#xff1a;1 字节&#xff08;8 位&#xff09;表示方式&#xff1a;char 存储的是一个字符的 A…...

CondaError: Run ‘conda init‘ before ‘conda activate‘解决办法

已经执行了conda init&#xff0c;但是还是会报错CondaError: Run ‘conda init’ before ‘conda activate’ 原因&#xff1a;权限不够 解决办法&#xff1a;以管理员身份运行cmd&#xff0c;然后进入要操作的文件夹下&#xff0c;重新执行 conda init 和 conda activate 就可…...

如何提高谷歌浏览器的稳定性

谷歌浏览器是全球使用最广泛的网络浏览器之一&#xff0c;以其速度和易用性著称。然而&#xff0c;随着时间的推移&#xff0c;用户可能会遇到一些稳定性问题&#xff0c;比如页面加载缓慢、崩溃或意外关闭等。本文将提供一些实用的技巧来帮助你提高谷歌浏览器的稳定性&#xf…...

Spring基础之——控制反转(IOC)、依赖注入(DI)与切面编程(AOP)概念详解(适合小白,初学者必看)

前言 本篇博客讲详细介绍Spring框架中的两个最核心且最基础的概念&#xff1a;控制反转&#xff08;IOC&#xff09;和面向切面编程&#xff08;AOP&#xff09;。以及如何通过IDEA来构建一个Spring项目&#xff0c;通过实战和理论结合的方式来让大家真的学会Spring这个最流行的…...

java排序算法汇总

一、排序算法我介绍 1.1、介绍 排序也称排序算法(Sort Algorithm)&#xff0c;排序是将一组数据&#xff0c;依指定的顺序进行排列的过程。 1.2、排序的分类&#xff1a; 1) 内部排序&#xff1a;指将需要处理的所有数据都加载到内部存储器中进行排序。 2) 外部排序法&…...

游戏引擎中LOD渲染技术

一.LOD(Level Of Detail) 为了降低GPU渲染压力,根据摄像机距离模型距离将面数较高的模型替换为面数较低的模型. LOD LOD0(distance<10) LOD1(distance<20) LOD2(distance<30) 故通常引擎中MetaMesh是由一个或多个LOD模型构成. MetaMesh mesh mesh.lod1 mesh.lod…...

【MacOS开发环境配置与应用开发--详细教程】

在macOS上进行应用开发&#xff0c;通常使用Xcode作为主要开发环境&#xff0c;Xcode集成了所有必需的工具和资源&#xff0c;支持多种编程语言&#xff0c;如Swift、Objective-C、C等。 MacOS开发环境配置与应用开发 1. 安装Xcode1.1 安装方法1.2 验证安装1.3 配置命令行工具…...

【回溯法】——组合总数

回溯核心思想 回溯算法的关键在于&#xff1a;不合适就退回到上一步具体的&#xff1a;通过枚举法&#xff0c;对所有可能性进行遍历&#xff0c;枚举顺序是一条路走到黑&#xff0c;走到头满足条件后&#xff0c;退一步&#xff0c;再尝试之前没走过的路&#xff0c;直到所有…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...