发表于:2010/12/30 23:52:49
#0楼
ce:使能发射或接收;
csn,sck,mosi,miso:spi引脚端,微处理器可通过此引脚配置nrf24l01:
irq:中断;
vdd:电源输入端;
vss:电源地:
xc2,xc1:晶体振荡器引脚;
vdd_pa:为功率放大器供电,输出为1.8 v;
ant1,ant2:天线接口;
iref:参考电流输入
使用io[/b]口模拟spi[/b],以龙丘科技的无线模块为例,使用m[/b]口模拟spi[/b]可如下定义[/b]
#define nrfirq ptm_ptm0[/b]
#define nrfce ptm_ptm1[/b]
#define nrfmiso ptm_ptm2[/b]
#define nrfcsn ptm_ptm3[/b]
#define nrfmosi ptm_ptm4[/b]
#define nrfsck ptm_ptm5[/b]
由图可知,发送时高位在前,低位在后,每写一个bit,返回一个状态字位,每次写操作都可读回一个完整的状态字。
以下是读回的状态字
status(地址:0x07)
保留
rx_dr
tx_ds
max_rt
rx_p_no
tx_full
rx_dr: 接收数据准备好,接收缓冲区有新的数据到达时被置为1,向该位写1可清除该位
tx_ds: 缓冲区数据被发送完后被置为1,如果自动应答启用的话,只有在对方应答到达后才会置1,向该位写1可清除该位
max_rt: 若没有收到对方确认,24l01会自动超时重传,当到达最大重传次数后,该位被置1,向该位写1可清除该位。若不清除该位则无法进一步通信。
rx_p_no: 3bit,表示正在读取缓冲区数据载荷的数据管道编号。000~101:数据管道编号。
110:没有使用
111:接收缓冲区空
ps[/b]:接收到新数据,数据发送完毕,重传到达最大次数都会引起中断,通过读取状态字可查询中断事件。[/b]
中断由irq[/b]引脚低电平触发。[/b]
spi写模式
/********************************************************************
spi读写函数
写入一个字节并返回一个字节
ch:需要写入的字节
*********************************************************************/
unsigned char spi_byte_rw(unsigned char ch)
{
unsigned char i;
for(i=1;i
{
if(ch&0x80)//如果ch最高位为1
nrfmosi=1;
else
nrfmosi=0;
nrfsck=1;//时钟置高
ch左移一位
_asm(nop);
_asm(nop);
nrfsck=0;//时钟置低
ch|=nrfmiso;
}
return(ch);
}
解释:
1、 该函数作用为一次spi数据交换,将ch中一个字节数据按照高位在前低位在后的顺序串行发送,每发送一个bit都读回一个bit,8个比特发送完毕,同时也和24l01完成一次数据交换。
2、 该函数是spi通信的基本函数
3、 注意spi通信中,可以一次读取或写入多个字节,顺序为低字节在前,高字节在后,每个字节是高位在前,低位在后。
4、 参考spi时序图,可见,上升沿写入1个bit,下降沿读入一个bit。
5、 该spi通信函数只涉及一个字节的读写,没有涉及cs信号线。
spi_byte_rw()函数应用举例,一次写入多个字节
/************************************************************************************************
函数:byte spi_write_buf(byte reg, byte *pbuf, byte len)
功能: 用于写数据:为寄存器地址,pbuf:为待写入数据地址,len:写入数据的个数
************************************************************************************************/
byte spi_write_buf(byte reg, byte *pbuf, byte len)
{
byte status,cnt;
nrfcsn = 0; //spi使能
status = spi_byte_rw(reg); //第一个字节返回状态字
for(cnt=0; cnt
spi_byte_rw(*pbuf++);
nrfcsn = 1; //关闭spi
return(status); //
}
ps:该函数完成多个字节的写入,返回状态字
本函数举例:
例:我们要设置本机地址,24l01的地址为5个字节,假设地址放在一个5字节的数组中
byte const tx_address[tx_adr_width]= {0x34,0x43,0x10,0x10,0x01}; //本地地址
写寄存器的指令字为001a aaaa, aaaaa用于表示写入的寄存器地址,各个寄存器地址可查阅数据手册
tx_addr寄存器在24l01中的地址为00010000,那么完整的指令字应该为00110000,可用如下定义和调用方法
//***********************nrf24l01指令字*******************************************************
#define read_reg 0x00 // 读寄存器指令
#define write_reg 0x20 // [/b]写寄存器指令[/b]
#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 // [/b]发送地址寄存器[/b]
#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栈入栈出状态寄存器设置
可用以下语句调用
spi_write_buf(write_reg + tx_addr, tx_address, tx_adr_width); // 写本地地址
24l01被设置为接收模式后,可通过6个不同的数据通道(data pipe)接收数据。每个数据通道都有一个唯一的地址但是各数据通道的频率是相同的。这意味着可以有6个被配置成发送状态的nrf24l01可以和一个配置成接收状态的nrf24l01通信,并且接收方可以区分。数据通道0有一个唯一的40bit的可设置的地址。其余的通道1到通道5则地址前32位相同,而后8位不同。所有的数据通道都可以实现enhanced shockburst模式。
nrf24l01使用数据通道的地址对接收的包进行确认。这意味着24l01在返回ack的时候使用相同的地址。在发送端,数据通道0被用来接收确认信息,因此通道0的地址必须等于发送地址,这样才能收到确认信息。
当一个24l01发送结束后,它会打开接收器并等待确认。如果没有收到确认,则重发,直到收到确认。当重发超过一定次数则发出中断并改变状态寄存器。重发次数的限制在setup_retr_arc寄存器中设置。
无论何时收到确认,都会认为上一个数据包发送成功,这个数据包将被从发送缓冲区清除,并且把tx_ds irq置为高。
每次开始spi写,读回来的都是状态字。
射频收发工作在2.4~2.4835g
收发共用天线接口
gfsk调制
250k,1m,2m的空中速率
发射输出功率最高0dbm,即1mw
6路1对6星型网络(使用6个data pipe)
增强型shockburst包格式
前置域1byte
地址域3-5byte
包控制域9bit
载荷0-32字节
crc1-2字节
地址域是接收机地址
包控制域
载荷长度6bit
pid2bit
no_ack1bit
载荷长度6bit说明最多32字节
pid用于包编号,用于确定是重发包还是新包
no_ack用于表示是否自动应答,如为1则表示无需自动应答
自动应答的延时和重发次数是可编程的。
/********************************************************************************/
/*函数:void setrx_mode(void)
/*功能:数据接收配置
/********************************************************************************/
void setrx_mode(void)
{
nrfce=0;
spi_rw_reg(write_reg + config, 0x0f); // irq收发完成中断响应,16位crc ,主接收
nrfce = 1;
dly_10us(15); //old is 130
}
将00001111写入config寄存器
以下是config寄存器说明
保留,为0
mask_rx_dr
mask_tx_ds
mask_max_rt
en_crc
crco
pwr_up
prim_rx
mask_rx_dr 和mask_tx_ds和mask_max_rt 主要用于设置status寄存器中的这三位表示的事件发生时 是否通过irq引脚来反映,1,不反映在irq上,0反映在irq上。
en_crc:1,启用crc校验,0不启用
crco:0:1个字节crc,1:两个字节crc
pwr_up:1:powerup 0:powerdown
prim_rx:1:prx 0:ptx
24l01的工作模式和寄存器及io口的关系如下
ce引脚的作用
增强型shockburst模式时序图
一个esb(enhanced shockburst)周期,发送一个字节连带收到ack大约339us
从powerdown状态需要先进入standyby状态,该状态转换需要1.5ms延迟,从standyby状态进入rx/tx状态,需要130us
置高ce维持最少10us,启动enhanced shockburst发射
直接传送模式发送
1.config寄存器:地址00
保留,为0
mask_rx_dr
mask_tx_ds
mask_max_rt
en_crc
crco
pwr_up
prim_rx
mask_rx_dr 和mask_tx_ds和mask_max_rt 主要用于设置status寄存器中的这三位表示的事件发生时 是否通过irq引脚来反映,1,不反映在irq上,0反映在irq上。
en_crc:1,启用crc校验,0不启用
crco:0:1个字节crc,1:两个字节crc
pwr_up:1:powerup 0:powerdown
prim_rx:1:prx 0:ptx
2.en_aa寄存器:地址01
保留,0
保留,0
enaa_p5
enaa_p4
enaa_p3
enaa_p2
enaa_p1
enaa_p0
是否启用各data pipe的自动应答功能,1启用,0,不启用,复位默认为启用
3. en_rxaddr寄存器:地址02
保留,0
保留,0
erx _p5
erx _p4
erx _p3
erx _p2
erx _p1
erx _p0
是否启用各data pipe, 1启用,0,不启用,复位为00000011,即默认启用datapipe1和datapipe 0
4. setup_aw寄存器:地址03
保留,0
保留,0
保留,0
保留,0
保留,0
保留,0
aw1
aw0
地址宽度,所有data pipe 都一样
aw1,aw0=00,非法,01,3字节地址,10,4字节地址,11,5字节地址,默认为11,即5字节地址
5. setup_retr寄存器:地址04(设置自动重传参数)
ard(复位为0000)
arc(复位为0011)
ard=0000,重传间隔为250+86us
0001,重传间隔为500+86us
…………………………….
1111, 重传间隔为4000+86us
arc=0000,禁止自动重传
0001,重传1次
……………………………..
1111,重传15次
6. rf_ch寄存器:地址0x05,设置频道
保留,0
rf_ch
7个bit用于设置通信频道,共126个频道,复位为00000010,频道2
7. rf_setup寄存器:地址0x06
保留,0
保留,0
保留,0
pll_lock
rf_dr
rf_pwr
lna_hcurr
pll_lock:
rf_dr:速率,0:1m 1:2m
rf_pwr:00 18dbm
01 12dbm
10 6dbm
11 0dbm
8. status寄存器:地址0x07
保留 0
rx_dr
tx_ds
max_rt
rx_p_no
tx_full
rx_dr: 接收数据准备好,接收缓冲区有新的数据到达时被置为1,向该位写1可清除该位
tx_ds: 缓冲区数据被发送完后被置为1,如果自动应答启用的话,只有在对方应答到达后才会置1,向该位写1可清除该位
max_rt: 若没有收到对方确认,24l01会自动超时重传,当到达最大重传次数后,该位被置1,向该位写1可清除该位。若不清除该位则无法进一步通信。
rx_p_no: 3bit,表示正在读取缓冲区数据载荷的数据管道编号。000~101:数据管道编号。
110:没有使用
111:接收缓冲区空
ps:接收到新数据,数据发送完毕,重传到达最大次数都会引起中断,通过读取状态字可查询中断事件。
中断由irq引脚低电平触发。
9. observe_tx寄存器:地址0x08(发送观察寄存器,用于观察发送状态)
plos_cnt
arc_cnt
plos_cnt:丢包计数器,最大到15,写rf_ch寄存器可清除计数值
arc_cnt:重发次数计数
10. cd寄存器:地址0x09(载波检测寄存器)
保留 0
保留 0
保留 0
保留 0
保留 0
保留 0
保留 0
cd
cd:检测到载波则置1,否则为0
11. rx_addr_p0寄存器:地址0x0a(data pipe 0接收地址)
共5个字节,低字节在前,高字节在后默认为0xe7e7e7e7e7
12. rx_addr_p1寄存器:地址0x0b(data pipe 1接收地址)
共5个字节,低字节在前,高字节在后默认为0xc2c2c2c2c2
13. rx_addr_p2寄存器:地址0x0c(data pipe 2接收地址)
共5个字节,低字节在前,高字节在后0xc2c2c2c2c3
14. rx_addr_p3寄存器:地址0x0d(data pipe 3接收地址)
共5个字节,低字节在前,高字节在后0xc2c2c2c2c4
15. rx_addr_p4寄存器:地址0x0e(data pipe 4接收地址)
共5个字节,低字节在前,高字节在后0xc2c2c2c2c5
16. rx_addr_p5寄存器:地址0x0f(data pipe 5接收地址)
共5个字节,低字节在前,高字节在后0xc2c2c2c2c6
17. tx_addr寄存器:地址0x10(发送地址寄存器,对发送端而言,相当于源地址,也是接收端发回确认的目的地址)
共5个字节,默认为0xe7e7e7e7e7
18. rx_pw_p0寄存器:地址0x11
保留 0
保留 0
rx_pw_p0
rx_pw_p0:data pipe0 的接收数据载荷长度
0:非法
1:1个字节
…………………..
32:32个字节
19. rx_pw_p1寄存器:地址0x12
保留 0
保留 0
rx_pw_p1
rx_pw_p1:data pipe1 的接收数据载荷长度
0:非法
1:1个字节
…………………..
32:32个字节
20. rx_pw_p2寄存器:地址0x13
保留 0
保留 0
rx_pw_p2
rx_pw_p2:data pipe2 的接收数据载荷长度
0:非法
1:1个字节
…………………..
32:32个字节
21. rx_pw_p3寄存器:地址0x14
保留 0
保留 0
rx_pw_p3
rx_pw_p3:data pipe3 的接收数据载荷长度
0:非法
1:1个字节
…………………..
32:32个字节
22. rx_pw_p4寄存器:地址0x15
保留 0
保留 0
rx_pw_p4
rx_pw_p4:data pipe4 的接收数据载荷长度
0:非法
1:1个字节
…………………..
32:32个字节
23. rx_pw_p5寄存器:地址0x16
保留 0
保留 0
rx_pw_p5
rx_pw_p5:data pipe5 的接收数据载荷长度
0:非法
1:1个字节
…………………..
32:32个字节
24. fifo_status寄存器:地址0x17
保留 0
tx_reuse
tx_full
tx_empty
保留 0
保留 0
rx_full
rx_empty
tx_reuse:
enhanced shockburst™ 模式下发送数据流程
1. 配置config寄存器,将prim_rx置为0,表示发送模式
2. 当需要发送数据时,首先需要配置地址tx_addr,这个地址应该是接收端地址,即应该是接收端6个data pipe地址中的一个即可保证对方收到。如果要使用自动应答,当对方进行自动应答时也会使用这个地址,应答消息由发送端的datapipe0接收,所以发送的datapipe0的地址应等于tx_addr,若需要自动应答则。(若是和上一次发送是相同地址,则可不用重写地址)
3. 配置tx_pld,将需要发送的数据送入nrf24l01,通过spi连续写入数据载荷时,nrf24l01将自动对字节数计数。(数据载荷必须在cs为低的时候连续写入)
4. 将ce置高并维持最少10us,这个脉冲将启动shockburst发送
5. nrf24l01:
a) 打开射频
b) 启动晶振
c) 数据打包
d) 发送
6. 如果启动了自动应答(且重传次数未达到最大值),nrf24l01将自动转入接收状态。若在规定时间内收到了应答包,则这是一次成功的发送,tx fifo中的数据被清除,同时置高status寄存器中的tx_ds位。如果在规定时间内未收到应答包则自动重传(当启用自动重传时,由setup_retr寄存器中的arc位指定重传次数)。当重传次数到达最大值依然没有收到应答,则status寄存器中的max_rt被置高,tx fifo缓冲区中的数据并不被移除。max_rt 或 tx_ds被置高都会在irq引脚上引起中断(低电平有效,重写status寄存器中的对应位可清除)。在到达最大重传次数并引发中断后,在没有清除max_rt之前,任何数据都不能发送。每次发生max_rt 中断,plos_cnt计数器都会加1,用于统计丢包数。
7. ce置低以后,设备进入standby_i状态。否则tx fifo缓冲区中的下一个数据载荷将被发送。如果数据缓冲区空,而ce仍然为高,设备将进入standby-ii模式。
如果设备处于standby-ii模式,当ce置低后,设备将进入standby-i模式。
(standby模式可减少电流的消耗,在该模式下,spi通信仍然可以完成)
enhanced shockburst™ 模式下接收数据流程
1. 设置config寄存器中的prim_rx为1,且置ce为高
2. 130us之后,nrf24l01开始监视射频信号
3. 当合法的包被接收到(地址匹配),数据被存储到rx-fifo缓冲区中,status寄存器中的rx_dr被置高,irq引脚同时发出中断信号(如果未屏蔽该信号)。status寄存器中的rx_p_no指示这个应该接收该数据的data pipe号。
4. 如果自动应答启用的话,一个应答信号将被发出
5. mcu将ce置为低将进入standby-i模式
6. mcu可通过spi读出接收到的数据
----------------------------------------------
此篇文章从博客转发
原文地址: Http://blog.gkong.com/more.asp?id=131817&Name=sfmcu