标题:
nrf24l01d发射机 接收机 无线通信程序那点事!!!!!
[打印本页]
作者:
hujia
时间:
2015-6-23 16:24
标题:
nrf24l01d发射机 接收机 无线通信程序那点事!!!!!
从2015年5月15号开始做无线通讯的。开始我并没有重视这个无线通信,但是偶尔一次去工地的路上看见一个城建钢筋场地里的龙门吊,那个傻逼竟然用遥控器控制龙门吊!!开始惊奇,转而又想我能不能做呢?我分析其实关于控制部分早在技校里就学了,正反转吗,不难,但是中间你要实现遥控就不易了,我还是模块化思路,我搞到了RF模块,开始进入了漫漫的实验之路,射频信号我在此之前根本不懂,也不知道是个什么东西,只是知道手机里有那个东西,数据手册有两种一种是英文的,一种是翻译的中文,因为在这方面我还是有经验的,不能尽心中文资料,要信英文资料,但是翻译太麻烦了要用中文资料为参考。
我的第一个实验便是RF模块与主控芯片之间的通信问题,因为无线通信的流程大概是这样的:发送端 数据和信号送入模块的数据区,CRC效验后打包,然后打包后的信号送往调制器进行调制,调制完毕后进入射频功率放大,然后通过天线发射出去;接收端 实时监测空中信号,如果有信号那么接收回来,解调处理,然后对包进行逆打包,CRC效验,地址是否匹配,如果一切正确那么就把数据信号送入数据缓冲区。也就完成了一次通信!和电视和收音机差不多,所以模块与主控通信的重要性关系到你能否驾驭它了!!可喜可贺的是我没用几天就解决这一问题了,因为它使用的外围数据接口以前我用的很多,解决了主机和模块之间的对话下一步是对RF模块的设置和通信的程序,我没想到这可是难倒我了,任凭我怎样设置怎样修改,就是无法发射,没有接收,没有任何的检测工具,我开始怀疑芯片的好坏!是不是坏了?那为什么还能读写呢?又上网找资料找朋友,但是这个东西可不像别的,没有任何教学视频可参考,网上的程序也很烂,说实话我看不下去,我只会用我的思路来编程,他们的太精致了,各种猜测,辗转反侧,夜不能寐。很快就过春节了,我和爸爸1月27号回的家,本想着在家里搞,可是到家后没时间搞,和老爸弄自来水管,写春联,收拾房屋,打扫卫生,可以这么说,今年的春节我是最累的,过了春季有忙着和朋友们玩DOTA,走亲戚,来亲戚,转眼初九了,又极不情愿的踏上了北上打工的旅途!哎!!!人啊!!!
接收机:
/*无线模块定义*/
sbit CE=P1^3;//nrf24l01d的模式控制线在 CSN 为低的情况下,CE 协同NRF24L01 的CONFIG 寄存器共同决定NRF24L01 的状态(参照NRF24L01 的状态机)
sbit CSN=P1^4;//nrf24l01d的片选线,低电平有效
sbit IRQ=P1^5;//nrf24l01d的中断信号
/*SPI定义
*/
sbit SI=P1^0;//MOSI主出-从入
sbit SO=P1^1;//MISO主入-从出
sbit SCK=P1^2;// 时钟信号
/*定义无线模块的收发状态位
*/
unsigned char bdata FLAGE;
sbit MAX_RT=FLAGE^4; //达到最大发送次数置1
sbit TX_DS=FLAGE^5;//数据发送被置1
sbit RX_DR=FLAGE^6;//数据接收被置1
/*可谓操作字节dat定义,用来构成最底层的SPT读写函数使用
*/
unsigned char bdata dat;
sbit dat_0=dat^0;
sbit dat_1=dat^1;
sbit dat_2=dat^2;
sbit dat_3=dat^3;
sbit dat_4=dat^4;
sbit dat_5=dat^5;
sbit dat_6=dat^6;
sbit dat_7=dat^7;
/*串口程序*/
void InitUART(void)
{
TMOD = 0x20;
SCON = 0x50;
TH1 = 0xFD;
TL1 = TH1;
PCON = 0x00;
EA = 1;
ES = 1;
TR1 = 1;
}
void UARTInterrupt(void) interrupt 4
{
if(RI)
{
RI = 0;
//add your code here!
}
else
TI = 0;
}
void SendOneByte(unsigned char c)
{
SBUF = c;
while(!TI);
TI = 0;
}
/*串口程序*/
/*SPI最底层写一个字节函数
无返回值
有参
带形参H
*/
void delay1ms(uchar time)//1ms
{
unsigned char a,b,c,d;
for(d=time;d>0;d--)
for(c=8;c>0;c--)
for(b=197;b>0;b--)
for(a=2;a>0;a--);
}
void delay10us(uchar time)//10us
{
unsigned char a,b,c;
for(c=time;c>0;c--)
for(b=1;b>0;b--)
for(a=52;a>0;a--);
}
/*************************
*
SPI写一个字节的最底层函数 *
有参 *
无返回值 *
***************************/
void write_spi_2401(uchar h)//SPI写一字节函数
{
dat=h;
SI=dat_7;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_6;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_5;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_4;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_3;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_2;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_1;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_0;
delay10us(10);
SCK=0;
SCK=1;
}
/************************
SPI最底层读取一个字节 *
返回值是读出的这一个字节 *
无参 *
*
*************************/
uchar read_spi_2401()//SPI读一字节函数
{
SO=1;//初始化SO线
SCK=1;
SCK=0;
dat_7=SO;
SCK=1;
SCK=0;
dat_6=SO;
SCK=1;
SCK=0;
dat_5=SO;
SCK=1;
SCK=0;
dat_4=SO;
SCK=1;
SCK=0;
dat_3=SO;
SCK=1;
SCK=0;
dat_2=SO;
SCK=1;
SCK=0;
dat_1=SO;
SCK=1;
SCK=0;
dat_0=SO;
return (dat);//返回读取数值
}
/****************************
*
写入寄存器命令函数 *
有参 *
无返回值 *
*
m:表示要操作的寄存器地址 *
date:表示要向内不写入的数据 *
*****************************/
void write_rge_nrf24l01(uchar m,uchar date)
{
SCK=0;//时钟预选拉低
CSN=1;
CSN=0; //SPI开
write_spi_2401((0x20+m));//写入写寄存器命令
write_spi_2401(date);//写入date指向的寄存器数据
CSN=1;//SPI关
}
/*************************
*
度寄存器子函数 *
将寄存器的数值读出 *
有参 M表示要读的寄存器 *
有返回值 返回读出的数据 *
*
**************************/
uchar read_reg_nrf24l01(uchar m)
{ uchar date;
SCK=0;
CSN=1;
CSN=0;
write_spi_2401(m);//读寄存器
date=read_spi_2401();
CSN=1;
return (date);
}
/***************************
*
待机模式进入后相关对寄存器 *
的设置函数 *
*
****************************/
void set_Register_tx()//"待机-I模式下的对寄存器的设置 接收机 接收地址是ABABABABAB,通道0,一字节有效数据
{
// 下段是寄存器设置在待机-I模式完成
write_rge_nrf24l01(0x01,0x3f);/*允许所有自动应答开启*///EN_AA使能自动应答功能
write_rge_nrf24l01(0x02,0x3f);/*允许所有接收地址开启*///EN_RXADDR接收地址允许
write_rge_nrf24l01(0x03,0x03);/*所有地址通道的收发地址宽度设为5字节*///STEUP_AW设置地址宽度所有通道
write_rge_nrf24l01(0x04,0x28);/*允许建立自动重发延时为(750+86us)自动重发计数次数为8次*///STEUP_RETR建立自动重发
write_rge_nrf24l01(0x11,0x01);/*接收数据通道0 有效数据宽度 一字节*///RX_PW_P0接收通道0有效数据宽度
/**********************************************/
// 本段是对接收机的地址设置在待机-I模式完成
//
/**********************************************/
/*这里有必要说明下,由于以上的设置寄存器都是一个字节的所以我使用了子函数,这个是发射/接收地址 我没使用因为上面的只能写一个字节*/
SCK=0;//时钟预选拉低
CSN=1;
CSN=0; //SPI开
write_spi_2401(0x2a);//写入写寄存器命令 /* RX_ADDR_P0 数据通道0接收地址设为0xABABABABAB */
write_spi_2401(0xab);//写入date指向的寄存器数据
write_spi_2401(0xab);//写入date指向的寄存器数据
write_spi_2401(0xab);//写入date指向的寄存器数据
write_spi_2401(0xab);//写入date指向的寄存器数据
write_spi_2401(0xab);//写入date指向的寄存器数据
CSN=1;//SPI关
}
void main () //主函数
{
uchar i;
InitUART();//初始化串口
SendOneByte(0xf8);//发送标志位
FLAGE=read_reg_nrf24l01(0x17);//状态寄存器读取
SendOneByte(FLAGE);
FLAGE=read_reg_nrf24l01(0x07);//状态寄存器读取;发射前读取状态寄存器
SendOneByte(FLAGE);
delay1ms(200);//开机上电复位延时200毫秒后进入掉电模式
CSN=1;
SCK=0;
CE=0; //发射使能关闭或叫初始化
write_rge_nrf24l01(0x00,0x0f);/*只允许中断开启,CRC使能,16位,PWR_UP=1(上电),PRIM_RX=1(接收模式)*///配置寄存器
delay1ms(50);//此处指着个延时很管用,标志着24L01由掉电模式向待机-I模式转换的过程,以上是掉电模式一下就是待机-I模式了
set_Register_tx();// 待机1模式下的寄存器配置
while(1)
{
//***********************************************************************
CE=1;//进入接收模式
//*888888888888888888888888888888888888888888888888888888
do
{
// SendOneByte(0xe8);//发送标志位
FLAGE=read_reg_nrf24l01(0x07);//状态寄存器读取;
//SendOneByte(FLAGE);
}
while((~RX_DR)); //检查是否接收数据?如果接收到向下,接收不到等待
CE=0;//进入待机一I模式
write_rge_nrf24l01(0x07,0x4e);/*清除接收中断信号*/
//***********************************
//这一步是读FIFO数据,读完FIFO清空
CE=0;
SCK=0;
CSN=1;
CSN=0;
write_spi_2401(0x61);//读FIFO寄存器
i=read_spi_2401();
//数据 注意这里我只要发送一个字节的数据,可以最大一次发送32字节 从0字节开始读
CSN=1;
//****************************************
SendOneByte(0xe8);//发送标志位
FLAGE=read_reg_nrf24l01(0x07);//状态寄存器读取;
SendOneByte(FLAGE);
SendOneByte(i); //发送接收到的数据到PC
}
}
复制代码
发射机程序:
/*无线模块定义*/
sbit CE=P1^3;//nrf24l01d的模式控制线在 CSN 为低的情况下,CE 协同NRF24L01 的CONFIG 寄存器共同决定NRF24L01 的状态(参照NRF24L01 的状态机)
sbit CSN=P1^4;//nrf24l01d的片选线,低电平有效
sbit IRQ=P1^5;//nrf24l01d的中断信号
/*SPI定义
*/
sbit SI=P1^0;//MOSI主出-从入
sbit SO=P1^1;//MISO主入-从出
sbit SCK=P1^2;// 时钟信号
/*无线模块的状态位定义
*/
unsigned char bdata FLAGE;
sbit MAX_RT=FLAGE^4; //达到最大发送次数置1
sbit TX_DS=FLAGE^5;//数据发送被置1
sbit RX_DR=FLAGE^6;//数据接收被置1
/*可谓操作字节dat定义,用来构成最底层的SPT读写函数使用
*/
unsigned char bdata dat;
sbit dat_0=dat^0;
sbit dat_1=dat^1;
sbit dat_2=dat^2;
sbit dat_3=dat^3;
sbit dat_4=dat^4;
sbit dat_5=dat^5;
sbit dat_6=dat^6;
sbit dat_7=dat^7;
/*串口程序*/
void InitUART(void)
{
TMOD = 0x20;
SCON = 0x50;
TH1 = 0xFD;
TL1 = TH1;
PCON = 0x00;
EA = 1;
ES = 1;
TR1 = 1;
}
void UARTInterrupt(void) interrupt 4
{
if(RI)
{
RI = 0;
//add your code here!
}
else
TI = 0;
}
void SendOneByte(unsigned char c)
{
SBUF = c;
while(!TI);
TI = 0;
}
/*串口程序*/
/*SPI最底层写一个字节函数
无返回值
有参
带形参H
*/
void delay1ms(uchar time)//1ms
{
unsigned char a,b,c,d;
for(d=time;d>0;d--)
for(c=8;c>0;c--)
for(b=197;b>0;b--)
for(a=2;a>0;a--);
}
void delay10us(uchar time)//10us
{
unsigned char a,b,c;
for(c=time;c>0;c--)
for(b=1;b>0;b--)
for(a=52;a>0;a--);
}
/**********************
SPI写一个字节的最底层函数
有参
无返回值
***********************/
void write_spi_2401(uchar h)//SPI写一字节函数
{
dat=h;
SI=dat_7;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_6;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_5;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_4;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_3;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_2;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_1;
delay10us(10);
SCK=0;
SCK=1;
SI=dat_0;
delay10us(10);
SCK=0;
SCK=1;
}
/*****************************
SPI最底层读取一个字节
返回值是读出的这一个字节
无参
******************************/
uchar read_spi_2401()//SPI读一字节函数
{
SO=1;//初始化SO线
SCK=1;
SCK=0;
dat_7=SO;
SCK=1;
SCK=0;
dat_6=SO;
SCK=1;
SCK=0;
dat_5=SO;
SCK=1;
SCK=0;
dat_4=SO;
SCK=1;
SCK=0;
dat_3=SO;
SCK=1;
SCK=0;
dat_2=SO;
SCK=1;
SCK=0;
dat_1=SO;
SCK=1;
SCK=0;
dat_0=SO;
return (dat);//返回读取数值
}
/***************************
写入寄存器命令函数
有参
无返回值
m:表示要操作的寄存器地址
date:表示要向内不写入的数据
****************************/
void write_rge_nrf24l01(uchar m,uchar date)
{
SCK=0;//时钟预选拉低
CSN=1;
CSN=0; //SPI开
write_spi_2401((0x20+m));//写入写寄存器命令
write_spi_2401(date);//写入date指向的寄存器数据
CSN=1;//SPI关
}
/**********************
度寄存器子函数
将寄存器的数值读出
有参 M表示要读的寄存器
有返回值 返回读出的数据
************************/
uchar read_reg_nrf24l01(uchar m)
{ uchar date;
SCK=0;
CSN=1;
CSN=0;
write_spi_2401(m);//读寄存器
date=read_spi_2401();
CSN=1;
return (date);
}
/*
在待机模式下对发射机的寄存器的设置
定义了发送地址和应答信号的接收通道和地址*/
void set_Register_tx()//"待机-I模式下的对寄存器的设置 发射机
{
uchar i;
/**********************************************/
// 本段是寄存器设置在待机-I模式完成
//
/**********************************************/
write_rge_nrf24l01(0x01,0x3f);/*允许所有自动应答开启*///EN_AA使能自动应答功能
write_rge_nrf24l01(0x02,0x3f);/*允许所有接收地址开启*///EN_RXADDR接收地址允许
write_rge_nrf24l01(0x03,0x03);/*所有地址通道的收发地址宽度设为5字节*///STEUP_AW设置地址宽度所有通道
write_rge_nrf24l01(0x04,0x28);/*允许建立自动重发延时为(750+86us)自动重发计数次数为8次*///STEUP_RETR建立自动重发
write_rge_nrf24l01(0x11,0x01);/*接收数据通道0 有效数据宽度 一字节*///RX_PW_P0接收通道0有效数据宽度
/**********************************************/
// 本段是对FIF0写入要发送的数据也在在待机-I模式完成
//
/**********************************************/
//***********************************
for(i=32;i;i--) //这一步是写32字节的数据到FIFO中,必须使CE=0;重复一次写一字节,
{ //重复N此写N字节当然最大是32字节;
CE=0; //困扰我多日的写FIFO数据问题解决了2011/2/24/18:47于天津第四项目部宿舍
SCK=0; //原来那个手册里的状态图是这么的重要啊I服了游!!!!(radio control state diagram)
CSN=1;
CSN=0;
write_spi_2401(0xa0);//写FIFO寄存器
write_spi_2401(0xcc);//数据 注意这里我只要发送一个字节的数据,可以最大一次发送32字节
CSN=1;
}
//****************************************
/**********************************************/
// 本段是对接收机的地址设置在待机-I模式完成
//
/**********************************************/
/*这里有必要说明下,由于以上的设置寄存器都是一个字节的所以我使用了子函数,这个是发射/接收地址 我没使用因为上面的只能写一个字节*/
SCK=0;//时钟预选拉低
CSN=1;
CSN=0; //SPI开
write_spi_2401(0x2a);//写入写寄存器命令 /* RX_ADDR_P0 数据通道0接收地址设为0xABABABABAB */
write_spi_2401(0xab);//写入date指向的寄存器数据
write_spi_2401(0xab);//写入date指向的寄存器数据 /*这里其实是用来接收接收机的应答的所以要和发送的地址一样,*/
write_spi_2401(0xab);//写入date指向的寄存器数据 /*你想,你要找王均伟,那么你要发送王均伟,王均伟听见后要回应王均伟*/
write_spi_2401(0xab);//写入date指向的寄存器数据
write_spi_2401(0xab);//写入date指向的寄存器数据
CSN=1;//SPI关
SCK=0;//时钟预选拉低
CSN=1;
CSN=0; //SPI开
write_spi_2401(0x30);//写入写寄存器命令
write_spi_2401(0xab);//写入date指向的寄存器数据 /* TX_ADDR 发送地址设为0xABABABABAB */
write_spi_2401(0xab);//写入date指向的寄存器数据
write_spi_2401(0xab);//写入date指向的寄存器数据
write_spi_2401(0xab);//写入date指向的寄存器数据
write_spi_2401(0xab);//写入date指向的寄存器数据
CSN=1;//SPI关
}
void main () //主函数
{
InitUART();//初始化串口
delay1ms(200);//开机上电复位延时200毫秒后进入掉电模式
delay1ms(200);//开机上电复位延时200毫秒后进入掉电模式
CSN=1;
SCK=0;
CE=0; //初始化端口
SendOneByte(0xf8); //发送个标志
FLAGE=read_reg_nrf24l01(0x17);//状态寄存器读取;发射前读取状态寄存器
SendOneByte(FLAGE);
FLAGE=read_reg_nrf24l01(0x07);//状态寄存器读取;发射前读取状态寄存器
SendOneByte(FLAGE);
write_rge_nrf24l01(0x00,0x0e);/*只允许中断开启,CRC使能,8位,PWR_UP=1(上电),PRIM_RX=0(发射模式)*///配置寄存器
delay1ms(50);//此处指着个延时很管用,标志着24L01由掉电模式向待机-I模式转换的过程,以上是掉电模式一下就是待机-I模式了
while(1)
{
set_Register_tx();// 待机1模式下的寄存器配置
//***********************************************************************
CE=1;
delay10us(2); //进入发射模式数据进行打包准备发送
CE=0;
delay10us(15); //130微秒后进入发射模式CE=0;发送完毕后转到待机一I模式
//*888888888888888888888888888888888888888888888888888888
do
{
SendOneByte(0x88);//发送标志位
FLAGE=read_reg_nrf24l01(0x07);
//P0=FLAGE;
SendOneByte(FLAGE);
}
while((~TX_DS)); //检查是否发送成功?成功向下,否则等待
//*********************************************
CE=0;//转到待机-I模式
write_rge_nrf24l01(0x07,0x2e);/*清除发送中断信号*/
SCK=0;
CSN=1;
CSN=0;
write_spi_2401(0xe1);//清除TX的FIFO寄存器为下一个包发送做准备
CSN=1;
SendOneByte(0xe8);//发送标志位
FLAGE=read_reg_nrf24l01(0x17);//状态寄存器读取
SendOneByte(FLAGE);
FLAGE=read_reg_nrf24l01(0x07);//状态寄存器读取;发射前读取状态寄存器
SendOneByte(FLAGE);
wk=0;
}
while(1);
}
复制代码
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1