基于nRF24L01的无线通信模块设计报告正文
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1前言
本次我们三人小组设计的是无线通信模块,根据设计要求我们选择了无线收发模块nRF24L01、单片机STC89C52、LCD1602和键盘模块等作为本次设计的硬件需求。
首先我们与老师一起讨论了一些设计的相关事宜和设计思路。
接下来我们一起画好了模拟电路图,在老师的帮助下我们对电路图进行了补充和完善。
完成这些基本工作后,在老师和同学的帮助下我们买回了自己所需的元器件。
接着我们变分工完成了元器件的焊接连接和程序的编写,然后便是模块的上电调试,设计的答辩和设计报告的完善。
我们本次之所以会选择无线通信模块的设计,是我们觉得无线通信技术是现代社会中一门很重要的技术,我们掌握好了这门技术对以后我们的工作生活都有很大的帮助。
我们本次设计的无线通信模块虽然只是我们的一次小小的体验,但我们都知道无线通信在我们现在所处的信息时代是多么的重要,如今我们生活的方方面面无不与无线通信息息相关。
我们所熟悉的手机、电脑、电视等等都与无线通信有着直接的联系。
甚至在某些高端领域方面无线通信技术能反映一个国家的科技水平和综合国力。
我们国家的无线通信技术虽然在世界上排在了前面的位置,但与一些发达国家相比我们任然有很大差距,如太空中有差不多80%的通信卫星是美国的。
当然我们本次设计的无线通信模块只是很基础的无线通信模块,我们所达到的效果就是两个模块间能相互发送一些简单的字符和数字。
2总体方案设计
本次设计我们考虑用C语言和汇编去实现模块的无线通信功能,但我们编写程序时发现汇编语言较难写且可读性差,因此我们选择了用C语言作为本次的软件实现。
要实现无线通信功能,我们选择了小巧轻便的无线收发模块nRF24L01。
在单片机方面考虑到52系列优于51系列且很好购买,我们选择了STC89C52单片机。
在液晶显示上,我们只要求能显示一些简单的数字和字母,我们选择了LCD1602。
键盘输入方面我们选择的是4×4矩阵键盘。
以上各模块的功能信息在后面都有更为具体的介绍。
图2.1无线通信模块框图
3单元模块设计
3.1 nRF24L01的简单介绍
nRF24L01 是 NORDIC 公司最近生产的一款无线通信通信芯片,采用 FSK 调制,内部集成 NORDIC 自己的 Enhanced Short Burst 协议。
可以实现点对点或是 1对 6 的无线通信。
无线通信速度可以达到 2M(bps)。
NORDIC 公司提供通信模块的 GERBER 文件,可以直接加工生产。
嵌入式工程师或是单片机爱好者只需要为单片机系统预留 5 个GPIO,1 个中断输入引脚,就可以很容易实现无线通信的功能,非常适合用来为 MCU 系统构建无线通信功能。
2.4GHz 全球开放ISM频段,最大0dBm发射功率,免许可证使用支持六路通道的数据接收低工作电压:1.9V ~
3.6V 低电压工作高速率:2Mbps,由于空中传输时间很短,极大的降低了无线传输中的碰撞现象(软件设置1Mbps或者2Mbps的空中传输速率)多频点:125频点,满足多点通信和跳频通信需要超小型:内置2.4GHz天线,体积小巧,15×29mm(包括天线)低功耗:当工作在应答模式通信时,快速的空中传输及启动时间,极大的降低了电流消耗。
低应用成本:nRF24L01集成了所有与RF协议相关的高速信号处理部分,比如:自动重发丢失数据包和自动产生应答信号等,nRF24L01的SPI接口可以利用单片机的硬件SPI口连接或用单片机I/O口进行模拟,内部有FIFO可以与各种高低速微处理器接口,便于使用低成本单片机。
便于开发:由于链路层完全集成在模块上,非常便于开发。
自动重发功能,自动检测和重发丢失的数据包,重发时间及自动存储未收到应答信号的数据包自动应答功能,在收到有效数据后,模块自动发送应答信号,无须另行编程载波检测—固定频率检测内置硬件CRC检错和点对多点通信地址控制数据包传输错误计数器及载波检测功能可用于跳频设置可同时设置六路接收通道地址,可有选择性的打开接收通道标准插针Dip2.54MM间距接口,便于嵌入式应用。
第3页
nRF24L01 功能框图
图3.1nRF24L01 功能框图
Fig.1 nRF24L01 BLOCK DIAGRAM
nRF24L01 的框图如 Fig.1所示,从单片机控制的角度来看,我们只需要关注 Fig.1 右面
的六个控制和数据信号,分别为 CSN、SCK、MISO、MOSI、IRQ、CE。
CSN:芯片的片选线,CSN为低电平芯片工作。
SCK:芯片控制的时钟线(SPI 时钟)
MISO:芯片控制数据线(Master input slave output)
MOSI:芯片控制数据线(Master output slave input)
IRQ:中断信号。
无线通信过程中 MCU主要是通过 IRQ与 nRF24L01 进行通信。
CE:芯片的模式控制线。
在 CSN 为低的情况下,CE 协同 nRF24L01 的 CONFIG 寄存器共同决定 nRF24L01 的状态(参照 nRF24L01 的状态机)。
图3.2 nRF24L01实物图
nRF24L01的引脚级说明
图3.3nRF24L01的引脚级说明
说明:(1)VCC脚接电压范围为1.9V ~3.6V之间,不能在这个区间之外,超过3.6V将会烧毁模块。
推荐电压3.3V左右。
(2)除电源VCC和接地端,其余脚都可以直接和普通的5V单片机IO口直接相连,无需电平转换。
当然对3V左右的单片机更加适用了。
(3)硬件上面没有SPI的单片机也可以控制本模块,用普通单片机IO口模拟SPI不需要单片机真正的串口介入,只需要普通的单片机IO口就可以了,当然用串口也可以了
3.2 STC89C52的简单介绍
STC89C52是一个低电压,高性能cmos8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,STC89C52单片机在电子行业中有着广泛的应用。
其主要特性功能: 1、兼容MCS51指令系统2、8k可反复擦写(大于1000次)Flash ROM;3、32个双向I/O口;4、256×8bit内部RAM;5、3个16位可编程定时/计数器中断;6、时钟频率0-24MHz;7、2个串行中断,可编程UART串行通道;8、2个外部中断源,共8个中断源;9、2个读写中断口线,3级加密位;10、低功耗空闲和掉电模式,软件设置睡眠和唤醒功能;
11、有PDIP、PQFP、TQFP及PLCC等几种封装形式,以适应不同产品的需求。
第5页
STC89C52的引脚图
图3.4 STC89C52的引脚图
3.3 LCD1602的简单介绍
LCD1602是工业字符型液晶,能够同时显示16×02即32个字符。
(16列2行)1602液晶也叫1602字符型液晶它是一种专门用来显示字母、数字、符号等的点阵型液晶模块它有若干个5×7或者5×11等点阵字符位组成,每个点阵字符位都可以显示一个字符。
每位之间有一个点距的间隔每行之间也有间隔起到了字符间距和行间距的作用,正因为如此所以他不能显示图形。
图3.5LCD1602实物图
LCD1602的引脚图
图3.6LCD1602的引脚图
3.4 其它的器件
当然我们本次设计还用到了一些其他的元器件,包括键盘、连接导线、排针、发光二极管、电阻、电容等等。
3.5 各单元模块的联系
键盘输入是人机交换的接口其主要功能是设置nRF24L01的工作模式和实现键盘输入字符、数字等。
单片机是主控模块实现数据的储存、处理,将各模块联系起来协调各模块的工作。
LCD1602主要功能就是显示作用,将键盘输入或接收到的信息显示出来。
第7页
4软件设计
我们搭建好硬件电路并确认无误后,进行了软件设计。
本次无线通信模块设计我们选择了用C语言实现其功能,我们在PC机Keil uVision 4下编写调试了C程序并将C 程序下载到STC89C52单片机里进行了运行调试。
图5.1软件实现的流程图
5系统调试
在调试环境中我们首先检查了我们焊接的硬件电路是否有问题,如有无短路,有无虚焊等。
确认硬件电路完善无误后。
我们再次对程序进行了检查与调试,都发现没有问题后,我们对模块进行了上电并将程序下载进去运行调试。
一开始我们发现并没有达到预期的效果,发现键盘输入与发送的字符数字不匹配,接搜端也无法搜到相应的信号。
经过我们的仔细检查和思考后,我们发现程序中定义的端口与硬件电路的端口没有意义对应,程序的一些其他地方也并不是很完善,我们又对程序进行了改进,对程序的改进过程中,有时会遇到修改程序后会出现错误,这是若去一行一行的运行调试程序就会很麻烦和花去大量的时间。
这时就要认真检查思考程序出错在哪里,几个人一起检查就加快了效率,节约了大量时间,直到调试达到了我们所预期的效果。
5.1主要问题及分析
开始时我们想到的是在ISIS里画好原理图并仿真,但在ISIS上面我们没有找到我们想要的元器件,因此我们只能直接去调试硬件电路。
首先我们设计好程序并确认无误后再将程序下载到单片机里进行硬件调试,结果我们发现LCD1602无显示,经过仔细的检查思考后,我们发现我们所写的程序与单片机和液晶屏的引脚并不是一一对应的,经过对程序和硬件电路的修改后液晶屏终于有了显示。
虽然液晶屏有了显示,但我们的键盘输入,发送与接收还是存在问题。
考虑到时间有限我们将原来的矩阵键盘输入改为了较简单的单一键盘输入,这样我们解决的键盘输入问题。
经过反复的调试修改后,我们的无线通信模块终于达到的预期的效果。
5.2调试工具
此次调试过程中,我们主要用到了Keil uVision 4、STC-ISP.exe、AltiumDesigne r。
Keil uVision 4是用来编写程序,并编译成HEX文件,以便下载到单片机中。
当有了HEX文件之后,要将此文件下载到单片机中,不可缺少的工具就是STC-ISP.exe。
通过它,可以对单片机内部的程序进行反复修改。
AltiumDesigne r是用来查看电路原理图,并有绘制原理图的功能,在实际调试过程中,应当将软件与硬件相结合,所以电路图的研究不可缺少。
第9页
6系统功能、指标参数
6.1系统能实现的功能
本次我们三人小组所做的无线通信模块主要能实现两个模块间的一些简单通信,实现两个模块间一些简单字符、数字的发送与接收。
我们先对键盘输入进行一些定义,如定义键盘输入为一些字符或数字,但我们按相应的建后就输入相应的字符或数字,输入完成后,我们在按发送键,预先输入的信息便发送了出去,接送的也会收到相应的信息。
6.2系统指标参数测试
在系统指标参数的测试中,我们首先测试了两个无线收发模块间能传输的范围,经过我们多次的改变两个模块的距离后,我们发现两个模块能传输的最大距离约为10米,在穿透效果的测试中,我们发现两个模块间可以穿过一壁普通的墙,当两个模块间隔有两面及两面以上的普通墙时,两个模块间就很难传输信号了。
我们试图测试模块的抗电磁干扰能力的测试是,我们发现很找到一个精确的量来描述,我们大致得出在较弱和频率与我们用的nRF24L01的频率相差较大时的干扰不明显,但当电磁干扰较强很干扰波频率接近nRF24L01的频率时的干扰较为强烈。
6.3系统的指标功能及参数分析
nRF24L01的无线速率达到2 Mbit/s,SPI接口速率为0~8 Mbit/s,具自动应答机制,极大地降低丢包率,完全满足了我们本次设计的需求。
将nRF24L01配置成增强型ShockBurst模式,使得双向链接协议执行更为简易有效。
发送方要求终端设备在接收数据后有应答信号,以便发送方检测有无数据丢失。
一旦数据丢失则通过重新发送功能将丢失的数据恢复。
单片机内部EEPROM应用子程序进行扇区的擦除、写入以及读出功能,实现系统信息的读取保存。
nRF24L01在外置天线时传输距离可以到达25m,我们本次没有使用外置天线,传输的距离约为10m,一切都满足我们本次设计的需求。
7结论
本次智能测控应用系统设计,我们三人小组成功的的完成了无线通信模块的设计与制作。
虽然我们在模块的设计、制作、调试过程中也遇到了不少困难,但在老师和同学的细心指导帮助之下和我们自己的努力,最终还是达到了预期的效果,完成了本次的智能化测控应用系统设计。
我们本次所设计的无线通信模块在无线通信领域有着很大的发展空间,nRF24L01是一种高效率低成本的无线收发模块,125频点,满足多点通信和跳频通信需要超小型:内置2.4GHz天线,体积小巧,15x29mm(包括天线)低功耗:当工作在应答模式通信时,快速的空中传输及启动时间,极大的降低了电流消耗。
低应用成本:nRF24L01集成了所有与RF协议相关的高速信号处理部分,比如:自动重发丢失数据包和自动产生应答信号等,nRF24L01的SPI接口可以利用单片机的硬件SPI口连接或用单片机I/O口进行模拟,内部有FIFO可以与各种高低速微处理器接口,便于使用低成本单片机。
便于开发:由于链路层完全集成在模块上,非常便于开发。
自动重发功能,自动检测和重发丢失的数据包,重发时间及自动存储未收到应答信号的数据包自动应答功能,在收到有效数据后,模块自动发送应答信号,无须另行编程载波检测—固定频
率检测内置硬件CRC检错和点对多点通信地址控制数据包传输错误计数器及载波检测功能可用于跳频设置可同时设置六路接收通道地址,可有选择性的打开接收通道标准插针Dip2.54MM间距接口,便于嵌入式应用。
因此基于nRF24L01的无线通信在当今我们的生活中有着极大的发展空间。
第11页
8总结与体会
在本次智能化测控应用系统设计中我们收获了不少。
在之前我们都是学习了书本上的东西,而很少将其应用到实际中去,虽然之前我们也做过一些课程设计、工艺实习之类的,但这次的课程设计更加从实。
我们从选取题目,画原理图到购买元器件再到焊接电路还有后面的调试测试工作我们都一一的亲身经历并学到了不少课本上学不到的东西。
以前我们学习课本上的知识,觉得要将其应用到实际中会是一件较为轻松的事,也看其他人做的东西很有意义,但我们自己实际去设计制作时,才发现了要做好一个作品是那么的不容易,自己去做时,才发现自己的种种不足,动起手来是那么的笨拙。
老师常常给我们讲动手能力对我们自动化的同学有多么种要,因此我们也都一直想着要提高我们的动手能力,这次实习对我们来说是一次难的机会,对于我们提高自己的动手能力有很大的帮助。
我们不仅学到了怎样去改进、优化、美化电路布局,也掌握更多调试、测试电路的方法,也学到了不少怎样去选取合适的元器件的方法。
在以后的学习工作做,我们要不断的提高自己的动手能力,就要不断亲身去设计、自作实际的东西,这样才不会被时代所淘汰成为对社会有用的人。
9参考文献
[1]赵亮、候国锐.单片机C语言编程与实例[M].北京:人民邮电出版社,2003年9月
[2]海创.无线收发模块nRF24L01开发包资料[J].海创电子科技,2010年
[3]张毅刚.单片机原理及应用[M].北京:高等教育出版社,2010年11月
[4]康华光.电子技术基础模拟部分(第五版)[M].北京:高等教育出版社,2010年5月
[5]康华光.电子技术基础数字部分(第五版)[M].北京:高等教育出版社,2010年11月
[6]谢自美.电子线路设计.实验.测试[M].武汉:华中科技大学出版社,2009年7月
第13页
10附录
10.1相关设计图
图10.1无线收发模块PCB图
图10.2无线收发模块电路原理总图
图10.3正5V电源模块图
第15页
图10.3复位电路模块图图10.4程序下载模块接口图
图10.5正3V电源模块图
图10.6单片机接口图
第17页
图10.3显示仿真图
图10.4无线收发模块实物图
10.2相关的程序
无线收发模块发送程序
#include <reg52.h>
#include <intrins.h>
//****************************************IO端口定义
sbit MISO=P1^5;
sbit MOSI=P1^2;
sbit SCK=P1^3;
sbit CE=P1^1;
sbit CSN=P1^0;
sbit IRQ=P1^4;
sbit lcdrs =P2^0;
sbit lcden =P2^1;
sbit key1 =P2^4;//发送数据键
sbit key2 =P2^5;//接收数据键
sbit key3 =P2^6;//清空键
unsigned char num1,num2;
unsigned char tx_Buf[]={0,0,0}; //待发送数据
unsigned char rx_Buf[]={0,0}; //待接受数据赋0,以便接受数据
//*********************************************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 3 // 20 uints TX payload //发送数据
宽度
#define RX_PLOAD_WIDTH 2 // 20 uints TX payload //接受数据
宽度
unsigned char const TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //本地地址
unsigned char const RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01};
第19页
//接收地址
//***************************************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 write_com(unsigned char com);
void write_date(unsigned char date);
void Delay(unsigned int s);
void inerDelay_us(unsigned char n);
void init_nRF24L01(void);
unsigned int SPI_RW(unsigned int uuchar);
unsigned char SPI_Read(unsigned char reg);
void SetRX_Mode(void);
void tetRX_Mode(void);
unsigned int SPI_RW_Reg(unsigned char reg, unsigned char value);
unsigned int SPI_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char 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++);
}
//************************************************************************* ****
bdata sta; //状态标志
sbit RX_DR =sta^6;
第21页
sbit TX_DS =sta^5;
sbit MAX_RT =sta^4;
/************************************************************************** ***
/*延时函数*/
void inerDelay_us(unsigned char n)
{
for(;n>0;n--)
_nop_();
}
//************************************************************************* **
/*lcd1602写命令
//************************************************************************* **/
void write_com(unsigned char com)
{
lcdrs=0;
P0=com;
Delay(5);
lcden=1;
Delay(5);
lcden=0;
}
//************************************************************************* ***
/*lcd1602初始化
//************************************************************************* ***/
void init()
{
lcden=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
}
//************************************************************************* **
/*lcd1602写数据
//************************************************************************* **/
void write_date(unsigned char date)
{
lcdrs=0;
P0=date;
Delay(5);
lcden=1;
Delay(5);
lcden=0;
}
//************************************************************************* ****
/*nRF24L01初始化
//************************************************************************* ****/
void init_nRF24L01(void)
{
inerDelay_us(100);
CE=0; // chip enable
CSN=1; // Spi disable
SCK=0; // Spi clock line init high
}
/************************************************************************** ****
第23页
/*函数:uint SPI_RW(uint uchar)
/*功能:nRF24L01的SPI写时序
/************************************************************************** /
unsigned int SPI_RW(unsigned int uuchar)
{
unsigned int bit_ctr;
for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit
{
MOSI = (uuchar & 0x80); // output 'uchar', MSB to MOSI uuchar = (uuchar << 1); // shift next bit into MSB.. SCK = 1; // Set SCK high..
uuchar |= MISO; // capture current MISO bit
SCK = 0; // ..then set SCK low again
}
return(uuchar); // return read uchar
}
/************************************************************************** ****
/*函数:uchar SPI_Read(uchar reg)
/*功能:nRF24L01的SPI时序
/************************************************************************** ***/
unsigned char SPI_Read(unsigned char reg)
{
unsigned char reg_val;
CSN = 0; // CSN low, initialize SPI communication... SPI_RW(reg); // Select register to read from..
reg_val = SPI_RW(0); // ..then read registervalue
CSN = 1; // CSN high, terminate SPI communication return(reg_val); // return register value
}
/**************************************************************************
***/
/*功能:nRF24L01读写寄存器函数
/************************************************************************** ***/
unsigned int SPI_RW_Reg(unsigned char reg, unsigned char value)
{
unsigned int status;
CSN = 0; // CSN low, init SPI transaction
status = SPI_RW(reg); // select register
SPI_RW(value); // ..and write value to it..
CSN = 1; // CSN high again
return(status); // return nRF24L01 status uchar
}
/************************************************************************** ***/
/*函数:uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)
/*功能: 用于读数据,reg:为寄存器地址,pBuf:为待读出数据地址,uchars:读出数据的个数
/************************************************************************** ***/
unsigned int SPI_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char uchars)
{
unsigned int status,uchar_ctr;
CSN = 0; // Set CSN low, init SPI tranaction status = SPI_RW(reg); // Select register to write to and read status uchar
for(uchar_ctr=0;uchar_ctr<uchars;uchar_ctr++)
pBuf[uchar_ctr] = SPI_RW(0); //
第25页
CSN = 1;
return(status); // return nRF24L01 status uchar
}
/************************************************************************** ****
/*函数:uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
/*功能: 用于写数据:为寄存器地址,pBuf:为待写入数据地址,uchars:写入数据的个数
/************************************************************************** ***/
unsigned int SPI_Write_Buf(unsigned char reg, unsigned char *pBuf, unsigned char uchars)
{
unsigned int status,uchar_ctr;
CSN = 0; //SPI使能
status = SPI_RW(reg);
for(uchar_ctr=0; uchar_ctr<uchars; uchar_ctr++) //
SPI_RW(*pBuf++);
CSN = 1; //关闭SPI
return(status); //
}
/************************************************************************** ***/
/*函数:void SetTX_Mode(void)
/*功能:数据发送设置
/************************************************************************** ***/
void SetTX_Mode(void)
{
CE=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,如果需要多频道可以参考Page21
SPI_RW_Reg(WRITE_REG + RF_CH, 40); // 设置信道工作为2.4GHZ,收发必须一致
SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度,本次设置为8字节
SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); //设置发射速率为1MHZ,发射功率为最大值0dB
SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); // IRQ收发完成中断响应,16位CRC,主发送
CE = 1;
inerDelay_us(130);
}
/************************************************************************** *****
//*函数:void SetRX_Mode(void)
/*功能:数据接收设置************************************************************/
void SetRX_Mode(void)
{
CE=0;
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);
SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); // 频道0自动 ACK应答允许
SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // 允许接收地址只有频道0,如果需要多频道可以参考Page21
SPI_RW_Reg(WRITE_REG + RF_CH, 40); // 设置信道工作为2.4GHZ,收发必须一致
第27页
SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度,本次设置为8字节
SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); //设置发射速率为1MHZ,发射功率为最大值0dB
SPI_RW_Reg(WRITE_REG + CONFIG, 0x0F);
CE=1;
}
/************************************************************************** ****/
/*函数: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 buffer
revale =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;
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 装载接收端地址
SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH); // 装载数据
CE=1; //置高CE,激发数据发送
}
//************************************主函数
void main(void)
{
void init();
init_nRF24L01();
while(1)
{
if( key1==0 )
{
void init();
init_nRF24L01();
SetTX_Mode();
nRF24L01_TxPacket(tx_Buf);
write_com(0x80);
for(num1=0;num1<TX_PLOAD_WIDTH;num1++)
{
write_date(tx_Buf[num1]);
Delay(1);
}
}
if( key2==0)
{
void init();
init_nRF24L01();
第29页
SetRX_Mode();
nRF24L01_RxPacket(rx_Buf);
write_com(0x80+0x40);
for(num2=0;num2<RX_PLOAD_WIDTH;num2++)
{
write_date(rx_Buf[num2]);
Delay(5);
}
}
if( key3==0 )
{
void init();
init_nRF24L01();
}
}
}
无线收发模块接收程序
#include <reg52.h>
#include <intrins.h>
//****************************************IO端口定义sbit MISO=P1^5;
sbit MOSI=P1^2;
sbit SCK=P1^3;
sbit CE=P1^1;
sbit CSN=P1^0;
sbit IRQ=P1^4;
sbit lcdrs =P2^0;
sbit lcden =P2^1;
sbit key1 =P2^4;//发送数据键
sbit key2 =P2^5;//接收数据键
sbit key3 =P2^6;//清空键
unsigned char num1,num2;
unsigned char tx_Buf[]={0,0}; //待发送数据
unsigned char rx_Buf[]={0,0,0}; //待接受数据赋0,以便接受数据
//*********************************************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 3 // 20 uints TX payload //发送数据
宽度
#define RX_PLOAD_WIDTH 2 // 20 uints TX payload //接受数据
宽度
unsigned char const TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //本地地址
unsigned char 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校验模式以及收发状态响应
方式
//*****************************************长延时
void Delay(unsigned int s)
{#define EN_AA 0x01 // 自动应答功能设置
#define EN_RXADDR 0x02 // 可用信道设置
#define SETUP_AW 0x03 // 收发地址宽度设置
#define SETUP_RETR 0x04 // 自动重发功能设置
第31页
#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 write_com(unsigned char com);
void write_date(unsigned char date);
void Delay(unsigned int s);
void inerDelay_us(unsigned char n);
void init_nRF24L01(void);
unsigned int SPI_RW(unsigned int uuchar);
unsigned char SPI_Read(unsigned char reg);
void SetRX_Mode(void);
void tetRX_Mode(void);
unsigned int SPI_RW_Reg(unsigned char reg, unsigned char value);
unsigned int SPI_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char uchars);
unsigned char nRF24L01_RxPacket(unsigned char *rx_buf);
void nRF24L01_TxPacket(unsigned char *tx_buf);
unsigned int i;
for(i=0; i<s; i++);
for(i=0; i<s; i++);
}
//************************************************************************* ****
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_();
}
//************************************************************************* **
/*lcd1602写命令
//************************************************************************* **/
void write_com(unsigned char com)
{
lcdrs=0;
P0=com;
第33页
Delay(5);
lcden=1;
Delay(5);
lcden=0;
}
//************************************************************************* ***
/*lcd1602初始化
//************************************************************************* ***/
void init()
{
lcden=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
}
//************************************************************************* **
/*lcd1602写数据
//************************************************************************* **/
void write_date(unsigned char date)
{
lcdrs=0;
P0=date;
Delay(5);
lcden=1;
Delay(5);
lcden=0;
}
//************************************************************************* ****
/*nRF24L01初始化
//************************************************************************* ****/
void init_nRF24L01(void)
{
inerDelay_us(100);
CE=0; // chip enable
CSN=1; // Spi disable
SCK=0; // Spi clock line init high
}
/************************************************************************** ****
/*函数:uint SPI_RW(uint uchar)
/*功能:nRF24L01的SPI写时序
/************************************************************************** /
unsigned int SPI_RW(unsigned int uuchar)
{
unsigned int bit_ctr;
for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit
{
MOSI = (uuchar & 0x80); // output 'uchar', MSB to MOSI uuchar = (uuchar << 1); // shift next bit into MSB.. SCK = 1; // Set SCK high..
uuchar |= MISO; // capture current MISO bit
SCK = 0; // ..then set SCK low again
}
return(uuchar); // return read uchar
}
/************************************************************************** ****
第35页
/*函数:uchar SPI_Read(uchar reg)
/*功能:nRF24L01的SPI时序
/************************************************************************** ***/
unsigned char SPI_Read(unsigned char reg)
{
unsigned char reg_val;
CSN = 0; // CSN low, initialize SPI communication... SPI_RW(reg); // Select register to read from..
reg_val = SPI_RW(0); // ..then read registervalue
CSN = 1; // CSN high, terminate SPI communication return(reg_val); // return register value
}
/************************************************************************** ***/
/*功能:nRF24L01读写寄存器函数
/************************************************************************** ***/
unsigned int SPI_RW_Reg(unsigned char reg, unsigned char value)
{
unsigned int status;
CSN = 0; // CSN low, init SPI transaction
status = SPI_RW(reg); // select register
SPI_RW(value); // ..and write value to it..
CSN = 1; // CSN high again
return(status); // return nRF24L01 status uchar
}
/************************************************************************** ***/
/*函数:uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)
/*功能: 用于读数据,reg:为寄存器地址,pBuf:为待读出数据地址,uchars:读出
数据的个数
/************************************************************************** ***/
unsigned int SPI_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char uchars)
{
unsigned int status,uchar_ctr;
CSN = 0; // Set CSN low, init SPI tranaction status = SPI_RW(reg); // Select register to write to and read status uchar
for(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:写入数据的个数
/************************************************************************** ***/
unsigned int SPI_Write_Buf(unsigned char reg, unsigned char *pBuf, unsigned char uchars)
{
unsigned int status,uchar_ctr;
CSN = 0; //SPI使能
status = SPI_RW(reg);
第37页
for(uchar_ctr=0; uchar_ctr<uchars; uchar_ctr++) //
SPI_RW(*pBuf++);
CSN = 1; //关闭SPI
return(status); //
}
/************************************************************************** ***/
/*函数:void SetTX_Mode(void)
/*功能:数据发送设置
/************************************************************************** ***/
void SetTX_Mode(void)
{
CE=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,如果需要多频道可以参考Page21
SPI_RW_Reg(WRITE_REG + RF_CH, 40); // 设置信道工作为2.4GHZ,收发必须一致
SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度,本次设置为8字节
SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); //设置发射速率为1MHZ,发射功率为最大值0dB
SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); // IRQ收发完成中断响应,16位CRC,主发送
CE = 1;
inerDelay_us(130);
}。