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最高位输出到MOSI
       byte <<= 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]);        // 逐个字节写入nRF24L01
    CSN = 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);           // 使能接收通道0
    SPI_RW_Reg(WRITE_REG + RF_CH, 40);                 // NRF24L01使用文档.pdf选择射频通道0x40
    SPI_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 FIFO
    SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);       // 使能接收通道0自动应答
    SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);   // 使能接收通道0
    SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1a);  // 自动重发延时等待250us+86us,自动重发10次
    SPI_RW_Reg(WRITE_REG + RF_CH, 40);         // 选择射频通道0x40
    SPI_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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

地宫取宝(摘花生+最长上升子序列)C++

1212. 地宫取宝 - AcWing题库 #include <iostream>using namespace std;const int N 55; const int MOD 1000000007;int w[N][N],f[N][N][13][14]; int n,m,k;int main() {cin >> n >> m >> k;for (int i 1;i < n;i) {for (int j 1;j < m;j)…

2024 年 8 个最佳 API 设计工具图文介绍

8 个最佳 API 设计工具推荐&#xff0c;包括 Apifox、Postman、Swagger、Insomnia、Stoplight、Hoppscotch、RapidAPI和Paw。 详细介绍&#xff1a;2024 年 8 个最佳 API 设计工具推荐

minio 分布式

方案设计 需要5台服务器&#xff0c;一台nginx用作分发请求&#xff0c;4台minio服务器&#xff0c;每个minio服务器上至少2个盘。在这个方法中&#xff0c;我使用了lvm的缓存&#xff0c;在同种固态盘的情况下&#xff0c;可以使读性能提高数倍到十倍&#xff0c;使写性能提高…

kettle开发-Day43-数据对比

前言&#xff1a; 随着数字化的深入&#xff0c;各种系统及烟囱的建立&#xff0c;各系统之间的架构和数据存储方式不同&#xff0c;导致做数据仓库或数据湖时发现&#xff0c;因自建的系统或者非标准化的系统经常存在物理删除而不是软删除。这就延伸出一个问题&#xff0c;经常…

vscode中执行git合并操作需要输入合并commit信息,打开的nano小型文本编辑器说明-

1.前提&#xff1a; VScode中的git组件执行任何合并动作的时候需要提交远程合并的commit信息&#xff0c;然后编辑器自动打开的是nano文本编辑器 2.nano编辑器说明&#xff1a; 1.保存文件&#xff1a;按 Ctrl O&#xff0c;然后按 Enter 来保存文件。 2.退出编辑器&#xf…

Android音视频直播低延迟探究之:WLAN低延迟模式

Android WLAN低延迟模式 Android WLAN低延迟模式是 Android 10 引入的一种功能&#xff0c;允许对延迟敏感的应用将 Wi-Fi 配置为低延迟模式&#xff0c;以减少网络延迟&#xff0c;启动条件如下&#xff1a; Wi-Fi 已启用且设备可以访问互联网。应用已创建并获得 Wi-Fi 锁&a…

如何详细查询全球药品研发的进度信息?

药品的研发进展对于医药研发人员来说&#xff0c;不仅是知识和技能的积累&#xff0c;更是职业精神和价值观的塑造。通过了解药品的研发进展&#xff0c;研发人员可以更好地提高自己的专业知识和技能&#xff0c;激发创新思维&#xff0c;保持专业竞争力&#xff0c;提高研发效…

摄像机视频分析软件下载LiteAIServer视频智能分析软件抖动检测的技术实现

在现代社会中&#xff0c;视频监控系统扮演着至关重要的角色&#xff0c;其可靠性和有效性在很大程度上取决于视频质量。然而&#xff0c;由于多种因素&#xff0c;如摄像机安装不当、外部环境振动或视频信号传输的不稳定&#xff0c;视频画面常常出现抖动问题&#xff0c;这不…

Jmeter中的监听器(一)

监听器 1--查看结果树 用途 调试测试计划&#xff1a;查看每个请求的详细信息&#xff0c;帮助调试和修正测试计划。分析响应数据&#xff1a;查看服务器返回的响应数据&#xff0c;验证请求是否成功。检查错误&#xff1a;识别和分析请求失败的原因。 配置步骤 添加查看结果…

