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


本篇文章:

主要是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个信道里进行通信。

信道 频段
11 2405M
12 2410M
25 2475M
26 2480M

二、例子:无线通信收发数据【A节点通过无线的方式向B节点发送采集到的温湿度信息;B节点通过无线的方式向A节点发送数字"6"】

1)A节点代码

① main.c
#include<ioCC2530.h>
#include"74LS164_8LED.h"
#include"DHT11.h"
#include <stdio.h>
#include <string.h>
#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   Key5IEN2|=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 interruptsIEN2 |= 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<len;i++){RFD=pstr[i];}  //循环的作用是把我们要发送的数据全部压到发送缓冲区里面RFST = 0xE9; //这个寄存器一旦被设置为0xE9,发送缓冲区的数据就被发送出去while(!(RFIRQF1 & 0x02) );//等待发送完成RFIRQF1 = ~0x02;//清发送完成标志
}void main()
{LS164_Cfg();//74LS164控制数码管的初始化Init32M(); //主时钟晶振工作在32M (无线通信,晶振必须32M)KeysIntCfg(); //外部中断初始化Init_Uart();halRfInit();//无线通信的初始化  初始化相关的寄存器,配置工作信道,和PANIDSHORT_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 12while (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 interruptRFIRQM0 |= 0x40;// enable general RF interruptsIEN2 |= 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 flagRFST = 0xEC;//清接收缓冲器RFST = 0xE3;//开启接收使能 EA=1;
}
② 74LS164_8LED
  • 74LS164_8LED.h
#ifndef __74LS164_8LED_H__
#define __74LS164_8LED_H__
#include<ioCC2530.h>
#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<ioCC2530.h>
#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<8;i++){if(0x80 & Data){LS164_DATA=1;            }else{LS164_DATA=0; }Data=Data << 1;LS164_CLK=0;LS164_CLK=1;}
}
③ DHT11
  • DHT11.h
#ifndef __DHT11_H_
#define __DHT11_H_#include<iocc2530.h>
#define DATA_PIN  P0_0   // DHT11 的数据引脚typedef unsigned char uchar;/* 定义一个结构体,用来存储DHT11传出来的40位数据 */
typedef struct{uchar temp_H;uchar temp_L;uchar humi_H;uchar humi_L;uchar crc;
}DHT;/* 微秒延时 */
void Delay_us(int time);
/* 毫秒延时 */
void Delay_ms(int Time);
/* 定义DHT11的数据引脚为 输出 状态 */
void DHT_OUT(void);
/* 定义DHT11的数据引脚为 输入 状态 */
void DHT_IN(void);
/* 读取一个字节的数据(在DHT11响应主机之后调用该函数) */
uchar Read_Byte(void);
/* *主机与DHT11通信 * 一次完整的数据传输为40bit,高位先出* 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和 */uchar Read_DHT(void);void Init_32M();void Init_Uart();/* 串口发送一个字符 */
void Uart0_SendCh(char ch);#endif
  • DHT11.c
#include <iocc2530.h>
#include <stdio.h>
#include <string.h>
#include "DHT11.h"extern DHT dh; // 用来接收DHT11发过来的40位数据/* 微秒延时 */
void Delay_us(int time)
{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<8;i++){/*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/while(DATA_PIN==0);/*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,*通过检测 30 us后的电平即可区别这两个状 */Delay_us(30); //延时30us 这个延时需要大于数据0持续的时间即可/* 30 us后仍为高电平表示数据“1” */if(DATA_PIN==1){while(DATA_PIN==1); //等待数据1的高电平结束temp |= (uchar)(0x01<<7-i);  //把第7-i位置1,MSB先行}else{ // 30 us后为低电平表示数据“0”temp &= (uchar)~(0x01<<7-i);  //把第7-i位置0,MSB先行}}return temp;
}/* *主机与DHT11通信 * 一次完整的数据传输为40bit,高位先出* 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和 */uchar Read_DHT(void){Delay_ms(1200);//等待DHT11稳定,延时大于1秒DHT_OUT();    //输出模式     DATA_PIN=0;   //主机拉低Delay_ms(18); //延时18msDATA_PIN=1;   //总线拉高 Delay_us(40); //主机延时40usDHT_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;elsereturn 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使用备用位置2P0SEL |= 0x0C;   //P0_2 RXD P0_3 TXD 外设功能 0000 1100U0CSR |= 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;j<len;j++)   //一个字符一个字符的发送{ Uart0_SendCh(*Data++); } }
}

