STM32模拟SPI控制NRF24L01发送和接收

这篇具有很好参考价值的文章主要介绍了STM32模拟SPI控制NRF24L01发送和接收。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

STM32模拟SPI控制NRF24L01发送和接收

NRF24L01是一款2.4Ghz ISM频段无线收发芯片。NRF24L01模块可视为无需配对和连接型的WIFI或蓝牙模块。NRF24L01可工作于1发6收工作模式。一个NRF24L01模块工作于发送模式时,每次根据设定的接收端地址发送射频信号和数据;一个NRF24L01模块工作于接收模式时,可以接收来自1~6个发送端发来的射频信号和数据,对应内部的6个接收通道(Pipe)进行接收。一个NRF24L01模块可以根据场景进行发送和接收模式切换,从而分时进行发送和接收,此时对应半双工概念。

这里介绍STM32模拟SPI控制NRF24L01发送和接收的范例。市面上的模块也比较丰富:
STM32模拟SPI控制NRF24L01发送和接收

NRF24L01特性

NRF24L01的特性如下所示:
STM32模拟SPI控制NRF24L01发送和接收
NRF24L01可以和STM32供应相同的电压,从而管脚可以直接连接。

NRF24L01管脚连接

NRF24L01芯片的引脚图如下所示,红框选中的是芯片/模块和STM32进行信号连接的部分:
STM32模拟SPI控制NRF24L01发送和接收

STM32模拟SPI控制NRF24L01发送和接收
除了NRF24L01输出给外部MCU的状态中断IRQ(三种典型场景:Tx FIFO 发送完成、Rx FIFO接收到数据、发送达到最大重发次数),NRF24L01比标准SPI还多一个CE信号,在标准SPI的CSN片选信号有效时(低电平),由 CE 和 PWR_UP (CONFIG寄存器第1位)、 PRIM_RX(CONFIG寄存器第0位) 共同决定NRF24L01工作模式:
STM32模拟SPI控制NRF24L01发送和接收
简而言之,PWR_UP设置值为1则芯片正常工作,PWR_UP设置值为0则芯片关电不干活。PRIM_RX设置芯片数据方向即发送还是接收。
在发送模式,如果CE信号一直拉高,则所有的待发送FIFO数据会被发送出去,从而缓冲区清空,而当有新的待发送FIFO数据出现时也会马上被发送滚出去。
在发送模式,如果CE信号以脉冲形式出现,则要求每次脉冲出现的时候CE高电平保持超过10us,则每次CE信号脉冲触发待发送FIFO数据发送一次。
在发送模式,如果CE信号以脉冲形式出现,当待发送FIFO数据已为空时,NRF24L01在CE高电平阶段进入待机状态Standby-II模式,在CE低电平阶段进入待机状态Standby-I模式。
在接收模式,在CE高电平阶段进入接收模式,在CE低电平阶段进入待机状态Standby-I模式。

NRF24L01常规工作模式

NRF24L01采用Enhanced ShockBurst常规工作模式,即经过配置,可以自动进行一些包处理功能,如用于时序同步的同步头(preamble),CRC校验码编码/解码,要求发送回包,接收回包,没有接收到回包时重发等。主要涉及到(发送)包格式的理解:
STM32模拟SPI控制NRF24L01发送和接收
用于信号时序同步的preamble字节,不能出现多个连续的0或1:
STM32模拟SPI控制NRF24L01发送和接收
随地址发送首位是0或者1,而发送不同的同步训练序列。
地址如果出现归零或归一位数多,则出错率上升。如果地址第一个字节和同步训练序列相同也增加出错率。
如果发送为3字节地址,而有两个接收设备,一个地址为3字节,另一个为5字节,而这两个接收设备前3字节地址与发送地址相同,则两个接收设备都会接收到数据,但接收地址为5字节的会取出错误的CRC字节,从而CRC校验失败而丢弃改包。

地址则是3~5个字节,这里解释一下地址,实际上这个地址是接收端的地址,接收端基于收到的这个地址判断是不是发给自己的。那么,包格式里发送端的地址在哪?答案是莫有。因此,当接收端收到发给自己的包,并且发送端要求接收端发送“接收到”的回包时,接收端只能向唯一的这个地址发送回包,当然接收端会错开接收时隙,发送回包时自己不接收,毕竟还是这个地址,不然搞成无限循环了,而发送端通过接收通道0接收回包时,接收通道0的地址也还是这个唯一的地址,这样才能接收到。所以搞来搞去搞复杂后再搞简单,就是作为发送端时:发送地址(接收端地址)和回包接收地址(发送端地址)相同,作为发送端时,回包接收地址应配置在接收通道0。
而作为接收端时,有6个通道可以配置成不同的地址,从而可以接收来自6个不同发送端的数据包。在配置功能方面,通道0可以自由配置地址,而通道1~5高位地址相同,只有尾部1个字节地址不同进行通道区分:
STM32模拟SPI控制NRF24L01发送和接收
STM32模拟SPI控制NRF24L01发送和接收

