搜档网
当前位置:搜档网 › 关于NRF24l01的调试

关于NRF24l01的调试

NRF24l01的调试过程与方法小结

心得体会:最近老板给了几块nrf24l01模块我,初次上手难免走了许多的弯路,经过近一周的时间的不断调试,模块之间终于可以相互收发数据了。这样下来终于松了一口气。其间的各种辛苦与艰辛难于言表。上网大致看了一下,网上基于51的调试比较多,但是我们实验室用的是DSP2812,由于nrf24l01是SPI接口,2812上刚好有SPI的接口,这样貌似给使用带来了方便,但是51之类的芯片虽然没有SPI口,但是例程也最多,关于他的讨论比较多。最开始我的想法也比较混乱,想直接用SPI来调试,把底层函数稍微修改了一下,发现并没有结果,这个东西就像一个黑匣子一样,即看不见也摸不着,后来我慢慢改变了思路。既然网上基于IO口模拟的SPI的例程最多,我决定另外走一条路,先用2812的IO 口模拟SPI再用自带的SPI口去调试。这样一来我就有了两条可以走的路。

第一条:底层SPI时序用IO口模拟去写。

第二条:底层直接用2812的SPI去操作。

虽然这样一来,路好走了一点,有各类的程序可以参考,但是这样带来最大的一个问题,这也是后来我才发现的,nrf24l01的最大读写速率是有限制的,2812在150M运行时很显然是太大了一点,由于nrf24l01对时序的要求很高,端口的读写速率和时序都有严格的要求,所以我们才看到,在网上一般是15M左右的单片机来模拟IO口,没有谁用150M的DSP来模拟IO口的,当然既然确定了这样的方法后来也发现了问题,我还是继续走下去了。很重要的一点是系统的时钟频率。当然时序的要求也很高,这也就是为什么,网上说这个模块不好调试的原因,既然是调试,当然我们既然是调试,肯定有一个思路和方法。那么方法是什么呢?开始的时候我是一股脑将发送和接收的程序都写进去,然后啥现象也没有,然后就傻眼了。在网上看了看,于是有了一点思路。

方法是将发送和接收的调试分开来调试,以读取nrf24l01内部的寄存器为手段,先调试发送方,发送方调试没有问题以后,让发送方不断的发送数据,然后再来调试接收方,直到接收方也没有问题,再接着望下面去做。

秉着这样的一个想法,我开始了调试。

这里我只对一对一的调试进行说明,后续的一对多,以及调频之类虽然我有了想法,但是还没有开始实施。在开始调试之前建议将NRF24l01说明书读个三遍。

模块的外部端口

XL24LD01 是采用挪威N O R D I C 公司的n r f 2 4 L 0 1 2.4G 无线收发IC 设计的一款高性能2.4G无线收发模块,采用GFSK 调制,工作在2400‐2483M 的国际通用ISM 频段,最高调制速率可达2MBPS。XL24L01-D01 集成了所有与RF 协议相关的高速信号处理部分,如:自动重发丢失数据包和自动产生应答信号等,模块的SPI 接口可以利用单片机的硬件SPI 口连接或用单片机的I/O 口进行模拟,内部有FIFO 可以与各种高低速微处理器接口,便于使用低成本单片机。

在连线的时候要特别注意电源线不要弄反过来了,要注意电源的最大值不能超过3.6V,这个电压直接影响了模块的端口的输出电压值,由于我们的DSP端口的高电平在3.3V,一般将电压设置在这个附近左右。只有在硬件没有问题的基础上才能开始调试软件,否者会出现很多的问题。

还有一个,工作模式的问题,要注意在待机和掉电的模式下才能够进行寄存器的写操作。

模块内部的寄存器

在调试中对寄存器的读取操作是一个非常有效的验证方法。对芯片资料中给出的23个寄存器内容请看手册。对应的寄存器在头文件里面。

用IO口模拟SPI的方法

头文件如下:

#ifndef _NRF24L01_H_

#define _NRF24L01_H_

#define CPU_RATE 6.667L // for a 150MHz CPU clock speed (SYSCLKOUT)

// DO NOT MODIFY THIS LINE.

#define DELAY_US(A) DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L)

//这个函数是在150M下的us级延时函数

/*******************************************************/

#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接收地址

#define TX_ADDR 0x10//发送地址

#define RX_PW_P0 0x11//P0通道数据宽度设置

#define RX_PW_P1 0x12//P1通道数据宽度设置

#define RX_PW_P2 0x13//P2通道数据宽度设置

#define RX_PW_P3 0x14//P3通道数据宽度设置

#define RX_PW_P4 0x15//P4通道数据宽度设置

#define RX_PW_P5 0x16//P5通道数据宽度设置

#define FIFO_STATUS 0x17//FIFO状态寄存器

/*******************相关函数声明**************************/ unchar NRFACK();

unchar NRFSPI(unchar date);

unchar NRFReadReg(unchar RegAddr);

unchar NRFWriteReg(unchar RegAddr,unchar date);

unchar NRFReadRxDate(unchar RegAddr,unchar *RxDate,unchar DateLen); unchar NRFWriteTxDate(unchar RegAddr,unchar *TxDate,unchar DateLen); unchar NRFRevDate(unchar *RevDate);

void NRFSetTxMode(unchar *TxDate);

void NRF24L01Int();

void NRFSetRXMode();

unchar CheckACK();

/**nrf24l01状态寄存器的申明**/

struct STA_BITS { // bit description

Uint16 TX_FULL:1; // 0 FIFO寄存器满标志

Uint16 RX_P_NO:3; // 1:3 接收通道号

Uint16 MAX_RT:1; // 4 最大重发次数

Uint16 TX_DS:1; // 5 数据发送完成标志

Uint16 RX_DR:1; // 6 接收数据中断

Uint16 rsvd:1; // 7 reserved

};

union STA_REG {

Uint16 all;

struct STA_BITS bit;

};

struct LOOK_BITS { // bit description

Uint16 bit0:1; // 0

Uint16 bit1:1; // 1

Uint16 bit2:1; // 2

Uint16 bit3:1; // 3

Uint16 bit4:1; // 4

Uint16 bit5:1; // 5

Uint16 bit6:1; // 6

Uint16 bit7:1; // 7

};

union LOOK_REG {

Uint16 all;

struct LOOK_BITS bit;

};

/*********************************************************/

#endif

函数的底层如下:

/*****************************************

*创建:那是星期天

*时间:2015.4.15

*功能:NRF24L01射频模块C文件

*****************************************/

#include "DSP28_Device.h"

#include "NRF24L01.h"//nrf24l01的射频模块的头文件

unchar TxAddr[]={0x34,0x43,0x10,0x10,0x01};//发送地址

union STA_REG sta={0};

/*****************SPI时序函数*******************************

***********/

unchar NRFSPI(unchar data)

{

unchar i;

for(i=0;i<8;i++) // 循环8次

{

if(data&0x80)

GpioDataRegs.GPADAT.bit.GPIOA3=1;//MOSI

else

GpioDataRegs.GPADAT.bit.GPIOA3=0;// byte最高位输出到MISO data<<=1; // 低一位移位到最高位

GpioDataRegs.GPADAT.bit.GPIOA1=1;//SCLK=1

if(GpioDataRegs.GPADAT.bit.GPIOA2)//MISO

data|=0x01;

GpioDataRegs.GPADAT.bit.GPIOA1=0;//SCLK=0

}

data=data&0x00ff;

return(data);//返回读出的一个字节

}

/**********************NRF24L01初始化函数*******************************/

void NRF24L01Int()

{

DELAY_US(2);//延时2us//让系统什么都不干

GpioDataRegs.GPADAT.bit.GPIOA5=0; //ce=0待机模式1

GpioDataRegs.GPADAT.bit.GPIOA0=1; //CSN=1;

GpioDataRegs.GPADAT.bit.GPIOA1=0;// SCLK=0;

GpioDataRegs.GPADAT.bit.GPIOA4=1;// IRQ=1;

}

/*****************SPI读寄存器一字节函数*********************************/

unchar NRFReadReg(unchar RegAddr)

{

unchar BackDate;

GpioDataRegs.GPADAT.bit.GPIOA0=0; //CSN=0启动时序

NRFSPI(RegAddr);//写寄存器地址

BackDate=NRFSPI(0x00);//写入读寄存器指令

GpioDataRegs.GPADAT.bit.GPIOA0=1;// CSN=1

return(BackDate); //返回状态

}

/*****************SPI写寄存器一字节函数*********************************/

unchar NRFWriteReg(unchar RegAddr,unchar date)

