STM32软件SPI实现NRF24L01

STM32软件SPI实现NRF24L01

NRF一共是八个引脚,除去VCC和GND还有六个引脚。

所以我们只需要配置这六个引脚就可以了。

这六个引脚分别是SCK,MOSI,MISO,CSN,CE,IRQ

除了MISO和IRQ配置成输入,其他的都配置为输出即可,其实如果不配IRQ也没事,如果有需要的话可以配置,不配的也是可以的,不会影响单片机的通信。

配置输入和输出就和配置LED和按键输入是一样的,代码可以参考LED和按键输入的代码。

以上的代码是NRF的初始化

接下来我们需要几个宏定义,具体的作用是方面我们随时改变管教的高低电平

/* SCK PA0 */
#define NRF_SCK(x) GPIOA->ODR &=~(1<<0);GPIOA->ODR |= x<<0
/* MOSI PA1*/
#define NRF_MOSI(x) GPIOA->ODR &=~(1<<1);GPIOA->ODR |= x<<1
/* MISO PA2*/
#define NRF_MISO(x) GPIOA->ODR &=~(1<<2);GPIOA->ODR |= x<<2
#define NRF_MISO_VALUE  (u8)((GPIOA->IDR&0x04)>>2)
/* CSN PA3 */
#define NRF_CSN(x) GPIOA->ODR &=~(1<<3);GPIOA->ODR |= x<<3
/* CE  PA4 */
#define NRF_CE(x) GPIOA->ODR &=~(1<<4);GPIOA->ODR |= x<<4
/* IRQ PA5 */
#define NRF_IRQ_VALUE  (u8)((GPIOA->IDR&0x20)>>5)

这里我写的代码是基于寄存器的操作,这个是简单的宏定义,例如当我们写NRF_SCK(1)时PA0也就是接到NRF的SCK引脚配置为高电平。

我们还需要相应的寄存器的地址宏定义

#define NRF_READ_REG			0X00
#define NRF_WRITE_REG 		0X20
#define RD_RX_PLOAD 	0X61
#define WR_TX_PLOAD 	0XA0
#define FLUSH_TX			0XE1
#define	FLUSH_RX			0XE2
#define REUSE_TX_PL		0XE3
#define NOP						0XFF
#define CONFIG          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 NRF_FIFO_STATUS 0x17 
#define TX_ADR_WIDTH    5   	
#define RX_ADR_WIDTH    5   
#define TX_PLOAD_WIDTH  32	
#define RX_PLOAD_WIDTH  32	

这个时候我们基本已经完成了,现在我们可以写SPI了,简单的操作,具体几个函数如下

/* 写入的时候并读取一个字节 */
u8 NRF_WR(u8 byte)
{
	u8 i;
	for(i = 0;i<8; i++)
	{
		/* 先发送高位 */
		NRF_MOSI((byte & 0X80)>>7);
		byte = (byte << 1);
		NRF_SCK(1);
		byte |= NRF_MISO_VALUE;
		NRF_SCK(0);
	}
	return byte;
}
/* 向一个寄存器写入一个值 */
u8 NRF_WR_REG(u8 reg,u8 value)
{
	u8 status;
	NRF_CSN(0);
	status = NRF_WR(reg);
	NRF_WR(value);
	NRF_CSN(1);
	return status;
}
/* 读取寄存器 */
u8 NRF_READ(u8 reg)
{
	u8 reg_val;
	NRF_CSN(0);
	NRF_WR(reg);
	reg_val = NRF_WR(0XFF);
	NRF_CSN(1);
	return reg_val;
}
/* 读取指定长度的值 */
u8 NRF_READ_BUF(u8 reg,u8 *pBuf,u8 bytes)
{
	u8 status,byte;
	NRF_CSN(0);
	status = NRF_WR(reg);
	for(byte = 0;byte < bytes;byte ++)
	{
		pBuf[byte] = NRF_WR(0);
	}
	NRF_CSN(1);
	return status;
}
/* 写入指定长度的值 */
u8 NRF_WRITE_BUF(u8 reg,u8 *pBuf,u8 bytes)
{
	u8 status,byte;
	NRF_CSN(0);
	status = NRF_WR(reg);
	for(byte = 0;byte < bytes;byte ++)
	{
		NRF_WR(*pBuf++);
	}
	NRF_CSN(1);
	return status;
}

