NRF24L01+模块:一对一双向通信,成功!

2023-05-16

查找了很多资料,好多都是复制粘贴转发,或者安装英文手册直译的(比如我自己上篇笔记,,),看完还是一脸懵逼,没几个可行的,推荐几个比较实在的资料:手册我也不是完全弄明白,只能通过不断测试得出猜想的结论…
nRF24L01一对多通信及多对一通信,有中文手册可下载
一对多通信中通道地址设定注意事项
NRF24L01一对多通信方法看完这两个资料,发现关键的问题还是地址和收发问题:
得弄清几个概念:
1,在一个nRF24L01+模块中,有1个发送通道,6个接收通道。这就意味着可以发也能收但是不同时。
2,有256个通信频率,在同一个通信频率上,可挂载6个接收地址。
3,Enhance模式中,发送端发送数据后,需用接收通道0,接收发送端反馈过来的应答信号。这样发生端才知道自己发送成功了。
4,6个接收通道中,接收通道0,可看作带复用功能,除了和其它5个通道一样具有普通接收通道的作用,还有ACK自动应答接收的作用,也就是说,不是所有的通道都能接收自动应答信号ACK,若该模块除了接收数据外,它还想同时发送数据,那它就需要一个通道来接收应答信号ACK,这个接收通道只能是接收通道0,故他接收其他模块发来的数据,应该选择的其他5个通道。
5,单方向,频率要一致,也就是发送频率和对方的接收频率要一致,数据宽度要一致发射速率与发射功率须一致
6,实际上,一个模块同一时刻只能是发送或接收,不能同时收发,只是切换快,感觉起来收发是同时进行的。
7,三地址一致性:
比如发送端:
const u8 MTX_ADDRESS[TX_ADR_WIDTH]={0x30,0x43,0x10,0x10,0x01}; //主机发送地址
const u8 MRX_ADDRESS_ACK0[TX_ADR_WIDTH]={0x30,0x43,0x10,0x10,0x01}; //主机通道0接收ack地址
接收端
const u8 SRX_ADDRESS_0[TX_ADR_WIDTH]={0x30,0x43,0x10,0x10,0x01}; //从机通道0接收地址
在这里插入图片描述
拿左边的一收一发来说,测试时代码如下;
**

实验一,错误示范

**
设地址;

const u8 TX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址
const u8 RX_ADDRESS[RX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址

发送端配置:
通过接收通道1来接收应答

//通过接收通道1来接收应答,无法自动应答,直接“骗”自己说已经发送成功
void NRF24L01_TX_Mode(void)
{														 
	NRF24L01_CE=0;	    
  	NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址 
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)RX_ADDRESS,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK	  

  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x02);     //使能通道1的自动应答    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x02); //使能通道1的接收地址  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);       //设置RF通道为40
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
	NRF24L01_CE=1;//CE为高,10us后启动发送
}

接收端配置:
利用接收通道1接收数据

利用接收通道1接收数据
void NRF24L01_RX_Mode(void)
{
	NRF24L01_CE=0;	  
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
	  
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x02);    	//使能通道1的自动应答    
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x02);	//使能通道1的接收地址  	 
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);	    	//设置RF通信频率		  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH);//选择通道1的有效数据宽度 	    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);	//设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);		//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 
  	NRF24L01_CE = 1; //CE为高,进入接收模式 
}		

//利用接收通道0接收数据
//void NRF24L01_RX_Mode(void)
//{
//	NRF24L01_CE=0;	  
//  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
//	  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);    	//使能通道0的自动应答    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);	//使能通道0的接收地址  	 
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);	    	//设置RF通信频率		  
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道1的有效数据宽度 	    
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);	//设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);		//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 
//  	NRF24L01_CE = 1; //CE为高,进入接收模式 
//}	

或利用接收通道0接收数据

//利用接收通道1接收数据
//void NRF24L01_RX_Mode(void)
//{
//	NRF24L01_CE=0;	  
//  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
//	  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x02);    	//使能通道1的自动应答    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x02);	//使能通道1的接收地址  	 
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);	    	//设置RF通信频率		  
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH);//选择通道1的有效数据宽度 	    
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);	//设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);		//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 
//  	NRF24L01_CE = 1; //CE为高,进入接收模式 
//}		

//利用接收通道0接收数据
void NRF24L01_RX_Mode(void)
{
	NRF24L01_CE=0;	  
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
	  
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);    	//使能通道0的自动应答    
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);	//使能通道0的接收地址  	 
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);	    	//设置RF通信频率		  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道1的有效数据宽度 	    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);	//设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);		//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 
  	NRF24L01_CE = 1; //CE为高,进入接收模式 
}	

实验现象:
接收端分别采用两种接收通道接收,现象一致:发送端显示发送成功,但接收端并没有收到数据.
在这里插入图片描述
结论:当发送端采用接收通道1来接收应答信号时,接收不到应答或者不需要接收端应答(个人猜测).

实验二:正确的

在前面的基础上,接收方式仍然分别采用通道1和通道0接收
把发送端改为接收通道0接收应答信号.
发送端:
通过接收通道0来接收应答

通过接收通道0来接收应答
void NRF24L01_TX_Mode(void)
{														 
	NRF24L01_CE=0;	    
  	NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址 
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK	  

  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);     //使能通道0的自动应答    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);       //设置RF通道为40
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
	NRF24L01_CE=1;//CE为高,10us后启动发送
}

接收端:和实验一代码一致,分别用通道0和通道1接收
在这里插入图片描述
实验现象:当发送端采用接收通道0接收应答信号时,接收端采用接收通道1和接收通道0接收数据,都能收到!

注意到:
接收端的代码里有两个语句是被注释掉的,结果也能运行成功,初步猜测,正点原子的这两句代码貌似多余

