Nrf24L01 模块代码

NRF.h代码

#ifndef __SPI_NRF_H__
#define __SPI_NRF_H__
/*
开发板设备		所连接的管脚
CE						PC5
CSN						PC4
SCK						PA7
MOSI					PA6
MISO					PA5
IRQ						PA4
已知芯片的管脚是多功能复用型的管脚
芯片的管脚会有 输入功能 输出功能 复用功能 模拟功能
我们这次操作的是开发板上的无线通信模块Nrf24L01
已知该模块的接口是SPI接口,我们需要把模块接入到有SPI接口的管脚上
但是为了考虑到移植性的问题,我们还是采取使用GPIO的方式模拟SPI协议
*/
#include "stm32f10x_conf.h"//包含了该头文件所有的外设头文件均已包含
//让Nrf模块之间通信(一次发送数据<=32字节)
//用下面的这个结构体(32字节)进行通信
//里面的成员的含义自己说了算
struct nrf_msg_st//定义的发送数据包的结构体(不能超过32字节)
{
	u32 Dht_Hum;//存储DHT11的湿度
	u32 Dht_Temp;//存储DHT11的温度
	float Sht_Temp;//存储SHT30的温度
	float Sht_Hum;//存储SHT30的湿度
	u8 buf[16];//存储其他数据
};
//用GPIO来模拟SPI总线(移植性好)
//做代码移植时这部分需要修改(打开硬件原理图)
//这块也可以修改成位带操作
#define NRF_CSN_HIGH()      GPIO_SetBits(GPIOC, GPIO_Pin_4)//片选拉高(不能操作设备)
#define NRF_CSN_LOW()      	GPIO_ResetBits(GPIOC, GPIO_Pin_4)//片选拉低(可以操作设备)
#define NRF_CE_HIGH()	   		GPIO_SetBits(GPIOC, GPIO_Pin_5)//拉高CE(打开射频)
#define NRF_CE_LOW()	   		GPIO_ResetBits(GPIOC, GPIO_Pin_5)//拉低CE(关闭射频)
#define NRF_Read_IRQ()			GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4)//读中断的管脚(无论是发送数据还是接受数据都是低电平)

#define NRF_MOSI_HIGH()			GPIO_SetBits(GPIOA, GPIO_Pin_6)//MOSI拉高 
#define NRF_MOSI_LOW()			GPIO_ResetBits(GPIOA, GPIO_Pin_6)//MOSI拉低
#define NRF_CLK_HIGH()			GPIO_SetBits(GPIOA, GPIO_Pin_7)//CLK拉高
#define NRF_CLK_LOW()				GPIO_ResetBits(GPIOA, GPIO_Pin_7)//CLK拉低
#define NRF_Read_MISO()			GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5)//读MISO(主入从出)

#define TX_ADR_WIDTH 		5  	//发射地址宽度(5个字节)

#define RX_ADR_WIDTH    5		//每一个Nrf都会有一个地址(3 4 5bytes)

// SPI(nRF24L01) commands
#define NRF_READ_REG    0x00  // Define read command to register
#define NRF_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

#define MAX_RT      		0x10 //达到最大重发次数中断标志位(超时)
#define TX_DS						0x20 //发送完成中断标志位	  // 发送OK

#define RX_DR						0x40 //接收到数据中断标志位 //接收OK

void SPI_NRF_Init(void);//对Nrf进行初始化
u8 SPI_NRF_RW(u8 dat);//对Nrf进行读写
//(从SPI总线考虑Nrf的读和写时序一样,只不过第一个字节中的读写命令不一样)
u8 SPI_NRF_ReadReg(u8 reg);//读Nrf寄存器
u8 SPI_NRF_WriteReg(u8 reg,u8 dat);//写Nrf寄存器
u8 SPI_NRF_ReadBuf(u8 reg,u8 *pBuf,u8 bytes);//读Buf(可以一次对于多个寄存器进行操作<必须是连续的寄存器>)
u8 SPI_NRF_WriteBuf(u8 reg ,u8 *pBuf,u8 bytes);	//写Buf()

void NRF_RX_Mode(u8 *rxAddr, u8 channel, u8 recvLen);//把Nrf设置为接收模式(自己的地址,自己的通道,自己接收数据长度)
void NRF_TX_Mode(u8 *txAddr, u8 channel);//把Nrf设置为发送模式(发送的地址,通道)<发送地址和自己的接收地址一致>
u8 NRF_Rx_Dat(u8 *rxbuf, u8 recvLen);//接收数据
u8 NRF_Tx_Dat(u8 *txbuf, u8 recvLen);//发送数据
u8 NRF_Check(void); //检查STM32和NRF硬件上有没有连接好
//比如说给Nrf某个寄存器写个10再读一下这个寄存器,读回来的值没问题就说明OK
//上述函数实现用的都是轮询的方式(S5P6818上用的是中断的方式)
#endif 