好大致的操作已经完成了,我们现在向NRF寄存器中写入一个值,然后我们再去读这个NRF寄存器的值,应该就是我们写的值。这一步就是我们所说的NRF自检。

/* NRF自检 */
/* 就是先写入一个值 然后再读出一个值 看一下自己读出来的是否和自己写入的是否一样*/
/* 一样自检通过 不一样自检不通过 */
u8 NRF24L01_Check(void)
{
	u8 i;
	u8 buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
	NRF_WRITE_BUF((NRF_WRITE_REG+TX_ADDR),buf,5);
	NRF_READ_BUF(TX_ADDR,buf,5);
	for(i=0;i<5;i++)if(buf[i]!=0XA5)break;	 							   
	if(i!=5)return 1;
	return 0;		 
}

这个时候该配置的都配置了接下来就是两个单片机之间的通信了。

主机我们负责发送数据,我们需要配置发送地址和发送的速率

从机负责接受数据,我们需要配置接收地址和接受速率等

/* 配置接受和发送的地址 */
const u8 TX_ADDRESS[TX_ADR_WIDTH]={0x09,0x25,0x57,0x11,0x01}; //发送地址
const u8 RX_ADDRESS[RX_ADR_WIDTH]={0x09,0x25,0x57,0x11,0x01}; //发送地址
地址可以自己随意设定,但是主机和从机的地址应该一样,否则连接不上
/* RX模式 */
void RX_MODE(void)
{
	NRF_CE(0);
	/* 配置接收的地址 */
	NRF_WRITE_BUF(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);
	/* 通道0自动应答 */
	NRF_WR_REG(NRF_WRITE_REG+EN_AA,0x01);      
	/* 接收数据通道0允许 */
	NRF_WR_REG(NRF_WRITE_REG+EN_RXADDR,0x01); 
	/* 设置工作频率 */	
	NRF_WR_REG(NRF_WRITE_REG+RF_CH,40);	
	/* 接收数据有效宽度为32字节 */	
	NRF_WR_REG(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);	
	/* 低噪声放大 发射功率 数据传输率2M */
	NRF_WR_REG(NRF_WRITE_REG+RF_SETUP,0x0f); 
	/* 配置为接收 */
	NRF_WR_REG(NRF_WRITE_REG+CONFIG, 0x0f);
	NRF_CE(1);
}
/* TX模式 */
void TX_MODE(void)
{
	NRF_CE(0);
	/* 发送的地址 */
	NRF_WRITE_BUF(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);
	/* 有效的字节宽度为32字节 */
	NRF_WRITE_BUF(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);
	/* 通道0自动应答 */
	NRF_WR_REG(NRF_WRITE_REG+EN_AA,0x01); 
	/* 数据接收通道0允许 */
	NRF_WR_REG(NRF_WRITE_REG+EN_RXADDR,0x01); 	 
	/* 等待500+86us 自动重发次数为10次*/
	NRF_WR_REG(NRF_WRITE_REG+SETUP_RETR,0x1a);
	/* 设置工作频率 */
	NRF_WR_REG(NRF_WRITE_REG+RF_CH,40);
	/* 低噪声放大 发射功率 数据传输率2M */
	NRF_WR_REG(NRF_WRITE_REG+RF_SETUP,0x0f); 
	/* 配置为发送 */
	NRF_WR_REG(NRF_WRITE_REG+CONFIG, 0x0e);
	NRF_CE(1);
}


**好 至此我们配置已经全部完成了大致分为

  • SPI初始化(必须)
  • 引脚高低电平的宏定义(不是必须)
  • 地址宏定义(不写的话需要查NRF数据手册很麻烦)
  • 自检(检验NRF是否好坏,代码是否正确)
  • 配置接受发送模式(通信必须)
  • 配置相应的速率,接收发送地址等
  • 实现通信**
    代码地址
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值