PaaS云原生:分布式集群中如何构建自动化压测工具

场景 测试环境中&#xff0c;压测常常依赖环境中的各种工具获取基础信息&#xff0c;而这些工具可能集中在某个中控机上&#xff0c;此时想打造的自动化工具的运行模式是&#xff1a; 通过中控机工具获取压测所需的基本信息在中控机部署压测工具&#xff0c;实际压测任务分发…

数据结构-递归函数的调用栈过程

这道题考察的是递归函数的调用栈过程。 逐步分析程序的执行过程&#xff1a; main() 函数首先被调用&#xff0c;此时栈底是 main() 的信息。main() 函数调用 S(1)&#xff0c;此时 S(1) 的信息被压入栈中&#xff0c;位于 main() 之上。S(1) 函数内部调用 S(0)&#xff0c;因…

华为OD机试 - 芯片资源限制(Python/JS/C/C++ 2024 C卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

基于 Python 的 Django 框架开发的电影推荐系统

项目简介&#xff1a;本项目是基于 Python 的 Django 框架开发的电影推荐系统&#xff0c;主要功能包括&#xff1a; 电影信息爬取&#xff1a;获取并更新电影数据。数据展示&#xff1a;提供电影数据的列表展示。推荐系统&#xff1a;基于协同过滤算法实现个性化推荐。用户系…

使用 Web Search 插件扩展 GitHub Copilot 问答

GitHub Copilot 是一个由 GitHub 和 OpenAI 合作开发的人工智能代码提示工具。它可以根据上下文提示代码&#xff0c;还可以回答各种技术相关的问题。但是 Copilot 本身不能回答非技术类型的问题。为了扩展 Copilot 的功能&#xff0c;微软发布了一个名为 Web Search 的插件&am…

Sorting 排序

Goto Data Grid 数据网格 Sorting 排序 Sort Data 对数据进行排序 默认情况下&#xff0c;最终用户可以按任何列对数据进行排序&#xff0c;但具有 MemoExEdit、ImageEdit 和 PictureEdit 就地编辑器的列除外。在运行时&#xff0c;单击列标题一次可对数据进行升序排序。后续…

【笔记】Springboo项目启动失败

application run failed org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name adviceMapper defined in file 原因是mybatisplus和springboot的版本不匹配 修改后&#xff1a; springboot mybatisplus 成功

力扣 LeetCode 242. 有效的字母异位词(Day3:哈希表)

解题思路&#xff1a; 哈希表三种数据结构的选择 1. 数组&#xff1a;适用于数据量小的情况 2. set&#xff1a;适用于数据量大的情况 3. map&#xff1a;适用于key-value 什么时候用哈希表&#xff1f; 给你一个元素&#xff0c;判断该元素在这个集合里是否出现过 本题使…

项目财务管理软件有哪些优势?8款工具解析

本文分享的8款项目财务管理工具包括:1.PingCode&#xff1b;2.Worktile&#xff1b;3.用友U8&#xff1b;4.金蝶K3&#xff1b;5.泛微e-cology&#xff1b;6.明源云&#xff1b;7.Microsoft Project&#xff1b;8.QuickBooks。 在众多项目财务管理工具中挑选合适的一款&#xf…

sqoop import将Oracle数据加载至hive,数据量变少,只能导入一个mapper的数据量

sqoop脚本如下&#xff1a; sqoop import -D mapred.job.queue.namehighway \ -D mapreduce.map.memory.mb4096 \ -D mapreduce.map.java.opts-Xmx3072m \ --connect "jdbc:oracle:thin://1.2.3.4.5:61521/LZY2" \ --username root \ --password 123456 \ --query &…

k8clone二进制工具迁移k8s中的无状态应用

1 概述 k8clone是一个简便的Kubernetes元数据克隆工具&#xff0c;它可以将Kubernetes元数据&#xff08;对象&#xff09;保存为本地压缩包&#xff0c;在恢复时可将这些元数据恢复到目标集群中&#xff08;已存在的资源不会被覆盖&#xff09;。它不依赖远程存储&#xff0c…