NRF.c代码

#include "nrf24l01.h"//包含头文件

void SPI2_For_Nrf24l01(void)//初始化NRF所使用到的SPI接口的管脚
{
	GPIO_InitTypeDef GPIO_InitStructure;//定义了GPIO固件的结构体变量
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
	//通过APB2总线使能GPIOA组和GPIOC组的时钟
	
	//CSN PC4 OUT
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//选择了推挽的输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;//选择了4号管脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//选择了50MHz输出速度
	GPIO_Init(GPIOC, &GPIO_InitStructure);//按照上述配置初始化GPIOC组的管脚
	GPIO_SetBits(GPIOC, GPIO_Pin_4);//默认是高电平(低电平有效)
	
	//CE PC5 OUT
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//选择了推挽的输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//选择了5号管脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//选择了50MHz输出速度
	GPIO_Init(GPIOC, &GPIO_InitStructure);//按照上述配置初始化GPIOC组的管脚
	GPIO_ResetBits(GPIOC, GPIO_Pin_5);//默认是低电平(既不发送也不接收)

	//MOSI PA6 OUT
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//选择了推挽的输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//选择了6号管脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//选择了50MHz输出速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);//按照上述配置初始化GPIOA组的管脚
	
	//SPI2_CLK PA7 OUT
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//选择了7号管脚
	GPIO_Init(GPIOA, &GPIO_InitStructure);//按照上述配置初始化GPIOA组的管脚
	
	//MISO PA5 IN
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//选择了浮空输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//选择了5号管脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//选择了50MHz的输出速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);//按照上述配置初始化GPIOA组的管脚
	
	//IRQ PA4 IN
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//选择了上拉输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//选择了5号管脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//选择了50MHz的输出速度
	GPIO_Init(GPIOA, &GPIO_InitStructure);//按照上述配置初始化GPIOA组的管脚
}
//可以修改成delay_ms delay_us
void Delay(__IO u32 nCount)//延时函数
{
  for(; nCount != 0; nCount--);
} 
//----------------------------------------------------------------//


//----------以下代码与芯片无关------------------------------------//
//我们使用的是SPI总线的
//SCK初始低电平上升沿有效
/*
 * 函数名:SPI_NRF_RW
 * 描述  :对Nrf进行读写
 * 输入  :dat:将要写入的数据
 * 输出  :写每位数据时的状态
 * 调用  :内部调用
 */
u8 SPI_NRF_RW(u8 dat)//可以一边发一边收
{  	
	int count = 0;

	/*每一次循环写一位数据,并且获取一位数据*/
	for(count = 0; count < 8; count++){
		NRF_CLK_LOW();
		if(dat & 0x80) {
			NRF_MOSI_HIGH();
		} else {
			NRF_MOSI_LOW();
		}
		dat <<= 1;
		NRF_CLK_HIGH();
		dat |= NRF_Read_MISO();	
	}
	NRF_CLK_LOW();	

	return dat;
}



/*
 * 函数名:SPI_NRF_Init
 * 描述  :用于对Nrf进行初始化
 * 输入  :无
 * 输出  :无
 * 调用  :外部调用
 */
void SPI_NRF_Init(void)
{
	/*初始化Nrf24l01所使用的GPIO*/
	SPI2_For_Nrf24l01();
	/*默认不操作的状态下把片选拉高*/
	NRF_CSN_HIGH(); 
}

/*
 * 函数名:SPI_NRF_WriteReg
 * 描述  :用于向NRF特定的寄存器写入数据
 * 输入  :	reg:NRF的命令+寄存器地址。
						dat:将要向寄存器写入的数据
 * 输出  :NRF的status寄存器的状态
 * 调用  :内部调用
 */
u8 SPI_NRF_WriteReg(u8 reg,u8 dat)
{
	u8 status;
	/*关闭射频*/
	NRF_CE_LOW();
	/*置低CSN,使能SPI传输*/
	NRF_CSN_LOW();
				
	/*发送命令及寄存器号 */
	status = SPI_NRF_RW(reg);//在写的时候也读回来状态了
		 
	/*向寄存器写入数据*/
	SPI_NRF_RW(dat); 
	          
	/*CSN拉高,完成*/	   
	NRF_CSN_HIGH();	
		
	/*返回状态寄存器的值*/
	return(status);
}


