chiaming 发表于 2011-2-11 23:55:55

“ UART (USART)口的多机通信 ─ 利用 ZigBee 无线模块相互通信“ 发现了4种数据通

整个系统由“1台PC和5组感测模块(M16L + 6轴传感器)“组成,

其中:
主机部分:1块ZigBee无线通信模块由RS-232 to USB到1台PC,标志为0号。
从机部分:5块ZigBee无线通信模块各自和5组感测模块的UART接口串接,分别标志为1~5号。

总共有6个节点,而全部的ZigBee无线通信模块皆设置为“广播模式”。

程序流程为:
一、1~5号模块分别上电后,进入INITIAL状态,等待接收Capture命令。
二、由0号(PC)透过自身的ZigBee模块”广播”发送一个Capture命令(0xFF0xEC),让1~5号的ZigBee模块一起接收此命令。
三、1~5号模块判断接收到Capture命令(认定为几乎同时收到!?)以后,禁止接收功能(RXEN = 0)。
四、开始对传感器信号进行ADC,各轴轮流采样转换,各5次并且取平均值后,进入INITIAL状态,始能接收功能(RXEN = 1),等待接收ID命令。
五、其中,当1号模块完成ADC后,会自动进入发送数据状态(无需等待接收ID命令),发送全部的数据后,进入INITIAL状态,始能接收功能(RXEN = 1),
    之后又再次地等待0号发送Capture命令。
    数据包格式为: “ID地址、数据1、数据2、数据3、数据4、数据5、数据6“,共7个字节。
六、当0号(PC)接收完1号发送的完整数据包后,开始发送2号的ID命令(0xFFID地址),让2号模块传回它自身模块的数据包。
七、2号模块判断接收到ID命令后,进入发送状态,并且禁止接收功能;数据包发送完成后,进入INITIAL状态,始能接收功能,
    之后又再次地等待0号发送Capture命令。
八、3、4、5号的状态分别类似于六、和七、。
九、最后,0号接收完5号模块的完整数据包后,判断并处理1~5号的数据,又再次地”广播”发送Capture命令,让1~5号的ZigBee模块一起准备接收此命令,
    回到流程二、。

问题描述如下:
发现了4种数据通信的问题情况,导致整体流程通信到一半,就卡住停止了:
1. 0号(PC)开始发送Capture命令,整体流程通信了一段时间,突然1~5号模块没有收到Capture命令?
2. 整体流程通信了一段时间,突然1~5号模块的某一号模块没有收到0号发送的ID命令,以致数据只显示到上一号模块。
3. 同上,但情况变为:0号(PC)没有收到1~5号某一号模块的数据包,以致无法发送下一组的ID命令。
4. 同上,情况为:0号(PC)没有收到5号模块的数据包,以致无法发送Capture命令。

检查过PC收到的每一号模块的数据包内容,皆正确无误。
而这些问题发生的时间都是随机不固定的,有时发生在启动后2秒内,有时发生在启动后10秒内,甚至有时发生在2分钟内,但是有时候通信却很稳定。

已经思考了很久,但仍不知道哪里有问题,在此麻烦请教各位,谢谢。

(下方为2号模块的M16L程序内容)

chiaming 发表于 2011-2-11 23:57:21

/*****************************************************************************************************************************
   CPU : ATmega16L
   CLK : 7.3728 MHz
   Buad Rate : 57600         
*****************************************************************************************************************************/
#define F_CPU         7372800

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "ZIG100.h"

#defineID            0x32      //编号2
#defineSTART      0xEC      //模块启动命令
#defineCALLFLAG      0xFF      //接收起始旗标
#defineSENSOR          6         //感测轴数
#defineTIMES         5         //采样次数

/* 状态参数 */
#defineINITIAL         0         //初始
#defineACTION          1         //AD转换
#defineTX            2         //传送
#defineWAIT            4         //等待ADC完成

/* 指令接收参数 */
#defineQUANTITY      2         //指令数据2笔
#defineFIRST         0         //索引值 0
#defineSECOND          1         //索引值 1

/* USART参数 */
#defineFOSC            7372800               // Clock频率 //
#defineBUAD            57600               // Buad Rate //
#defineUBRR            (FOSC/(16*BUAD))-1

