从2015年5月15号开始做无线通讯的。开始我并没有重视这个无线通信,但是偶尔一次去工地的路上看见一个城建钢筋场地里的龙门吊,那个***竟然用遥控器控制龙门吊!!开始惊奇,转而又想我能不能做呢?我分析其实关于控制部分早在技校里就学了,正反转吗,不难,但是中间你要实现遥控就不易了,我还是模块化思路,我搞到了RF模块,开始进入了漫漫的实验之路,射频信号我在此之前根本不懂,也不知道是个什么东西,只是知道手机里有那个东西,数据手册有两种一种是英文的,一种是翻译的中文,因为在这方面我还是有经验的,不能尽心中文资料,要信英文资料,但是翻译太麻烦了要用中文资料为参考。
我的第一个实验便是RF模块与主控芯片之间的通信问题,因为无线通信的流程大概是这样的:发送端 数据和信号送入模块的数据区,CRC效验后打包,然后打包后的信号送往调制器进行调制,调制完毕后进入射频功率放大,然后通过天线发射出去;接收端 实时监测空中信号,如果有信号那么接收回来,解调处理,然后对包进行逆打包,CRC效验,地址是否匹配,如果一切正确那么就把数据信号送入数据缓冲区。也就完成了一次通信!和电视和收音机差不多,所以模块与主控通信的重要性关系到你能否驾驭它了!!可喜可贺的是我没用几天就解决这一问题了,因为它使用的外围数据接口以前我用的很多,解决了主机和模块之间的对话下一步是对RF模块的设置和通信的程序,我没想到这可是难倒我了,任凭我怎样设置怎样修改,就是无法发射,没有接收,没有任何的检测工具,我开始怀疑芯片的好坏!是不是坏了?那为什么还能读写呢?又上网找资料找朋友,但是这个东西可不像别的,没有任何教学视频可参考,网上的程序也很烂,说实话我看不下去,我只会用我的思路来编程,他们的太精致了,各种猜测,辗转反侧,夜不能寐。很快就过春节了,我和爸爸1月27号回的家,本想着在家里搞,可是到家后没时间搞,和老爸弄自来水管,写春联,收拾房屋,打扫卫生,可以这么说,今年的春节我是最累的,过了春季有忙着和朋友们玩DOTA,走亲戚,来亲戚,转眼初九了,又极不情愿的踏上了北上打工的旅途!哎!!!人啊!!!
接收机:
- /*无线模块定义*/
- ***it CE=P1^3;//nrf24l01d的模式控制线在 CSN 为低的情况下,CE 协同NRF24L01 的CONFIG 寄存器共同决定NRF24L01 的状态(参照NRF24L01 的状态机)
- ***it CSN=P1^4;//nrf24l01d的片选线,低电平有效
- ***it IRQ=P1^5;//nrf24l01d的中断信号
- /*SPI定义
- */
- ***it SI=P1^0;//MOSI主出-从入
- ***it SO=P1^1;//MISO主入-从出
- ***it SCK=P1^2;// 时钟信号
- /*定义无线模块的收发状态位
- */
- unsigned char bdata FLAGE;
- ***it MAX_RT=FLAGE^4; //达到最大发送次数置1
- ***it TX_DS=FLAGE^5;//数据发送被置1
- ***it RX_DR=FLAGE^6;//数据接收被置1
- /*可谓操作字节dat定义,用来构成最底层的SPT读写函数使用
- */
- unsigned char bdata dat;
- ***it dat_0=dat^0;
- ***it dat_1=dat^1;
- ***it dat_2=dat^2;
- ***it dat_3=dat^3;
- ***it dat_4=dat^4;
- ***it dat_5=dat^5;
- ***it dat_6=dat^6;
- ***it 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
- }
- }
发射机程序:
- /*无线模块定义*/
- ***it CE=P1^3;//nrf24l01d的模式控制线在 CSN 为低的情况下,CE 协同NRF24L01 的CONFIG 寄存器共同决定NRF24L01 的状态(参照NRF24L01 的状态机)
- ***it CSN=P1^4;//nrf24l01d的片选线,低电平有效
- ***it IRQ=P1^5;//nrf24l01d的中断信号
- /*SPI定义
- */
- ***it SI=P1^0;//MOSI主出-从入
- ***it SO=P1^1;//MISO主入-从出
- ***it SCK=P1^2;// 时钟信号
- /*无线模块的状态位定义
- */
- unsigned char bdata FLAGE;
- ***it MAX_RT=FLAGE^4; //达到最大发送次数置1
- ***it TX_DS=FLAGE^5;//数据发送被置1
- ***it RX_DR=FLAGE^6;//数据接收被置1
- /*可谓操作字节dat定义,用来构成最底层的SPT读写函数使用
- */
- unsigned char bdata dat;
- ***it dat_0=dat^0;
- ***it dat_1=dat^1;
- ***it dat_2=dat^2;
- ***it dat_3=dat^3;
- ***it dat_4=dat^4;
- ***it dat_5=dat^5;
- ***it dat_6=dat^6;
- ***it 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);
- }
|
0
|
|
|
|