基于ZigBee的远程液位监控系统
一、技术说明
在居民用水、工业生产等大量重要应用中,需要对液位进行监测和控制。在现在的液位监控系统中大多有以下问题:1、多使用压电、光电、超声波等传感器进行液位的检测,价格昂贵,原理也比较复杂。2、液位监控数据的远程监测和控制方式要么没有;要么较为单一。常见的远程监测系统多采用RS485等工业现场总线传输,布线麻烦,数据传输方式落后。
针对以上问题,本发明提出了新的低成本的液位检测方法和更先进的数据传输方式:
1、采用电容式液位检测原理:在容器中的不同深度插入多对电极,在阳极中通入高频交流信号,液体浸没电极时,与此阴阳极连接的电路电导增大,电路导通增大,对导通信号进行处理后转化为开关信号,指示相应的液面位置。
2、通过液位检测器上连接的ZigBee模块将液位监测数据发送至WSN;通过远程监控器上的ZigBee模块发送控制数据至WSN。数据传输和整合能力强。
1.1总体设计
整个系统由前端的液位检测电极、水位检测模块、单片机控制板、近端的ZigBee模块和远端的ZigBee模块构成,见系统整体架构图(图1.1)。
图1-1系统整体架构
其中水位检测电路检测液面位置,将其转化为开关信号,传送给单片机。水位检测模块检测到的开关信号输入到单片机I/O引脚。水位检测电路能够检测
到的液面位置数量L
N与需要分配的单片机I/O引脚数量
P
N存在如下关系:
2P N
L
N=
口发送给近端ZigBee 模块,接着近端ZigBee 模块再将液面数据发送给远端ZigBee 模块。单片机控制模块可以在本地自主控制液面位置,也可以接收远端ZigBee 模块命令,实现远程控制。远端ZigBee 模块在接收到液面数据后可显示在自己的液晶屏上,也可以通过串口再传送给电脑进行显示和存储。远端ZigBee 模块上面设置有控制按键,可以通过手动的方式发送控制指令给近端的单片机控制模块。一个指令由三个字节组成,分别是指令头、指令值、和帧校验。指令头用于指示指令的开始。为了保证指令传输的靠性,加入了一个校验字节,其生成方法是对前两个字节做CRC 运算。
1.2 液位检测原理
电容式传感器检测原理:
本发明采用了电容式传感器原理,在待检容器中N个水平面置入N对电极, 这样每对电极相当于相当于一个电容器。 图1-2在空气中 图1-3浸入液体中 此电极在空气中的电容记为C1,浸入液体中的电容记为C2,设空气的介电常数为0e ,液体的介电常数为1e ,则C1和C2分别为:
014S C kd e p =
(1) 124S
C kd
e p = (2)
(S 为极板面积,d 为两极板间相对距离)
设电极上施加的交流信号频率为f,则两种情况下的容抗分别为:
11
12C X fC p =
(3) 22
12C X fC p =
(4)
假定液体介质的电阻极大,则两者的电导分别为:
01
2C f S G kd e =(5) 122C f S G kd
e = (6) 则电导率之比:
2110//C C G G e e =(7)
通态电流之比:
2110//C C I I e e = (8)
由此可见,在这两种情况下的电流之比等于液体与空气的介电常数之比,
而且大部分液体的介电常数显著大于空气,所以在电极浸入液体的情况下电极间
电路的通态电流将会有明显的增加。从公式(6)可以看到,电极的通态电流强度还与电流频率成正比,所以在本系统使用高频交流信号进行检测,以提高电路的敏感度。
检测电路整体原理:
图1-4 检测电路整体原理
检测电路中首先由振荡性生电路产生高频交流电压信号施加在液位检测电极上。液位上升浸没电极后,交流信号由液体介质传导,经整流滤波电路处理后变成直流电压信号输入到电压比较电路与一参考电压比较。此参考电压由电阻分压电路得到,其电压值设置为大于电极在空气中时整流滤波电路的输出电压值,小于浸入介电液体时整流滤波电路的输出电压值。电压比较电路是由电压比较器构成的,整流滤波电路的输出电压接到电压比较器的反相端,参考电压接在同相端。这样在电极浸入液体前后,比较电路的输出电压将会性生翻转,指示浸入液面。此输出电压输入到单片机作为其进行液位控制的参量。 检测电路详细原理:
整个系统由振荡电路、LED 指示电路、继电器驱动电路、基准电压、供电电路及传感器电路构成。见图1-5(Altium 绘制):
图1-5 检测电路详细原理
①振荡电路:U1A及外围元个组成一个多谐振荡电路,工作在放大比较器状态。R1和R12对5V进行分压,R3为正反馈电阻,共同作为同相输入3脚的基准电压V+,反相输入端2脚V-取自R2,C1组成的积分电路C1两端。V+与V-进行比较决定输出SIG电压的高低,由于C1不断在正反两个反方向充电和放电,使V-的电压不断大于V+和小于V+,输出的SIG电压也就不断在高低电瓶间翻转,这样就产生了系统所需要的震荡信号SIG。
② LED指示电路:此电路包括整流滤波和电压比较两部分。C2为耦合电容,D1、D2、整流,C4滤波,在R4上形成整流滤波后的电压作为U1B反向输入端电压。同相输入端电压由基准电压VREF提供,同相输入端电压和反向输入端电压进行比较,若通向输入端大于反向输入端电压则输出高电平;反之输出低电平。J1和J2 外接液位传感器,相当于是由液位控制的两个开关,低液位时J1和J2均为开路状态,R4和R13上无电压。此时U1的7脚和8脚均输出高电平,故只有红色D6(低液位指示)发光。中液位时,液位传感器使J1短路,SIG信号经C8耦合,D4和D5整流,C9滤波在R13上形成电压作为U1C反向输入端电压,此电压大于U1C同相输入端电压,所以8脚输出低电平,红色D6(低液位指示)熄灭,D7黄色(中液位指示)发光。高液位时,液位传感器使J2也短路,SIG信
号经C3耦合、经导电液体到C2耦合。D1和D2整流。C4滤波在R4上形成电压
作为U1B反向输入端电压;此电压大于U1B同相输入端电压,所以7脚输出低电平,红色D7(中液位指示)熄灭,D3绿色(高液位指示)发光。
③基准电压:由R10与R11串联分压获得基准电压,C10起到进一步稳定基准电压的作用。电阻分压计算公式为VREV=5*R11/(R10+R11)
④供电电路:J3外接5V电源,C5、C6滤波。
⑤传感器电路:由两组镀锡走线构成,较长一组为中液位感应线,较短一组为
高液位感应线。如果在实际应用中感觉中液位和高液位距离不够,可用两条导电铜丝分别焊接在中液位感应线上。
⑥与单片机接口:中液位比较器的输出线接单片机的PTA3输入口;高液位比
较器的输出线接单片机的PTA2输入口。
1.3 单片机控制模块(要求有整体任务流程图)
单片机整体流程图
1、检测水位程序流程
单片机模块通过PTA2、PTA3引脚电位的高低来判断液位。在液位检测模块中,液体的低、中、高液位时U1中的7、8引脚电位会改变。通过导线把U1这两引脚的电位传输到单片机PTA2、PTA3引脚上。11低液位、10中液位、00高液位
void LEVEL(void) 液位检测子程序 {
level=PTA&0x0c; //0000 1100 提取液位引脚参数
switch (level)
{
case LOW_LEVEL: 11低液位时,数码管显示0
{
dspbf[3]=0;}
break;
case MID_LEVEL: 01中液位时,数码管显示1
{
dspbf[3]=1;}
break;
case HIGH_LEVEL: 00高液位时,数码管显示2
{
dspbf[3]=2;
}
break;
default: 引脚提取值非上述,则为乱码,数码管显示8 dspbf[3]=8;
break;
}
}
2.串口接收、发送协议及程序流程
A.串口通信
串口通信的概念:串口按位(bit )发送和接收字节。尽管比按字节(byte )的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。
RS-232针脚的功能: 数据:
TXD (pin 3):串口数据输出(Transmit Data) RXD (pin 2):串口数据输入(Receive Data) 握手:
RTS (pin 7):发送数据请求(Request to Send) CTS (pin 8):清除发送(Clear to Send) DSR (pin 6):数据发送就绪(Data Send Ready) DCD (pin 1):数据载波检测(Data Carrier Detect) DTR (pin 4):数据终端就绪(Data Terminal Ready) 地线:
GND (pin 5):地线 其他
RI (pin 9):铃声指示
本项目仅使用了串口的三根线: TXD (pin 3):串口数据输出(Transmit Data)
RXD (pin 2):串口数据输入(Receive Data) GND (pin 5):地线
地线相连,数据的输入、输出线交叉相连,以此来进行串口通信。
B.接收数据协议
*.当单片机没有接收到强制命令或接收到05恢复自动命令后,液位监控系统处于自动控制过程。在自动控制的过程中,通过单片机检测到液位,判断液位的低、中、高直接给PTA4一个电平,从而实现自动控制。当液位为低液位时,单片机会自动从PTA4端口输出1,从而打开电磁阀;当液位为中或高液位时,单片机会自动从PTA4端口输出0,从而关闭电磁阀。
*.在强制的控制的过程中,当单片机收到ZigBee模块通过串口发送过来强制命令后,对液位进行强制控制。该项目中设置的是06为强开、04为强闭。当单片机收到ZigBee模块发来的数据为06时,单片机在TA4端口输出为1,强制使继电器吸合,从而使电磁阀打开;。当单片机收到ZigBee模块发来的数据为04,单片机在TA4端口输出为0,强制使继电器断开,从而使电磁阀关闭;只有当单片机接收到ZigBee模块发送的的05数据时,恢复自动控制状态。
*.单片机收到ZigBee模块发送的数据为09时,则单片机把检测的液位反馈给ZigBee模块。本设计中的ZigBee模块是每间隔一定的时间段就向单片机发送09数据,单片机在接收到09数据后,将液位反馈给ZigBee模块。
3、水位控制-继电器控制电路原理、控制程序分析
水位控制-继电器控制电路原理:
单片机通过PTA4端口控制液位。当PTA4为高电平时,三极管导通,继电器处于工作状态,电磁阀打开;当PTA4为低电平时,三极管截止,继电器处于不工作状态,电磁阀关闭。
继电器控制子程序
void chuankou(void) //串口接收数据判断
{
switch (ch)
{
case 0x09: //判断接收到液位检测命令
LEVEL(); //液位检测函数
if (zd)
{
shuiweikongzhi(); //如果是自动模式,进入自动控制水位函数 }
SEND_BYTE(dspbf[3]+0x30); /*将A口的检测值发送出去*/
break;
case 0x06: //判断接收到启动上水命令
zd=0; //进入强制模式
LEVEL(); //液位检测函数
PTA_PTA4=1; //启动上水电磁阀
break;
case 0x04: //判断接收到关闭上水命令
zd=0; //进入强制模式
LEVEL(); //液位检测函数
PTA_PTA4=0; //关闭上水电磁阀
break;
case 0x05: //判断接收到自动控制命令
zd=1; //进入自动控制模式
LEVEL(); //液位检测函数
shuiweikongzhi(); //处于自动控制状态
break;
default:
break;
}
}
//------------------------------------------------------------------- shuiweikongzhi() //控制电磁阀的开关
{
if((level==HIGH_LEVEL)||(level==MID_LEVEL))
PTA_PTA4=0; //液位为中液位或高液位时,把PTA4置0
else if (level==LOW_LEVEL)
PTA_PTA4=1; //液位为低液位时,把PTA4置1
return PTA_PTA4;
}
2、检测水位程序流程
3、串口接收、发送协议及程序实现
4、水位控制-继电器控制电路原理、控制程序分析
1.4 ZigBee通信模块
1.4 ZigBee通信模块
1、通信协议
①无线协议
a协调器创建网络成功后,终端加入网络便可向协调器发送数据。
b将协调器和终端绑定(按下远端模块“LEFT”键触动绑定,绿灯亮),从而解决了协调器给终端发送数据。绑定模式为自动绑定。
②液位状态协议
a近端模块通过串口向单片机周期性发送采集液位状态请求“9”,单片机接收请求后采集液位状态并回发数据,近端模块接收分析数据并显示相应液位状态,并直接发送给远端模块。协议如下:
若单片机回发数据为“39 B0”则近端模块显示为“Low_LEVEL”,表示低液位;若单片机回发数据为“39 B0”则近端模块显示为“Middle_LEVEL”,表示中液位;若单片机回发数据为“39 B0”则近端模块显示为“High_LEVEL”,表示高液位。b远端模块接收到数据并显示相应的液位状态。协议如下:
若近端发送“176”则远端模块显示为“Low_LEVEL”,表示低液位;
若近端发送“177”则远端模块显示为“Middle_LEVEL”,表示中液位;
若近端发送“178”则远端模块显示为“High_LEVEL”,表示高液位。
③工作模式协议
a系统最初状态是自动模式。
b远端模块可通过按键来控制工作模式,并在远端模块和近端模块显示工作模式。协议如下:
若按下远端ZigBee模块“UP”键,则系统触动强制关闭模式;
若按下远端ZigBee模块“RIGHT”键,则系统触动自动模式;
若按下远端ZigBee模块“DOWN”键,则系统触动强制打开模式;
2、近端ZigBee的任务流程分析
首先设置串口,通过串口每隔2秒周期性发送采集水位请求给单片机,等待并接受单片机回应数据,分析数据,显示相应水位,再发送给远端ZigBee模块。
①设置串口
在GenericApp的EndDeviceEB工程的编译选项中定义ZTOOL_P(即HAL_UART 被定义为TURE), Zmain中的串口初始化程序将被执行。
在工程的编译选项中去掉“MT_TASK”的宏定义和“MT_ZDO_FUNC”宏的定义,在其前加上“x”即可。
另外还要对OnBoard.c中的第147行进行修改,改为:
#if defined (ZTOOL_PORT) && !defined(HAL_ADC)
MT_IndReset();
#endif
在MT层的SPIMgr.c中自定义一个专门为GenericApp任务进行串口参数配置的函数Uart_DMA_Init,同时还要在SPIMgr.h中添加一个外部函数调用的声明extern void Uart_DMA_Init (void);以便为SPIMgr.c范围之外的其它函数所调用。
void Uart_DMA_Init ()
{
halUARTCfg_t uartConfig;
/* UART Configuration */
uartConfig.configured = TRUE;
uartConfig.baudRate = SPI_MGR_DEFAULT_BAUDRATE; //波特率38400bps
uartConfig.flowControl = 0;//SPI_MGR_DEFAULT_OVERFLOW; no flow control
uartConfig.flowControlThreshold = SPI_MGR_DEFAULT_THRESHOLD;
uartConfig.rx.maxBufSize = SPI_MGR_DEFAULT_MAX_RX_BUFF;
uartConfig.tx.maxBufSize = SPI_MGR_DEFAULT_MAX_TX_BUFF;
uartConfig.idleTimeout = SPI_MGR_DEFAULT_IDLE_TIMEOUT; uartConfig.intEnable = TRUE;
//#if defined (ZTOOL_P1) || defined (ZTOOL_P2)//不需要的回调函数功能,删去
// uartConfig.callBackFunc = SPIMgr_ProcessZToolData;
//#elif defined (ZAPP_P1) || defined (ZAPP_P2)
// uartConfig.callBackFunc = SPIMgr_ProcessZAppData;
//#else
uartConfig.callBackFunc = NULL;
//#endif
/* Start UART */
#if defined (SPI_MGR_DEFAULT_PORT)
HalUARTOpen (SPI_MGR_DEFAULT_PORT, &uartConfig);
#else
/* Silence IAR compiler warning */
(void)uartConfig;
#endif
}
将Uart_DMA_Init()这个函数添加到应用层任务的初始化函数GenericApp_Init( taskID );中以便在操作系统初始化时完成当前串口参数的配置。
void GenericApp_Init( byte task_id )
{
………………………….
#if defined ( LCD_SUPPORTED )
Print8(HAL_LCD_LINE_2,20, "GenericApp", 1);
#endif
#if defined(ZTOOL_P1)
Uart_DMA_Init();
#endif
ZDO_RegisterForZDOMsg( GenericApp_TaskID, End_Device_Bind_rsp ); ZDO_RegisterForZDOMsg( GenericApp_TaskID, Match_Desc_rsp );
}
修改波特率
uint8 HalUARTOpen( uint8 port, halUARTCfg_t *config )
{
…………………………
#if HAL_UART_0_ENABLE
if ( port == HAL_UART_PORT_0 )
{
// Only supporting 38400 or 115200 for code size - other is possible. U0BAUD = (config->baudRate == HAL_UART_BR_38400) ? 59 : 216;
U0GCR = (config->baudRate == HAL_UART_BR_38400) ? 10 : 11;
U0BAUD = (config->baudRate == HAL_UART_BR_9600) ? 59 : 216;// 判断9600bps
U0GCR = (config->baudRate == HAL_UART_BR_9600) ? 8 : 11;
U0CSR |= CSR_RE;
#if HAL_UART_DMA == 1
cfg->flag = UART_CFG_DMA;
HAL_UART_ASSERT( (config->rx.maxBufSize <= 128) );
HAL_UART_ASSERT( (config->rx.maxBufSize > SAFE_RX_MIN) );
cfg->rxBuf = osal_mem_alloc( cfg->rxMax*2 );
osal_memset( cfg->rxBuf, ~DMA_PAD, cfg->rxMax*2 );
DMA_RX( cfg );
#else
cfg->flag = 0;
HAL_UART_ASSERT( (config->rx.maxBufSize < 256) );
cfg->rxBuf = osal_mem_alloc( cfg->rxMax+1 );
URX0IE = 1;
IEN2 |= UTX0IE;
#endif
…………………………
}
做完以上操作便可调用uint16 HalUARTWrite( uint8 port, uint8 *buf, uint16 len )(在hal_uart.c中)进行数据的串行DMA方式发送。
②采集并显示液位状态,再发送液位状态到远端ZigBee模块
在终端设备中添加液位采集自定义事件GENERICAPP_SEND_MSG_EVT,在终端设备加入到一个网络成功时(即ZDO_STATE_CHANGE系统事件),发送此用户自定义事件。代码如下:
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
…………………………………………
case ZDO_STATE_CHANGE:
GenericApp_NwkState = (devStates_t)(MSGpkt->hdr.status); if ( (GenericApp_NwkState == DEV_ZB_COORD)
|| (GenericApp_NwkState == DEV_ROUTER)
|| (GenericApp_NwkState == DEV_END_DEVICE) )
{
// Start sending "the" message in a regular interval.
osal_start_timerEx( GenericApp_TaskID,
GENERICAPP_SEND_MSG_EVT,
GENERICAPP_SEND_MSG_TIMEOUT );
if (GenericApp_NwkState == DEV_END_DEVICE)
//判断是否是终端,是终端才采集液位
osal_start_timerEx( GenericApp_TaskID,
GENERICAPP_VOLT_COLLECT_EVT,
GENERICAPP_VOLT_COLLECT_TIMEOUT );
}
break;
……………………………………………………..
}
添加对此用户自定义事件GENERICAPP_SEND_MSG_EVT的处理程序。
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
…………………………………………………
if ( events & GENERICAPP_SEND_MSG_EVT )
{
// Send "the" message
GenericApp_SendTheLevel();//采集并发送采集的节点液位到协调器
// Setup to send message again
osal_start_timerEx( GenericApp_TaskID,
GENERICAPP_VOLT_COLLECT_EVT,
GENERICAPP_VOLT_COLLECT_TIMEOUT );
// return unprocessed events
return (events ^ GENERICAPP_SEND_MSG_EVT);
………………………………………….
}
}
其中GenericApp_SendTheLevel ();的代码如下:
void GenericApp_SendTheLevel( void )
{
uint16 AdcVal;
unsigned char theMessageData[5]={0,0,0,0,0};
HalUARTWrite( SPI_MGR_DEFAULT_PORT,"9", 1);
HalUARTRead( SPI_MGR_DEFAULT_PORT,Uart, 2 );
if(Uart[0]==0x39)
{
AdcVal=Uart[1];
}
else
{AdcVal=0; }
_itoa(AdcVal,theMessageData,10);
//Print8(HAL_LCD_LINE_2,10," ", 1);
//Print8(HAL_LCD_LINE_3,10," ", 1);
//Print8(HAL_LCD_LINE_3,10," ", 1);
//Print8(HAL_LCD_LINE_2,16, theMessageData, 1);
if ( AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc, Level_CLUSTERID,
(byte)osal_strlen( theMessageData ) + 1, (byte *)&theMessageData,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS) == afStatus_SUCCESS ) }
switch(Uart[1])
{
case 0xb0:
//Print8(HAL_LCD_LINE_2,10," ", 1);
Print8(HAL_LCD_LINE_3,10," ", 1);
//Print8(HAL_LCD_LINE_2,16," ", 1);
Print8(HAL_LCD_LINE_3,16,"Low_LEVEL ", 1);
break;
case 0xb1:
//Print8(HAL_LCD_LINE_2,10," ", 1);
Print8(HAL_LCD_LINE_3,10," ", 1);
//Print8(HAL_LCD_LINE_2,16," ", 1);
Print8(HAL_LCD_LINE_3,16,"Middle_LEVEL ", 1);
break;
case 0xb2:
//Print8(HAL_LCD_LINE_2,10," ", 1);
Print8(HAL_LCD_LINE_3,10," ", 1);
//Print8(HAL_LCD_LINE_2,16," ", 1);
Print8(HAL_LCD_LINE_3,16,"High_LEVEL ", 1);
break;
default:
break;
}
在Z-Stack中调用AF_DataRequest函数实现基础的数据发送功能。
AF_DataRequest函数中目的地址参数的填充
GenericApp_DstAddr.addrMode = Addr16Bit; //单播方式
GenericApp_DstAddr.addr.shortAddr = 0x0000; //发送给协调器
GenericApp_DstAddr.endPoint = GENERICAPP_ENDPOINT; //使用当前端口发送无线个域网络的PANID的设置
在Tools中的f8wConfig.cfg文件中进行设置的,具体的PANID的设置是在f8wConfig.cfg文件的第55行:
-DZDAPP_CONFIG_PAN_ID=0x0015
无线个域网络的信道号的设置
信道的设置是在f8wConfig.cfg文件的31行开始,有16个选择(信道号11-26)这里选择信道25:
//-DDEFAULT_CHANLIST=0x04000000 // 26 - 0x1A
-DDEFAULT_CHANLIST=0x02000000 // 25 - 0x19
//-DDEFAULT_CHANLIST=0x01000000 // 24 - 0x18
//-DDEFAULT_CHANLIST=0x00800000 // 23 - 0x17
//-DDEFAULT_CHANLIST=0x00400000 // 22 - 0x16
③流程图如下
5、远端ZigBee 的任务流程分析
①远端Zig Bee 接收数据,并分析数据,显示相应液位。
系统事件循环在查询到有外部节点的数据输入事件后,将会通知应用层任务的事件处理函数进行处理。因为所有的发送到应用层任务的系统事件、消息以及数据都封装在afIncomingMSGPacket_t 这个数据结构中。所以应用层任务的事件处理函数要做的第一件工作就是把这个数据结构拆开,首先提取出存储系统事件的osal_event_hdr_t 类型的hdr 成员,判断其值,确定具体的事件类型。对于应用层接收外部数据这个事件,其值应是AF_INCOMING_MSG_CMD 。如果是这个事件,将会进入这个事件的处理函数中去,进行具体的处理。提取输入的数据,可通过指针操作选择afIncomingMSGPacket_t 包中的cmd 的data 成员来获取输入数据的指针。在GenericApp 的CoordinatorEB 工程中的接收应用层数据并处理的代码(GenericApp.C 227行): if ( events & SYS_EVENT_MSG )
{
MSGpkt=(afIncomingMSGPacket_t*)osal_msg_receive( GenericApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case ZDO_CB_MSG:
GenericApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt ); break;
case KEY_CHANGE:
GenericApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
break;
case AF_DATA_CONFIRM_CMD:
// This message is received as a confirmation of a data packet sent.
// The status is of ZStatus_t type [defined in ZComDef.h] // The message fields are defined in AF.h
afDataConfirm = (afDataConfirm_t *)MSGpkt;
sentEP = afDataConfirm->endpoint;
sentStatus = afDataConfirm->hdr.status;
sentTransID = afDataConfirm->transID;
(void)sentEP;
(void)sentTransID;
// Action taken when confirmation is received.
if ( sentStatus != ZSuccess )
{
// The data wasn't delivered -- Do something
}
break;
case AF_INCOMING_MSG_CMD:
GenericApp_MessageMSGCB( MSGpkt );
break;
……………………………….
上面代码首先通过osal_msg_receive()系统函数接收发送到应用层的afIncomingMSGPacket_t(应用层输入消息包),存储到MSGpkt中去。然后通过指针操作选择包中的系统事件类型:
MSGpkt->hdr.event
接着判断事件类型(应用层输入数据事件),转入应用层输入数据事件的处理代码中:
case AF_INCOMING_MSG_CMD:
GenericApp_MessageMSGCB( MSGpkt );
接着看事件处理函数GenericApp_MessageMSGCB( MSGpkt )
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
byte *temp;
byte lev;
temp=pkt->cmd.Data;
lev=*temp;
switch ( pkt->clusterId ) //提取出输入数据包中的簇ID
{
……………………………….
case Level_CLUSTERID:
if(lev==176)
{
Print8(HAL_LCD_LINE_2,10," ", 1);
Print8(HAL_LCD_LINE_3,10," ", 1);
Print8(HAL_LCD_LINE_2,16," ", 1);
Print8(HAL_LCD_LINE_3,16,"Low_LEVEL ", 1);
}
else if(lev==177)
{
Print8(HAL_LCD_LINE_2,10," ", 1);
Print8(HAL_LCD_LINE_3,10," ", 1);
Print8(HAL_LCD_LINE_2,16," ", 1);
Print8(HAL_LCD_LINE_3,16,"Middle_LEVEL ", 1);
}
else if(lev==177)
{
Print8(HAL_LCD_LINE_2,10," ", 1);
Print8(HAL_LCD_LINE_3,10," ", 1);
Print8(HAL_LCD_LINE_2,16," ", 1);
Print8(HAL_LCD_LINE_3,16,"High_LEVEL ", 1);
}
else
{}
}
}
②远端模块通过按键控制单片机执行“强制关闭”、“强制打开”模式。首先通过自动绑定给近端模块发送数据,近端模块接收到数据后再通过串口控制单片机,来控制系统的工作模式。
绑定
在 GenericApp中,设置了 PK液晶板上的 LEFT(左)键作为发送匹配描述符请求的触发按键。当LEFT(左)键按键按下将会触发一个系统的按键事件类型(KEY_CHANGE),相关的匹配描述符请求将在此按键事件的处理代码中添加。