气体传感器节点监控程序的设计
当检测到相应气体时,气体传感器的电导率会发生变化,传感器内部自动通过调节滑动电阻器的阻值调配适当的输出电压,以便检测输出信号,从而做出相应的判断。程序流程图如图所示。

①设置二氧化碳传感器
const struct _subDeviceInfosubDeviceList[SUBDEVICE_NUMBER]={
ZD_THERMO_SENSOR,//传感器类型
ZD_READ,//将传感器设置为可读模式
"CO2Sensor",//二氧化碳传感器
"",
"ppm",
};
②定义全局变量,用于保存传感器数据。
char buftestSensor[10]
核心代码(1)
③定义二氧化碳传感器的调用函数,本函数通过一个静态变量,将传感器数据进行存储和输出。
char *CO2Sensor(uint200pxd,uint8 dataLen,uint8 *data)
{
static float v;//定义静态变量
v=filter();//通过滤波函数读取数据
sprintf(buftestSensor,"%3.1f",v);//将读出的数据存放在全局变量中
return buftestSensor;
}
④设置二氧化碳传感器进程
typedef char*_DeviceCall(uint8 cmd,uint8 dataLen,uint8 *data);
_DeviceCall*SubDeviceProcessor[SUBDEVICE_NUMBER]=
{
CO2Sensor,
};
核心代码(2)
⑤通过回调函数或者函数处理表,调用所连接的设备,查找其中的二氧化碳传感器,并进行处理。
voidSubDeviceReceiveDataParse(uint8 cmd,uint8 subDev,uint8 dataLen,uint8* data)
{
if(subDev>=0&&subDev<SUBDEVICE_NUMBER)//检测传感器设备是否已连接
{
char *res;
if(subDev==0)//如果有传感器设备,此处0为第一个设备
{
res=CO2Sensor(cmd,dataLen,data);//调用前面的二氧化碳传感器定义函数
break;
}
if(res)
//处理二氧化碳传感器进程
DeviceCommandResponse(cmd,subDev,osal_strlen(res)+1,res);
else
DeviceCommandResponse(cmd,subDev,0,0);
}
}
//读取检测到的气体数据,并计算二氧化碳浓度
float Read一002Sensor()
{
float result;
uint16 U;
uint16 m;
PODIR=o; //定义PO口为输入口
ADCIF=o; //中断转换标志位
ADCCONl=0X33; //清除转换标志位
ADCCON2=Ox20; //参考内部电压1.25V,选用通道0,10位转换精度
ADCCON3=OxAO;//参考电压选为电源电压3.3V
while(!ADcIF);//循环等待
U=ADCL
m=ADCH
u:=m<<8;//把存储结果转化为十六进制数据
U>>=6;
result=(U*3.3)/512; //计算实际电压值
result=(result*380)/0. 97; //计算二氧化碳的浓度值
return result;
}
⑥为了保证处理结果准确,进行简单的数字滤波,避免一些噪声干扰。
float filter()
{
# defineN5
int count, i, j;
float vajue_buf[N],
float sum = O, temp = O;
for(count = O; count<N, count + + )
value_buf[count] = Read CO2Sensor();
delay(6000);
}
for(j = O, j<N-1; j + + )
{
for(i = O, i<N-j; i+ + )
{
if(vajue_buf[i]>vajue_buf[i+1]
{
temp= value buf[i];
value buf[i] = alue buf[i+1];
value_buf[i+l] = temp;
}
}
}
for( count = O; count<N; count + + )
sum + = vajue buf[cornt];
return( float) ( sum/(N));
}
通过读取气体传感器的数据,气体监控管理模块既可以简单判断是否有气体,也可以获取气体浓度,从而进一步管理和监控。
核心代码(3)
(2)气体传感器ZigBee协议栈的设计
在ZigBee协议栈中,通过调用函数SendData()来完成数据的发送,其原型如下:
uint8 SendData(uint8 *buf,uint16 addr, uint8 Leng)
功能描述:将缓冲区 buf 中的数据发送到地址为 addr 的节点中。
输入: buf(指向发送数据)
addr(目的节点地址)
Leng(发送数据的长度)
输出:发送成功返回 1,否则返回 0。
气体传感器节点通过调用SendData()函数将气体检测数据发送给嵌入式网关,嵌入式网关将在接收数据缓冲区RxBuf[50]中读取数据。
uintl6 CO2_ProcessEvent( uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t * MSGpkt;
if ( events& SYS EVENT_ MSG )
{
MSGpkt=(afIncomingMSGPacket_t *)osal_ msg_receive( CO2_ TaskID);
while ( MSGpkt )
{
switch ( MSGpkt - >hdr. event )
{
//通过按键输入,开始接收数据
case KEY_CHANGE:
CO2_ HandleKeys(((keyChange_t*) MSGpkt) ->state,(keyChange_t*)MSGpkt)
一> keys);
break;
//外部数据接收
case AF_INCOMING_MSG_CMD:
C02_MessageMSGCB( MSGpkt );
break:
//网络状态改变
case ZDO_STATE_CHANGE:
C02_NwkState=(devStates_t)(MSGpkt ->hdr.status);
if(C02_NwkState= =DEV_ZB_COORD)
||(C02_NwkState= =DEV_ROUTER)
||(C02_NwkState= =DEV_END_DEVICE))
{
#if defined(ZDO_COORDINATOR)
conPrintROMString("嵌入式网关建立网络成功\n");
conPrintROMString("嵌入式网关程序:物理地址:");
memcpy( RfTx.TXDATA.IEEE,NLME_GetExtAddr(),8); //获取物理地址
conPrintUINT8_noleadern(RfTx. TXDATA. IEEE,8);
conPrintROMString("嵌入式网关网络地址:");
RfTx.TXDATA.Saddr=NLME_GetShortAddr(); //获取网络地址
conPrintUINT16(RfTx. TXDATA. Saddr);
HalLedBlink(HAL_LED_4,4,50,250);
#elif defined(RTR_NWK)&&(!defined( ZDO_COORDINATOR))
conPrintROMString("路由节点加入网络成功\n");
HalLedBlik( HAL_LED_4, 3, 50, 250); //小灯闪烁
RfTx. TXDATA. HeadCom[0]= 'n'; //输入命令
RfTx. TXDATA. HeadCom[l]= 'e';
RfTx. TXDATA. HeadCom [2]='w';
RfTx. TXDATA. Node_ type[0] = 'R'; //节点类型
RfTx. TXDATA Node_type[l] = 'O';
RfTx. TXDATA Node_ type[2= 'U';
memcpy( RfTx. TXDATA.IEEE,NLME_GetExtAddr( ) , 8); //获取物理地址
RfTx. TXDATA. Saddr = NLME_GetShortAddr();//获取网络地址
SendData(RfTx. TxBuf, Ox0000, 32); //发送首次信息
# else
conPrintROMString("最终节点加入网络成功\n" ) ;
HalLedBlink( HAL_LED_4, 3, 50, 250 );
RfTx. TXDATA. HeadCom[0] = 'n'; //输人命令
RfTx. TXDATA. HeadCom[l] = 'e';
RfTx. TXDATA. HeadCom[2] = 'W';
RfTx. TXDATA. Node_type[0] = 'R'; //节点类型
RfTx. TXDATA. Node_type[l] = 'F';
RfTx. TXDATA. Node_type[2] = 'F';
memcpy( RfTx.TXDATA.IEEE, NLME_ GetExtAddr( ) , 8) ; //获取物理地址
RfTx.TXDATA.Saddr=NLME_GetShortAddr(); //获取网络地址
SendData( RfTx.TxBuf,Ox0000,32); //发送首次信息
# endif
//串行输出二氧化碳浓度数据
osal_start_timerEx( C02_TaskID,
C02_SEND_PERIODIC_MSG_EVT,
C02_SEND_PERIODIC_MSG_TIMEOUT);
}
else
{
break,
}
//释放内存
osal_msg_deallocate((uint8 * )MSGpkt );
MSGpkt = (afIncomingMSGPacket_t * )osal_msg_receive( C02_TaskID );
return (events ^ SYS_EVENT_MSG);
}
(3)风扇控制程序的设计
植物光合作用需要二氧化碳。二氧化碳浓度低于系统设定值时,系统自动开启风扇,加强通风,为植物提供充足的二氧化碳。风扇控制程序流程如图所示:
创建一个新的Qt GUI工程,然后在UI界面上拖放两个QLabel、两个QLineEdie、一个QCheckBox控件。摆放位置,并设定显示文字,效果如图所示

在新工程中添加串口类和ZigBee线程类文件,主要功能部分实现如下:
void Widget::timeUpdate()
{
flaat check_data;
QString s=ui - > check_data一>text();
check_data=s.tolnt();
if(ui - >checkBox - >checkState())
{
if(m_data<check_data) //小于设定值时,打开风扇
{
sendAutoCmd( true);
}
else if (m_ data>check_data) //大于设定值时,关闭风扇
{
sendAutoCmd( false);
}
}
emit sendlReadCmd(); //发送命令,读取传感器数据
}
这部分代码的主要功能是定时器每隔一秒响应一次,当自动选项是选中状态时,比较当前的二氧化碳浓度值。若低于设定的阈值,打开风扇;若高于设定的阈值,自动关闭风扇。