/*
 * 函数名:SPI_NRF_ReadReg
 * 描述  :用于从NRF特定的寄存器读出数据
 * 输入  :reg:NRF的命令+寄存器地址。
 * 输出  :寄存器中的数据
 * 调用  :内部调用
 */
u8 SPI_NRF_ReadReg(u8 reg)
{
 	u8 reg_val;

	/*关闭射频*/
	NRF_CE_LOW();
	/*置低CSN,使能SPI传输*/
 	NRF_CSN_LOW();
				
	/*发送寄存器号*/
	SPI_NRF_RW(reg); 

	/*读取寄存器的值 */
	reg_val = SPI_NRF_RW(NOP);
	            
	/*CSN拉高,完成*/
	NRF_CSN_HIGH();		
   	
	return reg_val;
}	


/*
 * 函数名:SPI_NRF_ReadBuf
 * 描述  :用于从NRF的寄存器中读出一串数据
 * 输入  :	reg:NRF的命令+寄存器地址。
						pBuf:用于存储将被读出的寄存器数据的数组,外部定义
						bytes:pBuf的数据长度	
 * 输出  :NRF的status寄存器的状态
 * 调用  :外部调用
 */
u8 SPI_NRF_ReadBuf(u8 reg,u8 *pBuf,u8 bytes)
{
 	u8 status, byte_cnt;

	NRF_CE_LOW();
	
	/*置低CSN,使能SPI传输*/
	NRF_CSN_LOW();
		
	/*发送寄存器号*/		
	status = SPI_NRF_RW(reg); 

 	/*读取缓冲区数据*/
	for(byte_cnt=0;byte_cnt<bytes;byte_cnt++)		  
		pBuf[byte_cnt] = SPI_NRF_RW(NOP); //从NRF24L01读取数据  

	/*CSN拉高,完成*/
	NRF_CSN_HIGH();	
		
 	return status;		//返回寄存器状态值
}


/*
 * 函数名:SPI_NRF_WriteBuf
 * 描述  :用于向NRF的寄存器中写入一串数据
 * 输入  :reg:NRF的命令+寄存器地址。
 		   pBuf:存储了将要写入写寄存器数据的数组,外部定义
		   bytes: pBuf的数据长度	
 * 输出  :NRF的status寄存器的状态
 * 调用  :外部调用
 */
u8 SPI_NRF_WriteBuf(u8 reg ,u8 *pBuf,u8 bytes)
{
	u8 status,byte_cnt;
	
	NRF_CE_LOW();
	/*置低CSN,使能SPI传输*/
	NRF_CSN_LOW();			

	/*发送寄存器号*/	
	status = SPI_NRF_RW(reg); 
 	
	/*向缓冲区写入数据*/
	for(byte_cnt=0;byte_cnt<bytes;byte_cnt++)
		SPI_NRF_RW(*pBuf++);	//写数据到缓冲区 	 
	  	   
	/*CSN拉高,完成*/
	NRF_CSN_HIGH();			
  
	return (status);	//返回NRF24L01的状态 		
}

/*
 * 函数名:NRF_RX_Mode
 * 描述  :配置并进入接收模式
 * 输入  :无	
 * 输出  :无
 * 调用  :外部调用
 */
void NRF_RX_Mode(u8 *rxAddr, u8 channel, u8 recvLen)
{
	NRF_CE_LOW();	

	SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0, rxAddr, RX_ADR_WIDTH);//设置RX_ADDR_P0的地址
	SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA, 0x01);    //使能通道0的自动应答    
	SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR, 0x01);//使能通道0的接收地址    
	SPI_NRF_WriteReg(NRF_WRITE_REG+SETUP_AW, 0x03);//地址为5位的
	SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH, channel); //设置RF通信频率    
	SPI_NRF_WriteReg(NRF_WRITE_REG+RX_PW_P0, recvLen);//选择通道0的有效数据宽度      
	SPI_NRF_WriteReg(NRF_WRITE_REG+RF_SETUP, 0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
	SPI_NRF_WriteReg(NRF_WRITE_REG+CONFIG, 0x0f);  //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 
	
	/*CE拉高,进入接收模式,射频开始工作*/	
  NRF_CE_HIGH();
	Delay(0xffff); 
}    

/*
 * 函数名:NRF_TX_Mode
 * 描述  :配置发送模式
 * 输入  :无	
 * 输出  :无
 * 调用  :外部调用
 */
