51单片机应用之无线通讯模块NRF24L01+.docx
《51单片机应用之无线通讯模块NRF24L01+.docx》由会员分享,可在线阅读,更多相关《51单片机应用之无线通讯模块NRF24L01+.docx(53页珍藏版)》请在冰豆网上搜索。
51单片机应用之无线通讯模块NRF24L01+
30、51单片机应用之............无线通讯模块NRF24L01+
(一)基础知识篇
今天刚调试好,先看图吧!
这张是AT89C2051控制NRF24L01+做发射调试。
看看NRF24L01细节吧!
这是LCD屏显示:
AT89S52做接收测试:
正在接收时的显示:
接收到数据后显示32个数据值:
无线模块NRF24L01+应用上篇结束,敬请期待NRF24L01+下篇的调试部分。
。
。
。
31、51单片机应用之............无线通讯模块NRF24L01+
(二)模块调试篇
32、51单片机应用之............无线通讯模块NRF24L01+(三)发送与接收模块的联调
33、51单片机应用之............无线通讯模块NRF24L01+(四)举例应用
34、补充NRF24L01+之————LED调试篇
写了前面四篇关于NRF24L01通讯调试的文章,看来大家还是很喜欢,有帮助的。
有很多大学生朋友问我说,我们没有两个LCD来显示调试状态,连一个也没有,能不能用几个LED来显示调试状态呢?
因此我就写这篇补充调试的文章,就用P0口的8个LED来显示调试NRF24L01到成功进行数据通讯。
先把51单片机的最小系统准备好,还有8个LED的小电路板,如果你的LED就在系统板上那省了这一步。
8个LED的小板子电路很简单,但你焊接要可靠,不然电路本身都不稳定,后面对判断故障会产生很大影响。
NRF24L01+模块电路还是前面说过的那样:
相同的两个模块的板子。
好!
假设我们用P0口来作LED显示、用P1口来作模块接口,下面我们先写一段最简单的程序,来确认LED电路,和P0、P1口的完好!
#include
#include
#defineuintunsignedint
typedefunsignedcharuchar;
//*********************************
// 延时函数
//在晶振为12MHz时,延时count毫秒
//*********************************
voidDelayms(uintcount)
{
uinti;
while(count--)
{for(i=0;i<80;i++){}
}
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
//*********************************
//主函数
//*********************************
voidmain()
{
P0=0x00;//P0口LED点亮
P1=0x00;//P1口LED点亮
P2=0x00;
P3=0x00;
Delayms(2000);//延时2秒
while
(1)
{
P0=~P0;//将P0口数据取反,原来亮的就熄灭
P1=~P1;//将P1口数据取反,原来亮的就熄灭
P2=~P2;
P3=~P3;
Delayms(500);//延时半秒
}
}
这是段极简单的程序,用来检测单片机电路连接的正确性,和IO口的工作状态是否正常,为后面调试NRF24L01做好准备。
它的工作状态如下:
同样的,把LED的接口再接到P1口,看看它是否一样的在全部闪烁。
做好了这步,准备工作就算完成了。
接下来我们把NRF24L01+的模块插上,要注意,接口要对清楚,电源要连接正确:
接下来我们写发送程序:
//**********************************
//NRF24L01+模块发射程序
//用8个LED调试
//Txz0012012.05.16
//**********************************
#include
typedefunsignedcharuchar;//将无符号字节类型重定义为uchar
typedefunsignedintuint;//将无符号整数类型重定义为Uint
//*********************NRF24L01函数定义****************************
voiddelayms(uintt);//毫秒延时
voidinit_NRF24L01(void);//模块初始化函数
ucharSPI_RW(ucharreg);//基本SPI读写时序
ucharSPI_Read(ucharreg);//从寄存器reg读一个字节
voidSetRX_Mode(void);//设置接收模式
ucharSPI_RW_Reg(ucharreg,ucharvalue);//向寄存器写一个字节
ucharSPI_Read_Buf(ucharreg,uchar*pBuf,ucharuchars);//从缓冲器读出uchars字节的数据
ucharSPI_Write_Buf(ucharreg,uchar*pBuf,ucharuchars);//向缓冲器写进uchars字节的数据
voidnRF24L01_TxPacket(uchar*tx_buf);//启动一次发送
ucharnRF24L01_RxPacket(uchar*rx_buf);//读取接收的数据,放入rx_buf数组
//***********NRF24L01模块IO端口定义******************
sbitCE=P1^0;
sbitCSN=P1^1;
sbitSCK=P1^2;
sbitMOSI=P1^3;
sbitMISO=P1^4;
sbitIRQ=P1^5;
//*****************NRF24L01常量**********************
#defineTX_ADR_WIDTH5//发送地址宽度5字节
#defineRX_ADR_WIDTH5//接收地址宽度5字节
#defineTX_PLOAD_WIDTH32//发送数据宽度32字节
#defineRX_PLOAD_WIDTH32//接收数据的宽度32字节
ucharconstTX_ADDRESS[TX_ADR_WIDTH]={0x01,0x02,0x03,0x04,0x05};//本地地址
ucharconstRX_ADDRESS[RX_ADR_WIDTH]={0x01,0x02,0x03,0x04,0x05};//接收地址
//*****************NRF24L01寄存器指令*******************
#defineREAD_REG0x00//读寄存器指令
#defineWRITE_REG0x20//写寄存器指令
#defineRD_RX_PLOAD0x61//读取接收数据指令
#defineWR_TX_PLOAD0xA0//写待发数据指令
#defineFLUSH_TX0xE1//清空发送缓冲区
//**************SPI(nRF24L01)寄存器地址常量*****************
#defineCONFIG0x00//配置收发状态,CRC校验模式以及收发状态响应方式
#defineEN_AA0x01//自动应答功能设置
#defineEN_RXADDR0x02//可用信道设置
#defineSETUP_AW0x03//收发地址宽度设置
#defineSETUP_RETR0x04//自动重发功能设置
#defineRF_CH0x05//工作频率设置
#defineRF_SETUP0x06//发射速率、功耗功能设置
#defineSTATUS0x07//状态寄存器
#defineOBSERVE_TX0x08//发送监测功能
#defineCD0x09//地址检测
#defineRX_ADDR_P00x0A//频道0接收数据地址
#defineRX_ADDR_P10x0B//频道1接收数据地址
#defineRX_ADDR_P20x0C//频道2接收数据地址
#defineRX_ADDR_P30x0D//频道3接收数据地址
#defineRX_ADDR_P40x0E//频道4接收数据地址
#defineRX_ADDR_P50x0F//频道5接收数据地址
#defineTX_ADDR0x10//发送地址寄存器
#defineRX_PW_P00x11//接收频道0接收数据长度
#defineRX_PW_P10x12//接收频道0接收数据长度
#defineRX_PW_P20x13//接收频道0接收数据长度
#defineRX_PW_P30x14//接收频道0接收数据长度
#defineRX_PW_P40x15//接收频道0接收数据长度
#defineRX_PW_P50x16//接收频道0接收数据长度
#defineFIFO_STATUS0x17//FIFO栈入栈出状态寄存器设置
/*****毫秒延时子程序*****/
voiddelayms(uintt)//约延时t毫秒
{
uinti;
while(t--)
{
for(i=0;i<125;i++);
}
}
/**********************************************
/*函数:
uintSPI_RW(uintuchar)
/*功能:
NRF24L01的SPI写时序
/**********************************************/
ucharSPI_RW(ucharuuchar)
{
ucharbit_ctr;
for(bit_ctr=0;bit_ctr<8;bit_ctr++)//输出8个位
{
MOSI=(uuchar&0x80);//输出uuhar的最高位
uuchar=(uuchar<<1);//左移一位
SCK=1;//将时钟线置‘1’
uuchar|=MISO;//同时读取STATUS
SCK=0;//然后再将时钟线置‘0’
}
return(uuchar);//返回读取的值
}
/***********************************************
/*函数:
ucharSPI_Read(ucharreg)
/*功能:
NRF24L01的SPI读取一个字节时序
/***********************************************/
ucharSPI_Read(ucharreg)
{
ucharreg_val;
CSN=0;//CSN置'0',允许指令操作
SPI_RW(reg);//写一条reg指令
reg_val=SPI_RW(0);//读取reg的值到reg_val
CSN=1;//CSN置'1',禁示操作
return(reg_val);//返回读取的值
}
/***********************************************
/*功能:
NRF24L01写一个字节到寄存器函数
/***********************************************/
ucharSPI_RW_Reg(ucharreg,ucharvalue)
{
ucharstatus;
CSN=0;//CSN置'0',允许操作
status=SPI_RW(reg);//这指令,并读STATUS
SPI_RW(value);//写数据值到reg
CSN=1;//CSN置'1',禁止操作
return(status);//returnnRF24L01statusuchar
}
/*****************************************************************
/*函数:
uintSPI_Write_Buf(ucharreg,uchar*pBuf,ucharuchars)
/*功能:
用于写数据:
reg:
为寄存器地址,
/*pBuf:
为待写入数据地址,
/*uchars:
写入数据的个数
/*****************************************************************/
ucharSPI_Write_Buf(ucharreg,uchar*pBuf,ucharuchars)
{
ucharstatus,uchar_ctr;
CSN=0;//SPI使能
status=SPI_RW(reg);
for(uchar_ctr=0;uchar_ctrSPI_RW(*pBuf++);
CSN=1;//关闭SPI
return(status);//
}
//******************************************
/*NRF24L01初始化
//******************************************/
voidinit_NRF24L01(void)
{
delayms
(1);
CE=0;//射频停止工作
CSN=1;//停止寄存器读写
SCK=0;//时种信号停止读写
IRQ=1;//中断复位
SPI_RW_Reg(WRITE_REG+EN_AA,0x00);//频道0自动ACK应答禁止
SPI_RW_Reg(WRITE_REG+SETUP_RETR,0x00);//禁止自动发送
SPI_RW_Reg(WRITE_REG+EN_RXADDR,0x01);//允许接收地址只有频道0,
SPI_RW_Reg(WRITE_REG+RF_CH,1);//设置信道工作为2.4GHZ,收发必须一致
SPI_RW_Reg(WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//设置接收数据长度,本次设置为32字节
SPI_RW_Reg(WRITE_REG+RF_SETUP,0x07);//设置发射速率为2MHZ,发射功率为最大值0dB
}
/******************************************************
/*函数:
voidnRF24L01_TxPacket(unsignedchar*tx_buf)
/*功能:
发送tx_buf中数据
/*******************************************************/
voidnRF24L01_TxPacket(unsignedchar*tx_buf)
{
CE=0;//StandByI模式
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);//装载接收端地址
SPI_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH);//装载数据
SPI_RW_Reg(WRITE_REG+CONFIG,0x0e);//IRQ收发完成中断响应,16位CRC,主发送
CE=1;//置高CE,激发数据发送
delayms
(1);
}
//************************************
//主函数
//************************************
voidmain()
{
ucharTxBuf[32];
ucharstatus;//定义一个变量用来装读取到的STATUS数值
init_NRF24L01();//NRF24L01初始化
SPI_RW_Reg(WRITE_REG+STATUS,0XFF);//清状态寄存器
status=SPI_Read(STATUS);//读取状态
P0=~status;//P0口显示读取的状态
delayms(4000);//显示延时4秒,以便从容看清楚
P0=0xff;//清除显示
delayms(600);
TxBuf[0]=1;//我们设置个初值1在想要发送的数组的第1个里变量里。
while
(1)
{TxBuf[0]=~TxBuf[0];//这句把要发送的第1个变量的值取反,如果原来是1,现再就为0
nRF24L01_TxPacket(TxBuf);//装载数据并进行一次发送操作
status=SPI_Read(STATUS);//发送完后再读取状态
P0=~status;//显示发送完后的状态
delayms(500);//显示发送后的信息停留1秒
P0=0xFF;//清除显示
delayms(500);
}
}
程序看上去挺长,其实大部分都是常量的定义。
主要的几句就在主函数里,要注意的是接口的定义跟你插在板子上接口要一致。
电源不能接错哦!
这个程序很简单,开始对NRF24L01初始化,然后读取它的状态值显示在P0口,正确的状态应为00001110,然后停顿4秒,让我可以从容看清状态。
然后进入循环发送状态,先将要发送的数据取反,就是说,这次发送0,下次就发送1,这样交替进行,以便后面接收时,我们可以看到变化。
接下来就是进行发送,发送完后,再读取状态并显示。