【Zigbee】基础篇(4) Zigbee无线通信过程、无线发送温湿度信息

您所在的位置:网站首页 简述蓝牙通信过程 【Zigbee】基础篇(4) Zigbee无线通信过程、无线发送温湿度信息

【Zigbee】基础篇(4) Zigbee无线通信过程、无线发送温湿度信息

2023-09-03 03:32| 来源: 网络整理| 查看: 265

大家好,我是皮皮猫吖! 每文一言:你所看到的惊艳,都曾经被平庸所历练!

本篇文章:

主要是Zigbee的无线通信,无线通信的过程,无线发送温湿度信息,抓包工具的使用。

正文如下: 一、无线通信 1)Zigbee无线通信是什么?

Zigbee无线通信,需要高频的载波来提供发射效率。Zigbee模块之间要想正常的收发数据,接收模块必须把接收频率和发射模块的载波频率设置一致。

2)信道和频段

信道:无线通信的通道。

频段:载波的频率落在某些频率区段,把这些区段叫做频段。

Zigbee使用的频段主要是2.4G频段、915M频段和896M频段。在这些频段上,Zigbee总共有27个载波可以进行通信,载波也叫做信道。

3)频段上分布的信道数

2.4G频段:分布16个信道

915M频段、896M频段:分布11个信道

TI公司所有支持Zigbee底层协议的芯片只能在2.4G频段的16个信道里进行通信。