//  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);    	//使能通道0的自动应答    
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);	//使能通道0的接收地址  	 
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x02);    	//使能通道1的自动应答    
//  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x02);	//使能通道1的接收地址  

实验二的通信模型:
在这里插入图片描述
其中地址是举例的,不和代码一致.展示了用接收通道0接收的情况.

实验三,主机从机双向通信,FreeRTOS版

通信模型:
在这里插入图片描述
主机------>从机,采用频率通道RF_CH=30
从机------>主机,采用频率通道RF_CH=40

主机端:

作为主机,发送数据给从机,设置主机发送地址为MTX_ADDRESS,使用接收通道0来接收从机的应答ack,地址为MRX_ADDRESS_ACK0,
对于从机也有个通道(选通道1)来接收,其地址为SRX_ADDRESS_1,三者地址要一致,即MTX_ADDRESS=MRX_ADDRESS_ACK0=SRX_ADDRESS_1,
采用频率通道为40
发送模式配置:

void NRF24L01_MTX_Mode(void)
{														 
	NRF24L01_CE=0;	    
  	NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)MTX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址 
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)MRX_ADDRESS_ACK0,RX_ADR_WIDTH); //设置接收通道0来接收来自接收方返回的应答ACK	  

  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);     //使能通道0的自动应答0000 0001    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,30);       //设置RF通信频率为30,与从机一致
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
	NRF24L01_CE=1;//CE为高,10us后启动发送
}

接收模式配置:

void NRF24L01_MRX_Mode(void)
{
	NRF24L01_CE=0;	  
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)MRX_ADDRESS_1,RX_ADR_WIDTH);//主机通过通道1接收才机
	  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x02);    	//使能通道1的自动应答,0000 0010    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x02);	//使能通道1的接收地址  	 
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);	    	//设置RF通信频率,与从机发送频率一致,设为40		  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH);//选择通道1的有效数据宽度 	    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);	//设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);		//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 
  NRF24L01_CE = 1; //CE为高,进入接收模式 
}	

从机端:

作为从机,发送数据给主机,设置从机发送地址为STX_ADDRESS,使用接收通道0来接收主机的应答ack,地址为SRX_ADDRESS_ACK0,
对于主机也有个通道(选通道1)来接收,其地址为MRX_ADDRESS_1,三者地址要一致,即STX_ADDRESS=SRX_ADDRESS_ACK0=MRX_ADDRESS_1,
采用频率通道为40
发送模式配置:

oid NRF24L01_STX_Mode(void)
{														 
	NRF24L01_CE=0;	    
  	NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)STX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址 
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)SRX_ADDRESS_ACK0,RX_ADR_WIDTH); //设置通道0来接收主机的应答ACK	  

  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);     //使能通道0的自动应答 00000001   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);       //设置RF通信频率为40,与主机接收频率一致
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);    //0000 1110 配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,发送模式,开启所有中断
	NRF24L01_CE=1;//CE为高,10us后启动发送
}

接收模式配置:

void NRF24L01_SRX_Mode(void)
{
	NRF24L01_CE=0;	  
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)SRX_ADDRESS_1,RX_ADR_WIDTH);//从机使用通道1接收主机数据
	  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x02);    	//使能通道1的自动应答    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x02);	//使能通道1的接收地址  	 
	  NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,30);	    	//设置RF通信频30,与主机发送频率一致		  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH);//选择通道1的有效数据宽度 	    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);	//设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);		//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 
  	NRF24L01_CE = 1; //CE为高,进入接收模式 
}		

模式切换与数据传输需

同一个时刻,只能一种模式,要么发要么收,要做到主机发的时候从机收,主机接收到应答后立马切换为收,从机接到数据后立马切换为发.
在实时操作系统FreeRTOS中,任务采用时间片调度,为避免在发送模式一切换,还没来得及发送数据就被切为收,或者接收模式一切换,还没收到数据就被切换才发送模式,需要使得这两个任务作为一个整体轮流切换运行,采用二值信号量的方式,
主机端:

SemapMTX_Handle_t=xSemaphoreCreateBinary();	
//创建接收任务二值信号量								
SemapMRX_Handle_t=xSemaphoreCreateBinary();
//从发送任务开始运行,然后再接收任务运行,如此反复,同时只有一个任务运行
xSemaphoreGive(SemapMTX_Handle_t);
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "lcd.h"


#include "ds18b20.h"   
#include "key.h"
#include "spi.h"
#include "24l01.h"

#include "FreeRTOS.h"
#include "task.h"
//#include "queue.h"
#include "semphr.h"

/************************************************
 
************************************************/
//开始任务
#define START_TASK_PRIO		1
#define START_STK_SIZE 		128  
TaskHandle_t StartTask_Handler;
void start_task(void *pvParameters);
//LCDShow任务
#define LCDShow_TASK_PRIO		1	
#define LCDShow_STK_SIZE 		100  
TaskHandle_t LCDShowTask_Handler;
void LCDShow_task(void *pvParameters);
//LEDShow任务
#define LEDShow_TASK_PRIO		1
#define LEDShow_STK_SIZE 		100  
TaskHandle_t LEDShowTask_Handler;
void LEDShow_task(void *pvParameters);


//ShowTemperature任务
#define ShowTemperature_TASK_PRIO		2	
#define ShowTemperature_STK_SIZE 		100  
TaskHandle_t ShowTemperatureTask_Handler;
void ShowTemperature_task(void *pvParameters);

//NRFreceive任务
#define NRFreceive_TASK_PRIO		3
#define NRFreceive_STK_SIZE 		100  
TaskHandle_t NRFreceiveTask_Handler;
void NRFreceive_task(void *pvParameters);