/* ADC参数 */
#defineADC_INITI       0x60      // ADC参考电压:AVcc,数据向左对齐 //

/* 各个输入通道 */
#defineADC1            0x01
#defineADC2            0x02
#defineADC3            0x03
#defineADC4            0x04
#defineADC5            0x05
#defineADC6            0x06

volatile int State = 0;

int RxNum = 0;
int Axis = 0, Count = 0;                     //惯性轴和采样次数

unsigned int ADC_Data;      //组合ADC数据
unsigned int ADC_Average;            //ADC平均

unsigned char RX_Command;

//ADC取5次平均//
void AverageFilter(void)
{
int axis, count;

for(axis = 0; axis < SENSOR; axis++)
{
    ADC_Average = INITIAL;                     //清空上一堆数据

    for(count = 0; count < TIMES; count++)
    {
      ADC_Average += ADC_Data;      //不断累加
    }

    ADC_Average /= TIMES;                        //平均=累加和/5
}
}

//无线传送ADC值//
void ADC_Tx(void)
{
int axis;

ZIG100_Tx(ID);                                       //传送ID

for(axis = 0; axis < SENSOR; axis++)
{
    ZIG100_Tx((unsigned char)ADC_Average);       //数据1~6
}
}

//USART接收中断程序//
ISR(USART_RXC_vect)
{
RX_Command = UDR;                   //读取UDR值,更新RXC

switch(RxNum)
{
    case FIRST:
      if(RX_Command == CALLFLAG)
      {
      RxNum = SECOND;
      }
      break;

    case SECOND:
      switch(RX_Command)
      {
      case START:                   //Capture 命令
          UCSRB &= ~_BV(RXEN);
          State = ACTION;
          break;

      case ID:                      //ID 命令
          UCSRB &= ~_BV(RXEN);
          State = TX;
          break;
      }
      RxNum = FIRST;
      break;
}
}

//ADC中断程序//
ISR(ADC_vect)
{
//在取样次数内即可转换,超过即取平均//
if(Count < TIMES)
{
    ADC_Data = ADCH;

    ADMUX++;                              //切换channel

    Axis++;                                 //切换axis

    //重新切换并采样次数+1//
    if(Axis == SENSOR)
    {
      ADMUX = ADC_INITI | ADC1;             //再从ADC1开始

      Axis = INITIAL;

      Count++;
    }

    State = ACTION;
}
else
{
    AverageFilter();                        //Count超过后,开始取平均

    Count = INITIAL;                        //重新计数采样次数

    State = INITIAL;
}
}

int main(void)
{
DDRA = 0x00;                     //PA为传感器输入
PORTA = 0x00;

//USART抗干扰//
DDRD = 0x02;                     //RXD输入,TXD输出
PORTD = 0x03;                  //RXD上拉电阻有效,TXD输出

ADMUX = ADC_INITI | ADC1;      //从 ADC1 开始 //

USART_Initi(UBRR);               //设定USART和buad rate

//ADC enable, ADC interrupt enable, ADC_clk=7.3728 M/64=115.2 KHz//
ADCSRA = _BV(ADEN) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1);

sei();                           //全局中断

while(1)
{
    switch(State)
    {
      case INITIAL:
      State = WAIT;
      UCSRB |= _BV(RXEN);      //启动RX,准备接收讯号进入中断
      break;

      case ACTION:
      ADCSRA |= _BV(ADSC);       //ADC start (单次转换, 每次到完成都需要25个ADC_clk周期)
      State = WAIT;
      break;

      case TX:
      ADC_Tx();
      State = INITIAL;
      break;

      case WAIT:
      // 等待 //
      break;
    }
}
}

------------------------------------ZIG100.h------------------------------------------------
void USART_Initi(unsigned int ubrr)
{
UBRRH = (unsigned char)(ubrr >> 8);
UBRRL = (unsigned char)ubrr;
UCSRB = (1 << RXCIE) | (1 << RXEN) | (1 << TXEN);
UCSRC = (1 << URSEL) | (3 << UCSZ0);
}

void ZIG100_Tx(unsigned char data)
{
while( !(UCSRA & (1 << UDRE)) );
UDR = data;
}

superrf 发表于 2011-2-12 09:09:33

无线传输的一大特点就是不可靠,容易受干扰
Zigbee不是可靠通讯的协议栈不同于有线网的TCP
而且串口通信业会产生误码,最好加上数据包头和校验数据

sailen 发表于 2011-2-12 09:14:25

是否因为无线网络部稳定?出现数据误传,或者丢失?没有看到楼主的握手协议部分,建议加入0号和1~5号的握手试试。

chiaming 发表于 2011-2-13 00:56:30

回复【2楼】superrf
无线传输的一大特点就是不可靠,容易受干扰
zigbee不是可靠通讯的协议栈不同于有线网的tcp
而且串口通信业会产生误码,最好加上数据包头和校验数据
-----------------------------------------------------------------------

后来有尝试将数据包的内容修改,加了数据包头 (0xFF0xAA0x55),并且再增加一个测试节点,接收主/从机的所有数据。
发现:
不论是主或从机部分,所发送出来的数据内容都正确;但是依然会有类似的问题 --- 系统通信了一段时间,主(从)机有广播发送出数据,然而从(主)机似乎没收到命令,所以没传回自身数据。

而系统没在最后加上checksum,是因为希望单单就通信的部分,先能够稳定发送和接收数据不会间断。

烦请指导,谢谢。

chiaming 发表于 2011-2-13 01:19:31

回复【3樓】sailen
是否因為無線網絡部穩定?出現數據誤傳,或者丟失?沒有看到樓主的握手協議部分,建議加入0號和1~5號的握手試試。
-----------------------------------------------------------------------

数据部分似乎没有误传,有增加测试节点来做测试。
不论是主/从机,每个节点发送或接收到的数据内容都正确,但就是会有此问题:通信了一段时间,主(从)机有广播发送出数据,然而从(主)机似乎没收到命令,所以没传回自身数据。
烦请指导,谢谢。

sytu_xww 发表于 2011-2-13 16:19:44

其实你的情况很简单的啊,你没有加上超时处理的啊,不可以无限等待某一个一节点给你回复。必须设置超时时间,等待一定时间后没有收到回复,要么重发,要么丢弃发下一个节点。
不知道你ZigBee是哪家的芯片?有没有走协议栈。

chiaming 发表于 2011-2-13 18:49:47

回复【6楼】sytu_xww芦苇
-----------------------------------------------------------------------

全部使用的ZigBee模块是ZIG-100,模块上的芯片是CC2420。

PC(0号)端的程序是使用DataReceived触发的,接收到上一个节点的数据,处理后便会发送呼叫下一个节点回传数据。
但是通信一段时间,在某个时间点,PC端却没有进入触发程序 (下一个节点没有回传数据);透过测试端接收测试的话,确实有收到下一个节点发送的回传数据,这是不懂的问题所在。

为了固定并缩短整体的采样周期,请问能否不加上超时处理呢?因为并不知道何时会发生超时,或是发生的次数也不固定。

烦请指导,谢谢。

renkaikaiser 发表于 2011-2-24 11:55:26

你是不是遇到同频干扰的问题了?

renkaikaiser 发表于 2011-2-24 11:59:00

我也用过cc2420,遇到了通信瘫痪的问题。
这里假定你没有用协议栈,那么你在发送数据之前,要用CCA探测一下,如果信道空闲,再随机退避一个时间,把数据发送出去。
记得2420是具有cca_txon功能的。用这个命令发送,STXONCCA。

chiaming 发表于 2011-2-28 17:04:52

回复【9楼】renkaikaiser
-----------------------------------------------------------------------

我使用的是应用层部分,协议栈应该都被产品(ZIG-100)写好了。
在每次通信期间,我都有延迟一小段时间再发送,还是会发生模块或PC机有收不到数据的情况,但是单纯接收的测试端就都有收到?

icexiong 发表于 2012-7-16 10:50:35

chiaming 发表于 2011-2-28 17:04 static/image/common/back.gif
回复【9楼】renkaikaiser
-----------------------------------------------------------------------



我也遇到同楼主一样的问题,总感觉Zigbee通讯的稳定性太差了,我感觉好像有丢包,只能通过应用层加一些超时,重发来处理了。

付新辉 发表于 2013-3-17 15:05:53

周末没事 mark优秀帖
页: [1]
查看完整版本: “ UART (USART)口的多机通信 ─ 利用 ZigBee 无线模块相互通信“ 发现了4种数据通