{

unchar BackDate;

GpioDataRegs.GPADAT.bit.GPIOA0=0; //CSN=0启动时序

BackDate=NRFSPI(RegAddr);//写入地址

NRFSPI(date);//写入值

GpioDataRegs.GPADAT.bit.GPIOA0=1;// CSN=1

return(BackDate);

}

/*****************SPI读取RXFIFO寄存器的值********************************/

unchar NRFReadRxDate(unchar RegAddr,unchar *RxDate,unchar DateLen)

{ //寄存器地址//读取数据存放变量//读取数据长度//用于接收

unchar BackDate,i;

GpioDataRegs.GPADAT.bit.GPIOA0=0; //CSN=0启动时序

BackDate=NRFSPI(RegAddr);//写入要读取的寄存器地址

for(i=0;i

{

RxDate[i]=NRFSPI(0);

}

GpioDataRegs.GPADAT.bit.GPIOA0=1;// CSN=1

return(BackDate);

}

/*****************SPI写入TXFIFO寄存器的值**********************************/

unchar NRFWriteTxDate(unchar RegAddr,unchar *TxDate,unchar DateLen)

{ //寄存器地址//写入数据存放变量//读取数据长度//用于发送

unchar BackDate,i;

GpioDataRegs.GPADAT.bit.GPIOA0=0; //CSN=0启动时序

BackDate=NRFSPI(RegAddr);//写入要写入寄存器的地址

for(i=0;i

{

NRFSPI(*TxDate++);

}

GpioDataRegs.GPADAT.bit.GPIOA0=1;// CSN=1

return(BackDate);

}

/*****************NRF设置为发送模式并发送数据******************************/

void NRFSetTxMode(unchar *TxDate)

{//发送模式

GpioDataRegs.GPADAT.bit.GPIOA5=0; //CE=0

NRFWriteReg(W_REGISTER+CONFIG,0x00);//在掉电模式中配置寄存器

NRFWriteReg(W_REGISTER+FLUSH_TX,0x00);//清除TX FIFO寄存器

NRFWriteReg(W_REGISTER+SETUP_AW,0x03);//设置发射地址的宽度为5位 NRFWriteTxDate(W_REGISTER+TX_ADDR,TxAddr,TX_ADDR_WITDH);//写寄存器指令+接收地址使能指令+接收地址+地址宽度

NRFWriteTxDate(W_REGISTER+RX_ADDR_P0,TxAddr,TX_ADDR_WITDH);//为了应答接收设备,接收通道0地址和发送地址相同

NRFWriteTxDate(W_TX_PAYLOAD,TxDate,TX_DATA_WITDH);//写入数据

/******下面有关寄存器配置**************/

NRFWriteReg(W_REGISTER+EN_AA,0x00);//

NRFWriteReg(W_REGISTER+EN_AA,0x01); // 使能接收通道0自动应答NRFWriteReg(W_REGISTER+EN_RXADDR,0x00);//NRFWriteReg(W_REGISTER+EN _RXADDR,0x01); // 使能接收通道0

NRFWriteReg(W_REGISTER+SETUP_RETR,0x00);//NRFWriteReg(W_REGISTER+SE TUP_RETR,0x0a); // 自动重发延时等待250us+86us,自动重发10次NRFWriteReg(W_REGISTER+RF_CH,0x40); // 选择射频通道0x40

NRFWriteReg(W_REGISTER+RF_SETUP,0x07); // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益

NRFWriteReg(W_REGISTER+CONFIG,0x0e); // CRC使能,16位CRC校验,上电

GpioDataRegs.GPADAT.bit.GPIOA5=1;//CE=1

DELAY_US(10);//保持10us以上

}

/*****************NRF设置为接收模式并接收数据******************************/

//主要接收模式

void NRFSetRXMode()

{

GpioDataRegs.GPADAT.bit.GPIOA5=0;// CE=0;

NRFWriteReg(W_REGISTER+CONFIG,0x00);//在掉电模式中配置寄存器

NRFWriteReg(W_REGISTER+FLUSH_RX,0x00);//清除TX FIFO寄存器

NRFWriteReg(W_REGISTER+SETUP_AW,0x03);//设置发射地址的宽度为5位NRFWriteTxDate(W_REGISTER+RX_ADDR_P0,TxAddr,TX_ADDR_WITDH); // 接

收设备接收通道0使用和发送设备相同的发送地址

NRFWriteReg(W_REGISTER+EN_AA,0x01); // 使能接收通道0自动应答

NRFWriteReg(W_REGISTER+EN_RXADDR,0x01); // 使能接收通道0 NRFWriteReg(W_REGISTER+RF_CH,0x40); // 选择射频通道0x40

NRFWriteReg(W_REGISTER+RX_PW_P0,TX_DATA_WITDH); // 接收通道0选择和发送通道相同有效数据宽度

NRFWriteReg(W_REGISTER+RF_SETUP,0x07); // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益*/

NRFWriteReg(W_REGISTER+CONFIG,0x0f); // CRC使能,16位CRC校验,上电,接收模式

GpioDataRegs.GPADAT.bit.GPIOA5=1;// CE = 1;

DELAY_US(10);//保持10us以上

}

/****************************检测应答信号******************************/

unchar CheckACK()

{ //用于发射

sta.all=NRFReadReg(R_REGISTER+STATUS); // 返回状态寄存器

// sta.all=NRFReadReg(R_REGISTER+0x17);

if(sta.bit.TX_DS||sta.bit.MAX_RT) //发送完毕中断

{

NRFWriteReg(W_REGISTER+STATUS,0xff); // 清除TX_DS或MAX_RT中断标志

GpioDataRegs.GPADAT.bit.GPIOA0=0;// CSN=0;

NRFSPI(FLUSH_TX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!

GpioDataRegs.GPADAT.bit.GPIOA0=1;// CSN=1;

return(0);

}

else

return(1);

}

/******************判断是否接收收到数据,接到就从RX取出*********************/

//用于接收模式

unchar NRFRevDate(unchar *RevDate)

{

unchar RevFlags=0;

sta.all=NRFReadReg(R_REGISTER+STATUS);//发送数据后读取状态寄存器

if(sta.bit.RX_DR) // 判断是否接收到数据

{

GpioDataRegs.GPADAT.bit.GPIOA5=0; // CE=0; //SPI使能

NRFReadRxDate(R_RX_PAYLOAD,RevDate,RX_DATA_WITDH);// 从RXFIFO读取数据

RevFlags=1; //读取数据完成标志

}

NRFWriteReg(W_REGISTER+STATUS,0xff); //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标

return(RevFlags);

}

void InitGpio(void)

{

EALLOW;

///设置SPI口外设功能

GpioMuxRegs.GPAMUX.bit.PWM1_GPIOA0=0;//CSN

GpioMuxRegs.GPAMUX.bit.PWM2_GPIOA1=0;//sck

GpioMuxRegs.GPAMUX.bit.PWM3_GPIOA2=0;//MISO

GpioMuxRegs.GPAMUX.bit.PWM4_GPIOA3=0;//MOSI

GpioMuxRegs.GPAMUX.bit.PWM5_GPIOA4=0;//IRQ

GpioMuxRegs.GPAMUX.bit.PWM6_GPIOA5=0;//CE

GpioMuxRegs.GPADIR.bit.GPIOA0=1;

GpioMuxRegs.GPADIR.bit.GPIOA1=1;

GpioMuxRegs.GPADIR.bit.GPIOA2=0; //MISO为输入

GpioMuxRegs.GPADIR.bit.GPIOA3=1;

GpioMuxRegs.GPADIR.bit.GPIOA4=1;

GpioMuxRegs.GPADIR.bit.GPIOA5=1;

EDIS;

}

主函数中包涵了调试的内容:

#include "DSP28_Device.h"

#include "NRF24L01.h"

void WriteLED(unchar data); //点亮LED2函数

unchar TxDate[4];

union LOOK_REG look0={0};

union LOOK_REG look1={0};

union LOOK_REG look2={0};

union LOOK_REG look3={0};

union LOOK_REG look4={0};

union LOOK_REG look5={0};

union LOOK_REG look6={0};

union LOOK_REG look7={0}; union LOOK_REG look8={0}; union LOOK_REG look9={0}; union LOOK_REG look10={0}; union LOOK_REG look11={0}; union LOOK_REG look12={0}; union LOOK_REG look13={0}; union LOOK_REG look14={0}; union LOOK_REG look15={0}; union LOOK_REG look16={0}; union LOOK_REG look17={0}; union LOOK_REG look18={0}; union LOOK_REG look19={0}; union LOOK_REG look20={0}; union LOOK_REG look21={0}; union LOOK_REG look22={0}; union LOOK_REG look23={0};

void main(void)

{

/*初始化系统*/

InitSysCtrl();

/* 关中断*/

DINT;

IER = 0x0000;

IFR = 0x0000;

/* 初始化PIE控制寄存器*/

InitPieCtrl();

/* 初始化PIE参数表*/

InitPieVectTable();

/* 初始化外设寄存器*/

InitGpio();

InitSpi();

/*设置CPU*/

EINT; // 开全局中断

ERTM; // 开实时中断

NRF24L01Int();

while(1)

{

int ReadTempDate=6;

TxDate[0]=ReadTempDate;

// TxDate[1]=0;

//TxDate[2]=0;

//TxDate[3]=0;

NRFSetTxMode(TxDate);//发数据

while(CheckACK()); //检测是否发送完毕// GpioDataRegs.GPADAT.bit.GPIOA0=1;

look0.all=NRFReadReg(R_REGISTER+0x00);

look1.all=NRFReadReg(R_REGISTER+0x01);

look2.all=NRFReadReg(R_REGISTER+0x02);

look3.all=NRFReadReg(R_REGISTER+0x03);

look4.all=NRFReadReg(R_REGISTER+0x04);

look5.all=NRFReadReg(R_REGISTER+0x05);

look6.all=NRFReadReg(R_REGISTER+0x06);

look7.all=NRFReadReg(R_REGISTER+0x07);

look8.all=NRFReadReg(R_REGISTER+0x08);

look9.all=NRFReadReg(R_REGISTER+0x09);

look10.all=NRFReadReg(R_REGISTER+0x0a);

look11.all=NRFReadReg(R_REGISTER+0x0b);

look12.all=NRFReadReg(R_REGISTER+0x0c);

look13.all=NRFReadReg(R_REGISTER+0x0d);

look14.all=NRFReadReg(R_REGISTER+0x0e);

look15.all=NRFReadReg(R_REGISTER+0x0f);

look16.all=NRFReadReg(R_REGISTER+0x10);

look17.all=NRFReadReg(R_REGISTER+0x11);

look18.all=NRFReadReg(R_REGISTER+0x12);

look19.all=NRFReadReg(R_REGISTER+0x13);

look20.all=NRFReadReg(R_REGISTER+0x14);

look21.all=NRFReadReg(R_REGISTER+0x15);

look22.all=NRFReadReg(R_REGISTER+0x16);

look23.all=NRFReadReg(R_REGISTER+0x17);

TxDate[0]=ReadTempDate;

}

}

/******************************************************************** ********

*

*名称:WriteLED()

*

*功能:接收到的数据点亮LED

*

*入口参数:char data,需要发送的数据

*

*出口参数:无

*

********************************************************************* *******/

void WriteLED(unchar data)

{

int n,j;

for(n=0;n

{

GpioDataRegs.GPFDAT.bit.GPIOF8=1;

for(j=0;j<10000;j++);

GpioDataRegs.GPFDAT.bit.GPIOF8=0;

for(j=0;j<10000;j++);

}

}

SPI接口直接调试的方法

DSP2812的SPI的调试是nrf24l01的第一步,2812的spi在读写nrf24l01过程中会出现写入数据的错误,这个也是后来我用示波器观测的时候发现的现象,一切的调试都是建立在SPI的底层函数上,SPI有问题那么对24l01的操作就会出现问题,在我的调试过程中就发现这样的问题,我不知道这种问题是不是共性,但是SPI的调试出现问题无线收发模块就有问题。究其原因是因为在2812的时钟发射的上升沿发出数据,在时钟的下降沿时这种电平会保持到下一个时钟的上升沿才会改变,这样的改变对2812没有什么影响但是对24l01模块来说却是致命的,这样就会造成数据的混叠,我的解决方法很直接,直接将输出口改为普通的IO 口模式,使其在该高的地方高,在该底的地方底,这样数据的读写就不存在障碍了。对于SPI的调试我的初始化函数是对寄存器一个一个的给这样就方便找出问题。

void InitSpi(void)

{

SpiaRegs.SPICCR.bit.RESET = 0; // 软件复位SPI

SpiaRegs.SPICCR.bit.CLKPOLARITY = 0; // 上降沿输出数据

SpiaRegs.SPICCR.bit.SPILBK = 0; // 禁止环路自测模式

SpiaRegs.SPICCR.bit.SPICHAR = 0; // 1位字符长度

SpiaRegs.SPICTL.bit.OVERRUN = 0; // 禁止溢出中断使能

SpiaRegs.SPICTL.bit.CLK_PHASE = 0; // 信号无延时

SpiaRegs.SPICTL.bit.MASTER_SLAVE = 1; // 主机模式

SpiaRegs.SPICTL.bit.TALK = 1; // 使能发送

SpiaRegs.SPICTL.bit.SPIINTENA = 0; // 禁止发送、接收中断SpiaRegs.SPIBRR = 49; // SPI波特率= LSPCLK/(SPIBRR+1) = 37.5MHz/(49+1) = 750KHz

SpiaRegs.SPICCR.bit.RESET = 1; // 退出软件复位SPI

}

然后在程序里面让发送的引脚发数据,接收脚接收数据,然后比较发送的数据和接收的数据。我在程序里面是只给一位数据,方便我后面实现想要的时序,但是在调试SPI的时候当然是可以一次给更多的位的,因为是2812自己读写所以时序不存在问题,这里要注意的是在程序中只有给了SPITXBUF数据时钟才开始工作。

当调试SPI没有问题的时候再开始下面的工作,写NRF的SPI底层函数,这里的时序是按照自己的逻辑来的,验证没有问题。

/*****************SPI时序函数******************************* ***********/

unchar NRFSPI(unchar data)

{

unchar i;

for(i=0;i<8;i++)

{

if(data&0x80)

{

SpiaRegs.SPITXBUF=0x8000;

GpioDataRegs.GPFDAT.bit.GPIOF0=1;

}

else

{

SpiaRegs.SPITXBUF=0x0000;

GpioDataRegs.GPFDAT.bit.GPIOF0=0;

}

data<<=1;

while((SpiaRegs.SPISTS.all&0x0040) != 0x0040);

GpioDataRegs.GPFDAT.bit.GPIOF0=0;//这里要加否则时序不正确!!!!

if(SpiaRegs.SPIRXBUF&0x0001) data|=0x0001;

//这个函数的高两位的写入是有问题的,在这里用不到所以不深究}

return(data&0x00ff);//返回读出的一个字节

}

其他的变动和用IO口模拟基本上一样,没有什么本质的区别,然后就可以用这条新写的SPI去操作NRF24L01的寄存器了,思路很简单,先对其中的一个寄存器实现写某个数据的操作,然后实现对这个寄存器的读的操作,比较这两个数据,就可以验证SPI时序的正确性了。我对寄存器的读写操作时用以上函数发现8位数据的前两位写不正确,不知道是不是寄存器问题,但是其他的位是没有问题的,因为对寄存器用不到对高位的操作,所以这里不影响。

后续的验证思路和用IO口模拟的一模一样就是对寄存器逐个的验证,这里不用修改CPU的时钟频率,因为时钟引脚可以自己调整。然后就是CD载波的验证,如果通过,那么就可以尝试着发送一个数据点个数码管什么的。到这里基本上一对一的发送和接收的操作就完成了,我讲程序的代码贴到下面。

对于发送:

#include "DSP28_Device.h"

#include "NRF24L01.h"

unchar TxDate[4];

union LOOK_REG look0={0};

union LOOK_REG look1={0};

union LOOK_REG look2={0};

union LOOK_REG look3={0};

union LOOK_REG look4={0};

union LOOK_REG look5={0};

union LOOK_REG look6={0};

union LOOK_REG look7={0};

union LOOK_REG look8={0};

union LOOK_REG look9={0};

union LOOK_REG look10={0};

union LOOK_REG look11={0};

union LOOK_REG look12={0};

union LOOK_REG look13={0};

union LOOK_REG look14={0};

union LOOK_REG look15={0};

union LOOK_REG look16={0};

union LOOK_REG look17={0};

union LOOK_REG look18={0};

union LOOK_REG look19={0};

union LOOK_REG look20={0};

union LOOK_REG look21={0};

union LOOK_REG look22={0};

union LOOK_REG look23={0};

void main(void)

{

InitSysCtrl();

DINT;

IER = 0x0000;

IFR = 0x0000;

InitPieCtrl();

InitPieVectTable();

InitGpio();

InitSpi();

EINT; // 开全局中断

ERTM; // 开实时中断

NRF24L01Int();

while(1)

{

int ReadTempDate=169;

TxDate[0]=ReadTempDate;

TxDate[1]=0;

TxDate[2]=0;

TxDate[3]=0;

NRFSetTxMode(TxDate);//发数据

while(CheckACK()); //检测是否发送完毕

GpioDataRegs.GPFDAT.bit.GPIOF14=0; //CE=0

look0.all=NRFReadReg(R_REGISTER+0x00);

look1.all=NRFReadReg(R_REGISTER+0x01);

look2.all=NRFReadReg(R_REGISTER+0x02);

look3.all=NRFReadReg(R_REGISTER+0x03);

look4.all=NRFReadReg(R_REGISTER+0x04);

look5.all=NRFReadReg(R_REGISTER+0x05);

look6.all=NRFReadReg(R_REGISTER+0x06);

look7.all=NRFReadReg(R_REGISTER+0x07);

look8.all=NRFReadReg(R_REGISTER+0x08);

look9.all=NRFReadReg(R_REGISTER+0x09);

look10.all=NRFReadReg(R_REGISTER+0x0a);

look11.all=NRFReadReg(R_REGISTER+0x0b);

look12.all=NRFReadReg(R_REGISTER+0x0c);

look13.all=NRFReadReg(R_REGISTER+0x0d);

look14.all=NRFReadReg(R_REGISTER+0x0e);

look15.all=NRFReadReg(R_REGISTER+0x0f);

look16.all=NRFReadReg(R_REGISTER+0x10);

look17.all=NRFReadReg(R_REGISTER+0x11);

look18.all=NRFReadReg(R_REGISTER+0x12);

look19.all=NRFReadReg(R_REGISTER+0x13);

look20.all=NRFReadReg(R_REGISTER+0x14);

look21.all=NRFReadReg(R_REGISTER+0x15);

look22.all=NRFReadReg(R_REGISTER+0x16);

look23.all=NRFReadReg(R_REGISTER+0x17);

GpioDataRegs.GPFDAT.bit.GPIOF14=1; //CE=1

}

}

主函数里面这些结构体的操作就是为了实验的验证和调试。

对接收的操作:

#include "DSP28_Device.h"

#include "NRF24L01.h"

void WriteLED(unchar data); //点亮LED2函数

void WriteLED1(unchar data);

void delay_loop(void);

void Gpio_select(void);

unchar RxData[5]={0,0,0,0,0};

unchar TxData[5]={0,0,0,0,0};

unsigned table[]={

0xc0ff,0xf9ff,0xa4ff,0xb0ff,0x99ff,0x92ff,0x82ff,0xf8ff,0x00ff,0x90ff,

0xc0f9,0xf9f9,0xa4f9,0xb0f9,0x99ff,0x92f9,0x82f9,0xf8f9,0x00f9,0x90f9,

0xc0a4,0xf9a4,0xa4a4,0xb0a4,0x99a4,0x92a4,0x82a4,0xf8a4,0x00a4,0x90a4, 0xc0b0,0xf9b0,0xa4b0,0xb0b0,0x99b0,0x92b0,0x82b0,0xf8b0,0x00b0,0x90b0, 0xc099,0xf999,0xa499,0xb099,0x9999,0x9299,0x8299,0xf899,0x0099,0x9099, 0xc092,0xf992,0xa492,0xb092,0x9992,0x9292,0x8292,0xf892,0x0092,0x9092, 0xc082,0xf982,0xa482,0xb082,0x9982,0x9282,0x8282,0xf882,0x0082,0x9082, 0xc0f8,0xf9f8,0xa4f8,0xb0f8,0x99f8,0x92f8,0x82f8,0xf8f8,0x00f8,0x90f8,

0xc000,0xf900,0xa400,0xb000,0x9900,0x9200,0x8200,0xf800,0x0000,0x9000, 0xc090,0xf990,0xa490,0xb090,0x9990,0x9290,0x8290,0xf890,0x0090,0x9090, };

unchar cd=0;//测试用union LOOK_REG look0={0}; union LOOK_REG look1={0}; union LOOK_REG look2={0}; union LOOK_REG look3={0}; union LOOK_REG look4={0}; union LOOK_REG look5={0}; union LOOK_REG look6={0}; union LOOK_REG look7={0}; union LOOK_REG look8={0}; union LOOK_REG look9={0}; union LOOK_REG look10={0}; union LOOK_REG look11={0}; union LOOK_REG look12={0}; union LOOK_REG look13={0}; union LOOK_REG look14={0}; union LOOK_REG look15={0}; union LOOK_REG look16={0}; union LOOK_REG look17={0}; union LOOK_REG look18={0}; union LOOK_REG look19={0}; union LOOK_REG look20={0}; union LOOK_REG look21={0}; union LOOK_REG look22={0}; union LOOK_REG look23={0}; unsigned int var1 = 0; unsigned int var2 = 0;

void main(void)

{

InitSysCtrl();

DINT;

IER = 0x0000;

IFR = 0x0000;

InitPieCtrl();

InitPieVectTable();

InitGpio();

InitSpi();

EINT; // 开全局中断

ERTM; // 开实时中断

WriteLED(10);

GpioDataRegs.GPFDAT.bit.GPIOF8=1;//led熄灭GpioDataRegs.GPFDAT.bit.GPIOF9=1;

NRF24L01Int();

var1= 0x0000; // sets GPIO Muxs as I/Os

var2= 0xFFFF; // sets GPIO DIR as outputs

Gpio_select();

while(1)

{

int i,j=0;

NRFSetRXMode();//接收数据

for(i=0;i<1000;i++);

if(NRFRevDate(TxData))

WriteLED1(TxData[0]);

j=TxData[0];

GpioDataRegs.GPBDAT.all=table[j];

delay_loop();

j=0;

GpioDataRegs.GPFDAT.bit.GPIOF14=0; // CE=0;

look0.all=NRFReadReg(R_REGISTER+0x00); DELAY_US(1);

look1.all=NRFReadReg(R_REGISTER+0x01); DELAY_US(1);

look2.all=NRFReadReg(R_REGISTER+0x02); DELAY_US(1);

look3.all=NRFReadReg(R_REGISTER+0x03); DELAY_US(1);

look4.all=NRFReadReg(R_REGISTER+0x04); DELAY_US(1);

look5.all=NRFReadReg(R_REGISTER+0x05); DELAY_US(1);

look6.all=NRFReadReg(R_REGISTER+0x06); DELAY_US(1);

look7.all=NRFReadReg(R_REGISTER+0x07); DELAY_US(1);

look8.all=NRFReadReg(R_REGISTER+0x08); DELAY_US(1);

look9.all=NRFReadReg(R_REGISTER+0x09); DELAY_US(1);

look10.all=NRFReadReg(R_REGISTER+0x0a); DELAY_US(1);

look11.all=NRFReadReg(R_REGISTER+0x0b); DELAY_US(1);

look12.all=NRFReadReg(R_REGISTER+0x0c); DELAY_US(1);

look13.all=NRFReadReg(R_REGISTER+0x0d); DELAY_US(1);

look14.all=NRFReadReg(R_REGISTER+0x0e); DELAY_US(1);

look15.all=NRFReadReg(R_REGISTER+0x0f); DELAY_US(1);

look16.all=NRFReadReg(R_REGISTER+0x10); DELAY_US(1);

look17.all=NRFReadReg(R_REGISTER+0x11); DELAY_US(1);

look18.all=NRFReadReg(R_REGISTER+0x12); DELAY_US(1);

look19.all=NRFReadReg(R_REGISTER+0x13); DELAY_US(1);

look20.all=NRFReadReg(R_REGISTER+0x14); DELAY_US(1);

look21.all=NRFReadReg(R_REGISTER+0x15); DELAY_US(1);

look22.all=NRFReadReg(R_REGISTER+0x16); DELAY_US(1);

look23.all=NRFReadReg(R_REGISTER+0x17); DELAY_US(1);

NRFReadRxDate(RX_ADDR_P0,RxData,TX_ADDR_WITDH);

if(cd&0x01){NRFWriteReg(W_REGISTER+0x09,0x00); WriteLED(5);}

//CD载波验证是否收到信号

}

}

/******************************************************************** ********

*

*名称:WriteLED()

*

*功能:接收到的数据点亮LED

*

*入口参数:char data,需要发送的数据

*

*出口参数:无

*

********************************************************************* *******/

void WriteLED(unchar data)

{

int n,i,j;

for(n=0;n

{

GpioDataRegs.GPFDAT.bit.GPIOF8=0;

for(i=0;i<2000;i++)j=i;

GpioDataRegs.GPFDAT.bit.GPIOF8=1;

for(i=0;i<2000;i++)j=i;

}

}

void WriteLED1(unchar data)

{

int n,i,j;

for(n=0;n

{

GpioDataRegs.GPFDAT.bit.GPIOF9=0;

for(i=0;i<2000;i++)j=i;

GpioDataRegs.GPFDAT.bit.GPIOF9=1;

for(i=0;i<2000;i++)j=i;

}

}

void delay_loop()

{

short i;

for (i = 0; i < 10000; i++) {}

}

void Gpio_select(void)

{

EALLOW;

GpioMuxRegs.GPBMUX.all=var1;

GpioMuxRegs.GPBDIR.all=var2; // GPIO DIR select GPIOs as output EDIS;

}

关于使用STM32硬件SPI驱动NRF24L01

关于使用STM32硬件SPI驱动NRF24L01+ 今天是大年初一总算有时间做点想做很久的事了,说到NRF2401可能很多电子爱好者都有用过或是软件模拟驱动又或是用单片机自带的硬件SPI来驱动,但不管是用哪种方法来驱动我想都在调试方面耗费了不少的时间(可能那些所谓的电子工程师不会出现这种情况吧!)网上的资料确实很多,但大多数都并没有经过发贴人认真测试过,有的只是理论上可以行的通但上机测试只能说是拿回来给他修改。本文作者也是经过无助的多少天才算是调试成功了(基于STM32硬件SPI,软件模拟的以前用51单片机已经调通了今天就不准备再拿来讲了,当然如果以后有朋友有需要也可以告诉我,我也可以重新写一篇关于51的驱动的只要有时间是没有问题的。)因为我用的是STM32F103C8T6的系统而且是刚接触不知道别的系统和我用的这个系统有多大的差别所以我不会整个代码全贴上来就完事了,我将就着重思路配合代码写出来,这样对于刚接触单片机的朋友会有很好的作用,但是还有一点请大家要原谅,可能会存在一些说的不好的地方,毕竟我没有经过正规渠道系统地学习过电子知识,对于前辈来说存在这样那样的问题不可避免的,在此也希望大家指教! 贴个图先:

NRF2401+的资料大家上网查一下,我输字的速度有点不好说!下面我来说一下整个调试流程吧 1.先把STM32串口一调通(因为我不知道STM32 I/O口不知可不可以像51那样并口输出数据,如果可以那就更方便啰)。 2.与NRF2401建立起通信(这个才是问题的关键);

3.利用读NRF2401的一个状态寄存器(STATUS)的值并通过串口发送到PC后通过51下载软件的串口助手显示出来(如果你用液晶来调试那你太有才了,你液晶和NRF2401存在牵连可能就会给寻找不成功的原因造成困难,而且还有不少硬件工作要做)在这说一下本文只调试发送程序,致于接收只改一个程序参数就行了。 我们先来调试STM32F103C8T6的串口1吧(也就是USART1)!它是STM32F103C8T6的片上外设之一,使用它时相对来说简单了不少。首先我要说一下我们要使用STM32的片上外设那么我们必须先对其进行初始化,实际上就是经过这段初始化代码让外设根据我们的要求来工作: void USART1_AllInit(void)//意思是USART1的所有初始化工作,我的英文不好所以可能涵数名可能也不怎么规范 { RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟,它是在APB2这条总线上的 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIOA时钟,它也是在APB2这条总线上的,因为USART1要用到GPIOA的端口所以也要初始化 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;

校园智能路灯设计方案

校园智能路灯设计方案 一.设计名称 基于NRF24L01的校园智能路灯初步粗略设计方案 二.摘要 近年来,低碳生活,节能减排越来越受到国家的大力支持,在校园生活中平均一盏路灯的功率在200W-300W之间,每晚大概需要点亮时长为18:00--5:00,粗略的计算会发现每盏路灯的功耗大概在2.2--3.3kW·h,学校大多用电平局一度电在0.55元左右,因此,每晚一盏路灯所产生的电费大概在1.2--1.8元左右,大学校园犹如一个小城市,每个学校的路灯至少上百盏,路灯的数量有的会达到上千盏甚至更多。这给学校每天的开销带来了一部分没必要的浪费。 节约校园照明用电消耗成为响应国家对于节能号召的重要措施之一。一般的校园照明系统只是运用普通的声控及光控传感器组成开环的控制系统,其灵活性差,功耗大,不可人为干预。而市场上闭环控制的照明系统投入资金大,稳定性差,无法在校园中得到推广。 三.设计目的

1.了解NRF24L01的基本通信原理 2.掌握stm32f103芯片的AD转换原理 3.熟练掌握光敏电阻的应用 4.将本学年所学知识进行一次综合汇总 四.设计原理 系统的设计主要有以下四个模块部分:微控制器STM32,光敏电阻模块, LED照明电路.无线射频模块。 其中光敏电阻模块与LED照明电路组成检测照明部分,主要负责检测外界光的强度,人流高峰期会默认开启普通照明模式,夜间会默认开启节能模式。 微控制器STM32负责收集采集数据,以及AD转换,通过串口向PC机发送消息。 无线射频模块负责向主机传递信息,当从机照明电路出现错误时会触发射频模块发射数据,不同从机对应不同数据。发送完成结束传输。

SPI方式STM32F103与2.4G模块NRF24L01收发通讯

1.简介 通过SPI方式与NRF24L01模块进行通讯,接收到的数据通过串口1打印出来,实时监测是否收到数据,发送的数据是“2.4G TEST”,当收不到数据时打印“no data”。一块STM32F103ZET6开发板接收数据,另一块STM32F103RBT6开发板发送数据,两个淘宝买的2.4G NRF24L01模块。还用到一块USB转TTL模块用来电平转换传送数据,串口调试助手接收串口发送数据。 2.代码部分 ---------nrf24l01.h----------- #ifndef __24L01_H #define __24L01_H #include "sys.h" /////////////////////////////////////////////////////////////////////////////// /////////////////////////// //NRF24L01寄存器操作命令 #define NRF_READ_REG 0x00 //读配置寄存器,低5位为寄存器地址 #define NRF_WRITE_REG 0x20 //写配置寄存器,低5位为寄存器地址 #define RD_RX_PLOAD 0x61 //读RX有效数据,1~32字节 #define WR_TX_PLOAD 0xA0 //写TX有效数据,1~32字节 #define FLUSH_TX 0xE1 //清除TX FIFO寄存器.发射模式下用 #define FLUSH_RX 0xE2 //清除RX FIFO寄存器.接收模式下用 #define REUSE_TX_PL 0xE3 //重新使用上一包数据,CE为高,数据包被不断发送. #define NOP 0xFF //空操作,可以用来读状态寄存器 //SPI(NRF24L01)寄存器地址 #define CONFIG 0x00 //配置寄存器地址;bit0:1接收模式,0发射模式;bit1:电选择;bit2:CRC模式;bit3:CRC使能; //bit4:中断MAX_RT(达到最大重发次数中断)使能;bit5:中断TX_DS使能;bit6:中断RX_DR使能 #define EN_AA 0x01 //使能自动应答功能 bit0~5,对应通道0~5 #define EN_RXADDR 0x02 //接收地址允许,bit0~5,对应通道0~5 #define SETUP_AW 0x03 //设置地址宽度(所有数据通道):bit1,0:00,3字节;01,4字节;02,5字节; #define SETUP_RETR 0x04 //建立自动重发;bit3:0,自动重发计数器;bit7:4,自动重发延时 250*x+86us #define RF_CH 0x05 //RF通道,bit6:0,工作通道频率; #define RF_SETUP 0x06 //RF寄存器;bit3:传输速率(0:1Mbps,1:2Mbps);bit2:1,发射功率;bit0:低噪声放大器增益 #define STATUS 0x07 //状态寄存器;bit0:TX FIFO满标志;bit3:1,接收数据通道号(最大:6);bit4,达到最多次重发 //bit5:数据发送完成中断;bit6:接收数据中断; #define MAX_TX 0x10 //达到最大发送次数中断 #define TX_OK 0x20 //TX发送完成中断

nrf24l01使用与调试经验总结(包括一收多发)

nrf24l01使用与调试经验总结 (包括一收多发--1主机最多6从机) ---------------------------------------------------------------------------------------------------------------------------- 主要特性 工作在2.4GHz ISM 频段 调制方式:GFSK/FSK 数据速率:2Mbps/1Mbps/250Kbps 超低关断功耗:<0.7uA 超低待机功耗:<15uA 快速启动时间:<130uS 内部集成高PSRR LDO 宽电源电压范围:1.9-3.6V 数字IO 电压: 3.3V/5V 低成本晶振:16MHz±60ppm 接收灵敏度:<-83dBm @2MHz 最高发射功率:7dBm 接收电流(2Mbps):<15mA 发射电流(2Mbps):<12mA(0dBm) 10MHz 四线SPI 模块 内部集成智能ARQ 基带协议引擎 收发数据硬件中断输出 支持1bit RSSI 输出 极少外围器件,降低系统应用成本 QFN20 封装或COB 封装

注意:C代表了命令,S表示寄存器值,D表示数据 写数据:SPI写命令+寄存器地址----->SPI写入数据 读数据:SPI写寄存器地址(可以使用读命令+寄存器地址)----->SPI读取数据 不论是读取或者写入数据,甚至是读/写len长度的数据都要先写寄存器地址;

总的来说时候就三个模式: 1.待机模式(待机模式+掉电省电模式) 2.发送模式 3.接受模式 具体各个模式介绍参考数据手册。。。 ---------------------------------------------------------------------------------------------------------------- nrf发送数据是以包来发送。 其中前导码和CRC不用管。具体我们来看看中间三部分: 地址: 地址也就是接收到通道的地址,如果是能了自动应答,那么我们得将发送地址(TX_ADDR) 和 接受应答信号的通道地址(RX_ADDR_P0)设置为一样的。

关于NRF24l01的调试

NRF24l01的调试过程与方法小结 心得体会:最近老板给了几块nrf24l01模块我,初次上手难免走了许多的弯路,经过近一周的时间的不断调试,模块之间终于可以相互收发数据了。这样下来终于松了一口气。其间的各种辛苦与艰辛难于言表。上网大致看了一下,网上基于51的调试比较多,但是我们实验室用的是DSP2812,由于nrf24l01是SPI接口,2812上刚好有SPI的接口,这样貌似给使用带来了方便,但是51之类的芯片虽然没有SPI口,但是例程也最多,关于他的讨论比较多。最开始我的想法也比较混乱,想直接用SPI来调试,把底层函数稍微修改了一下,发现并没有结果,这个东西就像一个黑匣子一样,即看不见也摸不着,后来我慢慢改变了思路。既然网上基于IO口模拟的SPI的例程最多,我决定另外走一条路,先用2812的IO 口模拟SPI再用自带的SPI口去调试。这样一来我就有了两条可以走的路。 第一条:底层SPI时序用IO口模拟去写。 第二条:底层直接用2812的SPI去操作。 虽然这样一来,路好走了一点,有各类的程序可以参考,但是这样带来最大的一个问题,这也是后来我才发现的,nrf24l01的最大读写速率是有限制的,2812在150M运行时很显然是太大了一点,由于nrf24l01对时序的要求很高,端口的读写速率和时序都有严格的要求,所以我们才看到,在网上一般是15M左右的单片机来模拟IO口,没有谁用150M的DSP来模拟IO口的,当然既然确定了这样的方法后来也发现了问题,我还是继续走下去了。很重要的一点是系统的时钟频率。当然时序的要求也很高,这也就是为什么,网上说这个模块不好调试的原因,既然是调试,当然我们既然是调试,肯定有一个思路和方法。那么方法是什么呢?开始的时候我是一股脑将发送和接收的程序都写进去,然后啥现象也没有,然后就傻眼了。在网上看了看,于是有了一点思路。 方法是将发送和接收的调试分开来调试,以读取nrf24l01内部的寄存器为手段,先调试发送方,发送方调试没有问题以后,让发送方不断的发送数据,然后再来调试接收方,直到接收方也没有问题,再接着望下面去做。 秉着这样的一个想法,我开始了调试。 这里我只对一对一的调试进行说明,后续的一对多,以及调频之类虽然我有了想法,但是还没有开始实施。在开始调试之前建议将NRF24l01说明书读个三遍。 模块的外部端口 XL24LD01 是采用挪威N O R D I C 公司的n r f 2 4 L 0 1 2.4G 无线收发IC 设计的一款高性能2.4G无线收发模块,采用GFSK 调制,工作在2400‐2483M 的国际通用ISM 频段,最高调制速率可达2MBPS。XL24L01-D01 集成了所有与RF 协议相关的高速信号处理部分,如:自动重发丢失数据包和自动产生应答信号等,模块的SPI 接口可以利用单片机的硬件SPI 口连接或用单片机的I/O 口进行模拟,内部有FIFO 可以与各种高低速微处理器接口,便于使用低成本单片机。

NRF24L01配置说明

USB串口无线模块的配置说明 带USB接口的模块直接插电脑进行配置,不带USB接口的模块得借助USB转串口进行配置;(如下图所示)

1、USB转串口模块以及带USB的无线驱动模块需要安装CH341驱动; (文件在“CH341>>DRIVER>SETUP.EXE) 2、波特率默认设置为9600(带USB与不带USB的),波特率的选择范围为: 2400-115200,具体,请看配置参数对应的描述; 3、配置时,必须在断电的情况下,插上跳线帽,再从新上电;(注意:不能上 着电的情况下,插跳线帽!) 4、配置完成之后,必须得把跳线帽拔掉;(注意:必须得在断电的情况下拔, 然后,再重新上电!) 5、配置的格式为8个字节: “0X00+每个数据包的长度+0X01+频道+0X02+工作模式+单向/双向运行模式+‘波特率’” 注意: 1、必须插上跳线帽进行配置,配置完之后,必须拔掉跳线帽才能正常使用;(配 置时,在上电前就得插上跳线帽;当然,正常使用时也得在断电的情况下,拔跳线帽,再重新上电) 2、串口调试助手发送数据的格式为:十六进制;

3、USB转串口模块的TX,RX与NRF24L01驱动模块(无USB的)的TX,RX要交叉 相连,即一方的TX与另外一方的RX相连,然后,一方的RX与另外一方的TX相连; 4、两个模块的数据长度,频道得设置成一样,否则工作不正常;数据的长度选 择范围:(单向工作模式最小为1个字节,最大为32个字节)(双向工作模式最小为2个字节,最大为32个字节);频道的选择范围为:从0X00到0X7F 选择一个;(即0-127,从0开始,2的6次方) 5、同一个实验室的,为了不互相影响,得把频道设置成不一样,否则会互相干 扰,; 6、“工作模式”只分两种:TX模式(0X01)和 RX模式(0X00),注意:两个模 块的工作模式不能一样,必须得其中一个模块为TX模式,另外一个模块为RX模式,否则,不能实现两个模块的无线通信; 7、单向/双向运行模式,0X01:模块运行在双向通信模式,0X00:模块运行在 单向通信模式;双向模式相对单向模式而言,双向模式中,可以通过发送AT 指令来切换方向,具体请看双向模式的使用要求; 8、波特的选择,从小到大分别为:2400(0X07),4800(0X08), 9600(0X00), 14400(0X01), 19200(0X02), 38400(0X03), 56000(0X04), 57600(0X05), 115200(0X06); 9、数据的长度得选择适中,串口调试助手(单片机)的发送频率也得选择适中;

nRF2401A vs nRF24L01vs nRF905 vs CC1101 无线数传模块通讯距离测试[原创

nRF2401A vs nRF24L01+ vs nRF905 vs CC1101 无线数传模块通讯距离测试[原创] 1.测试准备 1.1测试环境 这次的测试环境选择了一条城区支线道路,路面不算宽共4车道。两侧有种植的树木,路灯和电线杆。选择这里主要是因为车流量少,这样可以尽量减少通行的车辆对测试结果的影响。也为人生安全提供了保障(同时也建议各位网友在进行类似的测试时也要多注意安全)。 1.2测试准备

本次测试使用2块“基于51单片机的T003无线开发测试板”作为测试主体。选用的无线输出换模块分别为工作频率为2.4GHz的nRF2401A与nRF24L01+,还有工作频率范围为433MHz的nRF905与CC1101。 为保证模块的参数一致性,每种型号均选用4个分为2组进行分组测试,所有无线模块都选配单独的外置全向胶棒天线。每个T003无线开发板均由4节AA镍氢电池提供电源。 1.3如何测试

T003无线开发测试板使用STC89C52RC作为核心,运行时分别作为发送端与接收端。发送端定时发送测试数据 ,接收端接收到数据后将数据直接回传至发送端。发送端接收数据后会对发送数据与接收数据进行比较,出现错误时按照丢包处理。同时发送端负责记录发送计数与接收成功计数。 测试中作为收发端的开发板距离地面高度均为1.5米左右,外置胶棒天线均朝向对方设备方向。 测试中的距离值使用汽车里程表作为依据。在测试前曾使用高速路的公里指示标牌对汽车的里程表进行了误差测 试,结果为百公里最大误差小于3%。 2.测试结果 2.1 nRF2401A(S001) 之前有过对nRF2401A无线数传模块的测试。nRF2401A工作于2.4GHz频段,使用GFSK调制模式,支持250kbps和1Mbps通讯速率,最大发送功率+0dBm,两个独立的数据接收通道,数据包最大长度为32Byte(含地址数据和CRC校验),支持CRC校验。关于nRF2401A的更多信息在我的其它文章中有详细的介绍。

nRF24L01调试经典

nRF24L01应用笔记(一)2011-03-31 11:15最近百度上一些朋友都在为nRF24L01头疼,我这段时间又比较忙不能花太多时间一个一个去帮忙调试,干脆今天抽点儿时间写个应用笔记,希望能给大家提供一些方法和帮助。有问题可以跟帖留言,我看到会尽量帮大家。 nRF24L01是Nordic公司生产的一个单芯片射频收发器件,是目前应用比较广泛的一款无线通讯芯片,具体手册资料网上大把,我就不再重复它的特性什么的了,直接说说它的调试方法,供大家参考。 24L01是收发双方都需要编程的器件,这就对调试方法产生了一定的要求,如果两块一起调,那么通讯不成功,根本不知道是发的问题还是收的问题,不隐晦的说,我当时也是没理清调试思路才浪费了大半天时间看着模块干瞪眼。正确的方法应该是先调试发送方,能保证发送正确,再去调接收,这样就可以有针对性的解决问题。 至于怎么去调发送方,先说下发送方的工作流程: ·配置寄存器使芯片工作于发送模式后拉高CE端至少10us ·读状态寄存器STATUS ·判断是否是发送完成标志位置位 ·清标志 ·清数据缓冲 网上的程序我也看过,大多都是成品,发送方发送-等应答-(自动重发)-触发中断。可是这样的流程就已经把接收方给牵涉进来了,就是说一定要接收方正确收到数据并且回送应答信号之后发送方才能触发中断,结束一次完整的发送。可是这跟我们的初衷不相符,我们想单独调试发送,完全抛开接收,这样就要去配置一些参数来取消自动应答,取消自动重发,让发送方达到发出数据就算成功的目的。 SPI_RW_Reg(WRITE_REG + EN_AA, 0x00); //失能通道0自动应答 SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x00); //失能接收通道0 SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x00); //失能自动重发 (注:以下贴出的寄存器描述由于中文资料上有一个错误,故贴出原版英文资料) 有了以上这三个配置,发送方的流程就变成了发送-触发中断。这样就抛开了接收方,可以专心去调试发送,可是怎么样才知道发送是否成功呢,要用到另外两个寄存器,STATUS 和FIFO_STATUS。 这样就很清晰了,我们可以通过读取STATUS的值来判断是哪个事件触发了中断,寄存器4、5、6位分别对应自动重发完成中断,数据发送完成中断,数据接收完成中断。也就是说,在之前的配置下,如果数据成功发送,那么STA TUS的值应该为0x2e。这样就可以作为一个检测标准,另外一个标准可以看FIFO_STA TUS寄存器,第5位的描述:发送缓冲器满标志,1为满,0为有可用空间;第4位的描述:发送缓冲器空标志,1为空,0为有数据;同样可以看到接收缓冲器的对应标志。这样在数据发送成功后,发送寄存器当然应该是空的,接收缓冲因为在之前已经失能,所以也应该是空,也就是说成功发送之后的FIFO_STATUS寄存器值应该是0x11。 有了这两个检测标准,我们即使不用接收方也可以确定发送方是否成功发送。当发送方调试成功之后,在程序里让它一直发送,然后我们就可以去调试接收方,思路是一样的,同样说下接收方工作流程先。

nRF24L01无线通信模块使用手册12要点

nRF24L01无线通信模块使用手册12要点nRF24L01是一种常用的无线通信模块,广泛应用于无线遥控、智能家居、物联网等领域。本文主要介绍nRF24L01无线通信模块的使用手册12要点。 1. 硬件连接 将nRF24L01模块插入Arduino板的SPI接口上,然后将CE、CSN、SCK、MOSI、MISO分别连接到Arduino板的Digital口上。 2. 初始化模块 在使用nRF24L01模块之前,必须对其进行初始化,在初始化代码中需要指定通信频率、发射功率、数据通道等等。 3. 设置通信频率 nRF24L01可以在2.4GHz频段内进行无线通信,可以通过设置通信频率来避免干扰。通信频率的设置需要与对方设备的频率相匹配。 4. 设置发射功率 nRF24L01具有多个发射功率级别,选择发射功率级别需要权衡通信距离和电池寿命。 5. 设置数据通道 nRF24L01具有多个数据通道,可以在多个设备之间相互独立传输数据。 6. 选择传输模式 nRF24L01可以选择多种不同的传输模式,包括单向、双向、广播等。 7. 发送数据 使用nRF24L01发送数据时,需要将数据写入到缓冲区中,并指定接收方的地址。 8. 接收数据 使用nRF24L01接收数据时,需要将接收方的地址写到接收方地址寄存器中,然后从缓冲区中读取数据。

9. 检查模块状态 使用nRF24L01时需要进行状态检查,可以检查发送、接收、空闲、数据发送 完成等等状态。 10. 错误处理 在进行nRF24L01通信时,可能会发生各种各样的错误,需要进行错误处理。 11. 调试技巧 在进行nRF24L01调试时,可以使用串口进行调试,输出各种调试信息。 12. 应用注意事项 在进行nRF24L01的应用时,需要注意如下事项:避免干扰、选择合适的电源、防止数据丢失等等。 以上为nRF24L01无线通信模块使用手册12要点,希望对大家有所帮助。

NRF24L01通道使用(DOC)

网上面关于多通道通信的好多资源都可以去共享,我也下了好多去调试,结果发现基本上都是调不通的。其实这个归根到底还是一个地址匹配问题,通道0和1还好说,它是默认开启的,一般没问题,但通道2至5,通道如何匹配,数据手册上也只是说地址要匹配,到底要怎么做它没讲。下面什么都不说了,直接上程序,这是用PIC16F877A来控制的,我会把要注意的重点标记出来,当然主要是多通道地址匹配的,其它的我就不多说了自己领悟。 接收部分: #include //调用头文件,可以去PICC软件下去查找PIC16F88X单片机的头文件 __CONFIG(XT&WDTDIS&LVPDIS&BORDIS); //定义配置字,晶振类型:XT,关闭开门狗,禁止低电压编程,禁止欠压复位#define u8 unsigned char #define u16 unsigned int #define BUZZER RB1 u8 i=0,a=0,data[13]=0; #define NRF24L01_MISO RC4 #define NRF24L01_MOSI RC5 //输出 #define NRF24L01_SCK RC3 //输出 #define NRF24L01_CE RC0 //使能控制设为输出#define NRF24L01_CSN RC2 //片选控制设为输出 #define NRF24L01_IRQ RC1 //中断标志设为输入 #define RS RE0 #define RW RE1

#define E RE2 unsigned char SPIx_ReadWriteByte(unsigned char byte) { unsigned char data; SSPBUF=byte; do { ; }while(SSPIF==0); SSPIF=0; data=SSPBUF; return(data); // return read byte } //24L01操作线 //#define NRF24L01_CE PAout(4) //24L01片选信号 //#define NRF24L01_CSN PCout(4) //SPI片选信号 //#define NRF24L01_IRQ PCin(5) //IRQ主机数据输入 #define READ_REG 0x00 //读配置寄存器,低5位为寄存器地址 #define WRITE_REG 0x20 //写配置寄存器,低5位为寄存

NRF24L01调试方法及经验总结

NRF24L01 :在通信中的应用方法,经验总结〔1〕 2021-07-31 13:15 首先说一下: 单片射频收发器件,工作于2.4 GHz~2.5 GHz ISM频段。内置频率合成器、功率放大器、晶体振荡器、调制器等功能模块,并融合了增强型ShockBurst技术,其中输出功率和通信频道可通过程序进行配置。nRF24L01功耗低,在以-6 dBm的功率发射时,工作电流也只有9 mA;接收时,工作电流只有12.3 mA,多种低功率工作模式(掉电模式和空闲模式)使节能设计更方便。 是想将这个IC调通,首先要多读一下技术文档: 下载技术文档 以下C51驱动nRF24.L01 的源代码库〔nRF24.L01.h〕 此库文件适合发送端使用,在接收端会有所不同,请看第2 局部的分析 在使用过程中,需要引用 //****************************************NRF24L01端口定义 *************************************** sbit CE =P2^0; sbit CSN =P2^1; sbit SCK =P2^2; sbit MOSI =P2^3;

sbit MISO =P2^4; sbit IRQ =P2^5; //*********************************************NRF24L01********* **************************** #define TX_ADR_WIDTH 5 // 接收地址宽度,一般设置为5 不要动它 #define RX_ADR_WIDTH 5 // 接收地址宽度,一般设置为5 不要动它 #define TX_PLOAD_WIDTH 1 //接收数据的数据宽度〔最大为32 字节〕,这里我设置为最小的1 字节,方便调试 #define RX_PLOAD_WIDTH 1 //发送数据的数据宽度〔最大为32 字节〕,这里我设置为最小的1 字节,方便调试 uchar const TX_ADDRESS[TX_ADR_WIDTH]= {0x35,0x43,0x10,0x10,0x03}; // 这里就是设置了5 个字节的本地地址 /* 此处的地址:在IC内部真实地址是反过来的。即:address = 0310104334 在数据发送时,发送到对方去的数据包括:数据本身+本地地址。与接收地址无关。 */ uchar const RX_ADDRESS[RX_ADR_WIDTH]= {0xEF,0xEF,0xEF,0xEF,0xEF}; //接收地址 /* 是指接受来自于发送方的地址〔指发送方的本地地址〕,但在自动模式下,得到的应答信息

基于51单片机和NRF24L01的无线温度监控教材

单片机C 语言课题设计报告 设计题目:远程无线温度监测 指导老师:施 芸老师 设 计 人:张登翔 学 号:201212020216 班 级:2012级电子信息1班 设计时间:2014.5.17~ 2014.6.19

四川工程职业技术学院 电气系2012级电子信息一班 张登翔 201212020216 登临对晚晴 翔云列晓阵 1 摘要 本课题以51单片机为核心实现智能化远程无线温度监控。利用18B20温度传感器获取温度信号,将需要测量的温度信号自动转化为数字信号,通过无线模块NRF24L01一对一传送将数据传送到接收机,最终单片机将信号转换成LCD 可以识别的信息显示输出。 基于STC89C52RC+NRF24L01+LCD1602的单片机的智能远程无线温度监控系统,设计采用18B20温度传感器,其分辨率可编程设计。本课题设计应用于温度变化缓慢的空间,综合考虑,以降低灵敏度来提高显示精度。设计使用12位分辨率,因其最高4位代表温度极性,故实际使用为11位半,而温度测量范围为-55℃~+125℃,则其分辨力为0.0625℃。 设计使用LCD1602显示器,可显示16*2个英文字符,显示器显示实时温度和过温警告信息。报警采用蜂鸣器加LED 组成的声光电报警。

单片机C语言课题设计报告指导老师:施芸 目录 一、设计功能 (3) 二、系统设计 (3) 三、器件选择 (4) 3.1温度信号采集模块 (4) 3.2 液晶显示器1602LCD (9) 3.3 无线NRF24L01 (11) 四、软件设计 (11) 4.1 程序设计流程图................... 错误!未定义书签。 五、设计总结 (21) 六、参考文献 (22) 七、硬件原理图 (22) 八、程序清单 (23) 没有天生的聪明只有不懈的努力 2

无线通信下配网终端手持式调试仪探析

关键词:配网自动化;配网终端调试仪;FTU设计;配电终端测试 1概述 随着智能电网的发展,应用智能化、自动化技术提高电力系统配网的运行稳定性、用户的用电可靠性已是电力行业发展的必然途径。其中,配网自动化技术的应用是重要一环。配网自动化可以利用先进的自动控制技术、计算机通信技术、电子技术等技术,实现在线实时监管,实时收集配电网运行数据,掌握电网结构参数等信息集成,并构建完整的自动化电力管理系统[1]。配网自动化系统一般采用分布式结构,依靠通信网络将配网主站、子站和终端连接起来,构成一个完整的系统。配网自动化主站是配网监控和管理系统的核心,实现对整个配电网的监视、控制和有效管理,从而使配电网处于最优运行状态;配网子站起到一个上传下达的沟通作用,采用多种通信方式向上与配网主站通信、向下与所属配网终端通信;配网终端设备是配网自动化系统的最底层,主要负责柱上开关、配电变压器、环网柜、开闭所等一次设备运行状态信息的采集、处理及对一次设备的控制等功能。馈线自动化终端(FTU)大多安装于户外杆塔上,采用串口或以太网调试,给运维人员进行设备调试、参数整定、程序更新等工作带来很大不便。目前,市面上有的配电终端测试设备,如配电之星P-2200A2配电自动化终端测试仪,可对配电自动化终端(FTU、DTU、TTU、故障指示器)及馈线自动化(FA)进行全功能测试,其具有简洁直观的操作界面,丰富全面的测试功能,稳定高效的硬件平台,整机设计便携耐用。该测试仪提供网口,串口,USB,GPS,WiFi等多种通讯接口。本文探讨了一种手持式的配电终端的调试仪器,采用调试仪与配网终端进行调频配对,从而达到无线传输通信,能与配网终端进行规约测试和保护整定值下发等功能,具有成本低廉、携带方便、简单易用等特点,非常适合作为配电终端的调试手段。 2手持式调试仪硬件设计 2.1整体硬件结构(图1) 本次调试仪选用ALIENTEK探索者STM32F407ZGT6作为控制芯片,探索者STM32F407是正点原子推出的一款基于ARMCortex-M4内核的开发板,自带1M字节FLASH,并外扩192K 字节SRAM,满足基本的内存需求。时钟最高主频为168Mhz,可以保障控制算法的执行速度和代码效率。该开发板具有丰富的板载资源,开发板上现有114个IO口,其中通信接口多达17个,可以进行以太网、CAN、SPI、串口等方式通信,方便进行各种外设开发。例如,我们在原有开发板的基础上,插入无线通信模块NRF24L01卡,充分发挥了开发板的无线通信功能。另外,本次调试仪选用一块10000mA的充电宝作为电源,再经过电压电流变换转换为开发板STM32正常的工作电压、电流。放置在调试仪手柄内,节省空间。整个调试仪采用塑料外壳封装,防摔、防水,便于携带。 2.2无线通信模块(图2) 无线通信模块即NRF24L01是NORDIC公司生产的一款无线通信通信芯片,采用FSK调制,内部集成NORDIC自己的EnhancedShortBurst协议。可以实现点对点或是1对6的无线通信。无线通信速度可以达到2M(bps)。NORDIC公司提供通信模块的GERBER文件,可以直接加工生产。嵌入式工程师或是单片机爱好者只需要为单片机系统预留5个GPIO,1个中断输入引脚,就可以很容易实现无线通信的功能,非常适合用来为MCU系统构建无线通信功能。NRF24L01的工作模式有四种:收发模式、配置模式、空闲模式、关机模式,本文设计的手持式配电终端调试仪主要采用这四种工作方式中的收发模式。NRF24L01的所有配置工作都是通过SPI完成,共有30字节的配置。我们将NRF24L01工作于EnhancedShockBurstTM收发模式。ShockBurstTM的配置字可以分为数据宽度、地址宽度、地址、CRC四个部分,能使NRF24L01能够处理射频协议,在配置完成后,NRF24L01工作的过程中,只需改变其最低一个字节中的内容,以实现接收模式和发送模式之间切换。这种工作模式下,系统的程序编制会更加简单,并且稳定性也会更高。

基于nRF24L01的远程温度检测系统大学本科方案设计书

摘要 温度检测在日常生活、工作和工程实践中具有重要的应用。随着生活水平的提高和科学技术的进步,无论是工业还是农业或者是日常生活中对温度检测的要求越来越高。不仅要做到低耗,还要求进行一定距离的传输。基于这点我们运用两片主控芯片,一个温度传感器,及数码管显示部分,解决了这个日常生活工作中的问题。出于低功耗本设计我们选择了以低功耗见长的430单片机中的F149系列作为主控芯片,工作场所的温度采集用到了温度采集芯片DS18B20来达到一定的准确度和精确度,最后采用nRF24L01模块对采集到的温度数据进行无线传输,从而打破传统温度操作受到距离限制的缺陷。在经过软硬件测试后,我们基本实现了用温度传感器采集温度,用nRF24L01进行一定距离传输后在接受端的数码管上显示出来的模型。传输距离>30m,温度范围达到0至125摄氏度,精度1摄氏度。 关键词: msp430f149;nRF24L01;温度;无线传输

ABSTRACT Temperature measurement have important applications in daily life,work and engineering practice.With the improvement of living standards and technological progress,whether industry,agriculture or daily life become increasingly demanding of temperature detection. Not only to achieve low power consumption,but also requires a certain distance transmission. For this reason we solved the problem of daily life and work using two control chips, a temperature sensor, and the led display part. For low-power design we have chosen the low-power microcontroller known for the F149 series of 430 as the master chip, temperature acquisition DS18B20 has used to achieve a certain accuracy and precision, Finally nRF24L01 module temperature data collected by wireless transmission, thus breaking the distance limitations of traditional temperature operation. After software and hardware testing, we basically realize our Initial target. Transmission distance>30m, temperature range 0 to 125 degrees, 1 degree accuracy. Keywords: msp430f149;nRF24L01;Temperature;Wireless

相关主题