//NRFsend任务
#define NRFsend_TASK_PRIO		3
#define NRFsend_STK_SIZE 		100  
TaskHandle_t NRFsendTask_Handler;
void NRFsend_task(void *pvParameters);

//创建二值信号量
SemaphoreHandle_t SemapMTX_Handle_t;//发送任务二值信号量句柄
SemaphoreHandle_t SemapMRX_Handle_t;//接收任务二值信号量句柄

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LCD_Init();//初始化LCD屏幕	
  LED_Init();		  		//初始化与LED连接的硬件接口
 	KEY_Init();				//按键初始化
	NRF24L01_Init();    	//初始化NRF24L01  
	while(NRF24L01_Check())	//检查NRF24L01是否在位.	
	{
		LCD_ShowString(10,100,200,16,16,"NRF24L01 Error");
		delay_ms(200);
		LCD_Fill(10,100,200,100+16,WHITE);
 		delay_ms(200);
	}	
	 LCD_ShowString(10,100,200,16,16,"NRF24L01 OK");	
	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
	 //创建LCDShow任务
    xTaskCreate((TaskFunction_t )LCDShow_task,     
                (const char*    )"LCDShow_task",   
                (uint16_t       )LCDShow_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LCDShow_TASK_PRIO,
                (TaskHandle_t*  )&LCDShowTask_Handler);  		
   //创建LEDShow任务
    xTaskCreate((TaskFunction_t )LEDShow_task,     
                (const char*    )"LEDShow_task",   
                (uint16_t       )LEDShow_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LEDShow_TASK_PRIO,
                (TaskHandle_t*  )&LEDShowTask_Handler);	
    //创建ShowTemperature任务
    xTaskCreate((TaskFunction_t )ShowTemperature_task,     	
                (const char*    )"ShowTemperature_task",   	
                (uint16_t       )ShowTemperature_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )ShowTemperature_TASK_PRIO,	
                (TaskHandle_t*  )&ShowTemperatureTask_Handler);   
								
		//创建NRFreceive任务
    xTaskCreate((TaskFunction_t )NRFreceive_task,     
                (const char*    )"NRFreceive_task",   
                (uint16_t       )NRFreceive_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )NRFreceive_TASK_PRIO,
                (TaskHandle_t*  )&NRFreceiveTask_Handler);

   //创建NRFsend任务
    xTaskCreate((TaskFunction_t )NRFsend_task,     
                (const char*    )"NRFsend_task",   
                (uint16_t       )NRFsend_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )NRFsend_TASK_PRIO,
                (TaskHandle_t*  )&NRFsendTask_Handler); 	
		//创建发送任务二值信号量								
    SemapMTX_Handle_t=xSemaphoreCreateBinary();

		
		//创建接收任务二值信号量								
   SemapMRX_Handle_t=xSemaphoreCreateBinary();
								
		//从发送任务开始运行,然后再接收任务运行,如此反复,同时只有一个任务运行
		xSemaphoreGive(SemapMTX_Handle_t);						
    //vTaskSuspend(ShowTemperatureTask_Handler);		
		//vTaskSuspend(NRFsendTask_Handler);
     //vTaskSuspend(NRFreceiveTask_Handler);									
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//LCDShow任务函数
void LCDShow_task(void *pvParameters)
{
  	
    //POINT_COLOR=RED;
	  LCD_ShowString(70,0,160,24,24,"master!");
	  LCD_ShowString(110,290,110,24,24,"2020/11/14");		//显示一个字符串,240*320 的分辨率
    while(1)
    {
			
			vTaskDelay(10);  
    }
}

//LEDShow任务函数
void LEDShow_task(void *pvParameters)
{
  	LED_Init();//初始化LED		
    while(1)
    {
			LED0=~LED0;
      vTaskDelay(300);  
			LED1=~LED1;
			vTaskDelay(300); 
    }
}


//ShowTemperature任务函数 
void ShowTemperature_task(void *pvParameters)
{
  u8 t=0;			    
	short temperature;     
 	while(DS18B20_Init())	//DS18B20初始化	
	{
		LCD_ShowString(10,50,200,16,16,"DS18B20 Error");
		delay_ms(200);
		LCD_Fill(10,50,239,50+16,WHITE);
 		delay_ms(200);
	}								   
	LCD_ShowString(10,50,200,16,16,"DS18B20 OK");
 	LCD_ShowString(10,70,200,16,16,"Temp:   . C");	 
	while(1)
	{	    	    
 		if(t%10==0)//每100ms读取一次
		{									  
			temperature=DS18B20_Get_Temp();	
			if(temperature<0)
			{
				LCD_ShowChar(10+40,70,'-',16,0);			//显示负号
				temperature=-temperature;					//转为正数
			}else LCD_ShowChar(10+40,70,' ',16,0);			//去掉负号
			LCD_ShowNum(10+40+8,70,temperature/10,2,16);	//显示正数部分	    
   		LCD_ShowNum(10+40+32,70,temperature%10,1,16);	//显示小数部分 		   
		}				   
	 	delay_ms(10);
		t++;
		if(t==20)
		{
			t=0;
		}
	}
}  


//NRFreceive任务函数
void NRFreceive_task(void *pvParameters)
{
	u8 tmp_buf[33]; 
	LCD_ShowString(10,120,200,16,16,"MRX_Mode");	
	LCD_ShowString(10,140,239,16,16,"Received Data From Slave:");			  
	while(xSemaphoreTake(SemapMRX_Handle_t,portMAX_DELAY))
	{	 //接收模式	
    NRF24L01_MRX_Mode(); 			
		while(NRF24L01_RxPacket(tmp_buf)!=0)
		{
//    	LCD_ShowString(10,160,239,16,16,"receiving....");   
//			vTaskDelay(100);
//			LCD_Fill(10,160,239,160+16,WHITE);//闪烁提示
      vTaskDelay(100);			
		}
		//LCD_Fill(10,160,239,160+16,WHITE);//清空上面的显示	
		POINT_COLOR=RED;
		LCD_ShowString(10,160,239,24,24,tmp_buf); 
		POINT_COLOR=BLACK;
    xSemaphoreGive(SemapMTX_Handle_t);	//直到发送成功才释放二值信号量,允许接收任务运行
	};		
}