void NRF_TX_Mode(u8 *txAddr, u8 channel)
{  
	NRF_CE_LOW();		

	SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR, txAddr, TX_ADR_WIDTH);//设置TX_ADDR地址 
	SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0, txAddr, RX_ADR_WIDTH);//设置RX节点地址,主要为了使能ACK   
	SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA, 0x01);     //使能通道0的自动应答    
	SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR, 0x01); //使能通道0的接收地址 
	SPI_NRF_WriteReg(NRF_WRITE_REG+SETUP_AW, 0x03);//地址为5位的
	SPI_NRF_WriteReg(NRF_WRITE_REG+SETUP_RETR, 0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
	SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH, channel);       //设置RF通道为CHANAL
	SPI_NRF_WriteReg(NRF_WRITE_REG+RF_SETUP, 0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
	SPI_NRF_WriteReg(NRF_WRITE_REG+CONFIG, 0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,发射模式,开启所有中断
	
	/*CE拉高,进入发送模式*/	
  NRF_CE_HIGH();
	Delay(0xffff); //CE要拉高一段时间才进入发送模式
}


/*
 * 函数名:NRF_Check
 * 描述  :主要用于NRF与MCU是否正常连接
 * 输入  :无	
 * 输出  :SUCCESS/ERROR 连接正常/连接失败
 * 调用  :外部调用
 */
u8 NRF_Check(void)
{
	u8 buf[5]={0xC2,0xC2,0xC2,0xC2,0xC2};
	u8 buf1[5];
	u8 i; 
	 
	/*写入5个字节的地址.  */  
	SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,buf,5);

	/*读出写入的地址 */
	SPI_NRF_ReadBuf(TX_ADDR,buf1,5); 
	 
	/*比较*/               
	for(i=0;i<5;i++){
		if(buf1[i]!=0xC2)
			break;
	} 
	       
	if(i==5){
		return SUCCESS ;        //MCU与NRF成功连接 
	}else{
		return ERROR ;        //MCU与NRF不正常连接
	}
}

 /*
 * 函数名:NRF_Tx_Dat
 * 描述  :用于向NRF的发送缓冲区中写入数据
 * 输入  :txBuf:存储了将要发送的数据的数组,外部定义	
 * 输出  :发送结果,成功返回TXDS,失败返回MAXRT或ERROR
 * 调用  :外部调用
 */ 
u8 NRF_Tx_Dat(u8 *txbuf, u8 sendLen)
{
	u8 state;
  
	/*ce为低,进入待机模式1*/
	NRF_CE_LOW();

	/*写数据到TX BUF 最大 32个字节*/						
	SPI_NRF_WriteBuf(WR_TX_PLOAD,txbuf,sendLen);

	/*CE为高,txbuf非空,发送数据包 */   
	NRF_CE_HIGH();
	  	
	while(NRF_Read_IRQ()!=0); //可以修改成中断处理
		                         
	state = SPI_NRF_ReadReg(STATUS);
   
	/*清除TX_DS或MAX_RT中断标志*/                  
	SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state); 	
	SPI_NRF_WriteReg(FLUSH_TX,NOP);    //清除TX FIFO寄存器 

	/*判断中断类型*/    
	if(state&MAX_RT){                     //达到最大重发次数
			 return MAX_RT; 
	}else if(state&TX_DS){                  //发送完成
		 	return TX_DS;
	}else{						  
			return ERROR;                 //其他原因发送失败
	}
} 

 /*
 * 函数名:NRF_Rx_Dat
 * 描述  :用于从NRF的接收缓冲区中读出数据
 * 输入  :rxBuf:用于接收该数据的数组,外部定义	
 * 输出  :接收结果,
 * 调用  :外部调用
 */ 
u8 NRF_Rx_Dat(u8 *rxbuf, u8 recvLen)
{
	u8 state; 
	NRF_CE_HIGH();	 //进入接收状态
	 /*等待接收中断*/
	while(NRF_Read_IRQ()!=0); 
	
	NRF_CE_LOW();  	 //进入待机状态
	/*读取status寄存器的值  */               
	state=SPI_NRF_ReadReg(STATUS);
	 
	/* 清除中断标志*/      
	SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state);

	/*判断是否接收到数据*/
	if(state&RX_DR){                                 //接收到数据
	  SPI_NRF_ReadBuf(RD_RX_PLOAD,rxbuf,recvLen);//读取数据
		SPI_NRF_WriteReg(FLUSH_RX,NOP);          //清除RX FIFO寄存器
	  return RX_DR; 
	}else{    
		return ERROR;                    //没收到任何数据
	}
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值