信道频段112405M122410M……252475M262480M 二、例子:无线通信收发数据【A节点通过无线的方式向B节点发送采集到的温湿度信息;B节点通过无线的方式向A节点发送数字"6"】 1)A节点代码 ① main.c #include #include"74LS164_8LED.h" #include"DHT11.h" #include #include #define SENDVAL 6 int count = 0; char SendPacket[]={0x11,0x61,0x88,0x00,0x07,0x20,0xEF,0xBE,0x20,0x50}; DHT dh; // 用来接收DHT11发过来的40位数据 //第一个字节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--); } //cc2530切换到32M晶振 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 Uart0SendByte(char SendByte) { U0DBUF=SendByte; //把我们收到的数据通过串口再返回发出去 while(UTX0IF==0); UTX0IF=0; }*/ //射频的初始化 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+(24-11)*5);//(MIN_CHANNEL + (channel - MIN_CHANNEL) * CHANNEL_SPACING); //设置载波为2475M,25号信道 //设置个域网ID:2个字节的地址 PAN_ID0=0x07; PAN_ID1=0x20; //0x2007 //halRfRxInterruptConfig(basicRfRxFrmDoneIsr); 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;//清发送标志位 //为数据发送做好准备工作 //RFD 为128字节的接收缓冲区/为128字节的发送缓冲区 //RFD = xxx;表示向接收缓冲器写入数据 //xxx = RFD;表示从发送缓冲区读取数据 for(i=0;i LS164_Cfg();//74LS164控制数码管的初始化 Init32M(); //主时钟晶振工作在32M (无线通信,晶振必须32M) KeysIntCfg(); //外部中断初始化 Init_Uart(); halRfInit();//无线通信的初始化 初始化相关的寄存器,配置工作信道,和PANID SHORT_ADDR0=0x50; SHORT_ADDR1=0x20;//设置本模块地址 设置本模块的网络地址0x2050 //大小端模式问题, LS164_BYTE(1);//数码管显示数字1 while(1); } void RevRFProc() { static char len; static char ch; len=ch=0; RFIRQM0 &= ~0x40; IEN2 &= ~0x01; EA=1; //读缓冲寄存器中的数据 //读取到了封装好的数据中的第一个字节,第一个字节的数据存储的是后面还要多少字节的数据 len=RFD;//读第一个字节判断这一串数据后面还有几个字节; //读到 len=0x0C 12 while (len>0) {//只要后面还有数据那么就把它们都从接受缓冲区取出来 ch=RFD; if(3==len) { //如果倒数第三个字节等于7,那么我们把LED0取反 //读取到的第三个字节,就是在发送模块中编写的标志位 //读到的是几,就显示几 if(ch==6){ if(count==10){ count=0; } LS164_BYTE(count++); } } len--; } EA=0; // enable RXPKTDONE interrupt RFIRQM0 |= 0x40; // enable general RF interrupts IEN2 |= 0x01; } #pragma vector=P1INT_VECTOR __interrupt void Key3_ISR() //P1_1 { char *dht11; if(0x02 & P1IFG) { Delay(); if(0==P1_1) { P1DIR |=0X01; P1_0 ^=1; if(Read_DHT()){ sprintf(dht11, "湿度:%2d.%d 温度%2d.%d\n", dh.humi_H,dh.humi_L,dh.temp_H,dh.temp_L); SendPacket[10] = '0'+dh.humi_H/10; SendPacket[11] = '0'+dh.humi_H%10; SendPacket[12] = '0'+dh.humi_L%10; SendPacket[13] = '0'+dh.temp_H/10; SendPacket[14] = '0'+dh.temp_H%10; SendPacket[15] = '0'+dh.temp_L%10; //Uart_Send_String(dht11, 20); } RFSend(SendPacket,18); } } P1IFG=0; P1IF=0; } #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; } ② 74LS164_8LED 74LS164_8LED.h #ifndef __74LS164_8LED_H__ #define __74LS164_8LED_H__ #include #define LS164_DATA P1_3 #define LS164_CLK P1_2 #define UCHAR unsigned char void LS164_Cfg(); void LS164_BYTE(UCHAR Data);//P1.3 DATA P1.2 CLK #endif 74LS164_8LED.c #include #include"74LS164_8LED.h" static UCHAR LED_Map[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x00}; void LS164_Cfg() { P1SEL &=~0x0C;//xxxx 00xx 配置为普通IO模式 P1DIR |=0x0C;//xxxx 11xx 配置为输出模式 } void LS164_BYTE(UCHAR Index) //P1.3 DATA P1.2 CLK { UCHAR i=0; UCHAR Data=LED_Map[Index]; for(;i LS164_DATA=1; } else { LS164_DATA=0; } Data=Data while(time--){ asm("NOP"); } } /* 毫秒延时 */ void Delay_ms(int Time) { while(Time--){ Delay_us(1000); } } /* 定义DHT11的数据引脚为 输出 状态 */ void DHT_OUT(void){ P0SEL &= ~0x01; P0DIR |= 0x01; } /* 定义DHT11的数据引脚为 输入 状态 */ void DHT_IN(void){ P0SEL &= ~0x01; P0DIR &= ~0x01; P0INP &= ~0x01; P2INP &= ~0x20; } /* 读取一个字节的数据(在DHT11响应主机之后调用该函数) */ uchar Read_Byte(void){ uchar temp, i; /* 一位一位的读取 */ for(i=0;i while(DATA_PIN==1); //等待数据1的高电平结束 temp |= (uchar)(0x01 Delay_ms(1200);//等待DHT11稳定,延时大于1秒 DHT_OUT(); //输出模式 DATA_PIN=0; //主机拉低 Delay_ms(18); //延时18ms DATA_PIN=1; //总线拉高 Delay_us(40); //主机延时40us DHT_IN(); //主机设为输入 判断从机响应信号 /*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/ if(DATA_PIN==0){ while(DATA_PIN==0); //轮询直到从机发出 的80us 低电平 响应信号结束 while(DATA_PIN==1); //轮询直到从机发出的 80us 高电平 标置信号结束 /*开始接收数据*/ dh.humi_H=(uchar)Read_Byte(); dh.humi_L=(uchar)Read_Byte(); dh.temp_H=(uchar)Read_Byte(); dh.temp_L=(uchar)Read_Byte(); dh.crc=(uchar)Read_Byte(); /*读取结束,引脚改为输出模式*/ DHT_OUT(); DATA_PIN=1; //主机拉高 /*检查读取的数据是否正确*/ if(dh.humi_H+dh.humi_L+dh.temp_H+dh.temp_L==dh.crc) return 1; else return 0; } else return 0; } void Init_32M(){ SLEEPCMD &=0xFB;//1111 1011 开启2个高频时钟源 while(0==(SLEEPSTA & 0x40));// 0100 0000 等待32M稳定 Delay_us(63); CLKCONCMD &=0xF8;//1111 1000 不分频输出 CLKCONCMD &=0XBF;//1011 1111 设置32M作为系统主时钟 while(CLKCONSTA & 0x40); //0100 0000 等待32M成功成为当前系统主时钟 SLEEPCMD |=0x04; } void Init_Uart() { Init_32M(); //使用32MHz的外部晶振 PERCFG&=~0x01; //有2个备用位置,0使用备用位置1;1使用备用位置2 P0SEL |= 0x0C; //P0_2 RXD P0_3 TXD 外设功能 0000 1100 U0CSR |= 0xC0; //串口接收使能 1100 0000 工作UART模式+允许接受 U0UCR |= 0x00; //无奇偶校验,1位停止位 U0GCR |= 11; //U0GCR与U0BAUD配合 U0BAUD |= 216; // 波特率设为115200 IEN0 |= 0X04; //开串口接收中断 'URX0IE = 1',也可以写成 URX0IE=1; EA=1; } /* 串口发送一个字符 */ void Uart0_SendCh(char ch) { U0DBUF = ch; //将该字符写入串口数据发送寄存器 while(UTX0IF == 0); //检查标志位 UTX0IF = 0; //将标志位清零 } /* 串口发送一个字符串 */ void Uart_Send_String(char *Data,int len) { { int j; for(j=0;j0x0c,0x61,0x88,0x00,0x07,0x20,0x50,0x20,0xBE,0xEF,SENDVAL}; void Delay() { int y,x; for(y=1000;y>0;y--) for(x=30;x>0;x--); } //cc2530切换为32M晶振 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 Uart0_Cfg() { PERCFG &=0xFE;//把这个寄存器的第零位强行清零 1111 1110 //就是把串口0的脚位置配置在备用位置1 即P0_2 P0_3 P0SEL |=0x0C;//让P0_2 P0_3这两个脚工作在片上外设模式,而不是普通IO口 0000 1100 U0CSR |=0xC0; U0UCR =0; //串口0 典型的串口配置 校验位 停止位之类的东西 U0GCR =11; U0BAUD =216;//就是重官方数据手册中波特率表格中参照115200时的 配置值,前提是系统时钟在32M IEN0 |=0x04; //开接收数据的中断 0000 0100 EA=1; } //外部中断初始化 void KeysIntCfg() {//Key3 Key4 Key5 IEN2|=0x10;//开P1IE组中断 P1IEN|=0x02;//开Key3组内中断 PICTL|=0x02;//设置P1_1为下降沿 EA=1; //开总中断 } //串口上发送字节 void Uart0SendByte(char SendByte) { U0DBUF=SendByte; //把我们收到的数据通过串口再返回发出去 while(UTX0IF==0); UTX0IF=0; } /* 串口发送一个字符串 */ void Uart_Send_String(char *Data,int len) { { int j; for(j=0;j EA=0; FRMCTRL0 |= 0x60; // Recommended RX settings TXFILTCFG = 0x09; AGCCTRL1 = 0x15; FSCAL1 = 0x00; // enable RXPKTDONE interrupt RFIRQM0 |= 0x40; // enable general RF interrupts IEN2 |= 0x01; //选择25号信道 FREQCTRL =(11+(24-11)*5);//(MIN_CHANNEL + (channel - MIN_CHANNEL) * CHANNEL_SPACING); //设置个域网ID:进行通信的模块,个域网ID必须相同 PAN_ID0=0x07; PAN_ID1=0x20; //halRfRxInterruptConfig(basicRfRxFrmDoneIsr); 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;//清发送标志位 //为数据发送做好准备工作 //RFD 为128字节的接收缓冲区/为128字节的发送缓冲区 //RFD = xxx;表示向接收缓冲器写入数据 //xxx = RFD;表示从发送缓冲区读取数据 for(i=0;i LS164_Cfg();//74LS164控制数码管的初始化 Init32M(); //主时钟晶振工作在32M KeysIntCfg(); //外部中断初始化 Uart0_Cfg(); halRfInit(); //Uart0_Cfg(); //设置本模块地址 SHORT_ADDR0=0xEF; SHORT_ADDR1=0xBE;//设置本模块地址 0xBEEF LS164_BYTE(2); while(1); } void RevRFProc() { static char len; static char ch; char *str; len=ch=0; RFIRQM0 &= ~0x40; IEN2 &= ~0x01; EA=1; //读缓冲寄存器中的数据 //读取到了封装好的数据中的第一个字节,第一个字节的数据存储的是后面还要多少字节的数据 len=RFD;//读第一个字节判断这一串数据后面还有几个字节; //读到 len=0x0C 12 while (len>0) {//只要后面还有数据那么就把它们都从接受缓冲区取出来 ch=RFD; if(len2) { //如果倒数第三个字节等于7,那么我们把LED0取反 //读取到的第三个字节,就是在发送模块中编写的标志位 //读到的是几,就显示几 if(len==8){ sprintf(str, "湿度:"); Uart_Send_String(str, 5); } if(len==6){ Uart0SendByte('.'); } if(len==5){ sprintf(str, " 温度:"); Uart_Send_String(str, 6); } if(len==3){ Uart0SendByte('.'); } Uart0SendByte(ch); if(len==3){ Uart0SendByte('\n'); } } len--; } if(count==10){ count = 0; } LS164_BYTE(count++); EA=0; // enable RXPKTDONE interrupt RFIRQM0 |= 0x40; // enable general RF interrupts IEN2 |= 0x01; } #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; } #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; } ② 74LS164_8LED 74LS164_8LED.h #ifndef __74LS164_8LED_H__ #define __74LS164_8LED_H__ #include #define LS164_DATA P1_3 #define LS164_CLK P1_2 #define UCHAR unsigned char void LS164_Cfg(); void LS164_BYTE(UCHAR Data);//P1.3 DATA P1.2 CLK #endif 74LS164_8LED.c #include #include"74LS164_8LED.h" static UCHAR LED_Map[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x00}; void LS164_Cfg() { P1SEL &=~0x0C;//xxxx 00xx 配置为普通IO模式 P1DIR |=0x0C;//xxxx 11xx 配置为输出模式 } void LS164_BYTE(UCHAR Index) //P1.3 DATA P1.2 CLK { UCHAR i=0; UCHAR Data=LED_Map[Index]; for(;i LS164_DATA=1; } else { LS164_DATA=0; } Data=Data


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3