NRF24L01模块STM32通信-通信初始化

ops/2025/1/16 1:55:05/

目录

前言

一、IO口初始化

二、模拟SPI的基础代码

1.一些代码的宏定义

2.起始信号

3.CS,SCK,MOSI操作

4.MISO,IRQ操作

三.中间层代码

1.字节的输入和读取

 2.写操作

3.读操作

四.应用层代码

1.24L01的检测

2.在main函数进行简单验证

3.24L01宏定义的代码

总结


前言

环境:

芯片:STM32F103C8T6

Keil:V5.24.2.0

模块:NRF24L01


一、IO口初始化

根据:NRF24L01模块STM32通信-调试前言-CSDN博客

需要初始6个IO:4个输出,2个输入

我初始对应的IO口如下;

//输出
CSN		->PA3
CE		->PA4
MOSI	->PA7
SCK		->PA5	
//输入	
IRQ		->PB1
MISO	->PA6

 IO口初始化,包含了OLED和其他的初始化代码.

void Gpio_Init(void)
{
/* 输出
CSN		->PA3//
CE		->PA4
MOSI	->PA7
SCK		->PA5	输入	
IRQ		->PB1
MISO	->PA6
*/	
//outputRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOC, &GPIO_InitStructure);//inputGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);}

二、模拟SPI的基础代码

1.一些代码的宏定义

#define SPI_CS_PROT			GPIOA	//CS接线引脚通道,	CSN
#define SPI_CS_PIN			GPIO_Pin_3#define SPI_DO_PROT			GPIOA	//D0接线引脚通道,	MOSI
#define SPI_DO_PIN			GPIO_Pin_7#define SPI_SLK_PROT		GPIOA	//CL接线引脚通道,	SCK
#define SPI_SLK_PIN			GPIO_Pin_5#define SPI_DI_PROT			GPIOA	//DI接线引脚通道,	MISO
#define SPI_DI_PIN			GPIO_Pin_6#define SPI_IRQ_PROT		GPIOB	//DI接线引脚通道,	MISO
#define SPI_IRQ_PIN			GPIO_Pin_1#define MYSPI_W_CS(x) 		GPIO_WriteBit(SPI_CS_PROT,SPI_CS_PIN,(BitAction)(x))//对CS线进行操作
#define MYSPI_W_DI(x) 		GPIO_WriteBit(SPI_DI_PROT,SPI_DI_PIN,(BitAction)(x))//对DI线进行操作
#define MYSPI_W_DO(x) 		GPIO_WriteBit(SPI_DO_PROT,SPI_DO_PIN,(BitAction)(x))//对DO线进行操作
#define MYSPI_W_SLK(x) 		GPIO_WriteBit(SPI_SLK_PROT,SPI_SLK_PIN,(BitAction)(x))//对SLK线进行操作
#define NRF24L01_CE(x) 		GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)(x))//对CE线进行操作

2.起始信号

void MySPI_Start(void)
{MYSPI_W_CS(0);		//拉低为开始信号
}void MySPI_Stop(void)
{MYSPI_W_CS(1);		//拉高为结束信号
}

3.CS,SCK,MOSI操作

void MySPI_W_SS(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, SPI_CS_PIN, (BitAction)BitValue);  
}void MySPI_W_SCK(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, SPI_SLK_PIN, (BitAction)BitValue);
}void MySPI_W_MOSI(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, SPI_DO_PIN, (BitAction)BitValue);
}

4.MISO,IRQ操作

uint8_t MySPI_Read_MISO(void)
{return GPIO_ReadInputDataBit(SPI_DI_PROT, SPI_DI_PIN);
}uint8_t MySPI_Read_IRQ(void)
{return GPIO_ReadInputDataBit(SPI_IRQ_PROT, SPI_IRQ_PIN);
}

三.中间层代码

1.字节的输入和读取

uint8_t MySPI_SwapByte(uint8_t ByteSend)	//字节读取和交换
{uint8_t i,ByteReceive = 0x00;for(i = 0;i < 8;i ++){MySPI_W_MOSI(ByteSend & (0x80 >> i));MySPI_W_SCK(1);if (MySPI_Read_MISO() == 1){ByteReceive |= (0x80 >> i);}MySPI_W_SCK(0);}return ByteReceive;
}

 关于这段代码更详细的解说可以观看江科大的视频SPI部分.

 2.写操作

uint8_t NRF24l01_write_buf(uint8_t reg, uint8_t *pbuf, uint8_t len)
{uint8_t status, i;MySPI_Start();					  /* 使能SPI传输 */status = MySPI_SwapByte(reg); /* 发送寄存器值(位置),并读取状态值 */for (i = 0; i < len; i++){MySPI_SwapByte(*pbuf++);  /* 写入数据 */}MySPI_Stop();					 /* 关闭SPI传输 */                return status;                      /* 返回读到的状态值 */}

3.读操作