2)B节点代码

① main.c
#include<ioCC2530.h>
#include"74LS164_8LED.h"
#include<stdio.h>
#include<string.h>
#define SENDVAL 6
int count = 0;
char SendPacket[]={0x0c,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_3P0SEL  |=0x0C;//让P0_2  P0_3这两个脚工作在片上外设模式,而不是普通IO口       0000 1100U0CSR |=0xC0;U0UCR =0; //串口0 典型的串口配置  校验位 停止位之类的东西U0GCR =11;U0BAUD =216;//就是重官方数据手册中波特率表格中参照115200时的 配置值,前提是系统时钟在32MIEN0 |=0x04; //开接收数据的中断  0000 0100EA=1;
}//外部中断初始化
void KeysIntCfg()
{//Key3  Key4   Key5IEN2|=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<len;j++)   //一个字符一个字符的发送{ Uart0SendByte(*Data++); } }
}//射频初始化
void halRfInit(void)
{EA=0;FRMCTRL0 |= 0x60;// Recommended RX settings  TXFILTCFG = 0x09;AGCCTRL1 = 0x15;FSCAL1 = 0x00;// enable RXPKTDONE interrupt  RFIRQM0 |= 0x40;// enable general RF interruptsIEN2 |= 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<len;i++){RFD=pstr[i];}  //循环的作用是把我们要发送的数据全部压到发送缓冲区里面RFST = 0xE9; //这个寄存器一旦被设置为0xE9,发送缓冲区的数据就被发送出去while(!(RFIRQF1 & 0x02) );//等待发送完成RFIRQF1 = ~0x02;//清发送完成标志
}void main()
{LS164_Cfg();//74LS164控制数码管的初始化Init32M(); //主时钟晶振工作在32M KeysIntCfg(); //外部中断初始化Uart0_Cfg();halRfInit();//Uart0_Cfg();//设置本模块地址SHORT_ADDR0=0xEF;SHORT_ADDR1=0xBE;//设置本模块地址  0xBEEFLS164_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 12while (len>0) {//只要后面还有数据那么就把它们都从接受缓冲区取出来ch=RFD;if(len<=8 && len>2){//如果倒数第三个字节等于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 interruptRFIRQM0 |= 0x40;// enable general RF interruptsIEN2 |= 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 flagRFST = 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<ioCC2530.h>
#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<ioCC2530.h>
#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<8;i++){if(0x80 & Data){LS164_DATA=1;            }else{LS164_DATA=0; }Data=Data << 1;LS164_CLK=0;LS164_CLK=1;}
}

三、如果后续需要使用Zigbee进行无线通信的话,只需要在下面对应的部分修改为自己需要使用的代码即可:

1)数据包代码

PANID:这是一个2个字节的编码,用来区别不同的Zigbee无线局域网,个域网ID。

//无线数据包的内容
#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个字节 硬件自动追加

2)射频初始化代码

3)A节点射频接收无线数据处理代码【发送节点接收无线数据处理代码】

4)B节点射频接收无线数据处理代码【接收节点处理无线数据代码】

5)A节点封装数据包过程【发送节点封装数据过程】

四、无线通信过程

1)在Zigbee的无线局域网中,节点按照网络里面的功能划分为:协调器、路由器、中断。

硬件可以一模一样,节点之所以在网络里表现不同的功能,是因为它们下载了不同功能版本的代码。

我们说一个模块到底是协调器、路由器还是终端?前提是它必须在一个Zigbee无线局域网里,如果它还没有入网,那么它仅仅是一个下载了响应功能代码的模块而已。

下载了路由器和终端代码的模块,上电后第一件事是去寻找网络,请求加入;网络是不会平白无故产生的,所以创建网络这个工作由下载了协调器代码的模块来完成,下载协调器代码的模块上电的第一件事是去创建网络。

任何一个网络,第一个节点一定是该网络的协调器,一个网络里有且仅有一个协调器。

2)协调器

协调器:创建一个无线局域网络的模块叫做协调器。

协调器在创建网络之后,协调器的地位和路由器将是一样的,都是负责把终端的消息发送出去。

3)其他模块入网的过程

任何一个Zigbee模块要加入到某个网络,一定要一个处于该网络里的节点作为介绍人,并且这个介绍人不能是终端节点。

在节点加入到网络以后,介绍人节点和被介绍加入的节点互为父子关系,介绍人节点是被介绍加入节点的父节点,被介绍加入节点是介绍节点的子节点。

当被加入节点有多个介绍人可以选择加入的时候,根据相对于被加入节点的信号强度等一些其他的参数,选择最佳的介绍人节点加入。

Zigbee网络组建以后,网络里的节点可以进行相互通信,数据通信的方式有4种:单播、广播、组播、绑定。

4)各个功能型模块【路由器、终端、协调器】入网前的操作

① 路由器节点

路由器在加入局域网络之前,会一直发送信标请求帧,信标请求帧的作用是,让在它附近的所有具备介绍人资格的节点,都回复信标帧,这些返回的信标帧被这个想要加入的无线模块拿到,路由器模块通过这些信标帧,选出最佳介绍人节点,请求加入。

② 终端节点

终端节点在入网前的行为下载了路由器代码模块的入网前行为是一样的

③ 协调器节点

协调器在创建局域网络之前,会发送了一帧信标请求帧,发送这一帧也会得到周围具备介绍人资格的节点回复信标帧,但是协调器拿到这些信标帧,用来判断周围的环境情况,为创建网络做准备

当协调器创建网络成功以后,就会发送一个数据帧,这个帧里面可以看到协调器的地址0x0000、PANID(创建的网络ID),可以把这个帧叫做网络连接状态帧

五、路由器与协调器无线通信的过程:

1)协调器发出网络连接状态帧,表明协调器稳定工作,与路由器入网无关

  • Dest Address:目的地址
  • Source Address:自己的网络地址
  • Dest PAN:目的网络
  • 0XFFFF:表示是广播

2)路由器模块发出信标请求帧,用于发现周围的网络,请求加入

3)协调器模块发出信标请求帧,路由器模块在拿到这个帧之后,可以得到协调器模块相对于自己的信号强度,判断是不是最佳介绍人。

  • Source PAN:自己当前所处于的网络
  • Source Address:自己的网络地址

4)重复2-3的过程

5)补充:ACK、物理地址

在Zigbee网络里,如果一个模块发出的射频帧,非常明确的指明接收目标节点的地址,那么目标节点在接收到这个帧以后,硬件会自动回复一个ACK,表明已经收到了。

TI在CC2530出厂的时候在flash上固化一个8个字节编号唯一的值,这个值是这颗芯片的物理地址,又叫MAC地址,或叫IEEE地址,3种说法说的都是一回事。

6)路由器模块做出的判断帧:发送到协调模块的帧

这个帧的作用是,在前面路由器模块收到了协调器模块的信标帧,通过信标帧判断协调器是当前路由器模块的最佳介绍人。

路由器模块发送这一帧是告诉协调器,你是我当前的最佳介绍人,请你从作为我入网的介绍人,介绍我入网。并且在这个帧上携带了路由器自己的MAC地址。这个MAC地址是介绍人模块(协调器模块)给被介绍人模块(路由器模块)分配网络的地址的依据。

  • Source Address:路由器的MAC地址
  • Dest Address:目的地址
  • Dest PAN:目的网络
  • Source PAN:自己所在的网络

7)协调器发送给路由器ACK帧。

路由器模块明确了要发往的地址,所以协调器模块在收到信息后,硬件回复给路由器模块ACK,表明我已经收到了你发过来的帧!

8)路由器模块发给协调器模块的请求帧。

路由器模块请求协调器,请协调器模块根据路由器之前发送MAC地址,给路由器分配的网络地址,并把分配的网络地址发给路由器。这是一个数据请求帧

9)协调器发送给路由器ACK帧。

协调器回复给路由器ACK,表明收到了路由器发过来的数据请求帧。

10)协调器把为路由器分配好的网络地址发给路由器。

这个帧需要非常明确的发给路由器模块,但是路由器模块还不知道自己的网络地址是多少,所有在指定目标地址的时候用MAC地址。

  • Source Address:协调器的MAC地址(6550f)
  • Dest Address:路由器MAC地址(5581f)
  • 0xE9EB:路由器被分配的网络地址

11)路由器接收到协调器发送的帧,路由器向协调器发送ACK帧。

路由器模块根据自己的MAC地址收到了协调器分配给自己的网络地址,硬件自动回复ACK,表明已经收到了协调器发过来的帧。

12)路由器模块入网宣告。

告诉当前网络里所有的节点,我已经入网了,我的网络地址是0xE9EB。

  • Source Address:路由器的网络地址

13)协调器转发路由器广播的帧。

协调器模块在收到了路由器模块发的入网宣告帧以后,转发了路由器广播的帧。

14)协调器和路由器发送网络连接状态帧。

协调器模块和路由器模块在工作稳定时,发出的网络连接状态帧。

协调器和路由器在入网后,稳定工作时的行为是,每隔一段时间发送一次网络连接状态帧,默认是15S

六、终端与协调器无线通信过程

1)入网过程,终端的入网过程和路由器入网的过程,所有的行为都是一样的【(1)—(13)】

2)与路由器不同的是,终端在入网之后,终端节点会向它的父节点所在网络中的协调器节点发送数据请求帧,告诉父节点,自己还在线。协调器在收到终端发送的数据请求帧,硬件自动回复ACK。

七、上述是使用抓包工具(USBDongle抓取无线局域网里面的无线数据包

1)抓包工具USBDongle配置:

① 选择IEEE 802.15.4/Zigbee

② 选择驱动

③ 选择抓包信道:需要和你使用无线通信的信道相同

④ 选择ZigBee 2007/PRO


资源链接:https://pan.baidu.com/s/1KBxHLfRfJeEBVyTq3H5TGw

提取码:zjzb


希望本篇文章对大家有所帮助,后续会继续分享Zigbee相关学习知识…

如果文章内容有错误的地方,请在留言处留下你的见解,方便大家共同学习。谢谢!

如有侵权或其他任何问题请联系:QQ1370922071,本文主要用于学习交流,转载请声明!

作者:皮皮猫吖


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

  1. 【Zigbee】基础篇(1) Zigbee是什么?Zigbee的介绍及学习?

    大家好,我是皮皮猫吖! 每文一言:每一次跌倒都是为了华丽的站起来! 本篇文章: 从Zigbee是什么开始到如何学习Zigbee? 正文如下: 一.Zigbee是什么? 1)Zigbee是一种近距离.低 ...

  2. 【JAVA基础篇】对象初始化过程

    我们都知道,创建对象是由 new关键字调用构造方法 返回类实例(实际上还可以通过反射来创建实例). 例如 : Person jack = new Person(); 这句话到底做了什么事情呢 ? 其实 ...

  3. 不可不知的IEEE 802.15.4和ZigBee基础

    IEEE 802.15.4网络是指在一个POS内使用相同无线信道并通过IEEE 802.15.4标准相互通信的一组设备的集合,又名LR-WPAN网络.ZigBee是基于IEEE802.15.4标准的低 ...

  4. zigbee基础应用(五)uart串口通信

    zigbee基础应用(五)uart串口通信 1.硬件篇 P0.2为RX P0.3为TX 2.芯片篇 用到的芯片的概况 3.计算篇 波特率的计算公式,通过对UxBAUD.BAUD_M和UxGCR.BAU ...

  5. Zigbee基础知识介绍 - 新兵训练营(1)

    English | 中文 The article is released under license CC BY-NC-ND 4.0 IoT Boot Camp系列课程是由TorchIoTBootCa ...

  6. 菜鸟学习笔记:Java基础篇3(面向对象思想、程序执行过程内存分析、面向对象重要概念)

    菜鸟学习笔记:Java面向对象篇上 Java面向对象的思想 Java程序执行过程内存分析 Java垃圾回收机制 构造方法 方法重载(overload) static关键字 this关键字 Java面向 ...

  7. ZigBee基础知识(二)

    目录 2.1 设备类型(Device Types) 2.1.1 Coordinator(协调器) 2.1.2 Router(路由器) 2.1.3 End-Device(终端设备) 2.2 协议栈规范( ...

  8. zigbee基础知识学习

    一.Zigbee简介 近年来,由于无线接入技术的需求日益增大,无线通信和无线网络均呈现出指数增加的趋势. 这有力的推动力无线通信向高速通信方向的发展. 然而,工业.农业.车载电子系统. 家用网络.医疗 ...

  9. 编程模拟飞船加速变轨过程-物理基础篇(5) 摄动方程

    编程模拟飞船加速变轨过程物理基础篇(5) 摄动方程 根据前面的内容,我们已经能够做到当已知某时刻位矢和速度时,求出轨道形状了.但是,这些都是在只受中心引力的前提下求得的.本篇在原作中是讲其他微小力(稀 ...

  10. 编程模拟飞船加速变轨过程-物理基础篇(3)Kepler轨道及其描述(上)

    编程模拟飞船加速变轨过程物理基础篇(3) Kepler轨道及其描述(上) 开普勒轨道及其描述是用若干要素表示出飞船在地球中心引力场中绕地球飞行具体形状的一种方法,我们希望在已知这些要素的前提下精确的描 ...

最新文章

  1. cortex系列处理器排行_ARM推出Cortex-A78C处理器,欲夺X86笔记本市场
  2. LeetCode 575. 分糖果(set集合去重)
  3. 分治法:快排划分法(单向扫描法)
  4. linux 查看数据库和表
  5. 学计算机用苹果本,新手小白用苹果电脑搞科研,学会这些才不至于尴尬!
  6. Repository模式--采用EF Fluent API使用EntityTypeConfiguration分文件配置Model映射关系
  7. Entity FrameWork Core使用 Include查询关联数据以及机理。
  8. 巧用头条号及悟空问答引流
  9. fpd link III
  10. html表白程序源码_表白程序源码html_程序员表白代码html
  11. 小程序setData执行后,页面没有刷新
  12. 《计算机网络(谢希仁6版)》学习笔记(word导入)[待补全]
  13. linux无线usb网卡,Linux下USB无线网卡WL-167G驱动安装过程
  14. Android app内部下载安装
  15. python数据分析岗位_python拉勾数据职位分析
  16. XiaoHu日志 6/29~7/30
  17. dind(docker in docker)镜像-使用Docker学习Docker
  18. 前端开发:如何写一手漂亮的 Vue
  19. ElasticSearch --- elasticsearch.yml配置详解
  20. buuctf——rot

热门文章

  1. 从NCBI中查看已发现的基因可变剪接
  2. 将Ubuntu中文目录改为英文目录
  3. 【王者荣耀】入门战斗经验
  4. 金叉成功率_曝光MACD零轴上的秘密:“0线下方金叉买入”千万别小看,成功率达100%!...
  5. php 七牛云 视频加水印
  6. Microsoft Edge导出浏览历史记录
  7. 阿里巴巴面试题含答案
  8. python实现论文查重系统_基于数据仓库的图书数据挖掘系统设计与实现毕业论文+Python源码+知网查重报告...
  9. 超全!我常用的70个数据分析网址
  10. linux基础-mkdir touch cp