//NRFsend任务函数
void NRFsend_task(void *pvParameters)
{
	u8 *tmp_P[5]={"AAAAA","BBBBB","CCCCC","DDDDD","EEEEE"};//指针数组
  u8 i=0;
	LCD_ShowString(10,200,200,16,16,"MTX_Mode");	
	LCD_ShowString(10,220,239,16,16,"Sended Data To Slave:");	
	
	while(xSemaphoreTake(SemapMTX_Handle_t,portMAX_DELAY))
		{	 //发送模式	
	  NRF24L01_MTX_Mode(); 
		if(++i>4)i=0;
		while(NRF24L01_TxPacket(tmp_P[i])!=TX_OK)
			{
//				LCD_ShowString(10,240,239,16,16,"sending......."); 	
//				vTaskDelay(100);
//				LCD_Fill(10,240,239,240+16,WHITE);//闪烁提示	
				vTaskDelay(100);
			}
	//	LCD_Fill(10,240,239,240+16,WHITE);//清空上面的显示
    POINT_COLOR=MAGENTA;				
		LCD_ShowString(10,240,239,16,16,tmp_P[i]); 
		POINT_COLOR=BLACK;
		xSemaphoreGive(SemapMRX_Handle_t);//直到发送成功才释放二值信号量,允许接收任务运行
		};		   	
}


从机端:

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "lcd.h"


#include "ds18b20.h"   
#include "key.h"
#include "spi.h"
#include "24l01.h"

#include "FreeRTOS.h"
#include "task.h"
//#include "queue.h"
#include "semphr.h"

/************************************************
 
************************************************/
//开始任务
#define START_TASK_PRIO		1
#define START_STK_SIZE 		128  
TaskHandle_t StartTask_Handler;
void start_task(void *pvParameters);
//LCDShow任务
#define LCDShow_TASK_PRIO		1	
#define LCDShow_STK_SIZE 		100  
TaskHandle_t LCDShowTask_Handler;
void LCDShow_task(void *pvParameters);
//LEDShow任务
#define LEDShow_TASK_PRIO		1
#define LEDShow_STK_SIZE 		100  
TaskHandle_t LEDShowTask_Handler;
void LEDShow_task(void *pvParameters);


//ShowTemperature任务
#define ShowTemperature_TASK_PRIO		2	
#define ShowTemperature_STK_SIZE 		100  
TaskHandle_t ShowTemperatureTask_Handler;
void ShowTemperature_task(void *pvParameters);

//NRFsend任务
#define NRFsend_task_PRIO		3
#define NRFsend_STK_SIZE 		100  
TaskHandle_t NRFsendTask_Handler;
void NRFsend_task(void *pvParameters);

//NRFreceive任务
#define NRFreceive_task_PRIO		3
#define NRFreceive_STK_SIZE 		100  
TaskHandle_t NRFreceiveTask_Handler;
void NRFreceive_task(void *pvParameters);


//创建二值信号量
SemaphoreHandle_t SemapSTX_Handle_t;//发送任务二值信号量句柄
SemaphoreHandle_t SemapSRX_Handle_t;//接收任务二值信号量句柄

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LCD_Init();//初始化LCD屏幕	
  LED_Init();		  		//初始化与LED连接的硬件接口
 	KEY_Init();				//按键初始化
	NRF24L01_Init();    	//初始化NRF24L01  
	while(NRF24L01_Check())	//检查NRF24L01是否在位.	
	{
		LCD_ShowString(10,100,200,16,16,"NRF24L01 Error");
		delay_ms(200);
		LCD_Fill(10,100,239,100+16,WHITE);
 		delay_ms(200);
	}	
  LCD_ShowString(10,100,200,16,16,"NRF24L01 OK");	
  
	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
	 //创建LCDShow任务
    xTaskCreate((TaskFunction_t )LCDShow_task,     
                (const char*    )"LCDShow_task",   
                (uint16_t       )LCDShow_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LCDShow_TASK_PRIO,
                (TaskHandle_t*  )&LCDShowTask_Handler);  		
   //创建LEDShow任务
    xTaskCreate((TaskFunction_t )LEDShow_task,     
                (const char*    )"LEDShow_task",   
                (uint16_t       )LEDShow_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LEDShow_TASK_PRIO,
                (TaskHandle_t*  )&LEDShowTask_Handler);	
    //创建ShowTemperature任务
    xTaskCreate((TaskFunction_t )ShowTemperature_task,     	
                (const char*    )"ShowTemperature_task",   	
                (uint16_t       )ShowTemperature_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )ShowTemperature_TASK_PRIO,	
                (TaskHandle_t*  )&ShowTemperatureTask_Handler);   
    //创建NRFsend任务
    xTaskCreate((TaskFunction_t )NRFsend_task,     
                (const char*    )"NRFsend_task",   
                (uint16_t       )NRFsend_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )NRFsend_task_PRIO,
                (TaskHandle_t*  )&NRFsendTask_Handler);  

		//创建NRFreceive任务
    xTaskCreate((TaskFunction_t )NRFreceive_task,     
                (const char*    )"NRFreceive_task",   
                (uint16_t       )NRFreceive_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )NRFreceive_task_PRIO,
                (TaskHandle_t*  )&NRFreceiveTask_Handler); 	
    //创建发送任务二值信号量								
    SemapSTX_Handle_t=xSemaphoreCreateBinary();

		//创建接收任务二值信号量								
    SemapSRX_Handle_t=xSemaphoreCreateBinary();
			
    //从接收任务开始运行,然后再发送任务运行,如此反复,同时只有一个任务运行
		xSemaphoreGive(SemapSRX_Handle_t);		
    //vTaskSuspend(ShowTemperatureTask_Handler);		
    //vTaskSuspend(NRFsendTask_Handler);	
    //vTaskSuspend(NRFreceiveTask_Handler);								
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//LCDShow任务函数
void LCDShow_task(void *pvParameters)
{	
    //POINT_COLOR=RED;
	  LCD_ShowString(70,0,160,24,24,"slave!");
	  LCD_ShowString(110,290,110,24,24,"2020/11/14");		//显示一个字符串,240*320 的分辨率
    while(1)
    {
			vTaskDelay(10);  
    }
}

//LEDShow任务函数
void LEDShow_task(void *pvParameters)
{
  	LED_Init();//初始化LED		
    while(1)
    {
			
			LED0=~LED0;
      vTaskDelay(300);  
			LED1=~LED1;
			vTaskDelay(300); 
		}
 
}


//ShowTemperature任务函数 
void ShowTemperature_task(void *pvParameters)
{
  u8 t=0;			    
	short temperature;     
 	while(DS18B20_Init())	//DS18B20初始化	
	{
		LCD_ShowString(10,50,200,16,16,"DS18B20 Error");
		delay_ms(200);
		LCD_Fill(10,50,239,50+16,WHITE);
 		delay_ms(200);
	}								   
	LCD_ShowString(10,50,200,16,16,"DS18B20 OK");
 	LCD_ShowString(10,70,200,16,16,"Temp:   . C");	 
	while(1)
	{	    	    
 		if(t%10==0)//每100ms读取一次
		{									  
			temperature=DS18B20_Get_Temp();	
			if(temperature<0)
			{
				LCD_ShowChar(10+40,70,'-',16,0);			//显示负号
				temperature=-temperature;					//转为正数
			}else LCD_ShowChar(10+40,70,' ',16,0);			//去掉负号
			LCD_ShowNum(10+40+8,70,temperature/10,2,16);	//显示正数部分	    
   			LCD_ShowNum(10+40+32,70,temperature%10,1,16);	//显示小数部分 		   
		}				   
	 	delay_ms(10);
		t++;
		if(t==20)
		{
			t=0;
		}
	}
}  



//NRFsend任务函数
void NRFsend_task(void *pvParameters)
{			 
	//u8 tmp_buf[33]="Hi! I AM Slave"; 	
	u8 *tmp_buf[5]={"aaaaa","bbbbb!","nnnnn","eeeee","hhhhh"};//指针数组
  u8 i=0;
	LCD_ShowString(10,200,200,16,16,"STX_Mode");	
	LCD_ShowString(10,220,239,16,16,"Sended Data To Master:");	
	while(xSemaphoreTake(SemapSTX_Handle_t,portMAX_DELAY))
	{	
    //发送模式	
    NRF24L01_STX_Mode();	
    if(++i>4)i=0;		
		while(NRF24L01_TxPacket(tmp_buf[i])!=TX_OK)
		{	
//			LCD_ShowString(10,240,239,16,16,"sending...."); 
//			vTaskDelay(100);
//			LCD_Fill(10,240,239,240+16,WHITE);//闪烁提示
			vTaskDelay(100);
		}
		//LCD_Fill(10,240,239,240+16,WHITE);//清空上面的显示
		POINT_COLOR=RED;
		LCD_ShowString(10,240,239,24,24,tmp_buf[i]); 
    POINT_COLOR=BLACK;		
    xSemaphoreGive(SemapSRX_Handle_t);//直到接收成功才释放二值信号量,允许发送任务运行	
	};
}



//NRFreceive任务函数
void NRFreceive_task(void *pvParameters)
{
	u8 tmp_buf[33]; 
	LCD_ShowString(10,120,200,16,16,"SRX_Mode");	
	LCD_ShowString(10,140,239,16,16,"Received Data From Master:");			  
	while(xSemaphoreTake(SemapSRX_Handle_t,portMAX_DELAY))
	{	
   //接收模式
    NRF24L01_SRX_Mode();		
		while(NRF24L01_RxPacket(tmp_buf)!=0)
		{
//		LCD_ShowString(10,160,239,16,16,"receiving......"); 
//		vTaskDelay(100);
//		LCD_Fill(10,160,239,160+16,WHITE);//清空上面的显示
			vTaskDelay(100);
		}
	//	LCD_Fill(10,160,239,160+16,WHITE);//清空上面的显示
		POINT_COLOR=MAGENTA;
		LCD_ShowString(10,160,239,16,16,tmp_buf);
    POINT_COLOR=BLACK;		
		xSemaphoreGive(SemapSTX_Handle_t);//直到接收成功才释放二值信号量,允许发送任务运行	
	};			
}

实验结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

发送动态数据,连拍三张照片反应一下双向通信,

实验四,裸机版双向

主机端:

地址:

const u8 MTX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //主机地址
const u8 MRX_ADDRESS_ACK[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //主机ACK地址
//const u8 SRX_ADDRESS_p1[RX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //接收通道1地址

const u8 MRX_ADDRESS_p1[RX_ADR_WIDTH]={0x44,0x43,0x10,0x10,0x04}; //接收通道1地址

主机接收从机的数据:
//该函数初始化NRF24L01到RX模式
//设置RX地址,写RX数据宽度,选择RF频道,波特率和LNA HCURR
//当CE变高后,即进入RX模式,并可以接收数据了
//利用接收通道1接收数据
与从机的此函数一致,但是地址不同,该地址与从机发送地址和接收应答的通道地址一致

void NRF24L01_RX_Mode(void)
{
	NRF24L01_CE=0;	  
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)MRX_ADDRESS_p1,RX_ADR_WIDTH);//写RX节点地址
	  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x02);    	//使能通道1的自动应答    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x02);	//使能通道1的接收地址  	 
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,30);	    	//设置RF通信频率		  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH);//选择通道1的有效数据宽度 	    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);	//设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);		//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 
  	NRF24L01_CE = 1; //CE为高,进入接收模式 
}		

