-
NRF905
程序参考教程。
本资料主要是将程序中各部分子程序的功
能与
NRF905
的手册相关联,
使得各位同仁
在每个子程序为什么这么写都在手册中找
到具体的
体现,特别是
寄存器配置
。
内涵完整
参考程序
< br>,是
100%
可用程序。
p>
硬件
的连接方法在参考程序之后,
并介绍原
理。
本人
最后只是为了提供给大家一个入门的
资料或是引子罢了,
至于如
何应用的巧妙那
是后期编程巧妙的结果,
目前只是给刚进门
p>
的人士一个可以快速理解和掌握的浅显易
懂的教程罢了。本人疏忽之
处还请见谅。
按照惯例先展示作品抛砖引玉:
四路
AD
采集
+
温度采集
彩屏显示信息数据
GSM
手机电话
p>
最近做的,
音频功放四路电机控制大功率
l
ed
控制,
不解释。
以前做的,舵机和摄像头,不解释。
更早先的,
VGA
< br>显示,不解释。
已发送为例子。
1.
通过
spi
接口把寄存器相应的值写到
905
中
2.
把要发的数据写到
905
中
3.
把状态设置成发送
4.
数据被发出
那么操作
905
就主要是前三步的问题,
那么请带个这前三个
问题深入理解
下面的相关解释了。
无线通信模块的三个要素:
Nrf905
模式的配置
Nrf905
通过寄存器配置
Nrf905
需要
spi
通信配置寄存器
先看模式配置:程序加解释
PWR_UP
0
1
1
1
TRX_CE
X
0
1
1
TX_EN
X
X
0
1
操作模式
断电和
< br>SPI
编程
待机和
SPI
编程
射频接收模
式
射频发送模
式
根据这个图表,我们发觉有
四种模式
。捡重点的说
实现收发
功能有两种模式。
这两种模式在程序段中的实现是:
设置成接受模式,程序中没写
PWR_UP
,如果他是低电平
就变成断电,所以个程序段默认
PWR_
UP
为高电平。
void
SetRxMode(void)
{
TXEN=0;
TRX_CE=1;
Delay(1);
//
delay
for
mode
change(>=650us)
}
设置发送模式,这里会有疑问,在于
TRX_CE=0;
。这里给出的解
释是,如果我们直接写
p>
TRX_CE=1
;这样模块立即将其内
部所写好
的数据发送出去。
而对于编
程的人员来说编出的程序五花八门,就比如说这条,改
程序员的意图并不想让设置发送模
式时,数据就被立即发出,所以
写了
T
RX_CE=0;
。如果看后面的完整程序,你会发现在发送
时,有
TRX_CE=1
;这一步。
所以说,刚才那个图表没有问题。
这里可以认
为是准备发送模式
,而不是发送模式,一旦
T
RX_C
E=1;
那
么
数
据
立
即被发送。
void SetTxMode(void)
{
TRX_CE=0;
TXEN=1;
Delay(1);
// delay for
mode change(>=650us)
}
关于图表中前两种模式中,实例程序所应用的是第二种,即待机
spi<
/p>
编程模式。不管应用两种的哪一种,都是为了
spi
编程(通过
spi
通信配置
905
寄存器)
。
那么给出这个模式的应用程序段:
有
这
么
做
引
p>
脚
赋
予
各
种
电
平
先
不
用
管
他
< br>,
我
们
看
到
PWR=1;TRX_CE=0;TXEN=0;
这三个,在待机
spi
模式中
TXEN=x;
即可
以为任何值。说明现在是待机且<
/p>
spi
编程模式。
程序段中其他引脚功能罗列下:
<
/p>
Csn
:
spi
的有效与否的引脚,低电平有效。
如果只是单纯的设置
模式,该
引脚并没用处,只是后期程序的编写,所以做下配置。
p>
Sck
:
spi
的
时钟,现在只是设置模式,还没开始
spi
通信,所以
付个低电平。
DR
:数据是否准备好,现在没有什么可准备的。
AD
,
CD
也是一样,等到<
/p>
spi
通信的时候才需关系。这里做个引子
吧。
void
nRF905Init(void)
{
CSN=1;
// Spi disable
SCK=0;
// Spi clock line init low
DR=0;
//
Init DR for input
AM=0;
// Init AM for input
CD=0;
// Init CD for input
PWR=1;
// nRF905 power
on
TRX_CE=0;
//
Set nRF905 in standby mode
TXEN=0;
// set radio in Rx mode
}
Nrf905
寄存器的配置
配置
905
寄存器的意思是,通过
spi
传输一个值,放入
905
的寄
存器中,这个值可以让
905
传输数据时,产生各种你想要的效果,
类似于你用手调节耳机音量,你的手就相当于配置
耳机的寄存器。
那么我先给出主要需配置的寄存器然后再解释
.
如下面这个程序段:
unsigned char idata RFConf[11]=
{
0x00,
//
配置命令
//
0x4c,
//CH_NO,
配置频段在
430MHZ
0x0c, //
输出功率为
10db,
不重发,节电为正常模式
0x44, //
地址宽度设置,为
p>
4
字节
0x04,0x04, //
接收发送有效数据长度为
32
字节
0xCC,0xCC,0xCC,0xCC, //
接收地址
0x58, //CRC
充许,
8
位
CRC
校验,外部时钟信号不使能,
16M
晶振
};
0x00,
//
配置命令
//
后面的讲解中会说
,所以大家从第二个开
始看。
CH_NO
的意思如下,通过以下解
释设置不同的值,可以让
905
工作在不同频段,这个需
要的话再做详解,不需要,可以照搬默认值,或者程序。
CH_NO
9
和
<
/p>
HFREQ_PLL
一起进
行平率设置<
/p>
(
默认值
=
001101100b = 108d). fRF
= (
422.4 + CH_NOd
/10)*(1+HFREQ_PLLd)
MHz
于是乎相关的就引出以下这个寄存器
HFREQ_ PLL
1
使
PLL
工作于
433
或
868/915 MHz
模式
(
默
认值
= 0).
'0'
–
工作于
433MHz
频
段
'1'
–
工作于
868 or 915
MHz
频段
在这里给出个表格,如需更改该值可以参照:
工作频率
430.0 MHz
433.1 MHz
433.2 MHz
434.7
MHz
862.0 MHz
868.2 MHz
868.4
MHz
HFREQ_PLL
[0]
[0]
[0]
[0]
[1]
[1]
[1]
CH_NO
[001001100]
[001101011]
[001101100]
[001111011]
[001010110]
[001110101]
[001110110]
869.8 MHz
902.2
MHz
902.4 MHz
927.8 MHz
[1]
[1]
[1]
[1]
[001111101]
[100011111]
[100100000]
[110011111]
0x0c, //
输出功率为
10db,
不重发,节电为正常模式
这里做下说明:我们拆分看看这段话。
@
输出功率为
10db
@
不重发
@
节电为正常模式
输出功率为
10db
,这个对于的寄存器是:
如下表,二进制
10db
应该是
11
PA_PWR
2
输出功率
(
默
认值
= 00).
“
00
”<
/p>
-
10dBm
“
01
”
-
2dBm
“
10
< br>”
+6dBm
“11”
+10dBm
不重发,针对的寄存器是:
不管怎么
说,部分都不自动重发(一般情况)
,故
二进制是
0
AUTO_
RETRAN
1
如果
TRX_CE
和
TXEN
为高时,自动重发
(
默认
值
= 0).
'0'
–
不重发
'1'
–
数据包
重发
节电为正常模式,针对的寄存器是:
如下表,要是正常模式则二进制是
0
RX_RED_ PWR
1
接收方式节能,工作电流
1.6mA
.
灵敏度降低
(
默认
值
= 0).
'0'
–
正常工作
'1'
–
节能
模式
那么如下结论:
输出功率为
10db
--------------------11
不重发<
/p>
-----------------------------0
节电为正常模式
---------
------------0
按顺序写则是:
1100---
》
0000
1100
———》
0x0C
0x44, //
地址宽度设置,为
4
字节
如下面两个表:
< br>收地址宽度:
4
字节的
2
进制是
100
RX_AFW
3
接收地址宽度
(
默认值
=
100).
'001'
–
1 byte
RX
地址
'100'
–
4 byte
RX
地址
发
地址宽度:
4
字节的
2
进制是
100
TX_AFW
3
发送地址宽度
(default = 100)
. '001'
–
1 byte
TX
地址
'100'
–
4 byte
TX
地址
于是乎:
100
并上
100
,
< br>可认为是
0100
并上
0100
,
可认为是
4
并上
4
,
则
可
认为是
0x44.
0x04,0x04, //
接收发送有效数据长度为
32
字节
这条命令是我擅自更改的
,更改前是
2
字节,如是
0x04
p>
这是
32
字节。这样可以使
905
在一个数据包内传输更多信息。
那么我给出两个寄存器。
RX_PW
6
接收数据宽度
(
默认
=
100000).
'000001'
–
1 byte
接收数据宽度
'000010'
–
2
TX_PW
6
byte
接收数据
宽度
'100000'
–
32
byte
接收数据
宽度
发送数据宽度
(
默认
=
100000).
'000001'
–
1 byte
发送数据宽度
'000010'
–
2
byte
发送数据
宽度
.
'100000'
–
32
byte
发送数据
宽度
这里要把码补全,
10
0000
——》
0010 0000
—
—
0x40
这里实际是
0x40
一点没错但是程序中写的是
0x04
,仔细想
想,也没什么特别的
问题。这里我水平有限,不做说明了。
0xCC,0xCC,0xCC,0xCC,
//
接收地址
一看就知道,地址被从新改了下,默认地址是
E7
这种。<
/p>
RX_ ADDRESS
32
发送地址标识,使用字
节取决于
RX_AFW
(
默
认值
=
E7E7E7E7h).
0x58,
//CRC
充许,
8
位
CRC
校验,外
部时钟信号不使能,
16M
晶
振
CRC_EN
1
CRC
校验可用
(
默认值
=
1).
CRC_ MODE
1
'0'
–
不可用
'1'
–
可用
CRC
模式选择
端
(
默认值
=
1).
'0'
–
8
位
'1'
–
16
位
UP_CLK_ EN
1
输出时钟可用
(
默认值
=
1)
'0'
–
外面没有可用的时
钟信号
'1'
–
外面有可用的时钟
信号
晶振频率端,
必须与外部
的晶振频率相对应
(
默认
值
= 100).
'000'
–
4MHz '001'
–
8MHz '010'
–
12MHz
'011'
–
16MHz
'100'
–
20MHz
XOF
3
这块看着有点乱的话,请继续往后看。
我们既
然把相关寄存器的配置解释了一边,但是如果对于一个编
程序的人,或者程序开发来说,
这样的罗列虽然我们能弄懂每个寄
存器是咋回事,但是
实际编程
并自己配置寄存器的话,难度是很大
的。幸好,开发手册解决一切问题,下面是一个表,
表的后面我有
解释。
字节
0
1
寄存器内容
射频器配置寄存器(
p>
R/W
)
位内
容
[7:0],
最高有效
初始值
位
[7]
CH_NO[7:0]
0110_1100
bit[7:6] not used,
0000_0000
AUTO_RETRAN,
RX_RED_PWR,
2
3
4
5
6
7
8
9
PA_PWR[1:0],
HFREQ_PLL, CH_NO[8]
bit[7]
not
used,
0100_0100
TX_AFW[2:0]
,
bit[3]
not
used,
RX_AFW[2:0]
bit[7:6] not
used,
0010_0000
RX_PW[5:0]
bit[7:6] not used,
0010_0000
TX_PW[5:0]
RX_ADDRESS (device
E7
identity) byte 0
RX_ADDRESS (device
E7
identity)
byte 1
RX_ADDRESS (device
E7
identity)
byte 2
RX_ADDRESS (device
E7
identity)
byte 3
CRC_MODE,CRC_EN,
1110_0111
XOF[2:0],
UP_CLK_EN,
UP_CLK_FREQ[1:0]
解释:
这是手册中的一张表,假设寄存器的配置值是如图给的这
些。
那
么他的传输是从
0
字节开始到
9
字节截止
,
按顺序把
16
进制
码传进去,你的工作就完成了。
而你需要对那个寄存器进行微小的改动,只需找到手册相关寄存
器的说明进行改动就可以了。我们从上表中摘出一个小表看,小表
如下:
bit[7]
not
used,
0100_0100
TX_AFW[2:0]
,
bit[3]
not
used,
RX_AFW[2:0]
bit
[7]
就是该值得第七位,第七位没用上。
< br>TX
—
AFW
【
2:0
】意思是有三位被这个寄存器用了。
等等。
。
通
过这种字节的划分,将寄存器的配置变成了传多个
2
位十六进<
/p>
制数,使得寄存器的配置变得博大精深,新手上手困难。
不过对于驱动其他芯片也一样,配置寄存器就是这样配置的。像
是某些
器件如
saa7113
等芯片,配置寄存器时,前面还有地址,
弄
得更加复杂。
所以大家要通过学习
nrf905
了解芯片的驱动方法这才是关键。
spi
通信:
如何实现
spi
通信,在这个问题上,如果说正常学习应该是
,先
知晓
spi
的协议,
spi
的时序,
spi
写和
读的时序和协议。
但是如果将
其看成程序的话就比较方便。咱们
用程序谈这件事情。
该程序段式<
/p>
spi
的写程序
:
从
MOSI=(bit)(b &
0x80);
我们分析下。假设
b=abcdefgh
那
b & 0x80
就是
abcdefgh&10000000
可以想象
a<
/p>
被提取了出来。
至于
< br>bit
,其实可以没有,这里可以参考
c51
语言关于
‘与‘
p>
有
两个做法,一个是
&
,另一个是
&&
,即位与和整个值得与。
< br>
之后我们观察
sck
的变化,
sck
是
s
pi
的时钟,我们发现从
0
到
1
然
后回到
0
,
这是
sck
的变化。
在
sck
变到
1
之前,
mosi
已经有了一个值,<
/p>
那么当
sck=1
;的时候,也就是所谓
的上升沿,
mosi
被写入,这里可以
认为是写入
905
的内部了。
b<<=1;
这个语句等同于
b=b
《
1
;
意思是
b
左移一位
的新值付给
b,
比如
b=abcde
fgh
左移一位,那么
b=bcdefgh0
< br>,再左移一位,那么
b=cdefgh00
,以此类推左
移
8
次之后
b=00000000.
因为每移出一位,就代表着移进一位,移进的是
0
。
那么观察一下
0x80
——》
1000 0000
这个数
1000 0000
与上
abcdefgh
之后会提取出
a
左移之后,再次进行与运算,就会提取出<
/p>
b
,循环往复
abcdefgh
就
都提取出来了。并在每一次都把这个值付给了
mosi
。
我想通过梳理,大家应该
能看懂了,至于
spi
的通信协议,大家可以
< br>参考下网上资料,我想看懂了程序,再看看资料应该能彻底明白了。
void SpiWrite(uchar b)
{
uchar i=8;
while(i--)
{
Delay(10);
SCK=0;
MOSI=(bit)(b &
0x80);
b<<=1;
Delay(10);
SCK=1;
Delay(10);
SCK=0;
}
读
Spi
程序段:
_nop_();_nop
_();
是延时,延时是一个指令周期的时间。说白了,就
是延
时一段时间。
uchar ddata=0;
这条语句意味着
ddata
是完全为
< br>0
的。
且注意一个事
情
ddata
的定义是
uchar
,那么他的值最大能到
0xff
。
ddata|=MISO;
等同于
ddata=ddata|miso;
miso
是一个引脚的电
平。经过这条语句后
ddata
的最低位就是
miso
当时的电平了,这时左
移再次提取新的
miso
p>
电平,
当八个电平都提取之后,
ddata
的值就提取
完成了。
同样
sck
是
spi
时钟,
想提取下一个
miso
< br>的值必须让时钟波动一次。
uchar SpiRead(void)
{
uchar i=8;
uchar ddata=0;
while(i--)
{
ddata<<=1;
SCK=0;
_nop_();_nop_();
ddata|=MISO;
SCK=1;
_nop_();_nop_();
}
SCK=0;
return
ddata;
}
p>
到此为止,
905
的基本问题讲完了。那么
我们把它串联在一起。
我们先宏观的看下。以发送流程为例
905
现处于待机
spi
编程状态——》向
905
中传送寄存器值
————》
@
——》<
/p>
将
905
的状态设置为发送状态————
》
成功发
出
-----
》待机状态
如果想再发个数据,那么他的流程将变成
@
——》
将
905
的状态设置为发送状态————》
成功发出————》
待机状态
由此看来对同一个对象进
行发送,如果大家的设置都没改的话,寄存
器的值只需设置一次。剩下的就是重复发送到
待机这个环节了。
那么在
@
之前的问题,
大家都了解了,
剩下的就是
@
到把数据发
送这
一块了。这里我分为三个部分说这件事情。
向
905
传输一个命令
p>
向
905
装入待发送的数据、
把数据发出去
向
905
传
输命令:
这里定义了这些命令,先在语法上说下
#define WC
意思等价于
wc=0x00
;
那么我们先解释下这几个命令,大家理解下。
#define WC
#define RC
0x00
0x10
0x20
0x21
0x00
的
#define WTP
#define RTP
#define WTA
#define RTA
0x22
0x23
0x24
#define
RRP
如下是
< br>wc
的解释:
在讲解配置寄存器是有个值我没有讲解先在我告诉大家
指令名称
W_CONFIG
(WC)
指令格式
操作
写配置寄存器
AAAA
指
明哪个字节
。
写操作从哪个字节开始
取决于地址
AAAA
0000 AAAA
unsigned char idata RFConf[11]=
{
0x00,
//
配置命令
//
。
。
。
。
。
。
。
。
。
。
。
。
。
。<
/p>
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。<
/p>
0x00, //
配置命令
//
这就意味着
wc=0x00
,意思就是从
< br>0
字节开始进行写操作。举个例子看下
,0
字节代表的是哪个寄存器,
字节
0
寄存器内容
射频器配置寄存器(
R/W
)
<
/p>
位内容
[7:0],
最高有效
初始值
位
[7]
CH_NO[7:0]
0110_1100
写之后的操作就是开始写
1
字节,
这点上没什么问题最后写到第
九字节。前
面有这个
表的完整版,大家可以翻着看。
#define RC
0x10<
/p>
的解释如下:这个看表就知道不做解释了
跟
wc
意思差不多。
R_CONFIG
(RC)
0001 AAAA
读配置寄存器
AAAA
指
明哪个字节
。
读操作从哪个字节开始
取决于地址
AAAA
后几个命令都好理解我就都列出来大家自己吸收下:
那么到此,命令部分就说完了,能用的就这几个命令。
向
905
装
入待发送数据:
向
905
装入数据这件事情和刚才的命令结合着说。先看以下程
序段:
SpiWrite(WTP);
for (i=0;i<4;i++)
{
}
SpiWrite(TxRxBuf[i]);
// Write 32 bytes Tx data
// Write payload command
p>
先传了
wtp
命令,之后把
txrxbuf
数组中的前
4
字节传了进去。
那么执行外这条之后,数据就被传到
905
中了(还没有进行发
送)
。观察此函数,发现调用了
spiwrite
这个函数
,说明装入命
令和装入数据都是通过
spi
通信进行传输的。
观察以下程序段:
SpiWrite(WTA);
// Write
address command
// Write 4 bytes
address
for (i=0;i<4;i++)
{
}
SpiWrite(TxAddress[i]);
TxAddress[i]
和
S
piWrite(WTA);
是其
中的要素,
wta
是写地址命
令,那么
TxAddress[i]
就是地址咯,地址前面说过了,程序
中
除了那个
config
数组中有地址
的说法,另外在程序段中被单独
列出的地方是
code
TxAddress[4]={0xcc,0xcc,0xcc,0xcc};
那么通过这个程序段,功能就是把地址写进去。
以上的
两个程序段完成了数据和地址的写入,
这时只要设置成发
送状态
,
数据就可以被发出了。
那么从现在开始是重点部分,
就
是以上两段程序的组合,并加以延伸。
p>
仔细看下面这段程序,
主要关注红字部分。
程序之后有我的相关
解释。
void
TxPacket(uchar *TxRxBuf)
{
uchar i;
//Config905();
CSN=0;
SpiWrite(WTP);
for (i=0;i<4;i++)
{
SpiWrite(TxRxBuf[i]);
// Write 32 bytes Tx data
// Write
payload command
}// Spi enable for
write a spi command
CSN=1;
Delay(1);
CSN=0;
// Spi disable
//
Spi
enable
for
write
a
spi
command
SpiWrite(WTA);
// Write address command
//
Write 4 bytes address
for (i=0;i<4;i++)
{
}
CSN=1;
SpiWrite(TxAddress[i]);
// Spi disable
// Set TRX_CE high,start Tx data
TRX_CE=1;
-
-
-
-
-
-
-
-
-
上一篇:什么是委托书
下一篇:C51中变量和函数的绝对地址定位问题要点