uint8_t NRF24l01_read_buf(uint8_t reg, uint8_t *pbuf, uint8_t len)
{uint8_t status, i;    MySPI_Start();  /* 使能SPI传输 */status = MySPI_SwapByte(reg);         /* 发送寄存器值(位置),并读取状态值 */for (i = 0; i < len; i++){pbuf[i] = MySPI_SwapByte(0X55);   /* 读出数据 */		} return status;                              /* 返回读到的状态值 */
}

四.应用层代码

1.24L01的检测

/*** @brief       检测24L01是否存在* @param       无* @retval      0, 成功; 1, 失败;*/
uint8_t NRF24l01_check(void)
{uint8_t buf[5] = {0XA5, 0XA5, 0XA5, 0XA5, 0XA5};uint8_t i;NRF24l01_write_buf(NRF_WRITE_REG + TX_ADDR, buf, 5);    /* 写入5个字节的地址. */NRF24l01_read_buf(TX_ADDR, buf, 5);                     /* 读出写入的地址 */for (i = 0; i < 5; i++){if (buf[i] != 0XA5) break;}if (i != 5) return 1;   /* 检测24L01错误 */return 0;               /* 检测到24L01 */
}

 关于其中的一些宏定义,代码放在本文末.

2.在main函数进行简单验证

void MY24L01_Init(void)//对模块和通信线的前期操作
{NRF24L01_CE(0);
MYSPI_W_CS(1);
MYSPI_W_SLK(0);}while(1)
{while (NRF24l01_check())    /* 检查NRF24L01是否在线 */{OLED_ShowString(16, 18, "NRF24l01 NGNGNG", OLED_6X8);OLED_Update();}OLED_ShowString(32, 18, "GOOD", OLED_6X8);OLED_Update();
}

 可以使用OLED进行显示,当然因为结果只有0或1,所以也可以采用其他方式进行验证,如LED的亮灭

如果代码正确则可以进行后面的代码书写.

3.24L01宏定义的代码

/******************************************************************************************/
/* NRF24L01寄存器操作命令 */
#define NRF_READ_REG    0x00    /* 读配置寄存器,低5位为寄存器地址 */
#define NRF_WRITE_REG   0x20    /* 写配置寄存器,低5位为寄存器地址 */
#define RD_RX_PLOAD     0x61    /* 读RX有效数据,1~32字节 */
#define WR_TX_PLOAD     0xA0    /* 写TX有效数据,1~32字节 */
#define FLUSH_TX        0xE1    /* 清除TX FIFO寄存器.发射模式下用 */
#define FLUSH_RX        0xE2    /* 清除RX FIFO寄存器.接收模式下用 */
#define REUSE_TX_PL     0xE3    /* 重新使用上一包数据,CE为高,数据包被不断发送. */
#define NOP             0xFF    /* 空操作,可以用来读状态寄存器 *//* SPI(NRF24L01)寄存器地址 */
#define CONFIG          0x00    /* 配置寄存器地址;bit0:1接收模式,0发射模式;bit1:电选择;bit2:CRC模式;bit3:CRC使能; *//* bit4:中断MAX_RT(达到最大重发次数中断)使能;bit5:中断TX_DS使能;bit6:中断RX_DR使能 */
#define EN_AA           0x01    /* 使能自动应答功能  bit0~5,对应通道0~5 */
#define EN_RXADDR       0x02    /* 接收地址允许,bit0~5,对应通道0~5 */
#define SETUP_AW        0x03    /* 设置地址宽度(所有数据通道):bit1,0:00,3字节;01,4字节;02,5字节; */
#define SETUP_RETR      0x04    /* 建立自动重发;bit3:0,自动重发计数器;bit7:4,自动重发延时 250*x+86us */
#define RF_CH           0x05    /* RF通道,bit6:0,工作通道频率; */
#define RF_SETUP        0x06    /* RF寄存器;bit3:传输速率(0:1Mbps,1:2Mbps);bit2:1,发射功率;bit0:低噪声放大器增益 */
#define STATUS          0x07    /* 状态寄存器;bit0:TX FIFO满标志;bit3:1,接收数据通道号(最大:6);bit4,达到最多次重发 *//* bit5:数据发送完成中断;bit6:接收数据中断; */
#define MAX_TX          0x10    /* 达到最大发送次数中断 */
#define TX_OK           0x20    /* TX发送完成中断 */
#define RX_OK           0x40    /* 接收到数据中断 */#define OBSERVE_TX      0x08    /* 发送检测寄存器,bit7:4,数据包丢失计数器;bit3:0,重发计数器 */
#define CD              0x09    /* 载波检测寄存器,bit0,载波检测; */
#define RX_ADDR_P0      0x0A    /* 数据通道0接收地址,最大长度5个字节,低字节在前 */
#define RX_ADDR_P1      0x0B    /* 数据通道1接收地址,最大长度5个字节,低字节在前 */
#define RX_ADDR_P2      0x0C    /* 数据通道2接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等; */
#define RX_ADDR_P3      0x0D    /* 数据通道3接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等; */
#define RX_ADDR_P4      0x0E    /* 数据通道4接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等; */
#define RX_ADDR_P5      0x0F    /* 数据通道5接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等; */
#define TX_ADDR         0x10    /* 发送地址(低字节在前),ShockBurstTM模式下,RX_ADDR_P0与此地址相等 */
#define RX_PW_P0        0x11    /* 接收数据通道0有效数据宽度(1~32字节),设置为0则非法 */
#define RX_PW_P1        0x12    /* 接收数据通道1有效数据宽度(1~32字节),设置为0则非法 */
#define RX_PW_P2        0x13    /* 接收数据通道2有效数据宽度(1~32字节),设置为0则非法 */
#define RX_PW_P3        0x14    /* 接收数据通道3有效数据宽度(1~32字节),设置为0则非法 */
#define RX_PW_P4        0x15    /* 接收数据通道4有效数据宽度(1~32字节),设置为0则非法 */
#define RX_PW_P5        0x16    /* 接收数据通道5有效数据宽度(1~32字节),设置为0则非法 */
#define NRF_FIFO_STATUS 0x17    /* FIFO状态寄存器;bit0,RX FIFO寄存器空标志;bit1,RX FIFO满标志;bit2,3,保留 *//* bit4,TX FIFO空标志;bit5,TX FIFO满标志;bit6,1,循环发送上一数据包.0,不循环; *//******************************************************************************************/

总结

本文代码并未涉及很多的交互动作,只是验证基础代码和IO口的连接正确.操作相对简单,方便及时对代码进行验证,查缺补漏,方便后面代码的调试


http://www.ppmy.cn/ops/148997.html

相关文章

Nginx安全加固系列:防范XSS

XSS&#xff0c;就是跨站脚本攻击。就是浏览器渲染HTML的过程中&#xff0c;执行了不被预期的脚本指令&#xff0c;XSS就发生了。 所以&#xff0c;XSS就是一种HTML注入攻击&#xff0c;就是在我们的HTML页面上注入了恶意代码。最典型的就是在发表评论这些页面&#xff0c;在发…

C语言:单步调试与即时窗口的使用

1、单步调试 在实际开发中&#xff0c;常常会出现这样的情况&#xff0c;我们可以大致把出现问题的代码锁定在一定范围内&#xff0c;但无法确定到底是哪条语句出现了问题&#xff0c;该怎么办呢&#xff1f;按照前面的思路&#xff0c;必须要在所有代码行前面设置断点&#x…

负载均衡技术【内网去外网运营商出口负载均衡】

1 负载均衡概述 LB&#xff08;Load Balance&#xff0c;负载均衡&#xff09;是一种集群技术&#xff0c;它将特定的业务&#xff08;网络服务、网络流量等&#xff09;分担给多台网络设备&#xff08;包括服务器、防火墙等&#xff09;或多条链路&#xff0c;从而提高了业务…

大麦抢票科技狠活

仅供学习参考&#xff0c;切勿再令您所爱的人耗费高昂的价格去购置黄牛票 ⚠️核心内容参考: 据悉&#xff0c;于购票环节&#xff0c;大麦凭借恶意流量清洗技术&#xff0c;于网络层实时甄别并阻拦凭借自动化手段发起下单请求的流量&#xff0c;强化对刷票脚本、刷票软件以及…

Redis 安装与配置指南

Redis 安装与配置指南 目录 安装说明 Linux 安装 Redis 3.0 压缩包上传服务器编译和安装修改配置启动 Redis关闭 Redis 卸载 RedisRedis 集群配置 Master 主库配置启动 Master 节点的 Redis 和 Sentinel客户登录验证Slave 从库配置查看集群数据验证 安装说明 Linux 安装 R…

Java列表示例

示例1&#xff1a;使用ArrayList创建并操作列表 ArrayList是List接口最常用的实现之一&#xff0c;它内部使用数组来存储元素&#xff0c;因此对于随机访问具有很高的效率。但是&#xff0c;当涉及到频繁的插入或删除操作时&#xff0c;它的性能可能会受到影响&#xff0c;因为…

自动驾驶ADAS算法--测试工程环境搭建

测试环境 1、vs2022社区版本 2、onnx 3、opencv455 测试环境搭建和需要的文件下载 通过网盘分享的文件&#xff1a;附件 链接: https://pan.baidu.com/s/1F79g66nKa1jKoeeuY2Iygg 提取码: xwy8 环境搭建和配置 下载上述的文件并解压&#xff0c;解压后打开工程配置工程…

利用Python爬虫获取API接口:探索数据的力量

引言 在当今数字化时代&#xff0c;数据已成为企业、研究机构和个人获取信息、洞察趋势和做出决策的重要资源。Python爬虫作为一种高效的数据采集工具&#xff0c;能够帮助我们自动化地从互联网上获取大量的数据。而API接口作为数据获取的重要途径之一&#xff0c;为我们提供了…