嵌入式開發記錄-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