嵌入式开发记录-day52 zigbee模块介绍及测试


1、模块原理图

  电源部分:使用USB或者直流DC座供电;在使用一个电源模块将5V转为3.3V

 

   UART部分,由于模块使用的是串口,需要使用一个电平转换芯片,方便我们使用电脑上位机直接测试

   核心部分,zigbee封装的芯片,使用串口与外部通信

 2、模块的特性:

  1、配置正常启动后,可以组成多跳网状网络;

  2、网络中的模块之间可以相互发送数据;

  3、串口参数:数据位8,起始位1,停止位1,无校验。波特率可以修改;默认115200;

3、zigbee模块传输的协议

  1、Zigbee模块是一种自组网多跳无线通信模块。该模块工作时,会与周围的模块自动组成一个无线多跳网络,此网络为 对等网络,不需要中心节点。模块无线频率为2.4GHz~2.45GHz,属于 全球免费的无线频段。网络包含以下可配置参数:

  

   将多个Zigbee模块配置成地址不相同,信道和网络ID相同的状态,模块将组成一个网络。

  Zigbee模块使用定向扩散协议寻找路由,这种路由算法会记录网络的状态,每个节点平 均可记录130个目标节点的路由,在网络建立后传输速度和传输延时可到达最优。但这种算 法网络建立较慢,在节点刚刚启动时,网络需要1~5分钟的时间重新生成路由,在这段时间 内网络使用洪泛路由进行数据通信,此时网络的传输速度较慢。

  2、网络性能:

 

   3、包分割:

  在通信过程中,最常见的场合是单片机通过Uart告诉模块这样的信息:

     “将数据 00 AE 13 33 发往地址为0003的模块,目标端口为90,源端口为91。

  ” 对于单片机,需要将这些信息整理成一个包,通过Uart发给模块: FE 08 91 90 03 00 00 AE 13 33 FF 

  

   远程地址长度为2byte,使用小端模式进行传输,即先传输低8位,再传输高8位。

  传输过程中如果遇到数据部分、地址或者端口号中出现FF,则使用FE FD来代替;

  如果 出现FE,则用FE FC来代替。以免传输过程中出现的包头和包尾,使接收方误判断。在传输 中这种替换称为“转义”。 包长度不会受到转义的影响,例如发送的数据为09 FF时,替换为09 FE FD,但包头中 的数据长度仍然按照2+4来计算,这样,发送的包如下: FE 06 91 90 03 00 09 FE FD FF 虽然一共传输了7个字节,但包长为6。如果地址、端口号中出现了FF、FE也需要进行 转义。

  4、端口:

  。端口号的取值范围是0x00~0xFF,其中0x00~0x7F端口由模块内部程序占用, 0x80~0xFF端口开放给Uart连接的MCU或者电脑

4、模块测试的命令集合

1 读取模块命令:
查询IP地址
Send:    FE 05 90 21 00 00 01 FF
Rec:    FE 07 21 90 00 00 21 02 00 FF

读取网络ID
Send:    FE 05 90 21 00 00 02 FF
Rec:    FE 07 21 90 00 00 22 16 20 FF

读取信道:
Send:    FE 05 90 21 00 00 03 FF 
Rec:    FE 06 21 90 00 00 23 13 FF

读取波特率:
Send:    FE 05 90 21 00 00 04 FF
Rec:    FE 06 21 90 00 00 24 08 FF

2 修改模块的命令
修改IP地址:
Send:    FE 07 90 21 00 00 11 1F 00 FF
Rec:    FE 05 21 90 00 00 00 FF

修改网络ID:
Send:    FE 07 90 21 00 00 12 91 19 FF
Rec:    FE 05 21 90 00 00 00 FF

修改信道:
Send:    FE 06 90 21 00 00 13 12 FF
Rec:    FE 05 21 90 00 00 00 FF

修改波特率:
Send:FE 06 90 21 00 00 14 02 FF
Rec:FE 05 21 90 00 00 00 FF

重启包:
Send:FE 05 90 21 00 00 10 FF
Rec:无返回(模块绿灯亮2S 左右)
注意:配置完模块之后一定要发送重启包,配置才会生效。

3 模块间通信:
信道和网络ID必须相同,IP地址必须不同
模块0为66 4A,模块1为99 4A
Send:    FE 08 91 90 04 00 00 AE 13 33 FF        模块1的地址为04 00
修正为:FE 08 91 90 66 4A 00 AE 13 33 FF
 
Send:    FE 08 91 90 03 00 00 AE 13 33 FF        模块0的地址为03 00
View Code

 5、ZigBee协议分析

  

 

 

   其中包头、包尾格式固定,传输的数据区域可变,长度可变化;

  如果传输FE、FF这两个特殊字符需要使用转义字符,转义字符不引入数据长度的变化;