包控制字段则由如下部分组成:
STM32模拟SPI控制NRF24L01发送和接收
Payload length指定发送的数据字节数
STM32模拟SPI控制NRF24L01发送和接收
PID则是用于是否是重复接收到的包的识别(由于信号多径效应及发送端临界时序自动重发等)
STM32模拟SPI控制NRF24L01发送和接收
当接收端收到数据包时,通过PID进行判断,如果是当前已接收到的包的PID之前的PID,则认为是多径传输的延时无效包从而丢弃。如果是当前已接收到的包的PID之后的PID,则仍为是正常包,CRC校验后接收。如果在异常情况下,丢失了几个包的接收,从而再次收到和已接收的包的PID相同的包,则进行CRC尾值比较,如果相同,则认为接收到的是之前的包,从而丢弃,如果CRC值不同,则认为是新包,从而CRC校验后接收。

通过NO_ACK位设置通知接收端是否发送回复包,而接收端也有设置是否允许发送回复包:
STM32模拟SPI控制NRF24L01发送和接收
Payload是信息数据字节段,可以有0~32个字节。

CRC则是可选8位或16位CRC校验,发送端和接收端设置成同样即可:
STM32模拟SPI控制NRF24L01发送和接收

NRF24L01兼容工作模式

NRF24L01可以工作于兼容模式,以便NRF24L01和其它芯片如nRF2401A, nRF2402,nRF24E1和nRF24E2通讯时采用。简单介绍如下:
STM32模拟SPI控制NRF24L01发送和接收
包格式有不同:
STM32模拟SPI控制NRF24L01发送和接收
STM32模拟SPI控制NRF24L01发送和接收

NRF24L01收发流程

发送模式初始化:
1) CE置低
2) 写Tx模式节点地址(接收端地址)
3) 写Tx模式接收通道0的地址,用于自动应答过程接收回包
4) 使能Tx模式接收通道0的自动应答
5) 使能Tx模式接收通道0的接收地址
6) 设置自动重发间隔时间和最大自动重发次数
7) 设置RF通道
8) 配置TX射频参数(发射功率、无线速率)
9) 配置基本工作模式的参数(有无中断/CRC类型/POWER-ON/TX模式)
10)CE拉高,进入发送模式

发送操作:
1) CE置低
2) 写发送数据到FIFO
3) CE拉高,发送数据
4) 检查发送标识,处理异常

接收模式初始化:
1) CE置低
2)写Rx模式节点地址(0~5通道可选)
3)使能选定通道x的自动应答
4)使能选定通道x的接收地址
5)设置RF通信频率
6)选择通道x的有效数据宽度
7)设置RX射频参数(无线速率)
8)配置基本工作模式的参数(有无中断/CRC类型/POWER-ON/RX模式)
9)CE拉高,进入接收模式

接收操作:
1) 查询状态寄存器,检查是否接收到数据
2)如果接收到数据,清除状态寄存器数据接收到标识,及读取数据

如果不采用自动应答,就相当于UDP的底层工作模式,把数据包发出去就不管接收端是否收到了。不采用自动应答时,发送和接收端不使能自动应答即可。

NRF24L01操作指令

NRF24L01的操作指令涉及读寄存器,写寄存器,查询状态寄存器等:
STM32模拟SPI控制NRF24L01发送和接收

NRF24L01寄存器定义

NRF24L01寄存器定义如下:
STM32模拟SPI控制NRF24L01发送和接收
STM32模拟SPI控制NRF24L01发送和接收
STM32模拟SPI控制NRF24L01发送和接收
STM32模拟SPI控制NRF24L01发送和接收

NRF24L01发送接收范例

这里采用STM32CUBEIDE开发环境,两片STM32F103C6T6各自连接一片NRF24L01,一端发送,另一端接收,通过串口可以观察发送和接收状态。

TX端每秒发送一次数据给RX端,各自的UART1串口打印输出。

代码里通过如下开关选择是否采用自动应答模式:

#define Auto_Ack 1  //1: Enable Auto_Ack; 0: Disable Auto_Ack

发送端和接收端初始化函数支持配置通讯通道号(0~5),可以选择各个通道进行测试。

代码采用的微秒级延时函数实现,参考: STM32 HAL us delay(微秒延时)的指令延时实现方式及优化
UART串口printf打印输出配置,参考: STM32 UART串口printf函数应用及浮点打印代码空间节省 (HAL)

NRF24L01 工程配置

两片STM32F103C6T6的工程配置相同,首先建立基本工程并设置时钟:
STM32模拟SPI控制NRF24L01发送和接收
采用内部时钟或外部时钟都可以:
STM32模拟SPI控制NRF24L01发送和接收
配置USART1作为打印输出串口:
STM32模拟SPI控制NRF24L01发送和接收
选择6个GPIO作为与NRF24L01接口的管脚, 4发送2接收配置:
STM32模拟SPI控制NRF24L01发送和接收
保存并生成初始工程代码:
STM32模拟SPI控制NRF24L01发送和接收

NRF24L01 工程库代码

建立nrf24l01.h的头文件:

#ifndef INC_NRF24L01_H_
#define INC_NRF24L01_H_

#include "main.h"

//NRF24L01 address and data load operation width
#define TX_ADR_WIDTH    5                               //TX address width byte number
#define RX_ADR_WIDTH    5                               //RX address width byte number
#define TX_PLOAD_WIDTH  32                              //TX data load width byte number
#define RX_PLOAD_WIDTH  32                              //RX data load width byte number

//NRF24L01 register operation command
#define SPI_READ_REG    0x00     //Read command and status registers by SPI_READ_REG | 5bits_register_address
#define SPI_WRITE_REG   0x20     //Write command and status registers by SPI_WRITE_REG | 5bits_register_address, Executable in power down or standby modes only.
#define RD_RX_PLOAD     0x61     //Read RX-payload: 1 – 32 bytes. A read operation always starts at byte 0. Payload is deleted from FIFO after it is read. Used in RX mode.
#define WR_TX_PLOAD     0xA0     //Write TX-payload: 1 – 32 bytes. A write operation always starts at byte 0 used in TX payload.
#define FLUSH_TX        0xE1     //Flush TX FIFO, used in TX mode
#define FLUSH_RX        0xE2     //Flush RX FIFO, used in RX mode Should not be executed during transmission of acknowledge, that is, acknowledge package will not be completed.
#define REUSE_TX_PL     0xE3     //Used for a PTX device Reuse last transmitted payload. TX payload reuse is active until W_TX_PAYLOAD or FLUSH TX is executed. TX payload reuse must not be activated or deactivated during package transmission.
#define R_RX_PL_WID     0x60     //Read RX payload width for the top R_RX_PAYLOAD in the RX FIFO. Note: Flush RX FIFO if the read value is larger than 32 bytes.
#define W_ACK_PAYLOAD   0xA8     //Used in RX mode by W_ACK_PAYLOAD | 3bits_PPP. Write Payload to be transmitted together with ACK packet on PIPE PPP. (PPP valid in the range from 000 to 101). Maximum three ACK packet payloads can be pending. Payloads with same PPP are handled using first in - first out principle. Write payload: 1– 32 bytes. A write operation always starts at byte 0.
#define W_TX_PAYLOAD_NOACK 0xB0  //Used in TX mode. Disables AUTOACK on this specific packet.
#define NOP             0xFF     //No Operation. Might be used to read the STATUS register

//NRF24L01 register address
#define NCONFIG          0x00

#define EN_AA           0x01
#define EN_RXADDR       0x02
#define SETUP_AW        0x03
#define SETUP_RETR      0x04
#define RF_CH           0x05
#define RF_SETUP        0x06
#define STATUS          0x07

#define MAX_TX  	    0x10
#define TX_OK       	0x20
#define RX_OK   	    0x40

#define OBSERVE_TX      0x08
#define CD              0x09
#define RX_ADDR_P0      0x0A
#define RX_ADDR_P1      0x0B
#define RX_ADDR_P2      0x0C
#define RX_ADDR_P3      0x0D
#define RX_ADDR_P4      0x0E
#define RX_ADDR_P5      0x0F
#define TX_ADDR         0x10
#define RX_PW_P0        0x11
#define RX_PW_P1        0x12
#define RX_PW_P2        0x13
#define RX_PW_P3        0x14
#define RX_PW_P4        0x15
#define RX_PW_P5        0x16
#define FIFO_STATUS     0x17


uint8_t SPI_RW(uint8_t txd);
uint8_t NRF24L01_Write_Reg(uint8_t regaddr,uint8_t data);
uint8_t NRF24L01_Write_Buf(uint8_t regaddr, uint8_t *pBuf, uint8_t datalen);
uint8_t NRF24L01_Read_Reg(uint8_t regaddr);
uint8_t NRF24L01_Read_Buf(uint8_t regaddr,uint8_t *pBuf,uint8_t datalen);
uint8_t NRF24L01_Check(void);
void TX_Mode(uint8_t pipe_num);
void RX_Mode(uint8_t pipe_num);
uint8_t NRF24L01_TxPacket(uint8_t *txbuf);
uint8_t NRF24L01_RxPacket(uint8_t *rxbuf);

#endif /* INC_NRF24L01_H_ */

建立nrf24l01.c的源文件:

#include "nrf24l01.h"
#include "string.h"
extern void PY_Delay_us_t(uint32_t Delay);

#define  NRF24L01_SCK_H  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET)
#define  NRF24L01_SCK_L  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET)
#define  NRF24L01_MOSI_H  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET)
#define  NRF24L01_MOSI_L  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET)
#define  NRF24L01_MISO  HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14)

#define Set_NRF24L01_CSN  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET)
#define Clr_NRF24L01_CSN  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET)
#define Set_NRF24L01_CE  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_SET)
#define Clr_NRF24L01_CE  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET)
#define READ_NRF24L01_IRQ  HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8)

#define SPI_SPEED_DELAY 1
uint8_t SPI_RW(uint8_t txd)
{
		uint8_t rxd=0x00;

		for (uint8_t i = 0; i < 8; i++)
		{

				NRF24L01_SCK_L;
				if (txd&0x80)
				{
						NRF24L01_MOSI_H;
				}
				else
				{
						NRF24L01_MOSI_L;
				}
				txd <<= 1;
				rxd<<=1;
				PY_Delay_us_t(SPI_SPEED_DELAY);
				NRF24L01_SCK_H;
				if(NRF24L01_MISO)
				{
					rxd++;
				}
				PY_Delay_us_t(SPI_SPEED_DELAY);
				NRF24L01_SCK_L;
		}

		return rxd;
}

#define Auto_Ack 1  //1: Enable Auto_Ack; 0: Disable Auto_Ack

uint8_t TX_ADDRESS[]= {0xCC,0xCC,0xCC,0xCC,0XC1};
uint8_t RX_ADDRESS[]= {0xCC,0xCC,0xCC,0xCC,0XC1};


//Write NRF24L01 register
uint8_t NRF24L01_Write_Reg(uint8_t regaddr,uint8_t data)
{
	uint8_t status;
    Clr_NRF24L01_CSN;                    //Enable SPI transceiver
  	status =SPI_RW(regaddr);             //Send register address
  	SPI_RW(data);                        //Send register data
  	Set_NRF24L01_CSN;                    //Disable SPI transceiver
  	return(status);       		         //Return status
}

//Write NRF24L01 register for specific length from buffer
uint8_t NRF24L01_Write_Buf(uint8_t regaddr, uint8_t *pBuf, uint8_t datalen)
{
	uint8_t status,uint8_t_ctr;
	Clr_NRF24L01_CSN;                                                       //Enable SPI transceiver
  	status = SPI_RW(regaddr);                                               //Send register address
  	for(uint8_t_ctr=0; uint8_t_ctr<datalen; uint8_t_ctr++) SPI_RW(*pBuf++); //Send register data
  	Set_NRF24L01_CSN;                                                       //Disable SPI transceiver
  	return status;                                                          //Return status
}

//Read NRF24L01 register
uint8_t NRF24L01_Read_Reg(uint8_t regaddr)
{
	uint8_t reg_val;
	Clr_NRF24L01_CSN;                //Enable SPI transceiver
  	SPI_RW(regaddr);                 //Send register address
  	reg_val=SPI_RW(0XFF);            //Read register data
  	Set_NRF24L01_CSN;                //Disable SPI transceiver
  	return(reg_val);                 //Return status
}

//Read NRF24L01 register for specific length to buffer
uint8_t NRF24L01_Read_Buf(uint8_t regaddr,uint8_t *pBuf,uint8_t datalen)
{
	uint8_t status,uint8_t_ctr;
  	Clr_NRF24L01_CSN;                                                                        //Enable SPI transceiver
  	status=SPI_RW(regaddr);                                                                  //Send register address
	for( uint8_t_ctr=0; uint8_t_ctr<datalen; uint8_t_ctr++ ) pBuf[uint8_t_ctr]=SPI_RW(0XFF);  //Read register data
  	Set_NRF24L01_CSN;                                                                        //Disable SPI transceiver
  	return status;                                                                           //Return status
}


//Check NRF24L01 existing, 0: existing; 1: not existing
uint8_t NRF24L01_Check(void)
{
	uint8_t buf[5]={ 0x5A, 0x5A, 0x5A, 0x5A, 0x5A };

	NRF24L01_Write_Buf(SPI_WRITE_REG+TX_ADDR, buf, 5);      //Write 5-byte address

	memset(buf, 0 , 5);
	NRF24L01_Read_Buf(SPI_READ_REG+TX_ADDR, buf, 5);        //Read back 5-byte address

	for(uint8_t i=0;i<5;i++)
	{
		if(buf[i]!=0x5A) return 1;                          //NRF24L01 not existing
	}

	return 0;		                                        //NRF24L01 existing
}

//NRF24L01 TX mode initialization
//pipe_num: 0 ~ 5 for RX side
void TX_Mode(uint8_t pipe_num)
{
	Clr_NRF24L01_CE;
    //Write TX mode node address
	TX_ADDRESS[4] = 0xC1 + pipe_num ;
  	NRF24L01_Write_Buf(SPI_WRITE_REG+TX_ADDR, (uint8_t*)TX_ADDRESS, TX_ADR_WIDTH);
  	//Write TX mode RX Pipe 0 address for Auto-ACK
  	RX_ADDRESS[4] = 0xC1 + pipe_num ;
  	NRF24L01_Write_Buf(SPI_WRITE_REG+RX_ADDR_P0, (uint8_t*)RX_ADDRESS, RX_ADR_WIDTH);

    //Enable or disable Auto-Ack for TX mode RX Pipe 0
  	if(Auto_Ack) NRF24L01_Write_Reg(SPI_WRITE_REG+EN_AA,0x01);
  	else NRF24L01_Write_Reg(SPI_WRITE_REG+EN_AA,0x00);
    //Enable TX mode RX Pipe 0 address
  	NRF24L01_Write_Reg(SPI_WRITE_REG+EN_RXADDR,0x01);
  	//Config auto-repeat interval: 86us+250us*(1+1); maximum auto-repeat times: 10
  	NRF24L01_Write_Reg(SPI_WRITE_REG+SETUP_RETR,0x1a);
    //Config RF channel: 40
  	NRF24L01_Write_Reg(SPI_WRITE_REG+RF_CH,40);
  	//Config TX RF parameter: 0dbm output power, 1Mbps RF data rate
  	NRF24L01_Write_Reg(SPI_WRITE_REG+RF_SETUP,0x07);  //0x27 : 250Kbps;  0x07 : 1Mbps; 0x0F : 2Mbps
  	//Config basic parameter: no interrupt, CRC enable, 16-bit CRC, power-on and TX mode
  	NRF24L01_Write_Reg(SPI_WRITE_REG+NCONFIG,0x0e);
    //Set CE high, 10us delay to start sending
	Set_NRF24L01_CE;
}

//NRF24L01 RX mode initialization
//pipe_num: 0 ~ 5
void RX_Mode(uint8_t pipe_num)
{
	Clr_NRF24L01_CE;
    //Write RX mode node address
	RX_ADDRESS[4] = 0xC1 + pipe_num ;
  	NRF24L01_Write_Buf(SPI_WRITE_REG+RX_ADDR_P0+pipe_num, (uint8_t*)RX_ADDRESS, RX_ADR_WIDTH);

  	//Enable or disable Auto-Ack for RX node
  	if(Auto_Ack) NRF24L01_Write_Reg(SPI_WRITE_REG+EN_AA, 0x01<<pipe_num);
  	else NRF24L01_Write_Reg(SPI_WRITE_REG+EN_AA, 0x00);
  	//Enable RX node Pipe x address
  	NRF24L01_Write_Reg(SPI_WRITE_REG+EN_RXADDR, 0x01<<pipe_num);
    //Config RF channel: 40
  	NRF24L01_Write_Reg(SPI_WRITE_REG+RF_CH, 40);
    //Config RX node Pipe x data width: 32
  	NRF24L01_Write_Reg(SPI_WRITE_REG+RX_PW_P0+pipe_num, RX_PLOAD_WIDTH);
  	//Config RX RF parameter: 1Mbps RF data rate
  	NRF24L01_Write_Reg(SPI_WRITE_REG+RF_SETUP, 0x07);
  	//Config basic parameter: no interrupt, CRC enable, 16-bit CRC, power-on and RX mode
  	NRF24L01_Write_Reg(SPI_WRITE_REG+NCONFIG, 0x0f);
  	//Set CE high, 10us delay to start receiving
  	Set_NRF24L01_CE;
}

//NRF24L01 TX
uint8_t NRF24L01_TxPacket(uint8_t *txbuf)
{
	uint8_t state;
	Clr_NRF24L01_CE;
	NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//Write data to TX Buffer with 32-byte
	Set_NRF24L01_CE;                                     //Set CE high, 10us delay to start sendin
	while(READ_NRF24L01_IRQ!=0);                         //Waiting for completion of TX process
	state=NRF24L01_Read_Reg(STATUS);                     //Read status register
	NRF24L01_Write_Reg(SPI_WRITE_REG+STATUS,state);      //Clear TX_DS and MAX_RT interrupt flags
	if(state&MAX_TX)                                     //Maximum repeat times
	{
		NRF24L01_Write_Reg(FLUSH_TX,0xff);               //Clear TX FIFO register
		return MAX_TX;
	}
	if(state&TX_OK)                                      //TX OK
	{
		return TX_OK;
	}
	return 0xff;                                         //Unknown failure
}


//NRF24L01 RX
uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)
{
	uint8_t state;
	state=NRF24L01_Read_Reg(STATUS);                           //Read status register
	NRF24L01_Write_Reg(SPI_WRITE_REG+STATUS,state);            //Clear Data Ready interrupt flags
	if(state&RX_OK)                                            //RX OK
	{
		NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);   //Read data
		NRF24L01_Write_Reg(FLUSH_RX,0xff);                     //Clear RX FIFO register
		return 0;
	}
	return 1;                                                  //RX Got no data
}

NRF24L01 TX工程代码

在TX工程main.c文件里实现发送测试功能代码:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include "usart.h"
#include "nrf24l01.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
__IO float usDelayBase;
void PY_usDelayTest(void)
{
  __IO uint32_t firstms, secondms;
  __IO uint32_t counter = 0;

  firstms = HAL_GetTick()+1;
  secondms = firstms+1;

  while(uwTick!=firstms) ;

  while(uwTick!=secondms) counter++;

  usDelayBase = ((float)counter)/1000;
}

void PY_Delay_us_t(uint32_t Delay)
{
  __IO uint32_t delayReg;
  __IO uint32_t usNum = (uint32_t)(Delay*usDelayBase);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}
void PY_usDelayOptimize(void)
{
  __IO uint32_t firstms, secondms;
  __IO float coe = 1.0;

  firstms = HAL_GetTick();
  PY_Delay_us_t(1000000) ;
  secondms = HAL_GetTick();

  coe = ((float)1000)/(secondms-firstms);
  usDelayBase = coe*usDelayBase;
}
void PY_Delay_us(uint32_t Delay)
{
  __IO uint32_t delayReg;

  __IO uint32_t msNum = Delay/1000;
  __IO uint32_t usNum = (uint32_t)((Delay%1000)*usDelayBase);

  if(msNum>0) HAL_Delay(msNum);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */


/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
uint8_t uart_rxd[256];
uint8_t uart_txd[256];

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t NRF24L01_Status = 0xff;

uint8_t nrf24l01_rxd[32];
uint8_t nrf24l01_txd[32];

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  PY_usDelayTest();
  PY_usDelayOptimize();


  NRF24L01_Status = NRF24L01_Check();
  if(NRF24L01_Status==0)
  {
	  PY_Delay_us_t(1000000);
	  printf("\r\nNRF24L01 exists.\r\n");
  }
  else
  {
	  while(1)
	  {
		printf("\r\nNRF24L01 does't exist.\r\n");
		PY_Delay_us_t(1000000);
	  }
  }

  TX_Mode(0);

  for(uint32_t i=0; i<32; i++)
  {
	  nrf24l01_txd[i]=i;
  }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		  NRF24L01_Status = NRF24L01_TxPacket(nrf24l01_txd);

		  if(NRF24L01_Status==TX_OK) printf("\r\nData was sent OK.\r\n");
		  else if(NRF24L01_Status==MAX_TX) printf("\r\nData was sent Overtime.\r\n");
		  else printf("\r\nData was sent Error.\r\n");

		  PY_Delay_us_t(1000000);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13|GPIO_PIN_15, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);

  /*Configure GPIO pins : PB12 PB13 PB15 */
  GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PB14 */
  GPIO_InitStruct.Pin = GPIO_PIN_14;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PA8 */
  GPIO_InitStruct.Pin = GPIO_PIN_8;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PA11 */
  GPIO_InitStruct.Pin = GPIO_PIN_11;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */


NRF24L01 RX工程代码

在RX工程main.c文件里实现接收测试功能代码:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include "usart.h"
#include "nrf24l01.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
__IO float usDelayBase;
void PY_usDelayTest(void)
{
  __IO uint32_t firstms, secondms;
  __IO uint32_t counter = 0;

  firstms = HAL_GetTick()+1;
  secondms = firstms+1;

  while(uwTick!=firstms) ;

  while(uwTick!=secondms) counter++;

  usDelayBase = ((float)counter)/1000;
}

void PY_Delay_us_t(uint32_t Delay)
{
  __IO uint32_t delayReg;
  __IO uint32_t usNum = (uint32_t)(Delay*usDelayBase);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}
void PY_usDelayOptimize(void)
{
  __IO uint32_t firstms, secondms;
  __IO float coe = 1.0;

  firstms = HAL_GetTick();
  PY_Delay_us_t(1000000) ;
  secondms = HAL_GetTick();

  coe = ((float)1000)/(secondms-firstms);
  usDelayBase = coe*usDelayBase;
}
void PY_Delay_us(uint32_t Delay)
{
  __IO uint32_t delayReg;

  __IO uint32_t msNum = Delay/1000;
  __IO uint32_t usNum = (uint32_t)((Delay%1000)*usDelayBase);

  if(msNum>0) HAL_Delay(msNum);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
uint8_t uart_rxd[256];
uint8_t uart_txd[256];

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t NRF24L01_Status = 0xff;

uint8_t nrf24l01_rxd[32];
uint8_t nrf24l01_txd[32];

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  PY_usDelayTest();
  PY_usDelayOptimize();

  NRF24L01_Status = NRF24L01_Check();
  if(NRF24L01_Status==0)
  {
	  PY_Delay_us_t(1000000);
	  printf("\r\nNRF24L01 exists.\r\n");
  }
  else
  {
	  while(1)
	  {
		printf("\r\nNRF24L01 does't exist.\r\n");
		PY_Delay_us_t(1000000);
	  }
  }

  RX_Mode(0);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
        NRF24L01_Status = NRF24L01_RxPacket(nrf24l01_rxd);
	    if(NRF24L01_Status==0)
	    {
	    	printf("\r\nget data:");
	    	for(uint32_t i=0; i<RX_PLOAD_WIDTH; i++)
	    	{
	    		printf(" %d", nrf24l01_rxd[i]);
	    	}
	    	printf("\r\n");
	    }

	    PY_Delay_us_t(10);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13|GPIO_PIN_15, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);

  /*Configure GPIO pins : PB12 PB13 PB15 */
  GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PB14 */
  GPIO_InitStruct.Pin = GPIO_PIN_14;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PA8 */
  GPIO_InitStruct.Pin = GPIO_PIN_8;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PA11 */
  GPIO_InitStruct.Pin = GPIO_PIN_11;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

NRF24L01代码测试效果

发送端每次发送32个数据(从0~31),接收端收到后串口的打印输出为:
STM32模拟SPI控制NRF24L01发送和接收

NRF24L01范例下载

STM32F103C6T6控制NRF24L01发收例程下载

–End–文章来源地址https://www.toymoban.com/news/detail-473010.html

