NRF24L01+模块:一对一双向通信,成功!
查找了很多资料,好多都是复制粘贴转发,或者安装英文手册直译的(比如我自己上篇笔记,,),看完还是一脸懵逼,没几个可行的,推荐几个比较实在的资料:手册我也不是完全弄明白,只能通过不断测试得出猜想的结论…
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通道为40NRF24L01_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通道为40NRF24L01_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通道为30NRF24L01_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);// 设置中断优先级分组2uart_init(9600); //串口初始化为9600LED_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通道为40NRF24L01_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);// 设置中断优先级分组2uart_init(9600); //串口初始化为9600LED_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);// 设置中断优先级分组2uart_init(9600); //串口初始化为9600LED_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);// 设置中断优先级分组2uart_init(9600); //串口初始化为9600LED_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;//设置字体为黑色 }}
NRF24L01+模块:一对一双向通信,成功!相关推荐
- NRF24L01+模块实现双向通信(带ACK payload)
本文主要关于NRF24L01+ 2.4GHz无线模块的应用. 目录 说明 模块开发的大致步骤 使用方式 一.单向通信 二.双向通信(有应答包(ACK payload)) 寄存器配置 三.星状组网 注意 ...
- NRF24L01模块多发一收通信(STM32)
NRF24L01模块多发一收通信(STM32) 目录 NRF24L01模块多发一收通信(STM32) 前言 一.解决思路 二.实验过程 1.设备ID号定义 2.数据打包发送 3.数据接收拆解 总结 前 ...
- NRF24L01+实现一对一数据双向传输
NRF24L01+实现一对一数据双向传输 目录 说明 带负载数据ACK的双向通信 配置NRF24L01+的收发程序 收发双方数据的处理 测试代码和结果 目录 说明 最近在diy四轴飞行器的时候,需要实 ...
- Lora模块一对一和一对多
什么是LoRa LoRa是美国Semtech(升特)公司2013年发布和推广的一种基于扩频技术的超远距离.低功耗无线传输方案.这一方案改变了以往关于传输距离与功耗相矛盾的问题,为用户提供一种简单的能实 ...
- 【STM32】NRF24L01模块的收发调试
NRF24L01 发送端.c文件 发送端.h文件 接收端.c文件 接收端.h文件 接收端main函数 总结: 这里我是用了两块板子来做通信实验,这里我就直接贴发送端和接收端的.c.h文件,一个是用标准 ...
- NRF24L01模块实现一发一收和多发一收
折腾了两天还是弄出来了.什么24L01介绍就不要了,淘宝资料一堆. 使用的单片机型号是STMF103ZET6.还是简单介绍几点: 1.硬件连接 如图标记右下角是1脚 CE:模式控制线 CSN:SPI片 ...
- 【STM32CubeMX】NRF24L01模块实现“1对1“及“1对多“无线通信
大家好,我是小政.本篇文章我将针对NRF24L01模块实现"1对1"及"1对多"无线通信的STM32CubeMX配置过程进行详细的讲解,让准备学习HAL库的 ...
- arduino笔记32:nRF24l01模块使用 电磁波频率 距离限制 掉电模式 热待机模式
最近再arduino中文社区看到了一篇介绍nrf24l01基本原理的帖子,内容感觉蛮不错的,学习一下,记录一下学习笔记. 大部分内容都是Arduino中文社区的帖子,附上自己的一点点体会. 目录 一. ...
- 51驱动NRF24L01通信,NRF24L01与TTL转NRF24L01模块通信
51驱动NRF24L01通信,NRF24L01与TTL转NRF24L01模块通信 NRF24L01 一.简介 二.引脚功能描述 程序设计 一.对 24L01 的程序编程的基本思路如下: 二.Tx 与 ...
- 基于STM32F1与NRF24L01模块的SPI简单通信
一.前言 1.简介: 本文是基于STM32F1,将数据发送至NRF模块的寄存器,并将数据重新读取,通过串口发送出来的简单SPI单通信. 2.SPI简介: 调过STM8的都已经对SPI有所了解,调法都一 ...
最新文章
- 北京学python去哪里好_北京想学习Python应该去哪里好
- EF-Net一种适用于双流SOD的有效检测模型(Pattern Recognition)
- 学习 PixiJS — 碰撞检测
- mysql 手工注入教程_mysql手工注入步骤
- 沉梦云商城系统2.1.7免授权源码+搭建教程
- 设计一款知识性产品需要考虑十二个基本问题
- 关于updatepanel回传之后JS失效问题
- 用vue实时监听多个用户扫描二维码
- adb 环境变量配置 无效
- python检验多重共线性_python从机器学习角度处理共线性
- 永磁同步电机数学模型
- 如何将图片转成png格式?图片的格式怎么转换
- Centos 7/8 root密码重置
- 斐讯n1 linux连接wifi,斐讯 N1 部署 Docker 和 OpenWRT,并利用 Hostapd 开启 Wi-Fi 热点
- mapbox-gl加载three.js泛光效果(视频)
- 作业二:wireshark抓包与ping操作
- Swift可选类型(Optional)之星耀
- 3.2.3 存储器与CPU的连接(重难点 看完就会)
- android 进球数据布局,10个有趣的数据,总结梅西令人难以置信的2018-19赛季!
- 计算机密码学学习笔记(二)——Shannon理论
热门文章
- 如何使用代理服务器下载文件_8uftp怎么下载客户文件,怎么使用8uftp下载客户文件?...
- 12306网站抢票机制攻与防
- gsp计算机系统内审结论,GSP计算机系统内审表.docx
- Unity3D游戏框架设计
- 冰点下载器手机版apk_冰点文库下载器下载|冰点文库下载器手机版安卓版 3.1.7_ - 极光下载站...
- 【计算摄影】相机成像原理:从光到JPEG图像
- 计算机图形学-样条曲线Spline
- MyBatis源码阅读指南
- 蓝桥杯国赛之光敏电阻传感器
- 设计系统测试用例时应考虑的类型