//启动NRF24L01接收一次数据(一个字节)
//rxbuf:接收数据存放的首地址
//返回值:0,接收完成;其他,错误代码
//只能用来接收数据,但是不知道数据是什么时候发过来的,可以采用循环接收或者中断接收。
中断:
nRF24L01 的中断引脚( IRQ)为低电平触发,当状态寄存器中 TX_DS、 RX_DR 或 MAX_RT 为高时
触发中断。当 MCU 给中断源写‘ 1’时,中断引脚被禁止。可屏蔽中断可以被 IRQ 中断屏蔽。通过设置
可屏蔽中断位为高,则中断响应被禁止。默认状态下所有的中断源是被禁止的。

//需要结合IRQ中断来做一收到数据就做哪些操作

u8 NRF24L01_RxPacket(u8 *rxbuf)
{
	u8 sta;		    							   
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值    	 
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&RX_OK)//接收到数据
	{
		NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
		NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器 
		return 0; 
	}	   
	return 1;//没收到任何数据
}					   

主机发送数据给从机:
与从机的此函数一致,但地址不同,发送通道地址和接收应答通道的地址一致且要和从机机的接收通道地址一致

void NRF24L01_TX_Mode(void)
{														 
	NRF24L01_CE=0;	    
  	NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)MTX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址 
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)MRX_ADDRESS_ACK,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK	  

  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);     //使能通道0的自动应答    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,30);       //设置RF通道为30
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
	NRF24L01_CE=1;//CE为高,10us后启动发送
}

//启动NRF24L01发送一次数据(一个字节)
//txbuf:待发送数据首地址
//返回值:发送完成状况

u8 NRF24L01_TxPacket(u8 *txbuf)
{
	u8 sta;
	NRF24L01_CE=0;
  	NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF  32个字节
 	NRF24L01_CE=1;//启动发送	   
	while(NRF24L01_IRQ!=0);//等待发送完成
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值	   
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&MAX_TX)//达到最大重发次数
	{
		NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器 
		return MAX_TX; 
	}
	if(sta&TX_OK)//发送完成
	{
		return TX_OK;
	}
	return 0xff;//其他原因发送失败
}

主机main函数代码:

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "key.h"
#include "spi.h"
#include "24l01.h"   
 

void master_ReceiveDate(void);//发送数据
void master_SendDate(u8 *tmp_buf);//接收数据

u8 tmp_buf[33]; 

int main(void)
{ 	 
	delay_init();	    	 //延时函数初始化	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart_init(9600);	 	//串口初始化为9600
	LED_Init();		  		//初始化与LED连接的硬件接口
	LCD_Init();			   	//初始化LCD 	
 	KEY_Init();				//按键初始化
 	NRF24L01_Init();    	//初始化NRF24L01  
	LCD_ShowString(80,10,200,24,24,"Master");	
	LCD_ShowString(120,290,200,24,24,"2020/11/17");		  
 	while(NRF24L01_Check())	//检查NRF24L01是否在位.	
	{
		LCD_ShowString(10,130,200,16,16,"NRF24L01 Error");
		delay_ms(200);
		LCD_Fill(10,130,239,130+16,WHITE);
 		delay_ms(200);
	}								   
	LCD_ShowString(10,50,200,16,16,"NRF24L01 OK");
	while(1)
	{	
		NRF24L01_TX_Mode();
		master_SendDate("I am master!");
		//delay_ms(200);
	  NRF24L01_RX_Mode();
		while(NRF24L01_IRQ!=0);//等待数据到达
		master_ReceiveDate();	
	}
}

void master_ReceiveDate(void)//接收数据
{
	if(NRF24L01_RxPacket(tmp_buf)==0)//一旦接收到信息,则显示出来
	{
		LCD_ShowString(10,70,200,16,16,"master_RX_Mode");			  
		LCD_ShowString(10,90,200,16,16,"master_Received DATA:");	
		POINT_COLOR=RED;//设置字体为红色 
		LCD_ShowString(0,110,239,32,24,tmp_buf);   
		POINT_COLOR=BLACK;//设置字体为黑色  
	}		
}

void master_SendDate(u8 *tmp_send)//发送数据
{							     
  if(NRF24L01_TxPacket(tmp_send)==TX_OK)
	{
		LCD_ShowString(10,180,200,16,16,"master_TX_Mode:");	
		LCD_ShowString(10,200,239,32,16,"master_Sended DATA:");			
		POINT_COLOR=RED;//设置字体为红色 
		LCD_ShowString(10,220,239,32,24,tmp_send); 
		POINT_COLOR=BLACK;//设置字体为黑色 
	}
	
} 

从机端:

地址:

const u8 STX_ADDRESS[TX_ADR_WIDTH]={0x44,0x43,0x10,0x10,0x04}; //发送地址
const u8 SRX_ADDRESS_ACK[RX_ADR_WIDTH]={0x44,0x43,0x10,0x10,0x04}; //发送地址
//const u8 MRX_ADDRESS_p1[RX_ADR_WIDTH]={0x44,0x43,0x10,0x10,0x04}; //接收通道1地址

const u8 SRX_ADDRESS_p1[RX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //接收通道1地址
//初始化24L01的IO口

从机接收主机的数据:

与主机的此函数一致

u8 NRF24L01_RxPacket(u8 *rxbuf)
{
	u8 sta;		    							    
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值    	 
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&RX_OK)//接收到数据
	{
		NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
		NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器 
		return 0; 
	}	   
	return 1;//没收到任何数据
}

与主机的此函数一致,但是地址不同,该地址与主机发送地址和接收应答的通道地址一致
//该函数初始化NRF24L01到RX模式
//设置RX地址,写RX数据宽度,选择RF频道,波特率和LNA HCURR
//当CE变高后,即进入RX模式,并可以接收数据了
利用接收通道1接收数据,也可以选择其他接收通道,修改对于的通道配置即可,不需要和主机的接收通道对应。

void NRF24L01_RX_Mode(void)
{
	NRF24L01_CE=0;	  
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)SRX_ADDRESS_p1,RX_ADR_WIDTH);//写RX节点地址
	  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x02);    	//使能通道1的自动应答    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x02);	//使能通道1的接收地址  	 
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,30);	    	//设置RF通信频率		  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH);//选择通道1的有效数据宽度 	    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);	//设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);		//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 
  	NRF24L01_CE = 1; //CE为高,进入接收模式 
}		

与主机的此函数一致
具体见主机端的这个部分

u8 NRF24L01_RxPacket(u8 *rxbuf)
{
	u8 sta;		    							    
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值    	 
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&RX_OK)//接收到数据
	{
		NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
		NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器 
		return 0; 
	}	   
	return 1;//没收到任何数据
}

从机发送数据给主机

通过接收通道0来接收应答,个人推测,Enhance模式下,每个模块只有通道0 能接收应答,而且还是硬件自动的。
与主机的此函数一致,但地址不同,发送通道地址和接收应答通道的地址一致且要和主机的接收通道地址一致

void NRF24L01_TX_Mode(void)
{														 
	NRF24L01_CE=0;	    
  	NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)STX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址 
  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)SRX_ADDRESS_ACK,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK	  

  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);     //使能通道0的自动应答    
  	NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址  
  	NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,30);       //设置RF通道为40
  	NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
  	NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
	NRF24L01_CE=1;//CE为高,10us后启动发送
}

与主机的此函数一致
具体见主机端的这个部分

u8 NRF24L01_TxPacket(u8 *txbuf)
{
	u8 sta;   
	NRF24L01_CE=0;
  NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF  32个字节
 	NRF24L01_CE=1;//启动发送	   
	while(NRF24L01_IRQ!=0);//等待发送完成
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值	   
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&MAX_TX)//达到最大重发次数
	{
		NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器 
		return MAX_TX; 
	}
	if(sta&TX_OK)//发送完成
	{
		return TX_OK;
	}
	return 0xff;//其他原因发送失败
}

从机main函数代码:

与主机的此函数类似,其中while循环的语句顺序不用

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "key.h"
#include "spi.h"
#include "24l01.h"   

void slave_ReceiveDate(void);//发送数据
void slave_SendDate(u8 *tmp_buf);//接收数据
u8 tmp_buf[33]; 

int main(void)
 { 	 
	delay_init();	    	 //延时函数初始化	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart_init(9600);	 	//串口初始化为9600
	LED_Init();		  		//初始化与LED连接的硬件接口
	LCD_Init();			   	//初始化LCD 	
 	KEY_Init();				//按键初始化
 	NRF24L01_Init();    	//初始化NRF24L01  
	LCD_ShowString(80,10,200,24,24,"slave");	
	LCD_ShowString(120,290,200,24,24,"2020/11/17");		  
 	while(NRF24L01_Check())	//检查NRF24L01是否在位.	
	{
		LCD_ShowString(10,130,200,16,16,"NRF24L01 Error");
		delay_ms(200);
		LCD_Fill(10,130,239,130+16,WHITE);
 		delay_ms(200);
	}								   
	LCD_ShowString(10,50,200,16,16,"NRF24L01 OK");
	while(1)
	{
		NRF24L01_RX_Mode();
		while(NRF24L01_IRQ!=0);//等待数据到达
		slave_ReceiveDate();
		//delay_ms(200);
		NRF24L01_TX_Mode(); 
		slave_SendDate("I am slave!");
		
	}
}

void slave_ReceiveDate(void)//接收数据
{
	if(NRF24L01_RxPacket(tmp_buf)==0)//接收数据,并将标志位重置
	{
		POINT_COLOR=RED;//设置字体为红色 
		LCD_ShowString(0,110,239,32,24,tmp_buf);   
		POINT_COLOR=BLACK;//设置字体为黑色 	
		LCD_ShowString(10,70,200,16,16,"slave_RX_Mode");		  
		LCD_ShowString(10,90,200,16,16,"slave_Received DATA:");	
	}		
}

void slave_SendDate(u8 *tmp_send)//发送数据
{	
	if(NRF24L01_TxPacket(tmp_send)==TX_OK)//发送数据,并将标志位重置,再显示
	{	
		LCD_ShowString(10,180,200,16,16,"slave_TX_Mode:");
		LCD_ShowString(10,200,239,32,16,"slave_Sended DATA:");
		POINT_COLOR=RED;//设置字体为红色 
		LCD_ShowString(10,220,239,32,24,tmp_send); 
		POINT_COLOR=BLACK;//设置字体为黑色 		
  }		
} 

通信模型
选择的是同一频率通道,我猜想应该可以选择不同的频率,但要保证收发端的频率一致,因为同一个时刻,只有一种频率存在,比如我QQ发消息你,你微信发信息回我。这个模型相当于我QQ发信息你,你QQ回我。
在这里插入图片描述