到了这里,关于STM32模拟SPI控制NRF24L01发送和接收的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32在使用NRF24L01中PC(电脑)连接无显示数据以及出现error的解决办法

    1.1 问题情况 在使用 正点原子 的代码中有以下这样一段代码: 我们可以看到,这里调用了 NRF24L01 的自检函数 ,用于判断自检是否通过,当自检不通过时,在LCD上就会显示 NRF24L01 Error 1.2 解决办法 其实这个问题是 引脚冲突的问题 ,我们可以在正点原子提供的原理图(这里我

    2024年01月23日
    浏览(23)
  • STM32F103C8T6与2.4G无线模块NRF24L01连接

    最近使用到了这个2.4G无线模块NRF24L01,比蓝牙好用,需要同时使用两个来用,它长这样: 使用它需要代码支持,因此我在耗费了一些精力后,从网上东拼西凑了一些代码,修修补补后使它能够正常运行, 注意:我只测试了两个2.4G无线模块NRF24L01的连接。 下图是2.4G无线模块

    2024年02月12日
    浏览(20)
  • 51驱动NRF24L01通信,NRF24L01与TTL转NRF24L01模块通信

    NRF24L01 是 NORDIC 公司最近生产的一款无线通信通信芯片,采用 FSK 调制,内部 集成 NORDIC 自己的 Enhanced Short Burst 协议。可以实现点对点或是 1 对 6 的无线通信。无线通信速度可以达到 2M(bps)。NORDIC 公司提供通信模块的 GERBER 文件,可以直接加工生产。嵌入式工程师或是单片

    2024年02月03日
    浏览(16)
  • 无线收发模块——NRF24L01

    nRF24L01 是由NORDIC生产的工作 在2.4GHz~2.5GHz 的ISM 频段的 单片无线收发器芯片 。有着极低的电流消耗。 nRF24L01与5V单片机的连接通过 SPI 接口进行通讯,输出功率频道选择和协议的设置可以通过SPI 接口进行设置,几乎可以连接到各种单片机芯片,并完成无线数据传送工作。 引脚

    2024年02月01日
    浏览(20)
  • NRF24L01学习操作教程(二)——NRF实现一对一,一对多通讯

    上篇博客链接:https://blog.csdn.net/DIVIDADA/article/details/130599974?spm=1001.2014.3001.5501 以下单片机例程都是基于STM32 HAL库,在文档末尾,我会提供参考博客和源码程序的链接。 在CubeMx中配置单片机时钟、SPI通讯接口、NRF24L01接口等,并生成Keil工程 将NRF24L01的驱动程序的.c文件和.h文件

    2024年01月15日
    浏览(23)
  • NRF24L01 2.4G无线模块浅析(学习笔记)

    仅作为个人学习笔记 nRF24L01是由NORDIC生产的工作在2.4GHz~2.5GHz的ISM 频段的单片无线收发器芯片。无线收发器包括:频率发生器、增强型“SchockBurst”模式控制器、功率放大器、晶体振荡器、调制器和解调器。 应用领域 ● 无线鼠标 键盘 游戏机操纵杆 ● 无线门禁 ● 无线数据通

    2024年01月16日
    浏览(17)
  • stm32驱动NRF24L01_原理+代码解析

    目录 概念 废话篇(24L01简介) 引脚分配 工作模式 通信地址理解(个人疑难点) 原理分析 寄存器赏析 寄存器操作指令  配置寄存器(CONFIG,位置:0X00)  自动应答使能寄存器(EN_AA,0X01) RX地址使能寄存器(EN_RXADDR,0X02)  自动重发设置寄存器(SETUP_RETR,0X04)  射频频

    2024年01月18日
    浏览(24)
  • PCAP01介绍和STM32模拟SPI驱动

    Pcap01是德国acam公司设计的一款革命性的电容测量芯片。该芯片 内部有DSP计算单元,可以直接将电容元件接到Pcap01芯片,然后芯片计算出容值大小,通过SPI总线将电容容值数据传送给CPU,电容测量完全数字化。 PCAP测量的原理是基于电容的充放电时间比。 PCAP01有8个通道,每一

    2024年02月12日
    浏览(20)
  • STM32模拟SPI协议获取24位模数转换(24bit ADC)芯片AD7791电压采样数据

    STM32大部分芯片只有12位的ADC采样性能,如果要实现更高精度的模数转换如24位ADC采样,则需要连接外部ADC实现。AD7791是亚德诺(ADI)半导体一款用于低功耗、24位Σ-Δ型模数转换器(ADC) ,适合低频测量应用,提供50 Hz/60 Hz同步抑制。 这里介绍基于AD7791的24位ADC采样实现。 AD7791的管脚

    2024年02月09日
    浏览(28)
  • STM32模拟SPI时序配置读取双路24位模数转换(24bit ADC)芯片ADS1220采样数据

    TI公司的双路24位模数转换芯片ADS1220具有比较丰富的模式配置,双路差分输入采样也可以配置为4路单端输入信号采样。有多种参考电压源可选,内部增益(从1倍到128倍)和输出率(可达到2K/s)可配置,模拟电压和数字电路电压可单独设置等等。这里介绍STM32访问和读取ADS12

    2023年04月09日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包