预备知识
- Zigbee无线通信,需要高频的载波来提供发射效率,Zigbee模块之间要可以正常的收发,接收模块必须把接收频率设置和发射模块的载波频率一致。
- Zigbee有27个载波可以进行通信,载波叫做信道(无线通信的通道)。这些载波的频率落在某些频率区段,我们把这些区段叫做频段。
- 2.4G频段 16个信道
- 915M频段 896M频段 11个信道
- 但TI的所有支持Zigbee底层协议的芯片只能在2.4G频段的16个信道里进行通信,即11-26信道。
- 网络地址:在Zigb
- ee无线局域网里,每一模块都一个在该网络里唯一的2个字节的地址,这个地址叫做网络地址,网络短地址。
- PANID:这是一个2个字节的编码,用来区别不同的Zigbee无线局域网,个域网ID.
代码分析
这里不在详细介绍,只给出关键配置代码的代码模板
对于数据发送接收的程序来说,基本的无线通信的基础配置是固定的,只需要知道里面需要自己每次更改的部分即可
将两个接收和发送的代码分别烧录到两个开发板中,实验现象是:发送板按下按键发送你设定的数字
SENDVAL
到接收板,接收板通过数码管显示该数字
发送数据
分析
void halRfInit(void)
:无线通信初始化函数
void RFSend(char *pstr,char len)
:无线数据发送函数
__interrupt void RF_IRQ(void)
:无线通信中断函数
void RevRFProc()
:无线数据接收函数
无线通信初始化函数
在这个函数中,需要修改的只有
FREQCTRL
和PAN_ID1
两项的值
无线数据发送函数
可以直接看注释,这个函数基本不用改动,使用时直接掉这个函数就行,传入发送数组和数组长度即可
中断函数
发送数据包数组
char SendPacket[]={0x0c,0x61,0x88,0x00,0x07,0x20,0xEF,0xBE,0x20,0x50,SENDVAL};
- 第一个字节0x0C含义,这个自己后面还有12个字节要发送,实际上是10(后面跟的)+2(默认自动添加的CRC 码)
- 第5 6个字节表示的是PANID
- 第7 8个字节是无线模块目标设备的网络地址 0xBEEF
- 第9 10就是本地模块的网络地址
- 11 个字节是我们有用的数据
- CRC码 12 13个字节 是硬件自动追加
主函数中的注意事项
发送数据模板代码
将两个接收和发送的代码分别烧录到两个开发板中,实验现象是:发送板按下按键发送你设定的数字SENDVAL
到接收板,接收板通过数码管显示该数字
#include<iocc2530.h>
#include"74LS164_8LED.h"
#define SENDVAL 5
char SendPacket[]={0x0c,0x61,0x88,0x00,0x07,0x20,0xEF,0xBE,0x20,0x50,SENDVAL};
//第一个字节0x0C含义,这个自己后面还有12个字节要发送
//第5 6个字节表示的是PANID
//第7 8个字节是无线模块目标设备的网络地址 0xBEEF
//第9 10就是本地模块的网络地址
//11 个字节是我们有用的数据
// CRC码 12 13个字节 是硬件自动追加
void Delay()
{
int y,x;
for(y=1000;y>0;y--)
for(x=30;x>0;x--);
}
void Init32M()
{
SLEEPCMD &=0xFB;//1111 1011 开启2个高频时钟源
while(0==(SLEEPSTA & 0x40));// 0100 0000 等待32M稳定
Delay();
CLKCONCMD &=0xF8;//1111 1000 不分频输出
CLKCONCMD &=0XBF;//1011 1111 设置32M作为系统主时钟
while(CLKCONSTA & 0x40); //0100 0000 等待32M成功成为当前系统主时钟
}
void KeysIntCfg()
{//Key3 Key4 Key5
IEN2|=0x10;//开P1IE组中断
P1IEN|=0x02;//开Key3组内中断
PICTL|=0x02;//设置P1_1为下降沿
EA=1; //开总中断
}
void halRfInit(void)
{
EA=0;
FRMCTRL0 |= 0x60;
// Recommended RX settings
TXFILTCFG = 0x09;
AGCCTRL1 = 0x15;
FSCAL1 = 0x00;
// enable RXPKTDONE interrupt
RFIRQM0 |= 0x40;//把射频接收中断打开
// enable general RF interrupts
IEN2 |= 0x01;
//设置信道
FREQCTRL =(11+(25-11)*5);//(MIN_CHANNEL + (channel - MIN_CHANNEL) * CHANNEL_SPACING);
//设置载波为2475M
//设置ID
PAN_ID0=0x07;
PAN_ID1=0x20; //0x2007
RFST = 0xEC;//清接收缓冲器
RFST = 0xE3;//开启接收使能
EA=1;
}
//发送无线数据
void RFSend(char *pstr,char len)
{
char i;
RFST = 0xEC; //确保接收是空的
RFST = 0xE3; //清接收标志位
while (FSMSTAT1 & 0x22);//等待射频发送准备好
RFST = 0xEE;//确保发送队列是空
RFIRQF1 &= ~0x02;//清发送标志位
//为数据发送做好准备工作
for(i=0;i<len;i++)
{
RFD=pstr[i];
} //循环的作用是把我们要发送的数据全部压到发送缓冲区里面
RFST = 0xE9; //这个寄存器一旦被设置为0xE9,发送缓冲区的数据就被发送出去
while(!(RFIRQF1 & 0x02) );//等待发送完成
RFIRQF1 = ~0x02;//清发送完成标志
}
void main()
{
LS164_Cfg();//74LS164控制数码管的初始化
Init32M(); //主时钟晶振工作在32M
KeysIntCfg();
halRfInit();//无线通信的初始化 初始化相关的寄存器,配置工作信道,和PANID
SHORT_ADDR0=0x50;
SHORT_ADDR1=0x20;//设置本模块地址 设置本模块的网络地址0x2050
//大小端模式问题,
LS164_BYTE(1);
while(1);
}
#pragma vector=P1INT_VECTOR
__interrupt void Key3_ISR() //P1_1
{
if(0x02 & P1IFG)
{
Delay();
if(0==P1_1)
{
P1DIR |=0X01;
P1_0 ^=1;
RFSend(SendPacket,11);//发送数据
}
}
P1IFG=0;
P1IF=0;
}
#pragma vector=RF_VECTOR
__interrupt void RF_IRQ(void)
{//这个是射频中断函数,当小灯模块接收到开关模块发送来的数据时,小灯模块的CPU就会进入中断函数执行
EA=0;
if( RFIRQF0 & 0x40 )
{
RFIRQF0&= ~0x40; // Clear RXPKTDONE interrupt
}
S1CON= 0; // Clear general RF interrupt flag
RFST = 0xEC;//清接收缓冲器
RFST = 0xE3;//开启接收使能
EA=1;
}
接收数据
分析
初始化函数和发送数据的初始化函数一样,只需要把发送函数去掉,添加一个接收函数即可
注意
- 两相互通信的模块之间,初始化函数中的接收和发送的信道和PANID一定要一样
- 接收工程的主函数中设置的
SHORT_ADDR
网络地址需要和发送的数据包中的第7、8两个字节所生成的网络地址一致
中断函数
无线数据接收函数
接收数据模板代码
将两个接收和发送的代码分别烧录到两个开发板中,实验现象是:发送板按下按键发送你设定的数字SENDVAL
到接收板,接收板通过数码管显示该数字
#include<iocc2530.h>
#include"74LS164_8LED.h"
#define SENDVAL 5
char SendPacket[]={0x0c,0x61,0x88,0x00,0x07,0x20,0xEF,0xBE,0x20,0x50,SENDVAL};
//第一个字节0x0C含义,这个自己后面还有12个字节要发送
//第5 6个字节表示的是PANID
//第7 8个字节是无线模块目标设备的网络地址 0xBEEF
//第9 10就是本地模块的网络地址
//11 个字节是我们有用的数据
// CRC码 12 13个字节 是硬件自动追加
void Delay()
{
int y,x;
for(y=1000;y>0;y--)
for(x=30;x>0;x--);
}
void Init32M()
{
SLEEPCMD &=0xFB;//1111 1011 开启2个高频时钟源
while(0==(SLEEPSTA & 0x40));// 0100 0000 等待32M稳定
Delay();
CLKCONCMD &=0xF8;//1111 1000 不分频输出
CLKCONCMD &=0XBF;//1011 1111 设置32M作为系统主时钟
while(CLKCONSTA & 0x40); //0100 0000 等待32M成功成为当前系统主时钟
}
void halRfInit(void)
{
EA=0;
FRMCTRL0 |= 0x60;
// Recommended RX settings
TXFILTCFG = 0x09;
AGCCTRL1 = 0x15;
FSCAL1 = 0x00;
// enable RXPKTDONE interrupt
RFIRQM0 |= 0x40;//把射频接收中断打开
// enable general RF interrupts
IEN2 |= 0x01;
//设置信道
FREQCTRL =(11+(25-11)*5);//(MIN_CHANNEL + (channel - MIN_CHANNEL) * CHANNEL_SPACING);
//设置载波为2475M
//设置ID
PAN_ID0=0x07;
PAN_ID1=0x20; //0x2007
//halRfRxInterruptConfig(basicRfRxFrmDoneIsr);
RFST = 0xEC;//清接收缓冲器
RFST = 0xE3;//开启接收使能
EA=1;
}
//接受无线数据
void RevRFProc()
{
static char len;
static char ch;
len = ch = 0;
RFIRQM0 &= ~0x40;
IEN2 &= ~0x01;
EA = 0;
len = RFD;//读第一个字节判断这一串数据后面有几个字节;
while (len > 0)
{//只要后面还有数据那么就把他都从接受缓冲区取出来
ch=RFD;
if(3 == len)
{//读取倒数第三个字节的数字,通过数码管显示
LS164_BYTE(ch);
}
len--;
}
EA=1;
RFIRQM0 |= 0x40;
// enable general RF interrupts
IEN2 |= 0x01;
}
void main()
{
LS164_Cfg();//74LS164控制数码管的初始化
Init32M(); //主时钟晶振工作在32M
halRfInit();
SHORT_ADDR0=0xEF;
SHORT_ADDR1=0xBE;//设置本模块地址 0xBEEF
LS164_BYTE(2);
while(1);
}
#pragma vector=RF_VECTOR
__interrupt void RF_IRQ(void)
{//这个是射频中断函数,当小灯模块接收到开关模块发送来的数据时,小灯模块的CPU就会进入中断函数执行
EA=0;
if( RFIRQF0 & 0x40 )
{
RevRFProc();
RFIRQF0&= ~0x40; // Clear RXPKTDONE interrupt
}
S1CON= 0; // Clear general RF interrupt flag
RFST = 0xEC;//清接收缓冲器
RFST = 0xE3;//开启接收使能
EA=1;
}