自助个人网站注册,建网站报价表,推广公司产品,哪个平台建网站比较好NRF24L01简要介绍 这里主要介绍模块的最重要的参数#xff0c;废话就不多介绍了。 该模块是一款无线通信模块#xff0c;一个模块即可同时具备发射和接收数据的功能#xff0c;但是要想实现通信必须使用两个模块之间才能进行通信。NRF24L01模块使用的总线控制方式为SPI总…NRF24L01简要介绍 这里主要介绍模块的最重要的参数废话就不多介绍了。 该模块是一款无线通信模块一个模块即可同时具备发射和接收数据的功能但是要想实现通信必须使用两个模块之间才能进行通信。NRF24L01模块使用的总线控制方式为SPI总线。SPI的通信方式本文就不介绍了。
预备知识 首先需要知道NRF24L10的通信过程是怎样的这里主要是指具体的通信方式假设一个模块A设置为发送方另一个模块B设置为接收方那么A和B之间通信需要几个基本设置只有配置好这些参数后双方才能进行通信。
通道 通道是发送方与接收方的通信具体的一条路可以这么理解比如小时候我们玩的两个人用纸杯子连一条线来进行传话那么这里这条线就可以理解为通道因为双方的声音是通过这条线进行传输的。对于NRF24L01模块其最多有6个通道也就是说一个设备最多可以与6个设备同时进行通信。
发送地址与接收地址 模块通信中有TX_ADDR和RX_ADDR两个地址。 所谓发送地址就是对于当前模块你希望将数据在数据通道中发往哪个具体的地址这个地址就是发送地址。对于发送模式下需要对该地址进行配置。接收地址其实有些同学可能会越看越觉得难以理解其实我们换个说法就很容易理解了直接把接收地址理解为本地地址也就是你用这个地址来接收别人发送的数据的地址只有当别人发送过来的数据的发送地址和你的地址相同时你才将这个数据进行接收。 对于接收地址接收模式下需要进行配置这是理所当然的但是注意接收地址在发送模式中也要进行配置当工作在自动应答模式下为什么呢这是因为作为发送方我们发送完数据后还需要通过接收应答信号来确定接收方是否接收到了我们发送的数据那么这个接收方的应答信号来了的话发送方就需要去接收因此这也是我们配置接收地址的原因了。 在NRF24L01模块中发送地址TX_ADDR只有一个而接收地址最多可以配置6个。
NRF24L01引脚介绍 数据手册上有很多引脚的介绍但是我们实际使用的话主要用到其中6个引脚如下图。 其中SPI的四个引脚就不过多介绍了。主要介绍另外两个引脚CE和IRQ。在下一节可以看到CE的主要功能是用来配置NRF24L01的工作模式的。而另外一个引脚IRQ其实是中断引脚这里具体解释一下这个引脚的作用是什么。 当下面的情况发生时IRQ引脚会被硬件自动拉低用于提醒我们中断的产生 1、接收到数据时IRQ引脚会被硬件拉低 2、发送数据成功时IRQ引脚会被硬件拉低 3、达到最大重发次数时IRQ引脚会被硬件拉低 当上述三种情况发生时通过IRQ引脚的检测我们可以知道事件的发生比如在发射模式下我们可以通过检测IRQ引脚是否被拉低来得知发送是否完成或者是发送次数达到最大重发次数。当IRQ引脚发起中断后必须进行手动清除中断否则IRQ引脚将一直保持低电平状态在后面讲到的STATUS寄存器中我们可以通过对STATUS寄存器的RX_DR、TX_DS、MAX_RT三个位置1分别清除三种情况产生的中断。
NRF24L01工作模式 在数据手册中模块有6种工作模式如果只是进行简单的通信实验我们不需要了解那么多只需要知道三种模式掉电模式、发射模式、接收模式。掉电模式顾名思义就是让模块处于关机状态为了省电此时PWR_UP位为0。发射模式和接收模式的引脚具体配置如下图所示这里需要额外说明的有两点第一个是在配置为发射模式时需要将CE引脚拉低至少10us第二个是不管是配置为发射模式还是接收模式首先需要让模块处于掉电模式不过在实际操作过程中发现好像没有进行这一步操作也没什么问题但最好还是按手册规定来。
NRF24L01相关操作码 这里主要介绍需要用到的操作码。一般不会用到的操作码就不介绍了具体如下图所示。 R_REGISTER指令用于对寄存器进行读操作0x000A AAAA这里的A表示任意的数据也就是你寄存器的地址读操作时前面三位必须是0同理写寄存器操作时前面三位必须是001。 R_RX_PAYLOAD是读取接收数据寄存器中数据的操作码最多读32字节。 W_RX_PAYLOAD是写数据到发送数据寄存器的操作同样最多32字节。其实这里我不太理解为什么名称不是W_TX_PAYLOAD在实际代码中我还是比较喜欢用W_TX_PAYLOAD来表示这个操作码的。 FLUSH_RX和FLUSH_TX就是用于清空接收数据寄存器和发送数据寄存器的操作码因为有些情况寄存器中发送或者接收的数据会满了如果没有及时清空里面的内容会导致下一次的数据读取或接收产生错误。
寄存器地址 这里我们同样只介绍一般情况下需要用到的寄存器。
CONFIG寄存器 CONFIG寄存器主要用于对工作模式进行设置 CONFIG寄存器地址:0x00 发射模式下设置参数:0x0E 接收模式设置参数:0x0F
EN_AA寄存器 EN_AA寄存器主要用于使能通道自动应答 EN_AA寄存器地址:0x01 用到第几个通道就将对应的位置1例如用到通道0则EN_AA:0x01
EN_RXADDR寄存器 EN_RXADDR寄存器主要用于使能数据通道接收允许 EN_RXADDR地址0x02 用到第几个通道就将对应的位置1
SETUP_AW寄存器 SETUP_AW寄存器地址:0x03 SETUP_AW寄存器主要用于对地址长度进行配置第0位和第1位 具体配置规则见下表。注意这里的地址长度是发射地址和接收地址而不是单独某一个也就是说发射地址和接收地址的长度必须一样。
SETUP_RETR寄存器 SETUP_RETR寄存器地址:0x04 SETUP_RETR寄存器主要用于重发相关的参数配置主要包括重发时间间隔和重发次数
RF_CH寄存器 RF_CH寄存器地址:0x05 RF_CH寄存器主要用于设置通道的工作频率第0位到第6位
RF_SETUP寄存器 RF_SETUP寄存器地址:0x06 RF_SETUP寄存器主要用于配置传输速率第3位和发射功率第2位和第1位
STATUS寄存器 STATUS寄存器地址:0x07: STATUS寄存器主要用来获取当前模块状态的通过该寄存器可以得知模块是否发送数据成功发射模式下、接收到数据(接收模式下)、是否达到最大重发次数发射模式下及其他相关信息。通过检查STATUS寄存器的RX_DR位可以判断在接收状态下是否收到数据并对该位写1清除中断实现对该位的清零操作。对于TX_DS和MAX_RT位同理。 RX_ADDR_P0寄存器 RX_ADDR_P0寄存器地址0x0A RX_ADDR_P0寄存器主要用于设置接收通道0的接收地址最大长度为5 还有通道12345也是相同的就不一一列出了
TX_ADDR寄存器 TX_ADDR寄存器地址:0x10 TX_ADDR寄存器主要用于配置发射地址一个设备只有一个发射地址最大长度5
RX_PW_P0寄存器 RX_PW_P0寄存器地址0x11 RX_PW_P0寄存器主要用于设置接收通道0的接收地址宽度范围在1-32不能设置为0通道12345也是相同的就不一一列出了 至此所有需要用到的寄存器就全部介绍完了接下来我们进入代码部分。
各功能代码
相关定义
#ifndef __NRF_H__
#define __NRF_H__
#include STC8.H
#includeUART.hsbit CEP6^0;
sbit CSP6^1;
sbit CLKP6^2;
sbit MOSIP6^3;
sbit MISOP6^4;
sbit IRQP6^5;#define TX_ADDR_WIDTH 5
#define RX_ADDR_WIDTH 5
#define TX_PLOAD_WIDTH 1
#define RX_PLOAD_WIDTH 1#define READ_REG 0x00
#define WRITE_REG 0x20
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2#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 RX_ADDR_P0 0x0A
#define TX_ADDR 0x10
#define RX_PW_P0 0x11#define RX_FLAG 0x40
#define TX_FLAG 0x20
#define MAX_FLAG 0x10void NRF_Init();
void NRF_Tx_Mode();
uchar NRF_Tx_Data(uchar*buffer);
void NRF_Rx_Mode();
uchar NRF_Rx_Data(uchar*buffer);
#endif注意引脚对应需要按照你自己的接线方式来修改。
NRF24L01初始化
void NRF_Init()
{CE1;CS1;CLK0;
}SPI读写
uchar SPI_RW(uchar Byte)
{uchar i;for(i0;i8;i){if(Byte0x80)MOSI1;elseMOSI0;CLK1;Byte1;if(MISO)Byte|0x01;CLK0;}return Byte;
}NRF24L01写寄存器一个字节
uchar NRF_Write(uchar addr,Byte)
{uchar status;CS0;statusSPI_RW(addr);SPI_RW(Byte);CS1;return status;
}NRF24L01读寄存器一个字节
uchar NRF_Read(uchar addr)
{uchar Byte;CS0;SPI_RW(addr);ByteSPI_RW(0xFF);CS1;return Byte;
}NRF24L01写多个字节
uchar NRF_Write_Buffer(uchar addr,uchar*buffer,uchar len)
{uchar status;CS0;statusSPI_RW(addr);while(len--){SPI_RW(*buffer);buffer;}CS1;return status;
}NRF24L01读多个字节
uchar NRF_Read_Buffer(uchar addr,uchar*buffer,uchar len)
{uchar status;CS0;statusSPI_RW(addr);while(len--){*bufferSPI_RW(0xFF);buffer;}CS1;return status;
}NRF24L01配置为发射模式
void NRF_Tx_Mode()
{CE0;NRF_Write_Buffer(WRITE_REGTX_ADDR,TX_ADDRESS,TX_ADDR_WIDTH);NRF_Write_Buffer(WRITE_REGRX_ADDR_P0,RX_ADDRESS,RX_ADDR_WIDTH);NRF_Write(WRITE_REGEN_AA,0x01);NRF_Write(WRITE_REGEN_RXADDR,0x01);NRF_Write(WRITE_REGSETUP_AW,0x03);NRF_Write(WRITE_REGSETUP_RETR,0x0F);NRF_Write(WRITE_REGRF_CH,27);NRF_Write(WRITE_REGRF_SETUP,0x0F);NRF_Write(WRITE_REGRX_PW_P0,RX_PLOAD_WIDTH);NRF_Write(WRITE_REGCONFIG,0x0E);CE1;
}NRF24L01配置为接收模式
void NRF_Rx_Mode()
{CE0;NRF_Write_Buffer(WRITE_REGRX_ADDR_P0,RX_ADDRESS,RX_ADDR_WIDTH);NRF_Write(WRITE_REGEN_AA,0x01);NRF_Write(WRITE_REGEN_RXADDR,0x01);NRF_Write(WRITE_REGSETUP_AW,0x03);NRF_Write(WRITE_REGSETUP_RETR,0x0F);NRF_Write(WRITE_REGRF_CH,27);NRF_Write(WRITE_REGRF_SETUP,0x0F);NRF_Write(WRITE_REGRX_PW_P0,RX_PLOAD_WIDTH);NRF_Write(WRITE_REGCONFIG,0x0F);CE1;
}NRF24L01发送数据
// 这里的返回值只是我自己调试代码的过程中自己设置的 你可以不要返回值或者按照你的需要进行修改返回值
uchar NRF_Tx_Data(uchar*buffer)
{uchar state;CE0;NRF_Write_Buffer(W_TX_PAYLOAD,buffer,TX_PLOAD_WIDTH);CE1;while(IRQ);stateNRF_Read(STATUS);NRF_Write(WRITE_REGSTATUS,state);if(stateTX_FLAG)return 0x01;else if(stateMAX_FLAG){NRF_Write(FLUSH_TX,0xFF);return 0xFF;}return 0x00;
}NRF24L01接收数据
// 这里的返回值只是我自己调试代码的过程中自己设置的 你可以不要返回值或者按照你的需要进行修改返回值
uchar NRF_Rx_Data(uchar*buffer)
{uchar state;stateNRF_Read(STATUS);NRF_Write(WRITE_REGSTATUS,state);if(stateRX_FLAG){NRF_Read_Buffer(R_RX_PAYLOAD,buffer,RX_PLOAD_WIDTH);NRF_Write(FLUSH_RX,0xFF);return 0x01;}return 0x00;
}总体代码
NRF.h
#ifndef __NRF_H__
#define __NRF_H__
#include STC8.H
#includeUART.hsbit CEP6^0;
sbit CSP6^1;
sbit CLKP6^2;
sbit MOSIP6^3;
sbit MISOP6^4;
sbit IRQP6^5;#define TX_ADDR_WIDTH 5
#define RX_ADDR_WIDTH 5
#define TX_PLOAD_WIDTH 1
#define RX_PLOAD_WIDTH 1#define READ_REG 0x00
#define WRITE_REG 0x20
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2#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 RX_ADDR_P0 0x0A
#define TX_ADDR 0x10
#define RX_PW_P0 0x11#define RX_FLAG 0x40
#define TX_FLAG 0x20
#define MAX_FLAG 0x10void NRF_Init();
void NRF_Tx_Mode();
uchar NRF_Tx_Data(uchar*buffer);
void NRF_Rx_Mode();
uchar NRF_Rx_Data(uchar*buffer);
#endifNRF.h
#includeNRF.huchar TX_ADDRESS[]{0x00,0x11,0x22,0x33,0x44};
uchar RX_ADDRESS[]{0x00,0x11,0x22,0x33,0x44};void NRF_Init()
{CE1;CS1;CLK0;
}
uchar SPI_RW(uchar Byte)
{uchar i;for(i0;i8;i){if(Byte0x80)MOSI1;elseMOSI0;CLK1;Byte1;if(MISO)Byte|0x01;CLK0;}return Byte;
}uchar NRF_Write(uchar addr,Byte)
{uchar status;CS0;statusSPI_RW(addr);SPI_RW(Byte);CS1;return status;
}
uchar NRF_Read(uchar addr)
{uchar Byte;CS0;SPI_RW(addr);ByteSPI_RW(0xFF);CS1;return Byte;
}
uchar NRF_Write_Buffer(uchar addr,uchar*buffer,uchar len)
{uchar status;CS0;statusSPI_RW(addr);while(len--){SPI_RW(*buffer);buffer;}CS1;return status;
}
uchar NRF_Read_Buffer(uchar addr,uchar*buffer,uchar len)
{uchar status;CS0;statusSPI_RW(addr);while(len--){*bufferSPI_RW(0xFF);buffer;}CS1;return status;
}
void NRF_Tx_Mode()
{CE0;NRF_Write_Buffer(WRITE_REGTX_ADDR,TX_ADDRESS,TX_ADDR_WIDTH);NRF_Write_Buffer(WRITE_REGRX_ADDR_P0,RX_ADDRESS,RX_ADDR_WIDTH);NRF_Write(WRITE_REGEN_AA,0x01);NRF_Write(WRITE_REGEN_RXADDR,0x01);NRF_Write(WRITE_REGSETUP_AW,0x03);NRF_Write(WRITE_REGSETUP_RETR,0x0F);NRF_Write(WRITE_REGRF_CH,27);NRF_Write(WRITE_REGRF_SETUP,0x0F);NRF_Write(WRITE_REGRX_PW_P0,RX_PLOAD_WIDTH);NRF_Write(WRITE_REGCONFIG,0x0E);CE1;
}
uchar NRF_Tx_Data(uchar*buffer)
{uchar state;CE0;NRF_Write_Buffer(W_TX_PAYLOAD,buffer,TX_PLOAD_WIDTH);CE1;while(IRQ);stateNRF_Read(STATUS);NRF_Write(WRITE_REGSTATUS,state);if(stateTX_FLAG)return 0x01;else if(stateMAX_FLAG){NRF_Write(FLUSH_TX,0xFF);return 0xFF;}return 0x00;
}
void NRF_Rx_Mode()
{CE0;NRF_Write_Buffer(WRITE_REGRX_ADDR_P0,RX_ADDRESS,RX_ADDR_WIDTH);NRF_Write(WRITE_REGEN_AA,0x01);NRF_Write(WRITE_REGEN_RXADDR,0x01);NRF_Write(WRITE_REGSETUP_AW,0x03);NRF_Write(WRITE_REGSETUP_RETR,0x0F);NRF_Write(WRITE_REGRF_CH,27);NRF_Write(WRITE_REGRF_SETUP,0x0F);NRF_Write(WRITE_REGRX_PW_P0,RX_PLOAD_WIDTH);NRF_Write(WRITE_REGCONFIG,0x0F);CE1;
}
uchar NRF_Rx_Data(uchar*buffer)
{uchar state;stateNRF_Read(STATUS);NRF_Write(WRITE_REGSTATUS,state);if(stateRX_FLAG){NRF_Read_Buffer(R_RX_PAYLOAD,buffer,RX_PLOAD_WIDTH);NRF_Write(FLUSH_RX,0xFF);return 0x01;}return 0x00;
}UART.h
#ifndef __UART_H__
#define __UART_H__#include STC8.H#define uchar unsigned char
void Uart1_Init();
void UartSendByte(uchar Byte);#endifUART.c
#includeUART.hvoid Uart1_Init(void) //9600bps11.0592MHz
{SCON 0x50; //8位数据,可变波特率AUXR | 0x40; //定时器时钟1T模式AUXR 0xFE; //串口1选择定时器1为波特率发生器TMOD 0x0F; //设置定时器模式TL1 0xE0; //设置定时初始值TH1 0xFE; //设置定时初始值ET1 0; //禁止定时器中断TR1 1; //定时器1开始计时
}void UartSendByte(uchar Byte)
{SBUFByte;while(TI0);TI0;
}main.c
#include STC8.H
#includeUART.h
#includeNRF.h
// 0:接收 1:发射
#define MODE 0
void Delay500ms(void) //11.0592MHz
{unsigned char data i, j, k;i 29;j 14;k 54;do{do{while (--k);} while (--j);} while (--i);
}
uchar tx_buffer[1];
uchar rx_buffer[1];
/*
程序说明
该程序实现了独立接线的NRF24L01模块的通信实验
成功实现发送与接收 可通过MODE的值设置为发射还是接收模式
发射和接收地址:{0x00,0x11,0x22,0x33,0x44} 通道27
*/
void main()
{uchar state;Uart1_Init();NRF_Init();if(MODE)NRF_Tx_Mode();elseNRF_Rx_Mode();while(1){if(MODE){tx_buffer[0](tx_buffer[0]1)%10;stateNRF_Tx_Data(tx_buffer);UartSendByte(state);}else{stateNRF_Rx_Data(rx_buffer);if(state0x01)UartSendByte(rx_buffer[0]);}Delay500ms();}
}再次提醒模块必须使用两个才能进行通信需要用两块板子两个模块搭配才能进行通信如果看完这篇文章对你有帮助的话不妨点个赞吧~~~