物联网应用系统设计
----无线温度传输系统设计
作
业
报
告
目录
1 系统总体方案 (3)
1.1 系统需求分析 (3)
1.2 系统总体方案设计 (3)
2 系统硬件设计 (4)
2.1 终端节点硬件设计 (4)
2.2 协调器节点硬件设计 (4)
3 系统软件设计 (5)
3.1 通信协议设计 (5)
3.2 协调器节点软件流程 (5)
3.3 终端节点软件流程 (5)
3.4 上位机软件设计 (6)
4 部分代码 (6)
4.1通讯协议代码 (6)
4.2终端温湿度获取的代码 (6)
4.3协调器串口发送的代码 (7)
4.4上位机软件 (7)
4.4.1用户登录界面 (7)
4.4.2用户监控界面 (9)
5 系统测试 (13)
1 系统总体方案
1.1 系统需求分析
无线传感器网络是现在较热门的研究领域,其作为一个将数据采集、数据传输以及数据处理集成于一体的智能化系统,具有非常广阔的应用前景。传感器的无线数据传输可使用的技术包括Bluetooth 、WIFI 、Zigbee 、GPRS 等方式 ZigBee 协议的优势在于自组网能力,最多支持 65000 个设备组网; ZigBee 协议安全性很高,主要用于近距离无线连接。传感器节点能够采集和处理传感器的数据,并且通过ZigBee 无线传输到汇聚节点,最后由汇聚节点发送到监控中心(PC 机)。
1.2系统总体方案设计
选用功耗较小的CC2530芯片作为通信芯片来设计节点,基于ZigBee 协议栈设计了终端节点、协调器节点,并采用低功耗的传感器,以采集室内的温湿度、光照度数据为对象,终端利用无线收发模块将采集的数据发送出去,协调器接收到消息并利用串口与PC 机通信,在PC 机的用户界面进行实时显示。整个用户管理软件分为前台页面和后台管理两大模块,前台页面主要实现了用户可视化管理,方便用户随时查看、统计数据。采用Acess 2003数据库服务器保存系统数据,实现数据的定义、维护、访问、更新及管理,利用https://www.wendangku.net/doc/5f8993891.html, 技术将数据存储到数据库中。无线温度传输系统设计的整体思路如下图1-1所示:
传感器节点 汇聚节点 用户界面
图1-1无线温度传输系统设计的整体思路
2 系统硬件设计
本实验使用的是CC2530芯片, CC2530 具有一个IEEE 802.15.4 兼容无线收发器。RF 内核控制模拟无线模块。另外,它提供了MCU 和无线设备之间的一个接口,这使得可以发出命令,读取状态,自动操作和确定无线设备事件的顺序。
2.1 终端节点硬件设计
DS18B20是常用的数字温度传感器,采用单总线的接口方式与微处理器连接时仅需要一条口线,可实现微处理器与DS18B20的双向通讯,抗干扰能力强。终端节点主要涉及CC2530的LED模块、DS18B20传感器。其硬件原理图如图2-1-1、2-1-2所示:
图2-1-1 CC2530的LED模块图 2-1-2 温湿度传感器
2.2 协调器节点硬件设计
MUC和PC机通信都是通过串口来进行,CC2530有两个USB转串口,分别是USART0和USART1。USART0和USART1是串行通信接口,它们能够分别运行于异步UART模式或者同步SPI模式。USB转串口电路如图2-2-1所示:
图2-2-1 USB转串口电路
3系统软件设计
3.1 通信协议设计
终端节点传感器将获取的温度存在cmd[8] 、cmd[9] ,将获取的温度存在cmd[10] 、cmd[11] 将cmd数据包发送协调器,用串口发送给PC 机端。
说明:
SOF:固定为0xEE 0xCC,标志一帧的开始
Sensor type:温湿度传感器0x0A
Sensor index:固定为0x01
Cmd id:固定为0x01
Data:为6Byte传感器数据域
Exten Data:为2Byte扩展数据域
END:固定为0xFF,标志一帧的结束
3.2 协调器节点软件流程
系统软件数据接收端和串口发送程序组成,其包括初始化程序处理、接收点播消息程序、异常处理函
图3.3.1协调器软件流程图
3.3 终端节点软件流程
系统软件由数据采集和数据接收端程序组成,包括初始化程序处理、获取温湿度、光照度函数,发送点播消息程序。如下图3.3.2所示:
图3.3.2 终端软件流程图
3.4 上位机软件设计
经过CC2530芯片处理无线传输到协调器节点,将数据解析显示在用户界面上。建立实现数据的维护、访问、更新及管理,将用户界面的数据存储到数据库中。图3.3.3上位机软件软件流程图所示:
图3.3.3 上位机软件软件流程图
4部分代码
4.1通讯协议代码
void Protocol()
{ cmd[0] = 0xEE; cmd[1] = 0xCC; cmd[2] = sensor_type;cmd[3] = sensor_index;
cmd[4] = cmd_id;cmd[5] = 0x00; cmd[6] = 0x00;cmd[7] = 0x00;
cmd[8] = 0x00; cmd[9] = 0x00; cmd[10] = 0x00;cmd[11] = 0x00;
cmd[12] = 0x00; cmd[13] = 0xff;//结束标志位
}
4.2终端温湿度获取的代码
h_i = dht11_read_byte();h_f = dht11_read_byte(); //湿度整、小数部分;
t_i = dht11_read_byte();t_f = dht11_read_byte(); //温度小数部分;
check_sum = dht11_read_byte(); //校验和;
if(check_sm == ( h_i + h_f + t_i + t_f ) || (h_i != 100 && t_i != 100) )
{ if(flag == DHT11_STRING) {temp[0] = (t_i>>8)&0xff; temp[1] = t_i&0xff;
humi[0] = (h_i>>8)&0xff; humi[1] = h_i&0xff;}
else {*temp = t_i; *humi = h_i; } }
if ( events & DHT11)//用户事件
{ r_val = dht11_value(wendu , shidu , DHT11_STRING); //获取温湿度
Protocol();
if(r_val == 0) { sensor_type=0x0A; cmd[7]=wendu[0]; cmd[8]=wendu[1]; cmd[9]=shidu[0];
cmd[10]=shidu[1]; HalLedBlink( HAL_LED_2, 4, 50, 500 );
SampleApp_SendPeriodicMessage( ); cmd[7] = 0x00;cmd[8] = 0x00;
cmd[9] = 0x00; cmd[10] = 0x00; }
osal_start_timerEx( task_id , DHT11 , 100000 ); //10s;
return (events ^ DHT11); }
4.3协调器串口发送的代码
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{ uint16 flashTime;
switch ( pkt->clusterId ) {
case SAMPLEAPP_PERIODIC_CLUSTERID: //接收广播消息
HalLedBlink( HAL_LED_1, 4, 50,1000 ); HalUARTWrite(0 ,pkt->cmd.Data ,14 ); break;}} 4.4上位机软件
启动VC++6.0,创建一个基于对话框的MFC应用程序项目,选择Project菜单下Add to Project子菜单中的Components and Controls选项,在弹出的对话框中双击Registered ActiveX Controls项,则所有注册过的ActiveX控件出现在列表框中。
4.4.1用户登录界面
将控件列表框内的编辑框、静态文本、图像、按钮等控件添加到基本框内,如图4.1.1所示。
图4.4.1 用户登录界面
采用Acess 2003数据库保存用户注册信息,实现数据的定义、维护、访问、更新及管理。新建表、用户注册信息如表4.4.2所示、表4.4.3所示:
表4.4.2 新建表的字段名称及数据类型
表4.4.3 用户注册的信息
打开MFC ClassWizard对话框,单击Member Valuable为相应控件添加变量。添加变量名和类型如下表4.4.4所示:
表4.4.4 添加相应控件变量
数据库客户端编程主要使用https://www.wendangku.net/doc/5f8993891.html,方法, ADO编程的一般步骤:创建一个Connection对象打开数据源,建立同数据源的连接,执行一个SQL命令,使用结果集,终止连接。
导入ADO动态链接库 #import "c:\\Program Files\\Common Files\\System\\ADO\\msado15.dll" no_namespace rename("EOF","adoEOF")
在基于MFC的应用里,在应用类的InitInstance成员函数中初始化OLE/COM库环境,直接使用AfxOleInit,在退出应用时,该函数自动负责COM资源的释放。
try{m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=Fire_alarm.mdb","","",adModeUnknown); }
catch(_com_error e) { AfxMessageBox(e.Description() + _T("\n数据库连接失败")); } 使用Recordset对象操作数据库,录集提供了更多的控制功能。点击确定按钮进行登录与数据库中的用户信息进行对比。
CString sql;
sql.Format("SELECT * FROM Fire_alarm1 where UserID='%s' and UserPassword='%s'",m_UserID,m_Password);
try{//查询数据库,看是否有此用户和密码
m_pRecordset.CreateInstance("ADODB.Recordset");
m_pRecordset->Open((_variant_t)sql,_variant_t((IDispatch*)theApp.m_pConnection,true),adOpen
Static,adLockOptimistic,adCmdText);if(m_pRecordset->adoEOF){
AfxMessageBox("用户名或密码错误!");GetDlgItem(Edit1)->SetWindowText(NULL);
GetDlgItem(Edit1)->SetFocus();//聚焦 }
4.4.2用户监控界面
创建用户监控界面,MFC为列表视图控件的操作提供了CListCtrl类, 列表视图控件的创建,将下位机传的数据显示在接收缓冲区编辑框内,将通信协议解析,放在相应的列表控件中以十进制进行显示,并将数据存到数据库中,如表4.4.5所示。
表4.4.5 实时采集的温湿度数据
CString sql;
sql.Format("SELECT * FROM MonitorInfo");
m_pRecordset.CreateInstance(__uuidof(Recordset)); //创建实例
HRESULT hr=m_pRecordset->Open(sql.GetBuffer(0), _variant_t((IDispatch*)theApp.m_pConnection, true), adOpenDynamic, adLockPessimistic, adCmdText);
选择Microsoft Communications Con—trol version 6.0,单击insert按钮即可将通信控件插入该工程。将控件列表框内的编辑框、静态文本、图像、按钮、串口、listView等控件添加到基本框内,如图4.4.6所示。
图4.4.6 用户监控界面
为列表视图控件添加全行选中和栅格风格,并为列表视图控件添加六列。
BOOL CCMonter::OnInitDialog()
{CDialog::OnInitDialog();CRect rect; m_List.GetClientRect(&rect);
m_List.SetExtendedStyle(m_List.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); m_List.InsertColumn(0, _T("温度"), LVCFMT_CENTER, rect.Width()/6, 0);
m_List.InsertColumn(1, _T("湿度"), LVCFMT_CENTER, rect.Width()/6, 1);
m_List.InsertColumn(2, _T("光照"), LVCFMT_CENTER, rect.Width()/6, 2);
m_List.SetBkColor(RGB(255,255,255));
串口的配置,波特率的选择,为按钮IDC_ Button1T添加单击响应函数CCMonter::OnButton1() Void CCMonter::OnButton1(){m_ctrlcomm.SetInputMode(1);
m_ctrlcomm.SetInBufferSize(1024);m_ctrlcomm.SetOutBufferSize(512);
int indexcomm,indexbaud; indexcomm=((CComboBox*)GetDlgItem(IDC_COMBO2))->GetCurSel();
switch(indexcomm) {case 0:m_ctrlcomm.SetCommPort(1);break;
case 1:m_ctrlcomm.SetCommPort(2);break; case 2:m_ctrlcomm.SetCommPort(3);break;
case 3:m_ctrlcomm.SetCommPort(4);break; case 4:m_ctrlcomm.SetCommPort(5);break;
default:break; }
indexbaud=((CComboBox*)GetDlgItem(IDC_COMBO1))->GetCurSel();
switch(indexbaud) {case 0:m_ctrlcomm.SetSettings("4800,n,8,1");break;
case 1:m_ctrlcomm.SetSettings("9600,n,8,1");break;
case 2:m_ctrlcomm.SetSettings("19200,n,8,1");break;
case 3:m_ctrlcomm.SetSettings("38400,n,8,1");break;
case 4:m_ctrlcomm.SetSettings("115200,n,8,1");break;default:break;}
if(!m_ctrlcomm.GetPortOpen()){m_ctrlcomm.SetPortOpen(TRUE);
AfxMessageBox("串口打开成功!");}
else{AfxMessageBox("eeror!"); }
m_ctrlcomm.SetRThreshold(1); m_ctrlcomm.SetInputLen(0); m_ctrlcomm.GetInput(); }
串口事件处理函数void CCMonter::OnComm(),以便当接收缓冲区有数据时做相应处理。接受与发送缓冲区:
BYTE Recieve[14];unsigned char index=0;void CCMonter::OnComm(){
VARIANT variant_inp; COleSafeArray safearray_inp; LONG len,k; CString strtemp;
BYTE rxdata[2048]; if( m_ctrlcomm.GetCommEvent()==2) {variant_inp=m_ctrlcomm.GetInput(); safearray_inp=variant_inp; len=safearray_inp.GetOneDimSize();
for( k=0;k safearray_inp.GetElement(&k,rxdata+k);} for(k=0;k if(index==14){ AfxMessageBox("hello li!"); Protcol_Analy();index=0; }strtemp.Format("%2x",bt); m_strEditRXData+=strtemp; } UpdateData(FALSE); } void CCMonter::OnSent_data() { UpdateData(TRUE); int Count=m_strTXData.GetLength(); char TxData[1000]; int j; for(j=0;j CByteArray array; array.RemoveAll();array.SetSize(Count); for(j=0;j 将界面上实时显示的数据存到数据库中 void CCMonter::InsertLib(){ CString sql; sql = ("insert into MonitorInfo(TemperatureNum, ShiduNum,GuangzhaoNum,ManInfo) \ values("+sdatalib[0]+","+sdatalib[1]+","+sdatalib[2]+","+sdatalib[3]+")"); try{theApp.m_pConnection->Execute((_bstr_t)sql,NULL, adCmdText);} catch(_com_error e){CString temp; temp.Format("错误信息:%s",e.ErrorMessage()); AfxMessageBox(temp);}catch(...){MessageBox("操作失败!"); return;}} 上位机通信协议解析函数: long temp; unsigned char *pionter;char str1[1];char wendu[2],shidu[2],light[3]; CString sdatalib[4]; void CCMonter::Protcol_Analy() //协议解析 { pionter=Recieve; if(*pionter==0xee&&*(pionter+1)==0xcc) {if(*(pionter+2)==0x0a){ sprintf(&str1[0],"%x",*(pionter+8)); temp=hexToDec(str1);sprintf(wendu, "%d" ,temp); sdatalib[0]=wendu; m_List.SetItemText(1,0,(char *)wendu); sprintf(&str1[0],"%x",*(pionter+10));//十六进制转字符串str2 temp=hexToDec(str1);//字符转十进制sprintf(shidu, "%d" ,temp); //将整形转换为字符串 sdatalib[1]=shidu;m_List.SetItemText(1,1,(char *)shidu);} }else{return;} sdatalib[3]="0";InsertLib(); //数据插入数据库} 关闭串口,并清空接收和发送缓冲区: void CCMonter::Onclose() {if(m_ctrlcomm.GetPortOpen()){m_ctrlcomm.SetPortOpen(FALSE); AfxMessageBox("关闭串口!");}} void CCMonter::Onclear() {m_strEditRXData = "";UpdateData(FALSE);} void CCMonter::Onsend_clear() {m_strTXData = "";UpdateData(FALSE);} 十六进制转十进制 long CCMonter::hexToDec(char *piont){ long result = 0; long t = 1; int i,len,result1; len = strlen(piont); for(i=len-1; i>=0; i--) { char ch=*(piont + i); if(ch >= '0' && ch <= '9') { result1=ch - '0'; } else if(ch >= 'A' && ch <='F'){ result1=ch - 'A' + 10; } else if(ch >= 'a' && ch <= 'f') { result1=ch - 'a' + 10; } result += t * result1; t *= 16; } return result;} 5系统测试 将采集光照度、温湿度发送到协调器,协调器接收到采集数据消息后发送给串口,在上位机进行显示。终端1每隔10ms采集一次数据发送给上位机,如图5.1所示。 图5.1 终端与协调器进行组网 编译、链接、运行会在相应工程目录下的debug目录下生成可执行的EXE文件。用户登录界面如图5.2所示: 图5.2 用户成功登录界面 连接好串口线后,先用串口助手测试接受的数据,如图5.3所示: 图5.3 串口接受数据测试 运行该文件可进行串口通信,选择串口号COM2,波特率9600,点击打开串口按钮,运行结果如图5.4所示: 图5.4 用户监控界面 注:后期更改如图5.5所示: