NRF24L01参考程序(包含多个实例)
最新nrf24L01工作流程图型
n r f24L01工作流程
图型
NRF24L01流程图、引脚定义
N Y Y
N
N 开始
时钟IC 、LCD 液晶、温度传nRF24L01配置模式
判断键盘
数据采集 将采集到的数启动发射 发射是否完成? 按键处理子程是否处理
开始上电 待机模式I
CE=1有数据发射处理 发射模式
自动重NO_AC
K 有接收处理 置位置位CE=1有数据有数据CE=1待机模式
应答是应答 把ACK 加
置位TX_DS 发射处理
发射模式 接收模式 待机模式I CE=1CE=1接收处理 开始上电 接收接收到 自动应
是新数把数据包放入接收
FIFO 并置位RX_DR 丢弃该数据
把数据包放入接收FIFO 并置位RX_DR
开始
初始化串
数据发送结
把数据装载到
结束
S T C 89C 58
nRF24L01无线模块 LCD 液晶显示模块
键盘模块。
NRF24L01详细教程
NRF24L01详细教程近来课程的项目需要用到NRF24L01,用来做基本的收发,虽然资料拿到不少,但是,很多资料并不是很清晰、所带的例程并不够简洁或有不少冗余的部分,再加上对应的中文数据手册部分没翻译出来,翻译出来的不够有条理,很多地方模糊,甚至关键的地方看一两次还看不出来,导致了在学NRF24L01时花费了较多时间,所以,学完NRF24L01后,萌生了写个尽量清晰的教程的想法。
教程中的例程虽然是库开发方式,但基本都是最底层的操作才用到库函数譬如发一字节数据、GPIO置位等,虽然用的STM32,但我在看其他板子的例程时,发觉内容与流程都是差不多的,只是不同板引脚不同所导致的引脚配置的不同,不管用什么方式开发,用什么芯片,了解清楚NRF24L01如何配置,了解清楚其收发流程,基本上就会开发了,所以此文档虽然写的是以STM32为例,但看完此文档用NRF24L01基本也没什么大问题了。
教程说明:这教程是基于STMF103ZET6的,是野火的板子,例程也是从野火提供修改例程得来,用的是库开发的方式。
学习NRF24L01的步骤:1.学习SPI,SPI就是NRF24L01传送数据到单片机的一种协议,类似于USB,当然USB还是比较有难度的。
2.了解NRF24L01相关寄存器,结合中文数据手册了解NRF24L01的基本配置,收发数据前后的操作(如何启动发送接收、寄存器清空、标志位重置等)。
3.分析具体代码SPI的简介:具体的SPI教程,大家可以去野火的教程进行学习,在此只是简略介绍一下,SPI是一种一对多协议:一个主机(MCU)对应对多个从机,可以分时与多个从机通讯SPI 总线包含4 条总线,分别为SS、SCK、MOSI、MISO,其含义分别为SS:Slave Select,片选信号线,主机借此信号线选择一个从机,低电平有效。
MOSI:Master Output,Slave Input,主机数据从此线输出到从机,数据方向从主机到从机。
NRF24L01模块写论文可以用到的
(2)无线模块的选择模块方案一:采用nRF24L01无线收发芯片组成智能家庭安全系统的自适应无线传感和控制网络,网络拓扑图如图所示。
nRF24L01是一款新型单片射频收发器件。
工作于2.4 GHz~2。
5 GHz ISM频段。
内置频率合成器、功率放大器、晶体振荡器、调制器等功能模块,并融合了增强型ShockBurst技术,其中输出功率和通信频道可通过程序进行配置。
nRF24L01功耗低,在以一6 dBm的功率发射时,工作电流也只有9 mA;接收时,工作电流只有12.3 mA,多种低功率工作模式(掉电模式和空闲模式)使节能设计更方便。
nRF24L01主要特性如下:GFsK调制:硬件集成OSI链路层;具有自动应答和自动再发射功能:片内自动生成报头和CRC校验码;数据传输率为l Mb/s或2 Mb/s;SPI速率为0 Mb/s~10 Mb/s;125个频道:与其他nRF24系列射频器件相兼容;QFN20引脚4 mmx4 rain封装;供电电压为1.9 V~3.6 V。
而且nRF24L01价格在20元左右,性价比高。
为有效的实现对全局环境的检测,系统建立了无线传感网络,无线传感器网络拓扑图如图2-2所示。
图2-2 无线传感器网络拓扑图方案二:CC1100 是原Ch ipcon 公司推出的一种低成本、真正单片的超高频无线收发器, 为低功耗无线应用而设计。
整个应用电路的无线频率主要设定在315MHz、433MHz、868MHz 和915MHz 四个ISM (工业、科学和医学) 频段上, 也可以容易地设置为300MHz~348MHz、400MHz~ 464MHz 和800MHz~ 928MHz 的其它频率上。
芯片低电压(217V~ 316V ) 供电并且功耗较低(接收数据时为1516mA、214kbö s、433MHz)、灵敏度高(112kbös 下为110dBm ) , 可编程控制的数据传输率最高可达500kbö s。
NRF24L01无线模块C语言程序
NRF24L01无线模块C语言法式之巴公井开创作24MHz晶振#include#include#include#include#include#include#define U8 unsigned char#define U16 unsigned int#define TX_ADDR_WITDH 5 //发送地址宽度设置为5个字节#define RX_ADDR_WITDH 5 //接收地址宽度设置为5个字节#define TX_DATA_WITDH 1//发送数据宽度1个字节#define RX_DATA_WITDH 1//接收数据宽度1个字节#define R_REGISTER 0x00//读取配置寄存器#define W_REGISTER 0x20//写配置寄存器#define R_RX_PAYLOAD 0x61//读取RX有效数据#define W_TX_PAYLOAD 0xa0//写TX有效数据#define FLUSH_TX 0xe1//清除TXFIFO寄存器#define FLUSH_RX 0xe2//清除RXFIFO寄存器#define REUSE_TX_PL 0xe3//重新使用上一包有效数据#define NOP 0xff//空把持#define CONFIG 0x00//配置寄存器#define EN_AA 0x01//使能自动应答#define EN_RXADDR 0x02//接收通道使能0-5个通道#define SETUP_AW 0x03//设置数据通道地址宽度3-5#define SETUP_RETR 0x04//建立自动重发#define RF_CH 0x05//射频通道设置#define RF_SETUP 0x06//射频寄存器#define STATUS 0x07//状态寄存器#define OBSERVE_TX 0x08//发送检测寄存器#define CD 0x09//载波#define RX_ADDR_P0 0x0a//数据通道0接收地址#define RX_ADDR_P1 0x0b//数据通道1接收地址#define RX_ADDR_P2 0x0c//数据通道2接收地址#define RX_ADDR_P3 0x0d//数据通道3接收地址#define RX_ADDR_P4 0x0e//数据通道4接收地址#define RX_ADDR_P5 0x0f//数据通道5接收地址#define TX_ADDR 0x10//发送地址#define RX_PW_P0 0x11//P0通道数据宽度设置#define RX_PW_P1 0x12//P1通道数据宽度设置#define RX_PW_P2 0x13//P2通道数据宽度设置#define RX_PW_P3 0x14//P3通道数据宽度设置#define RX_PW_P4 0x15//P4通道数据宽度设置#define RX_PW_P5 0x16//P5通道数据宽度设置#define FIFO_STATUS 0x17//FIFO状态寄存器//NRF24L01U8 NRFACK();U8 NRFSPI(U8 date);U8 NRFReadReg(U8 RegAddr);U8 NRFWriteReg(U8 RegAddr,U8 date);U8 NRFReadRxDate(U8 RegAddr,U8 *RxDate,U8 DateLen);U8 NRFWriteTxDate(U8 RegAddr,U8 *TxDate,U8 DateLen);U8 NRFRevDate(U8 *RevDate);void NRFSetTxMode(U8 *TxDate);void NRF24L01Int();void NRFSetRXMode();U8 CheckACK();void Delay(U16 t);U8 bdata sta;//mainvoid Delay_10ms(U16 del);bit CE=P1^4; //RX/TX模式选择端sbit IRQ=P1^1; //可屏蔽中断端sbit CSN=P1^6; //SPI片选端//就是SSsbit MOSI=P1^0; //SPI主机输出从机输入端1sbit MISO=P1^2; //SPI主机输入从机输出端sbit SCLK=P1^3; //SPI时钟端U8 code TxAddr[]={0x34,0x43,0x10,0x10,0x01};//发送地址U8 bdata sta; //状态标识表记标帜sbit RX_DR=sta^6;sbit TX_DS=sta^5;sbit MAX_RT=sta^4;void Delay(U16 t){ U16 x,y; for(x=t;x>0;x--) for(y=110;y>0;y--);}U8 NRFSPI(U8 date){U8 i; for(i=0;i<8;i++) // 循环8次{ if(date&0x80) MOSI=1; else MOSI=0; // byte最高位输出到MOSI date<<=1; // 低一位移位到最高位 SCLK=1; if(MISO) // 拉高SCK,nRF24L01从MOSI读入1位数据, 同时从MISO输出1位数据 date|=0x01; // 读MISO 到byte最低位 SCLK=0; // SCK置低} return(date); // 返回读出的一字节}void NRF24L01Int(){ Delay(2);//让系统什么都不干CE=0; //待机模式1 CSN=1; SCLK=0; IRQ=1; }U8 NRFReadReg(U8 RegAddr){ U8 BackDate; CSN=0;//启动时序NRFSPI(RegAddr);//写寄存器地址BackDate=NRFSPI(0x00);//写入读寄存器指令CSN=1; return(BackDate); //返回状态}U8NRFWriteReg(U8 RegAddr,U8 date){ U8 BackDate; CSN=0;//启动时序BackDate=NRFSPI(RegAddr);//写入地址NRFSPI(date);//写入值CSN=1; return(BackDate);}U8 NRFReadRxDate(U8 RegAddr,U8 *RxDate,U8 DateLen){ //寄存器地址//读取数据寄存变量//读取数据长度//用于接收U8 BackDate,i; CSN=0;//启动时序BackDate=NRFSPI(RegAddr);//写入要读取的寄存器地址for(i=0;i { RxDate[i]=NRFSPI(0); } CSN=1; return(BackDate);}U8 NRFWriteTxDate(U8 RegAddr,U8 *TxDate,U8 DateLen){ //寄存器地址//写入数据寄存变量//读取数据长度//用于发送U8 BackDate,i; CSN=0; BackDate=NRFSPI(RegAddr);//写入要写入寄存器的地址 for(i=0;i { NRFSPI(*TxDate++); }CSN=1; return(BackDate);}void NRFSetTxMode(U8 *TxDate){//发送模式 CE=0; NRFWriteTxDate(W_REGISTER+TX_ADDR,Tx Addr,TX_ADDR_WITDH);//写寄存器指令+接收地址使能指令+接收地址+地址宽度NRFWriteTxDate(W_REGISTER+RX_ADDR_P0,TxAddr,TX_ADDR_WITDH);//为了应答接收设备,接收通道0地址和发送地址相同NRFWriteTxDate(W_TX_PAYLOAD,TxDate,TX_DATA_WITDH);//写入数据NRFWriteReg(W_REGISTER+EN_AA,0x01);// 使能接收通道0自动应答NRFWriteReg(W_REGISTER+EN_RXADDR,0x01); // 使能接收通道0 NRFWriteReg(W_REGISTER+SETUP_RETR,0x0a); // 自动重发延时等候250us+86us,自动重发10次NRFWriteReg(W_REGISTER+RF_CH,0x40);// 选择射频通道0x40 NRFWriteReg(W_REGISTER+RF_SETUP,0x07); // 数据传输率1Mbps,发射功率0dBm,低噪声放年夜器增益NRFWriteReg(W_REGISTER+CONFIG,0x0e); // CRC 使能,16位CRC校验,上电CE=1; Delay(5);//坚持10us秒以上}//主要接收模式void NRFSetRXMode(){ CE=0; NRFWriteTxDate(W_REGISTER+RX _ADDR_P0,TxAddr,TX_ADDR_WITDH); // 接收设备接收通道0使用和发送设备相同的发送地址NRFWriteReg(W_REGISTER+EN_AA,0x01);// 使能接收通道0自动应答NRFWriteReg(W_REGISTER+EN_RXADDR,0x01);// 使能接收通道0 NRFWriteReg(W_REGISTER+RF_CH,0x40);// 选择射频通道0x40 NRFWriteReg(W_REGISTER+RX_PW_P0,TX_DATA_WITDH);// 接收通道0选择和发送通道相同有效数据宽度NRFWriteReg(W_REGISTER+RF_SETUP,0x07);// 数据传输率1Mbps,发射功率0dBm,低噪声放年夜器增益*/ NRFWriteReg(W_REGISTER+CONFIG,0x0f);// CRC使能,16位CRC校验,上电,接收模式CE = 1; Delay(5);//坚持10us秒以上}U8 CheckACK(){ //用于发射sta=NRFReadReg(R_REGISTER+STATUS);// 返回状态寄存器if(TX_DS||MAX_RT) //发送完毕中断{ NRFWriteReg(W_REGISTER+STATUS,0xff); // 清除TX_DS或MAX_RT中断标识表记标帜CSN=0; NRFSPI(FLUSH_TX);//用于清空FIFO !!关键!!否则会呈现意想不到的后果!!!年夜家记住!! CSN=1; return(0); } else return(1);}//用于接收模式U8 NRFRevDate(U8 *RevDate){ U8RevFlags=0; sta=NRFReadReg(R_REGISTER+STATUS);//发送数据后读取状态寄存器 if(RX_DR) // 判断是否接收到数据{ CE=0; //SPI使能NRFReadRxDate(R_RX_PAYLOAD,RevDate,RX_DATA_WITDH);/ / 从RXFIFO读取数据RevFlags=1; //读取数据完成标识表记标帜} NRFWriteReg(W_REGISTER+STATUS,0xff); //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标 return(RevFlags);}void Delay_10ms(U16 del){ U16 i,j; for(i=0; i<del; i++) for(j=0; j<1827; j++) //这个是通过软件仿真得出的数;}// 做发射main(){ U8 TxDate[1]={0}; NRF24L01Int(); Delay(6000); while(1) { if(KEY==0) { if(KEY==0) { Delay_1 0ms(2); TxDate[0]=0x08;//发射按键标识值NRFSetTxMode(TxDate); while(CheckACK());TxDate[0]=0; } } }}//// 做接收:一直处于接受模式查询所获得的值是不是0x08main(){ U8 x; U8 RxBuf[1]={0}; NRF24L01Int(); Delay(6000);while(1) { NRFSetRXMode(); NRFRevDate(RxBuf); x=RxBuf[0]; if(x==0x08)//0x08为发射部份所发送的按键标识{ // //加入所要执行的功能函数 //固然了这里用到单片机io口的时候需要在之前界说//还有就是发送法式中的KEY也需要之前界说好 RxBuf[0]=0; } }}。
基于NRF24L01的程序
/*****************************************************************************概述:电气工程及其自动化2009级毕业设计课题:无线信息采集系统的设计与实现文件:无线信息采集系统数据接收端功能:接收数据存储、处理、显示、报警等。
编译:Keil uVision4硬件:AT89C52RC日期:2013年5月作者:蒋海鹏(广西大学行健文理学院)注:代码有些杂乱,头文件封装不建议用“类”封装(有显摆嫌疑,此设计只为练习该封装模式)该形式对普通函数调用是个麻烦。
在写管理器时建议采用该模式*****************************************************************************/ #include "StdC52.h"#define DATA_SIZE 6#define SENDTIME 100#define CHANGEDISPLAY 1#define RETURNDISPLAY 0static UCHAR m_BH1750RxBuff[DATA_SIZE];static UCHAR m_DHT11RxBuff[DA TA_SIZE];static UCHAR m_RxBuff[DATA_SIZE];static void LCD_Display_Init(void){C52LCDGET()->LCD_Display_String(LINE_ONE,0,"RH:"); //湿度C52LCDGET()->LCD_Display_String(LINE_ONE,5,"%");C52LCDGET()->LCD_Display_String(LINE_ONE,7,"TEMP:"); //温度C52LCDGET()->LCD_Display_Single(LINE_ONE,0X0E,0XDF-0x30); //0xdf='°',0x43='C'C52LCDGET()->LCD_Display_Single(LINE_ONE,0X0F,0X43-0x30); //0xdf='°',0x43='C'C52LCDGET()->LCD_Display_String(LINE_TWO,0,"LIGHT:"); //光强C52LCDGET()->LCD_Display_String(LINE_TWO,0X0B,"Lx"); //光强单位}static void LCD_Display_MODE(void){UINT TempData;UINT CalData;UCHAR RH1,RH2,TP1,TP2;CalData = (m_BH1750RxBuff[0]<<8) + m_BH1750RxBuff[1]; //合成数据,即光照数据TempData = (CalData*100)/120;C52LCDGET()->LCD_Display_Single(LINE_TWO,6,TempData/10000);C52LCDGET()->LCD_Display_Single(LINE_TWO,7,TempData%10000/1000);C52LCDGET()->LCD_Display_Single(LINE_TWO,8,TempData%1000/100);C52LCDGET()->LCD_Display_Single(LINE_TWO,9,TempData%100/10);C52LCDGET()->LCD_Display_Single(LINE_TWO,0X0A,TempData%10);RH1 = m_DHT11RxBuff[0]/10;RH2 = m_DHT11RxBuff[0]%10;TP1 = m_DHT11RxBuff[2]/10;TP2 = m_DHT11RxBuff[2]%10;C52LCDGET()->LCD_Display_Single(LINE_ONE,3,RH1);C52LCDGET()->LCD_Display_Single(LINE_ONE,4,RH2);C52LCDGET()->LCD_Display_Single(LINE_ONE,0X0C,TP1);C52LCDGET()->LCD_Display_Single(LINE_ONE,0X0D,TP2);}//接收数据static void NRF_RecvSystemData(UCHAR *pUersBuf){static UCHAR l_uCount = NULL;if(C52NRFGET()->NRF_RevDate(pUersBuf)) //读取接受到的数据{switch(l_uCount){case 0X00:m_DHT11RxBuff[l_uCount] = pUersBuf[l_uCount];l_uCount++;break;case 0X01:m_DHT11RxBuff[l_uCount] = pUersBuf[l_uCount];l_uCount++;break;case 0X02:m_DHT11RxBuff[l_uCount] = pUersBuf[l_uCount];l_uCount++;break;case 0X03:m_DHT11RxBuff[l_uCount] = pUersBuf[l_uCount];l_uCount++;break;case 0X04:m_BH1750RxBuff[0] = pUersBuf[l_uCount];l_uCount++;break;case 0X05:m_BH1750RxBuff[1] = pUersBuf[l_uCount];l_uCount = NULL;break;default:l_uCount = NULL;break;}C52LCDGET()->LCD_Display_String(LINE_TWO,0X0E,"Rx"); //接受成功C52LEDGET()->TP_Waring();C52LEDGET()->RH_Waring();C52LEDGET()->LX_Waring();}else{C52LEDGET()->Close_Waring();}}//主要实现各按键功能static void Key_Mode(void){UCHAR uReKey = NULL;static UCHAR m_StroeBuff[10];static UCHAR l_uFlag = NULL;//初始光标地址为3static UCHAR uCursor = 3;static UCHAR Store;uReKey = Key_Scan();if(NULL == l_uFlag){C52NRFGET()->NRF_SetRxMode(); //设置为接受模式NRF_RecvSystemData(m_RxBuff);LCD_Display_MODE();}if(DIS_CHANGE == uReKey){l_uFlag = CHANGEDISPLAY;C52IICGET()->C52IIC_Free(TRUE); //释放总线C52LCDGET()->LCD_Display_Single(LINE_ONE,3,C52IIC_Read(0X01)/10);C52LCDGET()->LCD_Display_Single(LINE_ONE,4,C52IIC_Read(0X01)%10);C52LCDGET()->LCD_Display_Single(LINE_ONE,0X0C,C52IIC_Read(0X11)/10);C52LCDGET()->LCD_Display_Single(LINE_ONE,0X0D,C52IIC_Read(0X11)%10);C52LCDGET()->LCD_Display_Single(LINE_TWO,6,C52IIC_Read(0X21));C52LCDGET()->LCD_Display_Single(LINE_TWO,7,C52IIC_Read(0X22));C52LCDGET()->LCD_Display_Single(LINE_TWO,8,C52IIC_Read(0X23));C52LCDGET()->LCD_Display_Single(LINE_TWO,9,C52IIC_Read(0X24));C52LCDGET()->LCD_Display_Single(LINE_TWO,0X0A,C52IIC_Read(0X25));C52LEDGET()->Close_Waring();}switch(l_uFlag){case LINE_ONE:C52LCDGET()->LCD_Write_Com(0X80+uCursor);C52LCDGET()->LCD_Write_Com(0X0F);if(CURSOR_ADD == uReKey){uCursor++;if(uCursor==5){uCursor = 0X0C;}if(uCursor==0X0E){uCursor = 6;l_uFlag++;}}if(CURSOR_DEC == uReKey){if((uCursor<=4)&&(uCursor>=3)) //4位置时候回3{uCursor--;if(uCursor<3) //如果在3位置回下行末尾{uCursor = 0X0A;l_uFlag++;}}if((uCursor<=0X0D)&&(uCursor>=0X0C)){uCursor--;if(uCursor<0X0C){uCursor = 4;}}}break;case LINE_TWO:C52LCDGET()->LCD_Write_Com(0X80+0X40+uCursor);C52LCDGET()->LCD_Write_Com(0X0F);if(CURSOR_ADD == uReKey){uCursor++;if(uCursor == 0X0B){uCursor = 3;l_uFlag = CHANGEDISPLAY;}}if(CURSOR_DEC == uReKey){if(uCursor>=0X06&&uCursor<=0X0A){uCursor--;if(uCursor<0X06){uCursor = 0X0D;l_uFlag = CHANGEDISPLAY;}}}break;}if(NUM_ADD == uReKey){switch(uCursor){case 0X03:if(++m_StroeBuff[0]>=10) //测量湿度范围20%-95%{m_StroeBuff[0] = 2;}C52LCDGET()->LCD_Display_Single(LINE_ONE,3,m_StroeBuff[0]);break;case 0X04:if(m_StroeBuff[0]!=9){if(++m_StroeBuff[1]>=10){m_StroeBuff[1] = NULL;}}else{if(++m_StroeBuff[1]>=6){m_StroeBuff[1] = NULL;}}C52LCDGET()->LCD_Display_Single(LINE_ONE,4,m_StroeBuff[1]);break;case 0X0C:if(++m_StroeBuff[2]>=6) //测量温度范围0-50{m_StroeBuff[2] = NULL;}C52LCDGET()->LCD_Display_Single(LINE_ONE,0X0C,m_StroeBuff[2]);break;case 0X0D:if(++m_StroeBuff[3]>=10){m_StroeBuff[3] = NULL;}C52LCDGET()->LCD_Display_Single(LINE_ONE,0X0D,m_StroeBuff[3]);break;case 0X06: //光强测量范围1-65535lxif(++m_StroeBuff[4]>=7) //万位最大为6{m_StroeBuff[4] = NULL;}C52LCDGET()->LCD_Display_Single(LINE_TWO,0X06,m_StroeBuff[4]);break;case 0X07:if(m_StroeBuff[4] == 6){if(++m_StroeBuff[5]>=6){m_StroeBuff[5] = NULL;}}else{if(++m_StroeBuff[5]>=10){m_StroeBuff[5] = NULL;}}C52LCDGET()->LCD_Display_Single(LINE_TWO,0X07,m_StroeBuff[5]);break;case 0X08:if((m_StroeBuff[4]==6)&&(m_StroeBuff[5]==5)){if(++m_StroeBuff[6]>=6){m_StroeBuff[6] = NULL;}}else{if(++m_StroeBuff[6]>=10){m_StroeBuff[6] = NULL;}}C52LCDGET()->LCD_Display_Single(LINE_TWO,0X08,m_StroeBuff[6]);break;case 0X09:if((m_StroeBuff[4]==6)&&(m_StroeBuff[5]==5)&&(m_StroeBuff[6]==5)) {if(++m_StroeBuff[7]>=4){m_StroeBuff[7] = NULL;}}else{if(++m_StroeBuff[7]>=10){m_StroeBuff[7] = NULL;}}C52LCDGET()->LCD_Display_Single(LINE_TWO,0X09,m_StroeBuff[7]);break;case 0X0A:if((m_StroeBuff[4]==6)&&(m_StroeBuff[5]==5)\&&(m_StroeBuff[6]==5)&&(m_StroeBuff[7]==3)){if(++m_StroeBuff[8]>=6){m_StroeBuff[8] = NULL;}}else{if(++m_StroeBuff[8]>=10){m_StroeBuff[8] = NULL;}}C52LCDGET()->LCD_Display_Single(LINE_TWO,0X0A,m_StroeBuff[8]);break;}}if(NUM_DEC ==uReKey){switch(uCursor){case 0X03:if(m_StroeBuff[0]>2) //测量湿度范围20%-95%{m_StroeBuff[0]--;}C52LCDGET()->LCD_Display_Single(LINE_ONE,3,m_StroeBuff[0]);break;case 0X04:if(m_StroeBuff[1]>0){m_StroeBuff[1]--;}C52LCDGET()->LCD_Display_Single(LINE_ONE,4,m_StroeBuff[1]);break;case 0X0C:if(m_StroeBuff[2]>0) //测量温度范围0-50{m_StroeBuff[2]--;}C52LCDGET()->LCD_Display_Single(LINE_ONE,0X0C,m_StroeBuff[2]);break;case 0X0D:if(m_StroeBuff[3]>0){m_StroeBuff[3]--;}C52LCDGET()->LCD_Display_Single(LINE_ONE,0X0D,m_StroeBuff[3]);break;case 0X06: //光强测量范围1-65535lxif(m_StroeBuff[4]>0) //万位最大为6{m_StroeBuff[4]--;}C52LCDGET()->LCD_Display_Single(LINE_TWO,0X06,m_StroeBuff[4]);break;case 0X07:if(m_StroeBuff[5]>0){m_StroeBuff[5]--;}C52LCDGET()->LCD_Display_Single(LINE_TWO,0X07,m_StroeBuff[5]);break;case 0X08:if(m_StroeBuff[6]>0){m_StroeBuff[6]--;}C52LCDGET()->LCD_Display_Single(LINE_TWO,0X08,m_StroeBuff[6]);break;case 0X09:if(m_StroeBuff[7]>0){m_StroeBuff[7]--;}C52LCDGET()->LCD_Display_Single(LINE_TWO,0X09,m_StroeBuff[7]);break;case 0X0A:if(m_StroeBuff[8]>0){m_StroeBuff[8]--;}C52LCDGET()->LCD_Display_Single(LINE_TWO,0X0A,m_StroeBuff[8]);break;}}if(NUM_AFFIRM == uReKey) //确定数值存入{l_uFlag = RETURNDISPLAY;uCursor = 3; //光标清回三C52LCDGET()->LCD_Write_Com(0x0C); //不显示光标C52IICGET()->C52IIC_Free(TRUE);Store = m_StroeBuff[0]*10 + m_StroeBuff[1]; //存入数值C52IIC_Write(0X01,Store);Store = NULL;Store = m_StroeBuff[2]*10 + m_StroeBuff[3];C52IIC_Write(0X11,Store);Store = NULL;C52NRFGET()->NRF_SetRxMode(); //设置为接受模式C52IIC_Write(0X21,m_StroeBuff[4]);C52IIC_Write(0X22,m_StroeBuff[5]);C52IIC_Write(0X23,m_StroeBuff[6]);C52IIC_Write(0X24,m_StroeBuff[7]);C52IIC_Write(0X25,m_StroeBuff[8]);}}int main(void){C52NRFGET()->NRF_Init();C52LCDGET()->LCD_Init(); //液晶初始化LCD_Display_Init();C52IICGET()->C52IIC_Init(); //IIC初始化C52IICGET()->C52IIC_SetID(0XA0); //设置器件IDC52IICGET()->C52IIC_SetRate(3);C52IICGET()->C52IIC_Free(TRUE); //释放IIC总线while(TRUE){C52NRFGET()->NRF_SetRxMode(); //设置为接受模式Key_Mode();DelayMs(SENDTIME);}}#include "..\StdC52.h"#include "LCD1602.h"static LCD1602 *hLCDBus = NULL;static LCD1602 m_Instance;static void LCD_Write_Com(UCHAR Com){LCDRS = FALSE;GPIOA = Com;DelayMs(5);LCDEN = TRUE;DelayMs(5);LCDEN= FALSE;}static void LCD_Write_Data(UCHAR Date){LCDRS = TRUE;GPIOA = Date;DelayMs(5);LCDEN = TRUE;DelayMs(5);LCDEN = FALSE;}static void LCD_Display_Single(UCHAR Line, UCHAR Address,UCHAR InData) {switch(Line){case 0x01:LCD_Write_Com(0X80+Address);break;case 0x02:LCD_Write_Com(0X80+0X40+Address);break;default:break;}LCD_Write_Data(0X30+InData);}static void LCD_Display_String(UCHAR Line,UCHAR Address,UCHAR *pBuff){switch(Line){case LINE_ONE:LCD_Write_Com(0X80+Address);break;case LINE_TWO:LCD_Write_Com(0X80+0X40+Address);break;default:break;}while(*pBuff!='\0'){LCD_Write_Data(*pBuff++);}}void LCD_Init(void){C52LCDGET()->LCD_Write_Com(0x38); //设置16X2显示,5X7点阵,8位数据接口C52LCDGET()->LCD_Write_Com(0x0c); //设置开显示,不显示光标C52LCDGET()->LCD_Write_Com(0x06); //写一个字符后地址指针加1C52LCDGET()->LCD_Write_Com(0x01); //显示清零,数据指针清零}static void NEW(void){hLCDBus = &m_Instance;hLCDBus->LCD_Init = LCD_Init;hLCDBus->LCD_Write_Com = LCD_Write_Com;hLCDBus->LCD_Write_Data = LCD_Write_Data;hLCDBus->LCD_Display_Single = LCD_Display_Single;hLCDBus->LCD_Display_String = LCD_Display_String;}LCD1602 *C52LCDGET(void){NEW();return hLCDBus;}----------------------------------------------------------------------------------------------------------------------#include "..\StdC52.h"#include "Globle.h"void DelayMs(UINT TimeMs){UCHAR Time;UINT Count;for(Count = TimeMs; Count>0; Count--)for(Time = 0;Time<110;Time++);}---------------------------------------------------------------------------------------------------------------------- #include "..\StdC52.h"#include "NRF24L01.h"//状态标志static UCHAR BDA TA m_Status;sbit RX_DR = m_Status^6;sbit TX_DS = m_Status^5;sbit MAX_RT = m_Status^4;//NRF对象指针static NRF *hNRFBus = NULL;//NRF实例static NRF m_Instance;//发送地址static UCHAR code TxAddr[]={0x34,0x43,0x10,0x10,0x01};//NRF24L01初始化函数void NRF_Init(void){DelayMs(2); //让系统什么都不干CE = FALSE; //待机模式1CSN = TRUE;SCK = FALSE;IRQ = TRUE;}//SPI时序函数static UCHAR NRF_SPI(UCHAR uDate){UCHAR i;for(i=0;i<8;i++){if(uDate&0x80){MOSI = TRUE;}else{MOSI = FALSE; // byte最高位输出到MOSI}uDate<<=1; // 低一位移位到最高位SCK = TRUE;if(MISO) // 拉高SCK,nRF24L01从MOSI读入1位数据,同时从MISO输出1位数据{uDate|=0x01; // 读MISO到byte最低位}SCK = FALSE; // SCK置低}return(uDate); // 返回读出的一字节}//SPI读寄存器一字节函数static UCHAR NRF_ReadReg(UCHAR RegAddr){UCHAR BackDate;CSN = FALSE; //启动时序NRF_SPI(RegAddr); //写寄存器地址BackDate=NRF_SPI(R_REGISTER); //写入读寄存器指令CSN = TRUE;return(BackDate); //返回状态}//SPI写寄存器一字节函数static UCHAR NRF_WriteReg(UCHAR RegAddr,UCHAR uDate){UCHAR BackDate;CSN = FALSE; //启动时序BackDate = NRF_SPI(RegAddr); //写入地址NRF_SPI(uDate); //写入值CSN = TRUE;return(BackDate);}//SPI读取RXFIFO寄存器的值//寄存器地址,读取数据存放变量,读取数据长度, 用于接收static UCHAR NRF_ReadRxDate(UCHAR RegAddr,UCHAR *RxDate,UCHAR Len){UCHAR BackDate,i;CSN = FALSE; //启动时序BackDate=NRF_SPI(RegAddr); //写入要读取的寄存器地址for(i=0;i<Len;i++) //读取数据{RxDate[i] = NRF_SPI(R_REGISTER);}CSN = TRUE;return(BackDate);}//SPI写入TXFIFO寄存器的值寄存器地址,写入数据存放变量,读取数据长度,用于发送static UCHAR NRF_WriteTxDate(UCHAR RegAddr,UCHAR *TxDate,UCHAR Len){UCHAR BackDate,i;CSN = FALSE;BackDate=NRF_SPI(RegAddr); //写入要写入寄存器的地址for(i=0;i<Len;i++) //写入数据{NRF_SPI(*TxDate++);}CSN = TRUE;return(BackDate);}//NRF设置为发送模式并发送数据/*void NRF_SetTxMode(UCHAR *TxDate){CE = FALSE;NRF_WriteTxDate(W_REGISTER+TX_ADDR,TxAddr,TX_ADDR_WITDH); //写寄存器指令+接收地址使能指令+接收地址+地址宽度NRF_WriteTxDate(W_REGISTER+RX_ADDR_P0,TxAddr,TX_ADDR_WITDH); //为了应答接收设备,接收通道0地址和发送地址相同NRF_WriteTxDate(W_TX_PAYLOAD,TxDate,TX_DA TA_WITDH); //写入数据NRF_WriteReg(W_REGISTER+EN_AA,0x01); // 使能接收通道0自动应答NRF_WriteReg(W_REGISTER+EN_RXADDR,0x01); // 使能接收通道0NRF_WriteReg(W_REGISTER+SETUP_RETR,0x0a); // 自动重发延时等待250us+86us,自动重发10次NRF_WriteReg(W_REGISTER+RF_CH,0x40); // 选择射频通道0x40NRF_WriteReg(W_REGISTER+RF_SETUP,0x07); // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益NRF_WriteReg(W_REGISTER+CONFIG,0x0e); // CRC 使能,16位CRC校验,上电CE = TRUE;DelayMs(5); //保持10us秒以上} *///NRF设置为接收模式void NRF_SetRxMode(void){CE = FALSE;NRF_WriteTxDate(W_REGISTER+RX_ADDR_P0,TxAddr,TX_ADDR_WITDH); // 接收设备接收通道0使用和发送设备相同的发送地址NRF_WriteReg(W_REGISTER+EN_AA,0x01); // 使能接收通道0自动应答NRF_WriteReg(W_REGISTER+EN_RXADDR,0x01); // 使能接收通道0NRF_WriteReg(W_REGISTER+RF_CH,0x40); // 选择射频通道0x40NRF_WriteReg(W_REGISTER+RX_PW_P0,TX_DATA_WITDH); // 接收通道0选择和发送通道相同有效数据宽度NRF_WriteReg(W_REGISTER+RF_SETUP,0x07); // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益*/NRF_WriteReg(W_REGISTER+CONFIG,0x0f); // CRC 使能,16位CRC校验,上电,接收模式CE = TRUE;DelayMs(5); //保持10us 秒以上//检测应答信号/*BOOL NRF_CheckACK(void){ //用于发射m_Status = NRF_ReadReg(R_REGISTER+STATUS); // 返回状态寄存器if(TX_DS||MAX_RT) //发送完毕中断{NRF_WriteReg(W_REGISTER+STA TUS,NOP); // 清除TX_DS或MAX_RT中断标志CSN = FALSE;NRF_SPI(FLUSH_TX); //用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!CSN = TRUE;return(FALSE);}elsereturn(TRUE);} *///判断是否接收收到数据,接到就从RX取出用于接收模式UCHAR NRF_RevDate(UCHAR *RevDate){BOOL l_bRevFlags = NULL;m_Status = NRF_ReadReg(R_REGISTER+STATUS); //发送数据后读取状态寄存器if(RX_DR) // 判断是否接收到数据{CE = FALSE; //SPI使能NRF_ReadRxDate(R_RX_PAYLOAD,RevDate,RX_DA TA_WITDH); // 从RXFIFO读取数据l_bRevFlags = TRUE; //读取数据完成标志}else{l_bRevFlags = FALSE;}NRF_WriteReg(W_REGISTER+STA TUS,NOP); //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标return(l_bRevFlags);}//创建static void New(void){hNRFBus = &m_Instance;hNRFBus->NRF_Init = NRF_Init;// hNRFBus->NRF_SetTxMode = NRF_SetTxMode;hNRFBus->NRF_SetRxMode = NRF_SetRxMode;hNRFBus->NRF_RevDate = NRF_RevDate;}//获取NRF实例句柄NRF *C52NRFGET(void){New();return hNRFBus;}---------------------------------------------------------------------------------------------------------------------- #include "..\StdC52.h"#include "C52IIC.h"#define ReWrTime 10//IIC对象指针static IIC *hIICBus = NULL;//IIC实例static IIC m_Instance;//IIC速率static UINT m_Baudrate = 3;//器件地址static UCHAR m_DeviceID = 0X00;//IIC总线延时static void IICBusDelay(UINT uTime){while(uTime--);}//模拟IIC总线的起始位static void IICBusStart(void){SDA = TRUE; //SDA = 1SCL = TRUE; //SCK = 1IICBusDelay(20);SDA = FALSE; //SDA = 0IICBusDelay(20);}//模拟IIC总线的停止位static void IICBusStop(){SDA = FALSE; //SDA = 0SCL = FALSE; //SCK = 0IICBusDelay(20);SCL = TRUE; //SCK = 1IICBusDelay(20);SDA = TRUE; //SDA = 1IICBusDelay(20);}//读IIC_SDA引脚电平static BOOL SDARead(void){UCHAR i;SCL = TRUE;IICBusDelay(20);while((TRUE == SDA)&&(i<0XFF))i++;if(SDA){return TRUE;}return FALSE;}//模拟IIC总线写一个字节数据(返回ACK)static BOOL IICBusWriteByte(UCHAR WRData){UCHAR i,ACK;for(i=0;i<8;i++){SCL = FALSE; //SCK = 0if( WRData&0x80 ){SDA = TRUE;}else{SDA = FALSE;}IICBusDelay(m_Baudrate);SCL = TRUE; // SCK = 1IICBusDelay(m_Baudrate);WRData = WRData<<1;}SCL = FALSE; //SCK = 0IICBusDelay(m_Baudrate);SCL = TRUE; //SCK = 1ACK = SDARead(); //读取SDA口高无响应,低响应IICBusDelay(m_Baudrate);SCL = FALSE; //SCK = 0SDA = TRUE; //SDA = 1IICBusDelay(m_Baudrate);return ACK;}//模拟IIC总线读一个字节数据static UCHAR IICBusReadByte(BOOL bIsACK){UCHAR i,RDData = NULL;for(i=0;i<8;i++){RDData = RDData<<1;SCL = FALSE; //SCK = 0IICBusDelay(m_Baudrate);SCL = TRUE; //SCK = 1if( SDARead() == TRUE ){RDData = RDData|0x01;}IICBusDelay(m_Baudrate);}if(bIsACK){SCL = FALSE; //SCK = 0SDA = FALSE; //SDA = 0IICBusDelay(m_Baudrate);SCL = TRUE; //SCK = 1IICBusDelay(m_Baudrate);SCL = FALSE; //SCK = 0 }else{SCL = FALSE; //SCK = 0SDA = TRUE; //SDA = 1IICBusDelay(m_Baudrate);SCL = TRUE; //SCK = 1IICBusDelay(m_Baudrate);SCL = FALSE; //SCK = 0 }return RDData;}//设置IIC速度void C52IIC_SetRate(UINT Rate){m_Baudrate = Rate;}//设置IIC器件地址void C52IIC_SetID(UCHAR ID){m_DeviceID = ID;}//写IIC数据BOOL C52IIC_Write(UCHAR Adress,UCHAR DATA) {UCHAR Vale = TRUE;UINT16 i = 0;IICBusStart();if(IICBusWriteByte(m_DeviceID)){Vale = FALSE;goto Exit;}if(IICBusWriteByte(Adress)){Vale = FALSE;goto Exit;}if(IICBusWriteByte(DATA)){Vale = FALSE;goto Exit;}Exit:IICBusStop();//根据不同芯片特性,设置读取速率DelayMs(ReWrTime);return Vale;}//读IIC数据UCHAR C52IIC_Read(UCHAR Adress) {UCHAR InData;IICBusStart();if(IICBusWriteByte(m_DeviceID)){goto Exit;}if(IICBusWriteByte(Adress)){goto Exit;}IICBusStart();if(IICBusWriteByte(m_DeviceID+1)){goto Exit;}InData = IICBusReadByte(FALSE); Exit:IICBusStop();//根据不同芯片特性,设置读取速率DelayMs(ReWrTime);return InData;}//初始化IICvoid C52IIC_Init(void){SDA = TRUE;IICBusDelay(20);SCL = TRUE;IICBusDelay(20);}//释放\占用IIC总线void C52IIC_Free(BOOL bIsFree){if(bIsFree){SCL = TRUE;SDA = TRUE;}else{SCL = FALSE;SDA = FALSE;}}//创建IICstatic void new(void){hIICBus = &m_Instance;hIICBus->C52IIC_SetRate = C52IIC_SetRate;hIICBus->C52IIC_SetID = C52IIC_SetID;hIICBus->C52IIC_Init = C52IIC_Init;hIICBus->C52IIC_Free = C52IIC_Free;}//获取IIC实例句柄IIC *C52IICGET(void){new();return hIICBus;}---------------------------------------------------------------------------------------------------------------------- #include "..\StdC52.h"#include "C52KEY.h"//读取IO口static UCHAR Read_GPIO(void){UCHAR uByte = NULL;uByte |= GPIO_KEY1;uByte = uByte << 1;uByte |= GPIO_KEY2;uByte = uByte << 1;uByte |= GPIO_KEY3;uByte = uByte << 1;uByte |= GPIO_KEY4;uByte = uByte << 1;uByte |= GPIO_KEY5;uByte = uByte << 1;uByte |= GPIO_KEY6;uByte = uByte << 2;return uByte;}static BOOL Key_Press(void){UCHAR uTemp;uTemp = Read_GPIO();uTemp &= 0XFC;if(uTemp!=0XFC)DelayMs(10);if(uTemp!=0XFC){return TRUE;}else{return FALSE;}}UCHAR Key_Scan(void){UCHAR KeyCode;DelayMs(10);if(Key_Press()){KeyCode = Read_GPIO();switch(KeyCode){case 0XF8:KeyCode = 0X01;break;case 0XF4:KeyCode = 0X02;break;case 0XEC:KeyCode = 0X03;break;case 0XDC:KeyCode = 0X04;break;case 0XBC:KeyCode = 0X05;break;case 0X7C:KeyCode = 0X06;break;default:KeyCode = NULL;break;}while(Key_Press());}else{KeyCode = NULL;}return KeyCode;}---------------------------------------------------------------------------------------------------------------------- #include "..\StdC52.h"#include "C52W ARING.h"static LED *hLEDBus = NULL;static LED m_Instance;static void TP_Waring(void){LED_TP = FALSE;}static void TP_Close(void){LED_TP = TRUE;}static void RH_Waring(void){LED_RH = FALSE;}static void RH_Close(void){LED_RH = TRUE;}static void LX_Waring(void){LED_LX = FALSE;}static void LX_Close(void){LED_LX = TRUE;}static void Close_Waring(void){LED_TP = TRUE;LED_RH = TRUE;LED_LX = TRUE;}static void New(void){hLEDBus = &m_Instance;hLEDBus->TP_Waring = TP_Waring;hLEDBus->RH_Waring = RH_Waring;hLEDBus->LX_Waring = LX_Waring;hLEDBus->TP_Close = TP_Close;hLEDBus->TP_Close = RH_Close;hLEDBus->TP_Close = LX_Close;hLEDBus->Close_Waring = Close_Waring;LED *C52LEDGET(void) {New();return hLEDBus;}。
(完整版)NRF24l01无线温度传感_毕业设计
A Dissertation Submitted toNanjing Institute of TechnologyFor the Academic Degree of Bachelor of ScienceBysupervised byCollege of Communication EngineeringNanjing Institute of TechnologyJune 2010NRF24l01无线温度传感摘要随着工农业生产对温度的要求越来越高,准确测量温度变得至关重要。
本系统的设计主要是针对恶劣环境下的工业现场以及高科技大范围的农业现场,布线困难,浪费资源,占用空间,可操作性差等问题做出的一个解决方案。
本文对上述问题提出一种无线解决方案,即基于SoC无线温度采集系统的设计。
该系统采用低功耗、高性能单片机及单总线数字式测温器件DS18B20构成测温系统,并且通过无线收发,最后在PC机上完成配置、显示和报警的功能。
在这次的设计中采用的单片机STC89C52RC的内核和MCS-51系列单片机一样,引脚也相同。
但是STC89C52RC可以通过STC_ISP软件下载进行烧录。
无线数据通信收发芯片NRF24L01是一款工业级内置硬件链路层协议的低成本无线收发器,工作于2.4 GHz全球开放ISM频段。
此外,温度传感器DS18B20以"一线总线"的数字方式传输,可大大提高系统的抗干扰性。
关键词:SoC;STC89C52RC;NRF24L01;温度传感器DS18B20;无线AbstractWith the industrial and agricultural production the temperature, accurate temperature measurement becomes critical.This system is a solution designed for wiring difficulties, wasting resources,taking up the space and poor maneuverability of the above mentioned problems is proposed, which is based on wireless solutions of SoC design of wireless temperature gathering system. This system USES low power consumption, PC complete configuration, display and alarm function.Used in the design of the microcontroller STC89C52RC and MCS-51 MCU core . But STC_ISP through STC89C52RC can burn to download software.Wireless data communication transceiver chip is an industrial grade NRF24L01 the 2.4 GHz band global open ISM. In addition, the temperature sensor DS18B20 to "bus line" digital mode transmission, greatly improves the power system.Key words:SoC,STC89C52RC,NRF24L01,Temperature sensor DS18B20,Wireless目录第一章绪论 (1)1.1概述 (1)1.2系统设计任务分析 (2)第二章总体方案设计与选择的论证 (2)2.1单片机最小系统 (2)2.1.1单片机的说明 (2)2.1.2单片机的应用 (2)2.1.3单片机的结构特点 (4)2.1.4单片机引脚配置 (4)2.2无线收发模块介绍 (6)2.2.1nRF24L01概述 (6)2.2.2 引脚功能及描述 (7)2.2.3工作模式 (7)2.2.4工作原理 (8)2.2.5配置字 (9)2.2.6nRF24L01应用原理框图 (10)2.3数码管温度显示和运行指示灯电路 (10)2.3.1LED数码管的基本结构 (10)2.3.2数码管动态显示的工作原理 (11)2.3.3运行指示灯说明 (12)2.4温度采集电路 (12)2.4.1 DS18B20概述 (12)2.4.2 DS18B20的管脚配置和内部结构 (13)2.4.3单总线介绍 (14)2.4.4DS18B20的工作原理 (14)2.5声报警电路设计 (20)2.6无线温度采集软件界面(MFC) (20)第三章软件设计报告 (24)3.1单片机软件设计 (24)3.1.1发送部分软件设计 (24)3.1.1.1温度传感DS18B20 (24)3.1.1.2 LED数码管显示 (29)3.1.1.3无线模块NRF24L01(发送) (29)3.1.2接收部分软件设计 (30)3.1.2.1无线模块NRF24L01(接收) (30)3.1.2.2 LED数码管显示 (30)3.1.2.3串口通信 (30)3.1.3无线温度采集软件设计 (32)3.1.3.1串口设置 (32)3.1.3.2温度上下限设置 (33)3.1.3.3曲线显示 (34)3.2流程图设计 (34)3.2.1发送部分流程图 (34)3.2.2接收部分流程图 (34)3.2.3 MFC程序流程图 (34)3.3操作说明(附图) (34)第四章总结与展望 (36)致谢 (38)参考文献 (39)附录 (40)第一章绪论1.1概述随着社会的进步和生产的需要,利用无线通信进行温度数据采集的方式应用已经渗透到生活各个方面。
nrf24l01的调试测试程序
nrf24l01的调试测试程序参考了很多程序,经过测试,才看懂nrf24l01的状态机,在看数据手册时很多地方都不懂后来看了关于调试的文章再自己测试了一下某些功能,只测试了一边发送,一边接收的功能,做的很妥跟网上的程序相差无几。
#include <REG51.H>#include 'NRF24L01.h'#define TX_ADDR_WIDTH 5 //本地发射地址宽度#define RX_ADDR_WIDTH 5 //本地接收地址宽度#define TX_DATA_WIDTH 3 //发送数据字节数最大字节数为32字节#define RX_DATA_WIDTH 3 //接收数据字节数unsigned char code TX_ADDRESS[TX_ADDR_WIDTH]={0x78,0x78,0x78,0x78,0x78}; //发射通道地址unsigned char code RX_ADDRESS_P0[RX_ADDR_WIDTH]={0x78,0x78,0x78,0x78,0x78 }; //接收通道地址unsigned char bdata status; //定义一个位与字节都可以访问的变量用来监控IRQ中断信号sbit RX_DR=status^6; //当接收到有效数据后变为1sbit TX_DR=status^5; //当数据发送完成后产生中断,在自动应答模式中接收到应答信号后为1sbit MAX_RT=status^4; //当达到最大重发次数后变为1,产生此中断后必须清零后才能再次通讯void usdelay(void) //误差 -0.149305555556us 12us{unsigned char a,b;for(b=1;b>0;b--)for(a=2;a>0;a--);}void usdelay130(void) //误差 -0.451388888889us{unsigned char a,b;for(b=11;b>0;b--)for(a=4;a>0;a--);}unsigned char SPI_RW(unsigned char uchar) //SPI协议{unsigned char i;for(i=0;i<8;i++){SCK=0;MOSI=uchar&0x80; //从字节高位向NRF24L01写数据uchar=uchar<<1;SCK=1;uchar=uchar|MISO; //接收从NRF24L01发过来的数据SCK=0;}return uchar; //返回读取的值}unsigned char SPI_read(unsigned char reg) //SPI读操作两个字节完成读一次 reg:读指令{unsigned char bl;CSN=0;SPI_RW(reg); //第一个字节写读某个寄存器的指令此时返回值为状态寄存器的值bl=SPI_RW(0); //第二个字节返回所需要的寄存器的值CSN=1;return bl;unsigned char SPI_write(unsigned char reg,unsigned char value) //SPI写操作写一个字节的数据先写指令说明往哪个寄存器写数据,reg:指令,value:数据{unsigned char status;CSN=0;status=SPI_RW(reg); //写指令并返回状态寄存器的值SPI_RW(value); //写数据CSN=1;return status; //返回状态寄存器的值}unsigned char SPI_read_more(unsigned char reg,unsigned char *puf_read,unsigned char width) //读取多个数据 reg:指令,*puf 存储数据的指针,width:要读取数据的长度{unsigned char i,status;CSN=0;status=SPI_RW(reg); //写指令并返回状态寄存器的值for(i=0;i<width;i++) //循环读出数据puf_read[i]=SPI_RW(0); //将循环读出的数据存储在一个数组中}CSN=1;return status;}unsigned char SPI_write_more(unsigned char reg,unsigned char *puf_write,unsigned char width) //写多个数据 reg:指令,*puf:要写的数据,width:数据长度{unsigned char i,status;CSN=0;status=SPI_RW(reg); //写指令并返回状态寄存器的值for(i=0;i<width;i++) //循环写入数据{SPI_RW(*puf_write++);}CSN=1;return status;}void receive_model() //接收模式初始化配置{CE=0; //掉电模式此时PWR_UP为0CSN=1; //停止寄存器读写SCK=0; //时钟信号停止读写IRQ=1; //中断复位SPI_write_more(WRITE_REG+RX_ADDR_P0,RX_ADDRESS_P0, RX_ADDR_WIDTH); //写本地接收的地址SPI_write(WRITE_REG+EN_AA,0x00); //失能自动应答SPI_write(WRITE_REG+EN_RXADDR,0x01); //接收通道0允许SPI_write(WRITE_REG+RF_CH,0x00); //通信频率 2.4GSPI_write(WRITE_REG+RX_PW_P0,TX_DATA_WIDTH); //设置数据通道0传输数据宽度为3个字节SPI_write(WRITE_REG+RF_SETUP,0x09); //设置发射参数:传输速率,发射功率SPI_write(WRITE_REG+CONFIG,0x0F); //配置寄存器,设置CRC 和工作模式(接收模式)CE=1; //启动}void send_model() //发射模式初始化配置{CE=0; //掉电模式此时PWR_UP为0CSN=1; //停止寄存器读写SCK=0; //时钟信号停止读写IRQ=1; //中断复位SPI_write_more(WRITE_REG+TX_ADDR,TX_ADDRESS,TX_AD DR_WIDTH); //写本地发射地址SPI_write_more(WRITE_REG+RX_ADDR_P0,RX_ADDRESS_P0,RX_ADDR_WIDTH); //写本地接收(主要用来使能自动应答) SPI_write(WRITE_REG+EN_AA,0x00); //失能自动应答功能SPI_write(WRITE_REG+EN_RXADDR,0x00); //失能接收通道0 SPI_write(WRITE_REG+SETUP_RETR,0x00); //失能自动重发SPI_write(WRITE_REG+RF_CH,0x00); //通信频率 2.4GSPI_write(WRITE_REG+RX_PW_P0,RX_DATA_WIDTH); //设置接收数据长度为3个字节SPI_write(WRITE_REG+RF_SETUP,0x09); //设置发射参数:传输速率2MHZ,发射功率SPI_write(WRITE_REG+CONFIG,0x0e); //配置寄存器,设置CRC 和工作模式(发射模式)CE=1; //启动}void send_data(unsigned char *pArray) //发送数据{CE=0; //停止射频工作,待机模式1//SPI_write_more(WRITE_REG+RX_ADDR_P0,TX_ADDRESS,TX_ADD R_WIDTH); //装载接收端地址此地址单对单发送时可只初始化一次SPI_write_more(WR_TX_PLOAD,pArray,3); //向nrf24l01传入要发送的数据// SPI_write(WRITE_REG+CONFIG,0x0e); //IRQ收发完成中断响应,16位CRC,发送模式此功能在但对单发送时可初始化一次CE=1; //置高CE,激发数据usdelay(); //10us的延时}unsigned char read_data(unsigned char *pArray) //读取接收的数据 *pArray:传入存放数据的数组{unsigned char mark;CE=1; //接收模式usdelay130(); //等待130usstatus=SPI_read(STATUS); //读取状态寄存器的值来判断数据的接收情况if(RX_DR==1){CE=0; //接收完数据变成待机模式1SPI_read_more(RD_RX_PLOAD,pArray,RX_DATA_WIDTH); //读取数据并将其存放在RX_DATA中mark=1; //读取完成标志}SPI_write(WRITE_REG+STATUS,status); //清除中断标志位return mark;}/************************************************************** ************************************************/void main(){unsigned char mark,i; //接收完成标志delay(1000);receive_model(); //接收模式初始化配置delay(1000);while(1){mark=read_data(RX_DATA);if(mark==1){i++;SPI_write(FLUSH_RX,0); //清空RX_FIFO 中的缓存数据接受不像发送会自动清空缓存区的数据if(RX_DATA[0]==0&&RX_DATA[1]==1&&RX_DATA[2]==2) {led0=0;delay(100);RX_DATA[0]=0;RX_DATA[1]=0;RX_DATA[2]=0;}mark=0;}SPI_read(STATUS); //读状态寄存器SPI_read(FIFO_STATUS); //读FIFO状态led0=1;}}。
NRF24L01无线串口开发板程序详解
1.源程序开发环境建立1.1程序编译软件编译软件用keil C51,打开安装文件,一路点击下一步即可完成。
1.2程序下载软件使用STC ISP下载软件。
2.源程序文件整体结构工程中,只有一个main.c文件,所有程序都写在这个文件里面。
Reg51.h是包含的头文件。
是不是非常简单!3.源程序执行流程无线数据处理程序:串口数据处理程序:4.串口配置函数void serial_open(void){SCON = 0X50;AUXR |= 0X04;TL2 = 0Xc0; // 9600TH2 = 0Xfd;AUXR|=0X10;}此串口配置函数,利用单片机内部的定时器2作为波特率发生器。
共用到4个寄存器:SCON AUXR TL2 TH2SM0和SM1的位决定串口工作的4种方式:程序中,SCON=0X50,即SM0=0 SM1=1,即串口工作在“方式1”;REN=1,允许串口接收数据。
TL2和TH2是定时器2的高位和低位寄存器。
程序中,首先AUXR|=0X40,最后AUXR|=0X10。
即首先把T2x12置1,然后把T2R置1。
即首先把定时器2设置为1T模式,然后把定时器打开。
5.串口发送数据函数void senddata(uchar data_buf){SBUF = data_buf;while(!TI);TI = 0;}用到了寄存器SBUF和寄存器SCON中的TI位。
SBUF寄存器是串口收发数据缓存寄存器,放到这个寄存器中的数据,会通过串口发送出去,接收到的串口数据,也会放到这个寄存器中。
也就是串口接收和发送都是使用这个寄存器。
程序中,SBUF=data_buf,就是把data_buf给了SBUF,单片机自动把SBUF里面的数据发送到串口。
TI是串口发送数据完成标志位,当串口发送完一个数据,此位置1,置位后,需要通过软件清0。
所以通过while(!TI),来检测TI位,达到检测串口是否发送完数据的目的。
NRF24L01多路通讯调试成功的关键--附程序文件
NRF24L01多路通讯调试成功的关键(附基于串口助手的无线通讯工具源代码)本文档部分容摘自网络,由于按照网上教程调试总不成功,特此分享自己的失败经验(红字加重)。
一、收发端共同的设置1、设置信道工作频率(收发必须一致)如:SPI_RW_Reg(WRITE_REG+RF_CH,40);2、设置发射速率(2mbps或1mbps)和发射功率(收发必须一致);如:SPI_RW_Reg(WRITE_REG+RF_SETUP,0x0f); //发射速率为2Mbps,发射功率最大为0dB二、接收端的设置(最关键)1、设置频道0-5,自动ACK应答允许如: SPI_RW_Reg(WRITE_REG+EN_AA,0x3f);2、设置接收通道全部允许如: SPI_RW_Reg(WRITE_REG+EN_RXADDR,0x3f);3、向发送地址寄存器写入本地地址(5byte)4、向各个频道的接收地址寄存器写入接收地址(调试成不成功的关键)频道0:5个字节的地址频道1:5个字节的地址(和频道0的地址必须不同)频道2:1个字节的地址(为该通道发射机地址的最后一个字节·)有一个配置为发射模式的24l01要通过该通道与接收机通信,发射机的本地地址为{0x37,0xa1,0xb3,0xc9,0xda};则接收机频道2的地址为(0x37)频道3:1个字节的地址(同上)频道4:1个字节的地址(同上)频道5:1个字节的地址(同上)5、向每个频道(用那个写那个,需要在上面配置允许通道接收和ack·)接收数据长度寄存器写入接收数据宽度(最快均为32)频道n:SPI_RW_Reg(WRITE_REG + RX_PW_Pn, RX_PLOAD_WIDTH);如:频道5:SPI_RW_Reg(WRITE_REG + RX_PW_P5, RX_PLOAD_WIDTH);6、配置为接收模式如:SPI_RW_Reg(WRITE_REG+CONFIG,0x0f);下面附上我的程序/***************************头文件******************************/#ifndef __NRF24L01_H__#define __NRF24L01_H__sbit CE = P1^2;sbit CSN = P1^3;sbit IRQ = P1^4;sbit MOSI = P1^5;sbit MISO = P1^6;sbit SCK = P1^7;void NRF24L01_init(); //初始化模块uchar TX_packet(uchar *tx_buf); //返回值判断是否成功uchar RX_packet(uchar *rx_buf); //返回值判断是否成功void TX_MODE(); //发送模式void RX_MODE(); //接收模式//****************************************************************//// SPI(nRF24L01) commands#define READ_REG 0x00 // Define read command to register#define 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//***************************************************************//#endif/*********************************程序***********************************/ #include<reg52.h>#include"define.h"#include"DELAY.h"#include"NRF24L01.h"uchar code TX_ADDRESS[5] = {0,1,1,1,1};uchar code RX_ADDRESS_P0[5] = {0,1,1,1,1};uchar code RX_ADDRESS_P1[5] = {1,1,1,1,1};uchar code RX_ADDRESS_P2[1] = {2};uchar code RX_ADDRESS_P3[1] = {3};uchar code RX_ADDRESS_P4[1] = {4};uchar code RX_ADDRESS_P5[1] = {5};uchar code Data_width = 1;uchar code Data_rt = 15;uchar SPI_RW(uchar dat) // SPI读写指令{uchar i;for(i=0;i<8;i++){SCK = 0;MOSI = (dat&0x80);dat <<= 1;SCK = 1;dat |= MISO;}SCK = 0;return dat;}uchar NRF24L01_read_reg(uchar reg) //读某个寄存器的状态{uchar value;CSN=0; //拉低CSN,允许操作SPI_RW(reg); //写寄存器指令value = SPI_RW(0); //读寄存器值CSN=1; //拉高CSN,禁止操作return value; //返回寄存器状态}uchar NRF24L01_write_reg(uchar reg,uchar value) //写向某个寄存器写指令,并读出状态{uchar status;CSN=0; //拉低CSN,允许操作status = SPI_RW(reg); //写寄存器指令,并读出寄存器状态SPI_RW(value); //写寄存器值CSN=1; //拉高CSN,禁止操作return status; //返回寄存器之前的值}uchar NRF24L01_read_buf(uchar reg,uchar *pbuf,uchar n){uchar i,status;CSN=0; //拉低CSN,允许操作status = SPI_RW(reg); //写寄存器指令,并读出寄存器状态for(i=0;i<n;i++)pbuf[i] = SPI_RW(0);//从寄存器读出一字节数据CSN = 1; //拉高CSN,禁止操作return status;}uchar NRF24L01_write_buf(uchar reg,uchar *pbuf,uchar n){uchar i,status;CSN=0; //拉低CSN,允许操作status = SPI_RW(reg); //写寄存器指令,并读出寄存器状态for(i=0;i<n;i++)SPI_RW(pbuf[i]); //写一字节数据到寄存器CSN = 1; //拉高CSN,禁止操作return status;}void NRF24L01_init(){CE = 0; //射频电路工作使能,高电平工作,低电平停止CSN = 1; //SPI操作高电平允许,低电平禁止SCK = 0; //时钟拉低,禁止读写寄存器IRQ = 1; //中断复位,等待产生中断信号NRF24L01_write_reg(WRITE_REG + EN_AA, 0x3f); //所有接受通道允许自动应答NRF24L01_write_reg(WRITE_REG + EN_RXADDR, 0x3f); //接收通道全部打开NRF24L01_write_reg(WRITE_REG + SETUP_AW, 0x03); //设置接收/发射地址宽度为5字节NRF24L01_write_reg(WRITE_REG + SETUP_RETR, Data_rt); //自动发送间隔250+86us,次数15NRF24L01_write_reg(WRITE_REG + RF_CH, 0x00); //设置信道工作为2.4Ghz,收发必须一致NRF24L01_write_reg(WRITE_REG + RX_PW_P0, Data_width); //设置通道0数据字节数NRF24L01_write_reg(WRITE_REG + RX_PW_P1, Data_width); //设置通道1数据字节数NRF24L01_write_reg(WRITE_REG + RX_PW_P2, Data_width); //设置通道2数据字节数NRF24L01_write_reg(WRITE_REG + RX_PW_P3, Data_width); //设置通道3数据字节数NRF24L01_write_reg(WRITE_REG + RX_PW_P4, Data_width); //设置通道4数据字节数NRF24L01_write_reg(WRITE_REG + RX_PW_P5, Data_width); //设置通道5数据字节数NRF24L01_write_reg(WRITE_REG + RF_SETUP, 0x0f); //发送速率为1Mhz,发送功率最大值0dbNRF24L01_write_buf(WRITE_REG + TX_ADDR,TX_ADDRESS,5); //写本机地地址NRF24L01_write_buf(WRITE_REG + RX_ADDR_P0,RX_ADDRESS_P0,5); //写数据通道0接收机地址NRF24L01_write_buf(WRITE_REG + RX_ADDR_P1,RX_ADDRESS_P1,5); //写数据通道1接收机地址NRF24L01_write_buf(WRITE_REG + RX_ADDR_P2,RX_ADDRESS_P2,1); //写数据通道2接收机地址NRF24L01_write_buf(WRITE_REG + RX_ADDR_P3,RX_ADDRESS_P3,1); //写数据通道3接收机地址NRF24L01_write_buf(WRITE_REG + RX_ADDR_P4,RX_ADDRESS_P4,1); //写数据通道4接收机地址NRF24L01_write_buf(WRITE_REG + RX_ADDR_P5,RX_ADDRESS_P5,1); //写数据通道5接收机地址void RX_MODE(){NRF24L01_write_reg(WRITE_REG + CONFIG, 0x0f);//IRQ收发完成中断响应,16位CRC,接收模式CE = 1;}void TX_MODE(){NRF24L01_write_reg(WRITE_REG + CONFIG, 0x0e);//IRQ收发完成中断响应,16位CRC,发送模式CE = 1;}uchar TX_packet(uchar *tx_buf){uchar tx_flag = 1;CE = 0; //停止射频电路工作NRF24L01_write_reg(WRITE_REG + STATUS,0xff); //清除中断标志位NRF24L01_write_buf(WR_TX_PLOAD,tx_buf,Data_width); //装载要发送的数据CE = 1; //置高CE,激发数据发送Delay_ms(Data_rt/2);if(NRF24L01_read_reg(STATUS)&0x10)tx_flag = 0;return(tx_flag);}uchar RX_packet(uchar *rx_buf){uchar revalue = 0,sta;sta = NRF24L01_read_reg(STATUS); //读状态寄存器if(sta&0x40) //如果接受中断标志位为1{CE = 0; //SPI使能NRF24L01_read_buf(RD_RX_PLOAD,rx_buf,Data_width); //读取数据revalue = 1; //读取数据完成标志置1NRF24L01_write_reg(WRITE_REG + STATUS,0xff); //清除中断标志位}CE = 1;return revalue;//返回读取数据完成标志}。
(完整word版)NRF24L01详细教程
先来看接口电路,使用的IO 口不是唯一的哦,可随意定义接口,当然是在使用IO 口模拟SPI 且IRQ 中断引脚不使用的使用查询方法判断接收状态的情况下了。
作为初探我们就是用简单的IO 模拟SPI 的方法了,中断使用查询的方式。
那么该教程讲解的接口与单片机的连接如下:首先您需要了解NRF24L01,请参阅“NRF24L01 芯片中文资料”或者“NRF24L01 芯片英文资料”。
我们的教程是以一个简单的小项目为大家展示NRF24L01 的使用方法与乐趣。
我们所写教程均是以这种方式的呢,让您在学习的时候明白它能做什么,使您学起来不至于枯燥无味。
作为简易的教程,我们只需要知道它是怎么使用的就够了,我们本教程的目的是用NRF24L01 发送数据和接收数据,且接收方会对比发送的数据与接收的数据,若完全相同则控制LED 闪烁一次,并且把接收到的数据通过串口发送到PC 端,通过串口工具查看接收到的数据。
具体的要求如下:1、具备发送和接收的能力。
2、发送32 个字节的数据,接收方接收到正确数据之后给予提示,通过LED 闪烁灯形式。
3、把接收到的数据传送到PC 进行查看。
4、发送端每隔大约1.5 秒发送一次数据,永久循环。
以上是程序的要求,若您想自行设计出硬件接口,您也是可以添加一条呢:使用DIY 方式设计NRF24L01 的接口板,且包含含单片机平台,使用PCB 方式或者万用板方式均可。
如果您想让自己学的很扎实,那么推荐您自行做出接口板子呢。
当然若您的能力不足,那么我们不推荐自行做板呢,因为这样会增加您学习的难度,反而起到了反效果呢。
我们知道NRF24L01 的供电电压是1.9V~3.6V 不能超过这个范围,低了不工作,高了可能烧毁NRF24L01 芯片。
我们常用的STC89C52 的单片机的供电电压是5V,我们不能直接给24L01 这个模块供电,我们需要使用AMS1117-3.3V 稳压芯片把5V 转成3.3V 的电压为24L01 模块供电。
nrf24l01调试程序
24L01调试+测试程序
由于电赛的需求,使用无线芯片24L01,初次使用,期间遇到的各种问题,现在拿出来与大家分享,以便日后度友们不要为此类问题感到苦恼。
一.硬件条件
这个是整个芯片测试的基础,首先根据芯片手册去认真的连接每个引脚,随后也是最重要的,那就是
3.3V的稳压。
建议:尽量使用AMS1117芯片稳压,测
试过的电阻分压完全不靠谱。
二.软件调试
1.推荐使用这个测试方法:
/link?url=IPHIUPey0LWVfpHs NxGSTUwdkJGFnUWiug_j4mKt6x6JooApWGPpidEEK9YUyd7Y8
U6z6PXMEGE1Hd0s3v7i1_h3wqLhkc9E0ZNj7RHn_Pe
2.发射端单独测试,可以将STATUS寄存器读出来,这样就可以明了发射的成功与失败。
3.接收端测试,如果无法成功接收,那就是发射端的时序刚好没有和接收端的接收时间不同步,自己在写程序时要自己尽量的将两个时间写到同步。
(后面我的空间会上传我整理的测试程序)
三.24L01通讯
由于我的题目中需求是在需要信息发射的时候发射,所以我的方案是:默认两个芯片都是处于接收状态,通过中断去判断接受还是发射的成功,然后再将芯片置于接受状态。
nrf24l01程序
// SPI(nRF24L01) 命令定义#define READ_REG 0x00 // 定义读寄存器命令#define 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 NOP1 0xFF // 定义空操作,用于读取状态寄存器// SPI(nRF24L01) registers(addresses)#define CONFIG 0x00 // “配置寄存器”地址#define EN_AA 0x01 // “使能自动应答寄存器”地址#define EN_RXADDR 0x02 // “使能接收地址寄存器”地址#define SETUP_AW 0x03 // “设置地址长度寄存器”地址#define SETUP_RETR 0x04 // “设置自动重发寄存器”地址#define RF_CH 0x05 // “RF(射频)频道寄存器”地址#define RF_SETUP 0x06 // “RF(射频)设置寄存器”地址#define STATUS_24L01 0x07 // “状态寄存器”地址#define OBSERVE_TX 0x08 // “?寄存器”地址#define CD 0x09 // “发现载波寄存器”地址#define RX_ADDR_P0 0x0A // “通道0接收寄存器”地址#define RX_ADDR_P1 0x0B // "通道1接收寄存器"地址#define RX_ADDR_P2 0x0C // "通道2接收寄存器"地址#define RX_ADDR_P3 0x0D // "通道3接收寄存器"地址#define RX_ADDR_P4 0x0E // "通道4接收寄存器"地址#define RX_ADDR_P5 0x0F // "通道5接收寄存器"地址#define TX_ADDR 0x10 // ”发送寄存器“地址#define RX_PW_P0 0x11 // ”通道0有效载荷(数据)长度寄存器“地址#define RX_PW_P1 0x12 // ”通道1有效载荷长度寄存器“地址#define RX_PW_P2 0x13 // ”通道2有效载荷长度寄存器“地址#define RX_PW_P3 0x14 // ”通道3有效载荷长度寄存器“地址#define RX_PW_P4 0x15 // ”通道4有效载荷长度寄存器“地址#define RX_PW_P5 0x16 // ”通道5有效载荷长度寄存器“地址#define FIFO_STATUS 0x17 // “FIFO状态寄存器的寄存器”地址//**-------------------------------#define TX_ADR_WIDTH 5 //发送地址字节数#define RX_PLOAD_WIDTH 16 //接收数据字节数#define TX_PLOAD_WIDTH 16 //发送数据字节数#define MAX_CONTROL_NUMBER 2 //2 line concrol 2 relay remote control#define NOP _nop_();#define NOP5 NOP;NOP;NOP;NOP;NOP;#define NOP10 NOP5;NOP5;#define NOP20 NOP10;NOP10;#define delay_130us() NOP20;NOP20;NOP20;NOP20;NOP20;NOP20;NOP10;#define uchar unsigned char#define BYTE unsigned charsbit CE = P2^2;sbit CSN = P2^3;sbit SCK = P2^4 ;sbit MOSI = P2^5;sbit MISO = P2^6 ; //数据输入引脚sbit IRQ_24L01= P2^7 ;//spi通讯端口定义/**---------------------------------*/unsigned char TX_ADDRESS[5]={0x1,0x02,0x03,0x04,0x05};unsigned char RX_ADDRESS[5]={0x01,0x02,0x03,0x04,0x05};/*_________________________________*/void nRF24L01_Config(void); // 配置函数uchar SPI_RW(uchar byte); // 写一个字节到24L01,同时读出一个字节//uchar SPI_READ_Reg(BYTE reg); // 读出寄存器的值uchar SPI_RW_Reg(BYTE reg, BYTE value); // 向寄存器reg写一个字节,同时返回状态字节uchar SPI_Read_Buf(BYTE reg, BYTE *pBuf, BYTE bytes); //nRF24L01读出字节uchar SPI_Write_Buf(BYTE reg, BYTE *pBuf, BYTE bytes); //nRF24L01写入字节unsigned char nRF24L01_RxPacket(unsigned char* rx_buf); //nRF24L01数据接收void nRF24L01_TxPacket(unsigned char * tx_buf); //nRF24L01数据发送bit rec_validate_end(void); //接收数据完成后进行校正处理void set_24L01_rec_mode(void);//void test_24l01_irq(void); //测试nRF24L01/*-----------------------------*公司名称:xxxxxx函数名称:nRF24L01数据读/写函数功能:写一个字节到24L01,同时读出一个字节设计时间:设计者:------------------------------*/uchar SPI_RW(uchar byte){uchar bit_ctr;bit_ctr=0;for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit{MOSI = (byte & 0x80); // wait output 'byte', MSB to MOSIbyte = (byte << 1); // shift next bit into MSB..SCK = 1; // Set SCK high..//--------------------------MISO=1;NOP5;///-------------------------byte |= MISO; // read capture current MISO bitSCK = 0; // ..then set SCK low again}return(byte); // return read byte}/*-----------------------------*公司名称:xxxxxx函数名称:nRF24L01数据读取函数功能:向寄存器reg写一个字节,同时返回状态字节设计时间:设计者:------------------------------*///uchar SPI_RW_Reg(BYTE reg, BYTE value){uchar status_24L01;status_24L01 = 0;CSN = 0; // CSN low, init SPI transactionstatus_24L01 = SPI_RW(reg); // select register 选择通道SPI_RW(value); // ..and write value to it..CSN = 1; // CSN high againreturn(status_24L01); // return nRF24L01 status byte//读数据uchar SPI_Read_Buf(BYTE reg, BYTE *pBuf, BYTE bytes){uchar status_24L01,byte_ctr;status_24L01 = 0;byte_ctr = 0;CSN = 0; // Set CSN low, init SPI tranactionstatus_24L01 = SPI_RW(reg); // Select register to write to and read status byte for(byte_ctr=0;byte_ctr<bytes;byte_ctr++)pBuf[byte_ctr] = SPI_RW(0); //选择信号通道?CSN = 1;return(status_24L01); // return nRF24L01 status byte}/*-----------------------------*公司名称:xxxxxx函数名称:nRF24L01函数功能:写入bytes字节的数据设计时间:设计者:------------------------------*/uchar SPI_Write_Buf(BYTE reg, BYTE *pBuf, BYTE bytes) {uchar status_24L01,byte_ctr;status_24L01=0;byte_ctr=0;CSN = 0;status_24L01 = SPI_RW(reg);for(byte_ctr=0; byte_ctr<bytes; byte_ctr++) //SPI_RW(*pBuf++); //;需要发送的数据在PBUF表格里;//;需要发送的字节数载bytes;//对其操作的命令在reg里CSN = 1; // Set CSN high againreturn(status_24L01); //}/*-----------------------------*公司名称:xxxxxx函数名称:nRF24L01__set_24L01_rec_mode函数功能:写寄存器命令;并寄存器配置地址设计时间:设计者:------------------------------*//*-----------------------------*公司名称:xxxxxx函数名称:nRF24L01 ** nRF24L01_RxPacket函数功能:接收函数,返回1表示有数据收到,否则没有数据接受到设计时间:设计者:测试通过------------------------------*/unsigned char nRF24L01_RxPacket(unsigned char* rx_buf){unsigned char sta,revale=0;sta =0;revale=0;// set in RX modeSPI_RW_Reg(WRITE_REG + CONFIG, 0x0f); // Set PWR_UP bit, enable CRC(2 bytes) & Prim:RX. RX_DR enabled..CE = 1; // Set CE pin high to enable RX devicedelay_130us();sta=SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // read register STATUS's value//读取nRF24L01所处于的状态if(sta&0x40) // if receive data ready (RX_DR) interrupt 如果准备接收数据则中断1;{CE = 0; // stand by modeSPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);// read receive payload from RX_FIFO buffer//读取16个字节的数据最大32BITrevale =1;}SPI_RW_Reg(WRITE_REG+STATUS_24L01,sta);// clear RX_DR or TX_DS or MAX_RT interrupt flagreturn revale;}/*-----------------------------*公司名称:xxxxxx函数名称:nRF24L01函数功能:发送函数设计时间:设计者:------------------------------*/void nRF24L01_TxPacket(unsigned char * tx_buf){CE=0;SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // 发送5个地址24l01SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // RX_Addr0 same as TX_Adr for Auto.AckSPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH); // Writes data to TX payloadSPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); // Set PWR_UP bit, enable CRC(2 bytes) & Prim:TX. MAX_RT & TX_DS enabled..CE=1;NOP20;CE=0;}/*-----------------------------*公司名称:xxxxxx函数名称:nRF24L01 ** nRF24L01_Config函数功能:配置函数设计时间:设计者:------------------------------*/void nRF24L01_Config(void){//initial io of 24L01CE=0; // chip enableCSN=1; // Spi disableSCK=0; // Spi clock line init highCE=0;SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f); // Set PWR_UP bit, enable CRC(2 bytes) & Prim:RX. RX_DR enabled..SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); //Enable auto_ack Pipe0// SPI_RW_Reg(WRITE_REG + EN_AA, 0x00); //DISable auto_ack Pipe0SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // Enable Pipe0SPI_RW_Reg(WRITE_REG + SETUP_AW, 0x03); // Setup address width=5 bytesSPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1a); // 500us + 86us, 10 retrans...SPI_RW_Reg(WRITE_REG + RF_CH, 0x02); //channel 2SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); // TX_PWR:0dBm, Datarate:1Mbps, LNA:HCURRSPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);CE=1;}/*------------------------------*/bit rec_validate_end(void){if(IRQ_24L01==1)return 0;// if(nRF24L01_RxPacket(remote_buf)&0x01)return (1);else return (0);}void set_24L01_rec_mode(void){SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f); // Set PWR_UP bit, enable CRC(2 bytes) & Prim:RX. RX_DR enabled..RX_ADDRESS[0]=0XF0;RX_ADDRESS[1]=0XF0;RX_ADDRESS[2]=0XF0;RX_ADDRESS[3]=0XF0;RX_ADDRESS[4]=0XC0;SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, &RX_ADDRESS[0], TX_ADR_WIDTH);CE = 1; // Set CE pin high to enable RX device}1|。
NRF24L01跳频程序及方法
The main functionality of the frequency agility protocol will be to: • Detect stationary disturbance. • Move in such nner that new disturbance from the same source will not occur. • Do not move if disturbed by a frequency hopping source. • Give priority to mouse traffic.
Nordic Semiconductor ASA - Vestre Rosten 81, N-7075 Tiller, Norway - Phone +47 72 89 89 00 - Fax +47 72 89 89 89
Revision: 1.0
Page 2 of 22
October 2004
APPLICATION NOTE
USB
USB MCU
nRF 2401
nRF 24E1
n2R4FE1 OpSteicnaslor
Figure 1: Wireless 2.4GHz mouse/keyboard application
nRF24L01调试经典
nRF24L01应用笔记(一)2011-03-3111:15最近百度上一些朋友都在为nRF24L01头疼,我这段时间又比较忙不能花太多时间一个一个去帮忙调试,干脆今天抽点儿时间写个应用笔记,希望能给大家提供一些方法和帮助。
有问题可以跟帖留言,我看到会尽量帮大家。
nRF24L01是Nordic公司生产的一个单芯片射频收发器件,是目前应用比较广泛的一款无线通讯芯片,具体手册资料网上大把,我就不再重复它的特性什么的了,直接说说它的调试方法,供大家参考。
24L01是收发双方都需要编程的器件,这就对调试方法产生了一定的要求,如果两块一起调,那么通讯不成功,根本不知道是发的问题还是收的问题,不隐晦的说,我当时也是没理清调试思路才浪费了大半天时间看着模块干瞪眼。
正确的方法应该是先调试发送方,能保证发送正确,再去调接收,这样就可以有针对性的解决问题。
至于怎么去调发送方,先说下发送方的工作流程:·配置寄存器使芯片工作于发送模式后拉高CE端至少10us·读状态寄存器STATUS·判断是否是发送完成标志位置位·清标志·清数据缓冲网上的程序我也看过,大多都是成品,发送方发送-等应答-(自动重发)-触发中断。
可是这样的流程就已经把接收方给牵涉进来了,就是说一定要接收方正确收到数据并且回送应答信号之后发送方才能触发中断,结束一次完整的发送。
可是这跟我们的初衷不相符,我们想单独调试发送,完全抛开接收,这样就要去配置一些参数来取消自动应答,取消自动重发,让发送方达到发出数据就算成功的目的。
SPI_RW_Reg(WRITE_REG + EN_AA, 0x00); //失能通道0自动应答SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x00); //失能接收通道0 SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x00); //失能自动重发(注:以下贴出的寄存器描述由于中文资料上有一个错误,故贴出原版英文资料)有了以上这三个配置,发送方的流程就变成了发送-触发中断。
NRF24L01单片机的应用和程序
3.1.4 电源电路单片机STC89C51芯片的第40脚为正电源引脚VCC,外接+5V电压。
第20脚为接地引脚GND。
本设计里与PC连接的单片机采用USB供电,同时nRF24L01芯片采用3.3V电压供电。
电路设计如图3-4。
图3-4 电源电路3.3 NRF24L01无线模块3.3.1 NRF24L01芯片概述NRF24L01 是一款工作在2.4~2.5GHz 世界通用ISM 频段的单片无线收发器芯片。
无线收发器包括:频率发生器、增强型SchockBurstTM 模式控制器、功率放大器、晶体振荡器、调制器、解调器、输出功率。
频道选择和协议的设置可以通过SPI 接口进行设置。
极低的电流消耗,当工作在发射模式下发射功率为-6dBm 时电流消耗为9.0mA,接收模式时为12.3mA 。
掉电模式和待机模式下电流消耗更低。
NRF24L01主要特性如下[12][13]:(1)真正的GFSK 单收发芯片(2)内置链路层(3)增强型ShockBurstTM(4)自动应答及自动重发功能(5)地址及CRC 检验功能(6)数据传输率1 或2Mbps(7)SPI 接口数据速率0~8Mbps(8)125个可选工作频道(9)很短的频道切换时间可用于跳频(10)极低的晶振要求60ppm(11)工作电压1.9~3.6V3.3.2芯片结构NRF24L01内置地址解码器、先入先出堆栈区、解调处理器、时钟处理器、GFSK 滤波器、低噪声放大器、频率合成器、功率放大器等功能模块。
需要很少的外围元件,因此使用起来非常方便。
QFN24引脚封装,外形尺寸只有5×5mm。
NRF24L01的功能模块[14]如图3-6所示。
图3-6 NRF24L01的芯片结构3.3.3引脚功能及描述NRF24L01的封装及引脚排列如图3-7所示。
各引脚功能如下:图3-7 NRF24L01的封装及引脚排各引脚功能说明如表3-1所示。
表3-1 各引脚功能引脚名称引脚功能描述1 CE 数字输入RX 或TX 模式选择2 CSN 数字输入SPI 片选信号3 SCK 数字输入SPI 时钟4 MOSI 数字输入从SPI 数据输入脚5 MISO 数字输出从SPI 数据输出脚6 IRQ 数字输出可屏蔽中断脚7 VDD 电源电源+3V8 VSS 电源接地0V9 XC2 模拟输出晶体震荡器2 脚10 XC1 模拟输入晶体震荡器1 脚/外部时钟输入脚11 VDD_PA 电源输出给RF 的功率放大器提供的+1.8V电源12 ANT1 天线天线接口113 ANT2 天线天线接口214 VSS 电源接地0V15 VDD 电源电源+3V16 IREF 模拟输入参考电流17 VSS 电源接地0V18 VDD 电源电源+3V19 DVDD 电源输出去耦电路电源正极端20 VSS 电源接地0V3.3.4 NRF24L01模块原理图NRF24L01单端匹配网络:晶振,偏置电阻,去耦电容。
NRF24l01无线温度传感 收发程序
{
inerDelay_us(100);
CE=0; // chip enable
CSN=1; // Spi disable
SCK=0; // Spi clock line init high
SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // 写本地地址
_nop_();
}
//****************************************************************************************
/*NRF24L01初始化
//***************************************************************************************/
uchar seg1[10]={0x40,0x4F,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
uchar data temp_data[2]={0x00,0x00}; //温度采集数据缓冲区
uchar dispaly[7]; //显示缓冲区
//***********************************数码管0-9编码***********************************************
uchar seg[10]={0xC0,0xCF,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; //0~~9段码
NRF24L01参考程序(包含多个实例)
(相关人员如觉得本人水平低下,还请见谅)Nrf24L01的使用程序和使用方法和简单操作:功能:无线对发程序。
两个模块a,b,实现按下一个按键,会在对方的数码管上显示3或4,在本机上显示1,2。
当一个模块,比如a模块。
当两个按键按下其中一个,则会在另一个模块b上显示数字3,4(具体根据按下哪个按键)。
以上功能描述,B模块按键按下,如同a模块一样的功能,不做系统性描述了。
下面给出程序中几个地方的解释:#define READ_REG 0x00 // 读寄存器指令#define WRITE_REG 0x20 // 写寄存器指令#define RD_RX_PLOAD 0x61 // 读取接收数据指令#define WR_TX_PLOAD 0xA0 // 写待发数据指令#define FLUSH_TX 0xE1 // 冲洗发送FIFO指令#define FLUSH_RX 0xE2 // 冲洗接收FIFO指令#define REUSE_TX_PL 0xE3 // 定义重复装载数据指令#define NOP 0xFF // 保留类似这种的描述,可以等同于READ_REG =0x00;这个是经过实际程序测试出来的,比如以下程序:#include<reg51.h>#define k 0xfevoid main(){P1=k;}则会出现此类结果:MOSI = (uchar & 0x80); // output 'uchar', MSB to MOSIuchar = (uchar << 1); // shift next bit into MSB..SCK = 1; // Set SCK high..uchar |= MISO; // capture current MISO bitSCK = 0;此处为spi的核心,是spi协议的编程,其中uchar |= MISO; 表示uchar |= MISO | uchar; MOSI = (uchar & 0x80);其中0x80是1000 0000,与上uchar,这种&,是按位与,故可以从uchar提取出一个电平给mosi。
nRF24L01无线通信模块使用手册12要点
nRF24L01无线通信模块使用手册一、模块简介该射频模块集成了NORDIC公司生产的无线射频芯片nRF24L01:1.支持2.4GHz的全球开放ISM频段,最大发射功率为0dBm2.2Mbps,传输速率高3.功耗低,等待模式时电流消耗仅22uA4.多频点(125个),满足多点通信及跳频通信需求5.在空旷场地,有效通信距离:25m(外置天线)、10m(PCB天线)6.工作原理简介:发射数据时,首先将nRF24L01配置为发射模式,接着把地址TX_ADDR和数据TX_PLD 按照时序由SPI口写入nRF24L01缓存区,TX_PLD必须在CSN为低时连续写入,而TX_ADDR在发射时写入一次即可,然后CE置为高电平并保持至少10μs,延迟130μs后发射数据;若自动应答开启,那么nRF24L01在发射数据后立即进入接收模式,接收应答信号。
如果收到应答,则认为此次通信成功,TX_DS置高,同时TX_PLD从发送堆栈中清除;若未收到应答,则自动重新发射该数据(自动重发已开启),若重发次数(ARC_CNT)达到上限,MAX_RT置高,TX_PLD不会被清除;MAX_RT或TX_DS置高时,使IRQ变低,以便通知MCU。
最后发射成功时,若CE为低,则nRF24L01进入待机模式1;若发送堆栈中有数据且CE为高,则进入下一次发射;若发送堆栈中无数据且CE为高,则进入待机模式2。
接收数据时,首先将nRF24L01配置为接收模式,接着延迟130μs进入接收状态等待数据的到来。
当接收方检测到有效的地址和CRC时,就将数据包存储在接收堆栈中,同时中断标志位RX_DR置高,IRQ变低,以便通知MCU去取数据。
若此时自动应答开启,接收方则同时进入发射状态回传应答信号。
最后接收成功时,若CE变低,则nRF24L01进入空闲模式1。
三、模块引脚说明四、模块与AT89S52单片机接口电路注:上图为示意连接,可根据自己实际需求进行更改;使用AT89S52MCU模块时,请将Nrf24L01通讯模块每个端口(MOSI、SCK、CSN和CE)接4.7K的排阻上拉到VCC增强其驱动能力(如下图:)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(相关人员如觉得本人水平低下,还请见谅)Nrf24L01的使用程序和使用方法和简单操作:功能:无线对发程序。
两个模块a,b,实现按下一个按键,会在对方的数码管上显示3或4,在本机上显示1,2。
当一个模块,比如a模块。
当两个按键按下其中一个,则会在另一个模块b上显示数字3,4(具体根据按下哪个按键)。
以上功能描述,B模块按键按下,如同a模块一样的功能,不做系统性描述了。
下面给出程序中几个地方的解释:#define READ_REG 0x00 // 读寄存器指令#define WRITE_REG 0x20 // 写寄存器指令#define RD_RX_PLOAD 0x61 // 读取接收数据指令#define WR_TX_PLOAD 0xA0 // 写待发数据指令#define FLUSH_TX 0xE1 // 冲洗发送FIFO指令#define FLUSH_RX 0xE2 // 冲洗接收FIFO指令#define REUSE_TX_PL 0xE3 // 定义重复装载数据指令#define NOP 0xFF // 保留类似这种的描述,可以等同于READ_REG =0x00;这个是经过实际程序测试出来的,比如以下程序:#include<reg51.h>#define k 0xfevoid main(){P1=k;}则会出现此类结果:MOSI = (uchar & 0x80); // output 'uchar', MSB to MOSIuchar = (uchar << 1); // shift next bit into MSB..SCK = 1; // Set SCK high..uchar |= MISO; // capture current MISO bitSCK = 0;此处为spi的核心,是spi协议的编程,其中uchar |= MISO; 表示uchar |= MISO | uchar; MOSI = (uchar & 0x80);其中0x80是1000 0000,与上uchar,这种&,是按位与,故可以从uchar提取出一个电平给mosi。
MOSI = (uchar & 0x80); // output 'uchar', MSB to MOSIuchar = (uchar << 1);这两句组合起来用,就实现了把uchar编程8位2进制数后的每一位都可以发送给mosi;Uchar的只待对象,就是上面的诸如#define FLUSH_TX 0xE1这样的数,或者是相关的发送数据。
*pBuf这个并不是一个主要的问题,实际这个是涉及指针问题的,带*的跟地址有关系,但是我们其实不需要很关心编译的时候数据被具体存入哪个地址,即使是很重要的数据。
void init_NRF24L01(void){inerDelay_us(100);CE=0; // chip enableCSN=1; // Spi disableSCK=0; //SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // 写本地地址SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); // 写接收端地址SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); // 频道0自动ACK应答允许SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // 允许接收地址只有频道0,如果需要多频道可以参考Page21SPI_RW_Reg(WRITE_REG + RF_CH, 0); // 设置信道工作为2.4GHZ,收发必须一致SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度,本次设置为32字节SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); //设置发射速率为1MHZ,发射功率为最大值0dB}在整个初始化中我们看到:CE=0; // chip enableCSN=1; // Spi disable这是设置整个的状态。
如过状态设置成待机,则引脚可能变为高阻。
(以上并非全部引脚)SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // 写本地地址SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); // 写接收端地址类似以上两句,这是应用spi的子程序,将寄存器指令放入nrf24l01。
如果需深究,请参考说明书,手册等。
或者可以通过#define READ_REG 0x00 // 读寄存器指令等了解大概流程。
在整个无线通信过程中,初始化只需设置一次。
TxBuf[]存放的是发送的数据。
并且此数据被发送时,是将这个数组的数全部发送的。
对方也全部接收。
RxBuf[]接收数组,用于存放对方发来的数据。
SetRX_Mode();nRF24L01_RxPacket(RxBuf);当主程序中包含这两个子函数时,且这时某个数据被发送过来,则会被接收到。
且被存放到了RxBuf[];反之包含nRF24L01_TxPacket(TxBuf);且TxBuf[]已经存入你想要的数据的时候,这个数据将被发送。
程序部分:下面给出程序,由于收发双方程序是完全一样的,所以只粘贴一份。
程序虽然不是自己写的,但是经过实际测试的,没有任何诡异的问题。
#include <reg52.h>#include <intrins.h>typedef unsigned char uchar;typedef unsigned char uint;//****************************************NRF24L01端口定义***************************************sbit MISO =P1^3;sbit MOSI =P1^4;sbit SCK =P1^2;sbit CE =P1^1;sbit CSN =P3^2;sbit IRQ =P3^3;//************************************按键***************************************************sbit KEY1=P3^6;sbit KEY2=P3^7;//************************************数码管位选*********************************************sbit led3=P2^0;sbit led2=P2^1;sbit led1=P2^2;sbit led0=P2^3;//************************************蜂明器***************************************************sbit BELL=P3^4;//***********************************数码管0-9编码*******************************************uchar seg[10]={0xC0,0xCF,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; //0~~9段码//*********************************************NRF24L01*********************** **************#define TX_ADR_WIDTH 5 // 5 uints TX address width#define RX_ADR_WIDTH 5 // 5 uints RX address width#define TX_PLOAD_WIDTH 20 // 20 uints TX payload#define RX_PLOAD_WIDTH 20 // 20 uints TX payloaduint const TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //本地地址uint const RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //接收地址//***************************************NRF24L01寄存器指令*******************************************************#define READ_REG 0x00 // 读寄存器指令#define WRITE_REG 0x20 // 写寄存器指令#define RD_RX_PLOAD 0x61 // 读取接收数据指令#define WR_TX_PLOAD 0xA0 // 写待发数据指令#define FLUSH_TX 0xE1 // 冲洗发送FIFO指令#define FLUSH_RX 0xE2 // 冲洗接收FIFO指令#define REUSE_TX_PL 0xE3 // 定义重复装载数据指令#define NOP 0xFF // 保留//*************************************SPI(nRF24L01)寄存器地址****************************************************#define CONFIG 0x00 // 配置收发状态,CRC校验模式以及收发状态响应方式#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 OBSERVE_TX 0x08 // 发送监测功能#define CD 0x09 // 地址检测#define RX_ADDR_P0 0x0A // 频道0接收数据地址#define RX_ADDR_P1 0x0B // 频道1接收数据地址#define RX_ADDR_P2 0x0C // 频道2接收数据地址#define RX_ADDR_P3 0x0D // 频道3接收数据地址#define RX_ADDR_P4 0x0E // 频道4接收数据地址#define RX_ADDR_P5 0x0F // 频道5接收数据地址#define TX_ADDR 0x10 // 发送地址寄存器#define RX_PW_P0 0x11 // 接收频道0接收数据长度#define RX_PW_P1 0x12 // 接收频道0接收数据长度#define RX_PW_P2 0x13 // 接收频道0接收数据长度#define RX_PW_P3 0x14 // 接收频道0接收数据长度#define RX_PW_P4 0x15 // 接收频道0接收数据长度#define RX_PW_P5 0x16 // 接收频道0接收数据长度#define FIFO_STATUS 0x17 // FIFO栈入栈出状态寄存器设置//***************************************************************************** *********void Delay(unsigned int s);void inerDelay_us(unsigned char n);void init_NRF24L01(void);uint SPI_RW(uint uchar);uchar SPI_Read(uchar reg);void SetRX_Mode(void);uint SPI_RW_Reg(uchar reg, uchar value);uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars);uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars);unsigned char nRF24L01_RxPacket(unsigned char* rx_buf);void nRF24L01_TxPacket(unsigned char * tx_buf);//*****************************************长延时*****************************************void Delay(unsigned int s){unsigned int i;for(i=0; i<s; i++);for(i=0; i<s; i++);}//***************************************************************************** *************uint bdata sta; //状态标志sbit RX_DR =sta^6;sbit TX_DS =sta^5;sbit MAX_RT =sta^4;/****************************************************************************** ************/*延时函数/****************************************************************************** ************/void inerDelay_us(unsigned char n){for(;n>0;n--)_nop_();}//***************************************************************************** ***********/*NRF24L01初始化//***************************************************************************** **********/void init_NRF24L01(void){inerDelay_us(100);CE=0; // chip enableCSN=1; // Spi disableSCK=0; //SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // 写本地地址SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); // 写接收端地址SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); // 频道0自动ACK应答允许SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // 允许接收地址只有频道0,如果需要多频道可以参考Page21SPI_RW_Reg(WRITE_REG + RF_CH, 0); // 设置信道工作为2.4GHZ,收发必须一致SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度,本次设置为32字节SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); //设置发射速率为1MHZ,发射功率为最大值0dB}/****************************************************************************** **********************/*函数:uint SPI_RW(uint uchar)/*功能:NRF24L01的SPI写时序/****************************************************************************** **********************/uint SPI_RW(uint uchar){uint bit_ctr;for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit{MOSI = (uchar & 0x80); // output 'uchar', MSB to MOSIuchar = (uchar << 1); // shift next bit into MSB..SCK = 1; // Set SCK high..uchar |= MISO; // capture current MISO bitSCK = 0; // ..then set SCK low again}return(uchar); // return read uchar}/****************************************************************************** **********************/*函数:uchar SPI_Read(uchar reg)/*功能:NRF24L01的SPI时序/****************************************************************************** **********************/uchar SPI_Read(uchar reg){uchar reg_val;CSN = 0; // CSN low, initialize SPI communication...SPI_RW(reg); // Select register to read from..reg_val = SPI_RW(0); // ..then read registervalueCSN = 1; // CSN high, terminate SPI communicationreturn(reg_val); // return register value}/****************************************************************************** **********************//*功能:NRF24L01读写寄存器函数/****************************************************************************** **********************/uint SPI_RW_Reg(uchar reg, uchar value){uint status;CSN = 0; // CSN low, init SPI transactionstatus = SPI_RW(reg); // select registerSPI_RW(value); // ..and write value to it..CSN = 1; // CSN high againreturn(status); // return nRF24L01 status uchar}/****************************************************************************** **********************//*函数:uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)/*功能: 用于读数据,reg:为寄存器地址,pBuf:为待读出数据地址,uchars:读出数据的个数/****************************************************************************** **********************/uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars){uint status,uchar_ctr;CSN = 0; // Set CSN low, init SPI tranactionstatus = SPI_RW(reg); // Select register to write to and read status ucharfor(uchar_ctr=0;uchar_ctr<uchars;uchar_ctr++)pBuf[uchar_ctr] = SPI_RW(0); //CSN = 1;return(status); // return nRF24L01 status uchar}/****************************************************************************** ***************************/*函数:uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)/*功能: 用于写数据:为寄存器地址,pBuf:为待写入数据地址,uchars:写入数据的个数/****************************************************************************** ***************************/uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars){uint status,uchar_ctr;CSN = 0; //SPI使能status = SPI_RW(reg);for(uchar_ctr=0; uchar_ctr<uchars; uchar_ctr++) //SPI_RW(*pBuf++);CSN = 1; //关闭SPIreturn(status); //}/****************************************************************************** **********************//*函数:void SetRX_Mode(void)/*功能:数据接收配置/****************************************************************************** **********************/void SetRX_Mode(void){CE=0;SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f); // IRQ收发完成中断响应,16位CRC ,主接收CE = 1;inerDelay_us(130);}/****************************************************************************** ************************//*函数:unsigned char nRF24L01_RxPacket(unsigned char* rx_buf)/*功能:数据读取后放如rx_buf接收缓冲区中/****************************************************************************** ************************/unsigned char nRF24L01_RxPacket(unsigned char* rx_buf){unsigned char revale=0;sta=SPI_Read(STATUS); // 读取状态寄存其来判断数据接收状况if(RX_DR) // 判断是否接收到数据{CE = 0; //SPI使能SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);// read receive payload from RX_FIFO bufferrevale =1; //读取数据完成标志}SPI_RW_Reg(WRITE_REG+STATUS,sta); //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标志return revale;}/****************************************************************************** *****************************/*函数:void nRF24L01_TxPacket(unsigned char * tx_buf)/*功能:发送tx_buf中数据/****************************************************************************** ****************************/void nRF24L01_TxPacket(unsigned char * tx_buf){CE=0; //StandBy I模式SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 装载接收端地址SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH); // 装载数据SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); // IRQ收发完成中断响应,16位CRC,主发送CE=1; //置高CE,激发数据发送inerDelay_us(10);}//************************************主函数************************************************************void main(void){unsigned char tf =0;unsigned char TxBuf[20]={0}; //unsigned char RxBuf[20]={0};init_NRF24L01() ;led0=0;led1=0;led2=0;led3=0;P0=0x00;TxBuf[1] = 1 ;TxBuf[2] = 1 ;nRF24L01_TxPacket(TxBuf); // Transmit Tx buffer dataDelay(6000);P0=0xBF;while(1){if(KEY1 ==0 ){P0=seg[1];TxBuf[1] = 1 ;tf = 1 ;}if(KEY2 ==0 ){P0=seg[2];TxBuf[2] =1 ;tf = 1 ;}if (tf==1){nRF24L01_TxPacket(TxBuf); // Transmit Tx buffer dataTxBuf[1] = 0x00;TxBuf[2] = 0x00;tf=0;Delay(1000);}//***************************************************************************** ******************SetRX_Mode();nRF24L01_RxPacket(RxBuf);if(RxBuf[1]|RxBuf[2]){if( RxBuf[1]==1){P0=seg[3];}if( RxBuf[2]==1){P0=seg[4];}Delay(1000);}RxBuf[1] = 0x00;RxBuf[2] = 0x00;}}如需要利用程序做nrf24l01改动应用在其他设计中。