(相关人员如觉得本人水平低下,还请见谅)
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
#define k 0xfe
void main()
{
P1=k;
}
则会出现此类结果:
MOSI = (uchar & 0x80); // output 'uchar', MSB to MOSI
uchar = (uchar << 1); // shift next bit into MSB..
SCK = 1; // Set SCK high..
uchar |= MISO; // capture current MISO bit
SCK = 0;
此处为spi的核心,是spi协议的编程,其中uchar |= MISO; 表示uchar |= MISO | uchar; MOSI = (uchar & 0x80);其中0x80是1000 0000,与上uchar,这种&,是按位与,故可以从uchar提取出一个电平给mosi。
MOSI = (uchar & 0x80); // output 'uchar', MSB to MOSI
uchar = (uchar << 1);
这两句组合起来用,就实现了把uchar编程8位2进制数后的每一位都可以发送给mosi;Uchar的只待对象,就是上面的诸如#define FLUSH_TX 0xE1
这样的数,或者是相关的发送数据。
*pBuf这个并不是一个主要的问题,实际这个是涉及指针问题的,带*的跟地址有关系,但是我们其实不需要很关心编译的时候数据被具体存入哪个地址,即使是很重要的数据。
void init_NRF24L01(void)
{
inerDelay_us(100);
CE=0; // chip enable
CSN=1; // Spi disable
SCK=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, 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 enable
CSN=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
#include
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 payload
uint 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
for(i=0; 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 enable
CSN=1; // Spi disable
SCK=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, 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 MOSI
uchar = (uchar << 1); // shift next bit into MSB..
SCK = 1; // Set SCK high..
uchar |= MISO; // capture current MISO bit
SCK = 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 registervalue
CSN = 1; // CSN high, terminate SPI communication
return(reg_val); // return register value
}
/****************************************************************************** **********************/
/*功能:NRF24L01读写寄存器函数
/****************************************************************************** **********************/
uint SPI_RW_Reg(uchar reg, uchar value)
{
uint 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:读出数据的个数
/****************************************************************************** **********************/
uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)
{
uint 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 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 SPI_RW(*pBuf++); CSN = 1; //关闭SPI return(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 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; //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 data Delay(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 data TxBuf[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改动应用在其他设计中。我把需要改动的地方交代出来。 主程序中保留部分: unsigned char tf =0; unsigned char TxBuf[20]={0}; // unsigned char RxBuf[20]={0}; init_NRF24L01() ; nRF24L01_TxPacket(TxBuf); SetRX_Mode(); nRF24L01_RxPacket(RxBuf); 这三个部分需保留,其中最上面是初始化必须要,中间是发送,当你写入这个函数,单片机执行到这里,将会把Txbuf中的数发出去。最后是接收,当执行到此处,原先rxbuf 中的数据将被替换成新的接收到得数据。 而除主程序之外的部分,比如一些诸如uchar seg[10]={0xC0,0xCF,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; 请用户自行甄别并删除。 最后附上关于nrf905模块的一个小成品,仅供参考。 #include NRF24L01无线模块收发程序(实测成功多图) 本模块是NRF24L01无线传输模块,用于无线传输数据,距离不远,一般只是能够满足小距离的传输,目测是4-5m,价格一般是4元左右,可以方便的买到。 51最小系统学习板就可以,当时是用了两块学习板,一块用于发送,一块用于接收。 小车也是比较容易购到的,四个端口控制两个电机,两个控制一个电机,当两个端口高低电平不同时电机就会转动,即为赋值1和0是电机转动,赋值可以用单片机作用,当然这是小车启动部分,前进后退左转右转就是你赋值0和1的顺序问题了。 整体思路是用发射端的按键控制小车,即为按键按下就前进,再按其他按键实现其他功能,本次程序是在用NRF24L01发射数据在接收端用1602显示的基础上改变。 下面是程序源码(有好几个文件,分别创建) ////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////// #include #include #include'1602.h' #include'delay.h' #include 'nrf24l01.h' #define uint unsigned int #define uchar unsigned char uint Weight_Shiwu=1234; unsigned char KeyScan(void);//键盘扫描 // unsigned char KeyScan(void);//键盘扫描 //#define KeyPort P0 sbit KEY1 = P0^0; sbit KEY2 = P0^1; sbit KEY3 = P0^2; sbit KEY4 = P0^3; sbit KEY5 = P0^4; void main() { // char TxDate[4]; // LCD_Init(); //初始化液晶屏 // LCD_Clear(); //清屏 RS-485标准在工业控制、电力通讯、智能仪表等领域中使用广泛。但是,在工业控制等现场环境中,情况复杂,常会有电气噪声干扰传输线路;在多系统互联时,不同系统的地之间会存在电位差,形成接地环路,会干扰整个系统,严重时会造成系统的灾难性损毁;还可能存在损坏设备或危害人员的潜在电流浪涌等高电压或大电流。因此,对RS-485接口的隔离是非常有必要的。 ADM2483是一款集成了信号通道隔离和RS-485收发器的芯片。以单芯片实现了对RS-485接口的隔离,电路连接简单,设计方便,性能上远高于繁琐的光耦隔离485电路设计。在某些系统应用中,由于I/O口数量有限,因此我们希望半双工的RS-485收发器能够实现自收发功能,以节省用于控制RE与DE的两路I/O端口。目前,实现这一功能的主流方案是采用74HC14芯片。下面,我们采用74HC14与ADM2483实现RS-485接口的信号隔离自收发设计。 硬件电路 隔离RS-485接口电路 之前我们经常采用的485接口隔离电路是利用三个光耦隔离收发及控制信号,加上485收发器共需要4片IC,且采用光耦隔离需要限流及输出上拉电阻,必要时还会使用三极管驱动。设计电路繁琐,耗费时间长,如果没有之前使用光耦的经验,那么在选用光耦限流及输出上拉电阻方面会耗费很多不必要的时间;且光耦的输出信号上升时间较长,在与数字I/O端口相接时,需另加施密特整形才能保证信号的波形符合标准,如在FPGA、DSP等系统中的应用。 ADM2483是内部集成了磁隔离通道和485收发器的芯片,内部集成的磁隔离通道原理与光耦不同,在输入输出端分别有编码解码电路和施密特整形电路,确保了输出波形的质量。且磁隔离功耗仅为光耦的1/10,传输延时为ns级,从直流到高速信号的传输都具有超越光耦的性能优势。内部集成的低功耗485收发器,信号传输速率可达500Kbps,后端总线可支持挂载256个节点。具有真失效保护、电源监控以及热关断功能。 要实现隔离RS-485接口的电路设计只需在ADM2483的电源与地之间接一个104的去耦电容即可。当然,DC-DC隔离电源是必不可少的。其电路连接如下图: //下面是接收的NRF24L01的程序。 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include 印制电路板设计规范 一、适用范围 该设计规范适用于常用的各种数字和模拟电路设计。对于特殊要求的,尤其射频和特殊模拟电路设计的需量行考虑。 应用设计软件为Protel99SE。也适用于DXP Design软件或其他设计软件。二、参考标准 GB 4588.3—88 印制电路板设计和使用 Q/DKBA—Y004—1999 华为公司内部印制电路板CAD工艺设计规范 三、专业术语 1.PCB(Print circuit Board): 印制电路板 2.原理图(SCH图):电路原理图,用来设计绘制,表达硬件电路之间各种 器件之间的连接关系图。 3.网络表(NetList表):由原理图自动生成的,用来表达器件电气连接的关 系文件。 四、规范目的 1.规范规定了公司PCB的设计流程和设计原则,为后续PCB设计提供了设 计参考依据。 2.提高PCB设计质量和设计效率,减小调试中出现的各种问题,增加电路 设计的稳定性。 3.提高了PCB设计的管理系统性,增加了设计的可读性,以及后续维护的 便捷性。 4.公司正在整体系统设计变革中,后续需要自主研发大量电路板,合理的 PCB设计流程和规范对于后续工作的开展具有十分重要的意义。 五、SCH图设计 5.1 命名工作 命名工作按照下表进行统一命名,以方便后续设计文档构成和网络表的生成。有些特殊器件,没有归类的,可以根据需求选择其英文首字母作为统一命名。 表1 元器件命名表 按键,命名为U100,在Lib Ref中描述为KEY。这样使得整个原理图更加清晰,功能明确。 5.2 封装确定 元器件封装选择的宗旨是 1. 常用性。选择常用封装类型,不要选择同一款不常用封装类型,方便元器件购买,价格也较有优势。 2. 确定性。封装的确定应该根据原理图上所标示的封装尺寸检查确认,最好是购买实物后确认封装。 3. 需要性。封装的确定是根据实际需要确定的。总体来说,贴片器件占空间小,但是价格贵,制板相同面积成本高,某些场合下不适用。直插器件可靠性高,焊接方便,但所占空间大,高性能的MCU已经逐步没有了直插封装。实际设计应该根据使用环境需求选择器件。如下几个例子说明情况: a. 电阻贴片和直插的选择 选择直插和贴片电阻主要从精度和功率方面考虑。直插电阻一般精度较高,可以选择0.1%甚至更高的精度,功率可以根据需要选择。常见直插电阻的功率为1/4W。一般在模拟回路采用直插封装,能够更好的保证精度。(特殊情况下也可选择贴片,但须考虑成本问题) 贴片电阻精度一般常见的为5%。功率为1/10W。基本用在数字电路。成本比直插高,但是占空间小。 b. BGA封装的问题 是否选择BGA封装的元器件,主要考虑实际的需求。BGA的特点是占空间小,管脚集成度高,可靠性好,受电磁干扰程度小。但是由于管脚密闭,对于管脚的调试不方便。同时由于BGA的环形管脚排布,使得BGA封装的元器件对于电路板设计有更高要求,一般至少需要4层以上。BGA越复杂,板的层数要求越高,设计成本越高。 c. 电源芯片的封装问题 一般的数字电路常用的稳压器芯片如AS1117-3.3/1.2等。选择封装的时候应该注意其三个管脚的定义是否与设计相同。确定电源芯片的封装定义。 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接收地址 //许多人都在找nrf24l01无线模块的c程序;我以前刚接触无线//时用的就是nrf24l01模块;搜索了许多程序有很多都没法直接用;甚至还怀疑模块是不是被我搞坏了;拿去让别人检测模块又是好的;为避免大家走弯路;我将我的程序发出来供大家参考; 这是nrf24l01无线模块pcb图; 下面有Nrf24l01无线模块的收发c程序;以下程序经本人亲自测试;绝对能用!! 请注意以下几点: 1、24L01模块的电源电压是否为3V-3.6V之间; 2、如果您用的单片机是5V的话,请在IO口与模块接口之间串一个1K电阻; 3、检查模块的GND是否与单片机的GND相连接 4、先用程序进行调试,如果IO口不同,请更改IO口或相关时序; 5、如果是51系列单片机,晶振请选用11.0592M Hz; 模块供电最好用asm1117 5v转3.3v 稳压 测试单片机是stc89c52;at89c52 通用; 收发一体; 一大截不废话了;上程序;此程序是按键控制led;当按下s的时候对应接受的led会闪闪发光;很简单的~如果要实现其他更先进的功能;自己发掘吧~~ 务必将硬件连接正确;否则;它不会工作的~~当然做什么都要严谨~~错一点就差大了~~ 《《收发一体程序》》 #include *************************************** sbit M ISO =P1^3; sbit M OSI =P1^4; sbit SCK =P1^2; sbit CE =P1^1; sbit CSN =P3^2; sbit IRQ =P3^3; //************************************按键*************************************************** sbit KEY=P2^0; //***************************************************************************** sbit led=P2^1; //*********************************************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 payload uint 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接收数据地址 普通电路设计协议书最新 甲方:_________ 乙方:_________ 甲方委托乙方为其设计制作电路,为保质保量完成任务,经甲乙双方协商达成如下协议: 1.在本协议书签订前,甲方应向乙方提供详细的电路设计任务书,明确设计制作电路的功能,各项参数等;该任务书作为乙方设计制作电路的依据。 2.在本协议书签订前,甲方应详细阅读有关乙方的电路设计细则说明。 3.在本协议书签订前,乙方应向甲方提交电路设计费用明细表,并详细介绍相关事项。 4.协议变更终止 (1)甲方终止协议:甲方承担一切已经用于该电路设计的费用,并支付乙方相应的劳务费用;乙方有权收回已交于甲方的所有有关电路设计的资料及产品,乙方并保留该设计的所有权利。 (2)乙方终止协议:乙方承担一切已经用于该电路设计的费用,并返还甲方在此之前所支付的所有费用。 (3)以上两条在不可抗拒因素发生时无效。 (4)因设计需要而变更本协议时,甲乙双方协商解决。 (5)乙方电路设计不满足设计任务书要求时,按乙方终止协议处理。 5.付费方式 (1)按照乙方向甲方提交的普通电路设计费用明细表,甲方应支付乙方设计该电路的全部费用为_________元。 (2)本协议书签定后的_________个工作日内,按照乙方应向甲方提交的普通电路设计费用明细表,甲方须预先支付乙方全部电路设计费用的1/2,计_________元,否则,按甲方终止协议处理;在乙方按设计任务书要求完成设计并向甲方交付设计时,甲方应支付乙方全部剩余费用,否则,按甲方终止协议处理。 6.本协议三项(协议书,设计说明书,费用明细表),一式两份,甲乙双 方各一份;其具有法律依据和效力;乙方保留其最终解释权。甲方(盖章):_________ 乙方(盖章):_________ 代表(签字):_________ 代表(签字):_________ ________年____月____日 ________年____月____日 NRF24L01使用文档 基于c8051f330单片机 目录 芯片简介 (3) 1 NRF24L01功能框图 (4) 2 NRF24L01状态机 (5) 3 Tx与Rx的配置过程 (7) 3.1 Tx 模式初始化过程 (7) 3.2 Rx模式初始化过程 (8) 4控制程序详解 (9) 4.1 函数介绍 (9) 4.1.1 uchar SPI_RW(uchar byte) (9) 4.1.2 uchar SPI_RW_Reg (uchar reg, uchar value) (10) 4.1.3 uchar SPI_Read (uchar reg); (10) 4.1.4 uchar SPI_Read_Buf (uchar reg, uchar *pBuf, uchar bytes); (11) 4.1.5 uchar SPI_Write_Buf (uchar reg, uchar *pBuf, uchar bytes); (11) 4.1.6 void RX_Mode(void) (12) 4.1.7 void TX_Mode(void) (13) 4.2 NRF24L01相关命令的宏定义 (13) 4.3 NRF24L01相关寄存器地址的宏定义 (14) 5 实际通信过程示波器图 (16) 1)发射节点CE与IRQ信号 (17) 2)SCK与IRQ信号(发送成功) (18) 3)SCK与IRQ信号(发送不成功) (19) 芯片简介 NRF24L01是NORDIC公司最近生产的一款无线通信通信芯片,采用FSK调制,内部集成NORDIC自己的Enhanced Short Burst 协议。可以实现点对点或是1对6的无线通信。无线通信速度可以达到2M(bps)。NORDIC公司提供通信模块的GERBER文件,可以直接加工生产。嵌入式工程师或是单片机爱好者只需要为单片机系统预留5个GPIO,1个中断输入引脚,就可以很容易实现无线通信的功能,非常适合用来为MCU系统构建无线通信功能。 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 方式或者万用板方式均可。如果您想让自己学的很扎实,那么推荐您自行做出接口板子呢。当然若您的能力不足,那么我们不推荐自行做板呢,因为这样会增加您学习的难度,反而起到了反效果呢。 我们使用的方式是画PCB 的方式呢,若您自己做了接口板子,那么您可以对比下一呢,O(∩_∩)O! 我们知道NRF24L01 的供电电压是1.9V~3.6V 不能超过这个范围,低了不工作,高了可能烧毁NRF24L01 芯片。我们常用的STC89C52 的单片机的供电电压是5V,我们不能直接给24L01 这个模块供电,我们需要使用AMS1117-3.3V 稳压芯片把5V 转成3.3V 的电压为24L01 模块供电。 为此我们的设计原理图如下:包含单片机最小系统、供电系统、下载程序接口、5V 转3.3V 电路、NRF24L01 模块接口。并且全部引出单片机的IO 口,另外还加了5 个电源输出接口,为扩展使用。还包括了电源指示LED 以及一个IO 口独立控制的LED,这个独立控制的LED用于NRF24L01 接收成功闪烁指示。为了保证系统的稳定性,在设计中添加了两个滤波电容。 C 电路原理图设计规 Hardware Revision List 目录 一、Purpose/ 目的.......................................................................................................................................................... - 4 - 二、Scope/ 适用围........................................................................................................................................................ - 4 - 三、Glossary/ 名词解释 ................................................................................................................................................ - 4 - 四、Necessary Equipment/ 必须文件............................................................................................................................ - 4 - 五、Procedure/ 流程规细则 .......................................................................................................................................... - 5 - 5.1确定图纸尺寸、标题规............................................................................................................................ - 5 - 5.2元器件标识规............................................................................................................................................ - 5 - (相关人员如觉得本人水平低下,还请见谅) 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 MOSI = (uchar & 0x80); // output 'uchar', MSB to MOSI uchar = (uchar << 1); // shift next bit into MSB.. SCK = 1; // Set SCK high.. uchar |= MISO; // capture current MISO bit SCK = 0; 此处为spi的核心,是spi协议的编程,其中uchar |= MISO; 表示uchar |= MISO | uchar; MOSI = (uchar & 0x80);其中0x80是1000 0000,与上uchar,这种&,是按位与,故可以从uchar提取出一个电平给mosi。 MOSI = (uchar & 0x80); // output 'uchar', MSB to MOSI uchar = (uchar << 1); 这两句组合起来用,就实现了把uchar编程8位2进制数后的每一位都可以发送给mosi;Uchar的只待对象,就是上面的诸如#define FLUSH_TX 0xE1 这样的数,或者是相关的发送数据。 *pBuf这个并不是一个主要的问题,实际这个是涉及指针问题的,带*的跟地址有关系,但是我们其实不需要很关心编译的时候数据被具体存入哪个地址,即使是很重要的数据。 void init_NRF24L01(void) { inerDelay_us(100); CE=0; // chip enable CSN=1; // Spi disable SCK=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, 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 enable CSN=1; // Spi disable 这是设置整个的状态。如过状态设置成待机,则引脚可能变为高阻。(以上并非全部引脚) //***************************************************发送程序**********************************************************// #include //*********************************************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 32 // 20 uints TX payload #define RX_PLOAD_WIDTH 32 // 20 uints TX payload uchar const TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //本地地址 uchar 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 // 可用信道设置 硬件电路板设计规范 制定此《规范》的目的和出发点是为了培养硬件开发人员严谨、务实的工作作风和严肃、认真的工作态度,增强硬件开发人员的责任感和使命感,提高工作效率和开发成功率,保证产品质量。 1、深入理解设计需求,从需求中整理出电路功能模块和性能指标要求; 2、根据功能和性能需求制定总体设计方案,对CPU等主芯片进行选型,CPU 选型有以下几点要求: 1)容易采购,性价比高; 2)容易开发:体现在硬件调试工具种类多,参考设计多,软件资源丰富,成功案例多; 3)可扩展性好; 3、针对已经选定的CPU芯片,选择一个与我们需求比较接近的成功参考设计。 一般CPU生产商或他们的合作方都会对每款CPU芯片做若干开发板进行验证,厂家最后公开给用户的参考设计图虽说不是产品级的东西,也应该是经过严格验证的,否则也会影响到他们的芯片推广应用,纵然参考设计的外围电路有可推敲的地方,CPU本身的管脚连接使用方法也绝对是值得我们信赖的,当然如果万一出现多个参考设计某些管脚连接方式不同,可以细读CPU芯片手册和勘误表,或者找厂商确认;另外在设计之前,最好我们能外借或者购买一块选定的参考板进 行软件验证,如果没问题那么硬件参考设计也是可以信赖的;但要注意一点,现在很多CPU都有若干种启动模式,我们要选一种最适合的启动模式,或者做成兼容设计; 4、根据需求对外设功能模块进行元器件选型,元器件选型应该遵守以下原则: 1)普遍性原则:所选的元器件要被广泛使用验证过的尽量少使用冷、偏芯片,减少风险; 2)高性价比原则:在功能、性能、使用率都相近的情况下,尽量选择价格比较好的元器件,减少成本; 3)采购方便原则:尽量选择容易买到,供货周期短的元器件; 4)持续发展原则:尽量选择在可预见的时间内不会停产的元器件; 5)可替代原则:尽量选择pin to pin兼容种类比较多的元器件; 6)向上兼容原则:尽量选择以前老产品用过的元器件; 7)资源节约原则:尽量用上元器件的全部功能和管脚; 5、对选定的CPU参考设计原理图外围电路进行修改,修改时对于每个功能模块都要找至少3个相同外围芯片的成功参考设计,如果找到的参考设计连接方法都是完全一样的,那么基本可以放心参照设计,但即使只有一个参考设计与其他的不一样,也不能简单地少数服从多数,而是要细读芯片数据手册,深入理解那些管脚含义,多方讨论,联系芯片厂技术支持,最终确定科学、正确的连接方式,如果仍有疑义,可以做兼容设计;当然,如果所采用的成功参考设计已经是 /******************************************************* ** 温度无线发送程序 ** 时间:2012.2.3 ** ——by Keliwen *******************************************************/ #include NRF24L01发送程序
NRF24L01无线模块收发程序(实测成功 多图)
低成本RS-485自收发电路的参考设计
NRF24L01无线模块收发程序例程
PCB印制电路板设计规范(doc 20页)完美版
NRF24L01无线模块C语言程序
nrf24l01无线模块NRF24L01模块收发c程序
普通电路设计协议书最新(标准版).doc
NRF24L01功能使用文档
NRF24L01无线发射简易教程
电路原理图设计规范标准
NRF24L01参考程序(包含多个实例)
NRF24L01发送程序(可用)
硬件电路设计规范
nRF24L01温度发送与接收程序