实验结果:
在这里插入图片描述
奇怪的一件事是,昨晚烧入代码后,结果不理想,跑了几公里才把烦躁去掉,今天早上重新上电,居然好了,屡试不爽,重新烧入代码还能达到效果,是不是昨晚烧写代码太频繁了,板子累了,我还在坚持,,,,,,,,,后续试试发送动态数据,这样我才放心。

实验五,裸机版双向,动态数据

在实验四的基础上,改下main,其他不变,成功!

从机端的main

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "key.h"
#include "spi.h"
#include "24l01.h"   
  

void slave_ReceiveDate(void);//发送数据
void slave_SendDate(u8 *tmp_buf);//接收数据

u8 RXtmp_buf[33]; 

u8 *date_send[]={"AAAAA","BBBBB","CCCCC","DDDDD","EEEEE","FFFFF"};
u8 **pdata=date_send;
int main(void)
 { 	
  u8 i=0;	 
	delay_init();	    	 //延时函数初始化	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart_init(9600);	 	//串口初始化为9600
	LED_Init();		  		//初始化与LED连接的硬件接口
	LCD_Init();			   	//初始化LCD 	
 	KEY_Init();				//按键初始化
 	NRF24L01_Init();    	//初始化NRF24L01  
	LCD_ShowString(80,10,200,24,24,"slave");	
	LCD_ShowString(120,290,200,24,24,"2020/11/17");		  
 	while(NRF24L01_Check())	//检查NRF24L01是否在位.	
	{
		LCD_ShowString(10,130,200,16,16,"NRF24L01 Error");
		delay_ms(200);
		LCD_Fill(10,130,239,130+16,WHITE);
 		delay_ms(200);
	}								   
	LCD_ShowString(10,50,200,16,16,"NRF24L01 OK");
	while(1)
	{
		NRF24L01_RX_Mode();
		while(NRF24L01_IRQ!=0);//等待数据到达
		slave_ReceiveDate();
		NRF24L01_TX_Mode(); 
		slave_SendDate(date_send[i]);
		i++;	
    if(i==6)i=0;
	}
}

void slave_ReceiveDate(void)//接收数据
{
	if(NRF24L01_RxPacket(RXtmp_buf)==0)//接收数据,并将标志位重置
	{
		POINT_COLOR=RED;//设置字体为红色 
		LCD_ShowString(0,110,239,32,24,RXtmp_buf);   
		POINT_COLOR=BLACK;//设置字体为黑色 	
		LCD_ShowString(10,70,200,16,16,"slave_RX_Mode");		  
		LCD_ShowString(10,90,200,16,16,"slave_Received DATA:");	
	}		
}

void slave_SendDate(u8 *tmp_send)//发送数据
{	
	if(NRF24L01_TxPacket(tmp_send)==TX_OK)//发送数据,并将标志位重置,再显示
	{	
		LCD_ShowString(10,180,200,16,16,"slave_TX_Mode:");
		LCD_ShowString(10,200,239,32,16,"slave_Sended DATA:");
		POINT_COLOR=RED;//设置字体为红色 
		LCD_ShowString(10,220,239,32,24,tmp_send); 
		POINT_COLOR=BLACK;//设置字体为黑色 		
  }		
} 

主机端的main

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "key.h"
#include "spi.h"
#include "24l01.h"   
 

void master_ReceiveDate(void);//发送数据
void master_SendDate(u8 *tmp_buf);//接收数据


u8 RXtmp_buf[33]; 
u8 *date_send[]={"UUUUU","VVVVV","WWWWW","XXXXX","YYYYY","ZZZZZ"};

int main(void)
{ 	
  u8 i=0;	
	delay_init();	    	 //延时函数初始化	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart_init(9600);	 	//串口初始化为9600
	LED_Init();		  		//初始化与LED连接的硬件接口
	LCD_Init();			   	//初始化LCD 	
 	KEY_Init();				//按键初始化
 	NRF24L01_Init();    	//初始化NRF24L01  
	LCD_ShowString(80,10,200,24,24,"Master");	
	LCD_ShowString(120,290,200,24,24,"2020/11/17");		  
 	while(NRF24L01_Check())	//检查NRF24L01是否在位.	
	{
		LCD_ShowString(10,130,200,16,16,"NRF24L01 Error");
		delay_ms(200);
		LCD_Fill(10,130,239,130+16,WHITE);
 		delay_ms(200);
	}								   
	LCD_ShowString(10,50,200,16,16,"NRF24L01 OK");
	while(1)
	{	
		NRF24L01_TX_Mode();
		master_SendDate(date_send[i]);	
    i++;	
    if(i==6)i=0;		

	  NRF24L01_RX_Mode();
		while(NRF24L01_IRQ!=0);//等待数据到达
		master_ReceiveDate();	
	}
}

void master_ReceiveDate(void)//接收数据
{
	if(NRF24L01_RxPacket(RXtmp_buf)==0)//一旦接收到信息,则显示出来
	{
		LCD_ShowString(10,70,200,16,16,"master_RX_Mode");			  
		LCD_ShowString(10,90,200,16,16,"master_Received DATA:");	
		POINT_COLOR=RED;//设置字体为红色 
		LCD_ShowString(0,110,239,32,24,RXtmp_buf);   
		POINT_COLOR=BLACK;//设置字体为黑色  
	}		
}

void master_SendDate(u8 *tmp_send)//发送数据
{							     
  if(NRF24L01_TxPacket(tmp_send)==TX_OK)
	{
		LCD_ShowString(10,180,200,16,16,"master_TX_Mode:");	
		LCD_ShowString(10,200,239,32,16,"master_Sended DATA:");			
		POINT_COLOR=RED;//设置字体为红色 
		LCD_ShowString(10,220,239,32,24,tmp_send); 
		POINT_COLOR=BLACK;//设置字体为黑色 
	}
	
} 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NRF24L01+模块:一对一双向通信,成功! 的相关文章

随机推荐