6、ZigBee软件协议框架

7、软件代码分析

  1、主程序中根据传入的命令分别设置不同的模式

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>

#include "main.h"

#define SETMODE  0
#define SENDMODE 1
#define RECMODE 2

extern int uart_init(void);
extern int set_config(int fd ,int length,char *cmd[]);
extern int send_data(int fd,int length,char *cmd[]);
extern int rec_data(int fd);

int para(int argc,char *argv[])
{
    if(argc < 2){
        printf("argv is less\n");
        printf("Usage:    test_zigbee [type] [cmd]\n");
        printf("    type: 0--set, 1--send, 2--recv\n");
        return -1;
    }
    
    return 0;
}

int main(int argc, char *argv[])
{
    int fd=0;
    
    if(para(argc,argv)<0){
        return -1;
    }
    
    fd = uart_init();  // 串口初始化
    if(fd < 0){
        return -1;
    }
    DPRINTF("atoi(argv[1]) is %d\n",atoi(argv[1]));
    switch(atoi(argv[1])){
        case SETMODE:   // 设置模式
            DPRINTF("set_config\n");
            set_config(fd,argc,argv);
            break;
        case SENDMODE:  // 发送模式
            DPRINTF("send_data\n");
            send_data(fd,argc,argv);
            break;
        case RECMODE:  // 接收模式
            DPRINTF("rec_data one time\n");
            rec_data(fd);
            break;
        default:
            break;
    }
    
    return 0;
}
View Code

  2、对串口初始化

int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop);

int uart_init(void)
{
    int fd;
    char *uart3 = "/dev/ttySAC3";   // 串口设备节点
    //打开串口
    if((fd = open(uart3,O_RDWR|O_NOCTTY|O_NDELAY))<0){
        printf("open %s is failed",uart3);
        return -1;
    }    
    else{
        set_opt(fd, 115200, 8, 'N', 1);
        printf("%s init success \r\n",uart3);
    }
    
    printf("uart_init success.\n");
    return fd;
    
}

int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
    struct termios newtio,oldtio;
    if  ( tcgetattr( fd,&oldtio)  !=  0) { 
        perror("SetupSerial 1");
        return -1;
    }
    bzero( &newtio, sizeof( newtio ) );
    newtio.c_cflag  |=  CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;

    switch( nBits )
    {
        case 7:
            newtio.c_cflag |= CS7;
            break;
        case 8:
            newtio.c_cflag |= CS8;
            break;
    }

    switch( nEvent )
    {
    case 'O':
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= PARODD;
        newtio.c_iflag |= (INPCK | ISTRIP);
        break;
    case 'E': 
        newtio.c_iflag |= (INPCK | ISTRIP);
        newtio.c_cflag |= PARENB;
        newtio.c_cflag &= ~PARODD;
        break;
    case 'N':  
        newtio.c_cflag &= ~PARENB;
        break;
    }

    switch( nSpeed )
    {
        case 2400:
            cfsetispeed(&newtio, B2400);
            cfsetospeed(&newtio, B2400);
            break;
        case 4800:
            cfsetispeed(&newtio, B4800);
            cfsetospeed(&newtio, B4800);
            break;
        case 9600:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
            break;
        case 115200:
            cfsetispeed(&newtio, B115200);
            cfsetospeed(&newtio, B115200);
            break;
        case 460800:
            cfsetispeed(&newtio, B460800);
            cfsetospeed(&newtio, B460800);
            break;
        default:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
            break;
    }
    if( nStop == 1 )
        newtio.c_cflag &=  ~CSTOPB;
    else if ( nStop == 2 )
        newtio.c_cflag |=  CSTOPB;
        newtio.c_cc[VTIME]  = 0;
        newtio.c_cc[VMIN] = 0;
        tcflush(fd,TCIFLUSH);
    if((tcsetattr(fd,TCSANOW,&newtio))!=0)
    {
        perror("com set error");
        return -1;
    }
    
    return 0;
}
View Code

  3、进入设置模式

#include "main.h"

int set_config(int fd ,int length,char *cmd[])
{
    unsigned char buffer[128],rec_buffer[1];
    int i,nByte=0,time=0,num,flag=0;
    int check_length=0;
    
    memset(buffer, 0, sizeof(buffer));
    memset(buffer, 0, sizeof(rec_buffer));
    
    DPRINTF("set_config setdata is : ");
    for(i = 0; i < length-2; i++){    
        buffer[i] = strtol(cmd[i+2], NULL, 16);    
        check_length++;
        if(buffer[i] == 0xfe){
            check_length--;
        }
        printf("0x%02x ",buffer[i]);
    }
    printf("\n");
    
    DPRINTF("length uis %d and %d\n",buffer[1],check_length);
    //pak_length = pkg_length - num_fe - 2 
    if(buffer[1] == check_length - 2){
        write(fd,buffer,i);
    }
    else{
        printf("cmd length is err\n");
        return -1;
    }
    
    check_length = 0;
    memset(buffer, 0, sizeof(buffer));
    while(1){
        while((nByte = read(fd, rec_buffer, 1))>0){
            if(rec_buffer[0] == 0xfe && flag != 1){
                num = 0;    
                flag = 1;
                printf("set_config rev data is : ");
            }
            if(flag==1){
                buffer[num] = rec_buffer[0];
                printf("0x%02x ",rec_buffer[0]);
                
                check_length++;
                if(rec_buffer[0] == 0xfe)
                    check_length--;
            }
            
            if(rec_buffer[0] == 0xff){
                goto rec_over;
            }
            
            memset(rec_buffer, 0, sizeof(rec_buffer));
            num++;
            nByte = 0;
            time = 0;
        }
    //if overtime 10ms , break.    
        usleep(1);
        time++;
        if(time>10000){
            DPRINTF("over time\n");
            close(fd);
            break;
        }
    }
    close(fd);
    return 0;
    
rec_over:
    printf("\n");
    if(buffer[1] == check_length - 2){
        DPRINTF("rec length check ok\n");
    }
    else{
        DPRINTF("rec length is err\n");
        return -1;
    }
    close(fd);
    return 0;
}
View Code

  4、进入到发送数据

#include "main.h"

int send_data(int fd,int length,char *cmd[])
{
    unsigned char buffer[128];
    int i,time=0,num,flag=0;
    int check_length=0;
    
    memset(buffer, 0, sizeof(buffer));
    
    printf("set_config setdata is : ");
    for(i = 0; i < length-2; i++){    
        buffer[i] = strtol(cmd[i+2], NULL, 16);    
        check_length++;
        if(buffer[i] == 0xfe){
            check_length--;
        }
        printf("0x%02x ",buffer[i]);
    }
    printf("\n");
    
    DPRINTF("length is %d and %d\n",buffer[1],check_length);
    //pak_length = pkg_length - num_fe - 2 
    if(buffer[1] == check_length - 2){
        write(fd,buffer,i);
    }
    else{
        DPRINTF("cmd length is err\n");
        return -1;
    }
    
    return 0;
}
View Code

  5、接收数据模式

#include "main.h"

int rec_data(int fd)
{
    unsigned char buffer[128],rec_buffer[1];
    int nByte,num,flag=0;
    int check_length=0;
    char buf[128];

    memset(rec_buffer, 0, sizeof(rec_buffer));
    memset(buffer, 0, sizeof(buffer));
    
    while(1){
        while((nByte = read(fd, rec_buffer, 1))>0){
            if(rec_buffer[0] == 0xfe && flag != 1){
                num = 0;    
                flag = 1;
                printf("set_config rev data is : ");
            }
            if(flag==1){
                buffer[num] = rec_buffer[0];
                printf("0x%02x ",rec_buffer[0]);
                printf("num is %d\n",num);
                if((num == 6) && (buffer[6] == 0x01))
                {
                    //system("echo 1 > /sys/class/gpio/gpio126/value");
                    system("./relay 1");
                }
                else if((num == 6) && (buffer[6] == 0x02))
                {
                    //system("echo 0 > /sys/class/gpio/gpio126/value");
                    system("./relay 0");
                }
                if((num == 6) && (buffer[6] == 0x03))
                {
                    system("./step_motor_app R 4076 3000");
                }
                else if((num == 6) && (buffer[6] == 0x04))
                {
                    system("./step_motor_app L 4076 3000");
                }
                check_length++;
                printf(" check_length is %d\n",check_length);
                if(rec_buffer[0] == 0xfe)
                    check_length--;
            }
            
            if(rec_buffer[0] == 0xff){
                //goto rec_over;
                num=0;
                flag=0;
                check_length=0;
                memset(buffer, 0, sizeof(buffer));
            }
            
            memset(rec_buffer, 0, sizeof(rec_buffer));
            num++;
        }
        usleep(100);
    }
    close(fd);
    return 0;
    
rec_over:
    printf("\n");
    if(buffer[1] == check_length - 2){
        DPRINTF("rec length check ok\n");
    }
    else{
        DPRINTF("rec length is err\n");
        return -1;
    }
    close(fd);
    return 0;
}
View Code

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM