本帖最后由 Katrina_WIZnet 于 2015-3-6 15:26 编辑
摘要:
本应用摆脱了以往嵌入式系统的数据采集方式,借助于最新的HTML5的Canvas API及WebSocket API两大特性,实现了数据的在线实时采集功能。提升了嵌入式采集系统的性能及体验。为嵌入式开发工作者提供参考。
关键字:HTML5;HTTP Server;Canvas;WebSocket;W5500;实时;采集系统;
当今信息社会,信息就是金钱,而但凡是信息便必然承载着时效性,过时的信息将不具有任何价值。由此可见,信息实时性的重要性。
随着近几年物联网在各行各业的迅猛发展,越来越多的终端设备连入网络,实现远程交互及控制;各式传感器的广泛普及,使得数据节点分布越来越多。而这些交互数据本身也属于一种原始信息,这些数据量需要我们采集、分析、处理、反馈,其数据真实有效性,准确性,以及实时性保证了整个工作的效率,质量以及价值。
在此,我们基于W5500实现了一个在线采集系统,并且为其引入了一个新鲜的元素——HTML5。通过这种最新的Web语言,为大家呈现一种更为实时、高效的在线实时采集系统。相信随着HTML5在嵌入式领域的不断深入推广,必然对产业效能及价值提升产生不小的作用。
在具体介绍这种实时采集系统前,让我们先简单的来认识一下HTML5。
HTML5和HTML的区别
HTML为创建网页Web使之能够在网络浏览器呈现而设计的一种标记语言。
HTML5为HTML的下一个修订版本。而广义的HTML5,包括了新的以及增强的HTML,CSS3,JavaScript API和事件的一套技术组合。
图1HTML5 **
以下为HTML5较HTML新增强的主要功能:
- 地理位置(Communication APIs);
Canvas API及Web Socket API
其实,实现该在线实时采集系统,得益于HTML5新增的2个API函数:Canvas及WebSocket。
Canvas,由04年苹果公司为MAC OS X仪表板开发的像素绘图元素发展而来。由Canvas元素和相应的JavaScript组成。使得开发者能够无需借助其他第三方插件,利用JavaScript的Canvas图形工具,在Canvas元素画板上实现动态绘制图形。
Websocket,提供了一个直接与服务器通讯的Socket。使得在通讯建立之后,客户端(浏览器)能够与网页服务器实现双向通讯,而无需客户端频繁轮询服务器实现。这样能够减少Http请求的额外开销,减轻数据包负担,而且通讯更加实时。
通过对于这2个API函数的灵活应用,我们实现了通过HTTP Server,实时的接收数据量,并在网页Web上动态模拟的功能。
在线实时采集系统演示
系统环境
a) 单片机:STM32F103RC,256K字节Flash,48K字节SRAM,2K字节EEPROM
b) 以太网控制器:W5500,SPI接口与单片机相连
c) 电源:USB供电
开发工具: IAR for ARM v5.41,这是我们工程所使用的版本。如果使用不同版本的IAR,请对STM的库稍作调整。
看代码之前,我们还是先来了解一下整个的程序流程,如下图所示。在硬件初始化完成之后,将进行网络参数配置,这是要根据自己网络的情况来配置W5500的IP地址等网络参数,确保W5500能连网;本程序中,我们会使用W5500的两个socket资源,一个用来创建Http Server,这样在浏览器上输入配置的IP地址,就能远程访问我们的硬件了;另一个用来创建Web Socket Server,与网页端建立通信链路,用来传输我们的温湿度数据。
图2硬件运行流程
当我们在浏览器上访问硬件的IP地址,会向W5500发送http请求,W5500在收到请求后将html5的网页信息发送给浏览器,这样浏览器上就能显示我们的温湿度检测系统的主界面了。在网页的代码中,浏览器会主动连接W5500的Web Socket Server,在完成握手操作后,数据通信通道即建立了。这样硬件就可以无障碍的将温湿度数据发送给浏览器端,浏览器在收到温湿度数据后,使用画布功能,在指定位置画出温湿度示数的点和曲线。以下是html5中Web Socket(网络套接字)和Canvas(画布)代码、W5500的Web Socket握手和数据帧协议、温湿度采集程序的介绍。
图3网页显示界面
Canvas和Web Socket
在浏览器端我们使用HTML5的Canvas绘制工具和WebSocket API搭建我们的web界面。当有新的温湿度数据来临时,在画布的坐标系里会有画点显示,并标识示数,并且随着采集次数的增加,多个数据连线,就可以看到曲线变化。网页程序步骤如下:
1) 创建页面和canvas所属的style、body标记
2) 绘制坐标轴,添加标题;建立WebSocket连接
3) 新数据到来,绘制点和线
利用Canvas绘图
下面先介绍如何创建一张画布以及代码中使用到的绘制函数。
1) 建立一张600x400的画布,单位是像素
<canvasid='graph'width='600'height='400'></canvas>
2) 定义画布的边框宽度、颜色和内边距大小。
#graph {
border: 1px solid #03F;
margin:0 40px 0 80px;
}
3) 为了在JavaScript中对canvas进行绘制,首先需要通过目标canvas的id获取绘制环境。代码需要通过id获取canvas元素,然后使用此元素的getContex方法获取其二维绘制环境的引用
canvas=document.getElementById('graph');
context=canvas.getContext('2d');
4) 绘制一条线段
context.lineWidth=2;//设置线宽
context.strokeStyle='#999';//设置线的颜色
context.moveTo(x1,y1);//移动到起点
context.lineTo(x2,y2);//创建到终点的路径
context.stroke();//实际绘出这段直线
5) 绘制圆
context.fillStyle='#000';//设置填充色
context.beginPath();
context.arc(x,y,2,0,Math.PI*2,true);//在坐标(x,y)处绘制半径2的圆
context.closePath();
context.fill();//在圆内填充颜色
6) 在指定位置写标题文字
context.fillText(text,x,y,maxWidth);
使用以上函数组合即可绘制如下的图了,如果您觉得这还不够炫,html5的canvas中还提供了渐变色、旋转、插图等函数,发挥你的设计才能动手制作属于自己的前端界面吧。
图4画布示例图
WebSocket的使用
接下来我们介绍html5中WebSocket的使用以及相关函数
1) 为了创建一个websocket连接,代码需要创建一个WebSocket接口实例,传入Web服务URL地址,sensorWebSocket对象会试图连接监听于相应的URL的服务
varwsUri='ws:192.168.10.111:1818';
sensorWebSocket=newWebSocket(wsUri);
2) 注册事件并为事件链接相应处理函数,例如,在浏览器页面收到来自服务器端的数据后,触发onmessage事件,进而调用onMessage函数,代码中我们注册了onopen、onmessage、onclose和onerror四个事件
sensorWebSocket.onmessage=function(evt){onMessage(evt)};
3) 消息处理函数,在硬件上我们将采集来的温湿度数据用‘.’号连接,在浏览器端,接收到数据后,使用字符串分割函数将温度和湿度数据分割,存储在一个数组对象里。之后的代码就是将示数转化成坐标值在画布上显示出来,这里不再赘述。
functiononMessage(evt){
vararrayTH=new Array(2);
arrayTH=evt.data.split('.');
……
}
4) 主动关闭websocket连接
sensorWebSocket.close();
怎么样,websocket的使用很简单吧,有了这个利器,就可以与远程服务器连接并接受和发送消息,该功能在双向通信方面十分有用,特别是在服务器需要主动向浏览器页面发送消息时。
Web Socket握手和数据帧
在服务器端创建好socket后,首先要与客户端完成握手才能开始数据通信,那么这个握手在程序上市如何实现的呢,先看下握手的流程:
表1握手流程
客户端的代码在上面已经介绍,下面是硬件中服务器1、2的代码:
#define WS_SERVER_PORT 1818//定义服务器监听的端口号
socket(s,Sn_MR_TCP, WS_SERVER_PORT,0x20);//W5500中建立socket连接
listen(s);//开启侦听 s变量为W5500的socket序号,此例程中使用2号
以下是给W5500配置的网络信息,其中IP地址即为我们浏览器页面程序websocket对象的监听地址。
uint8 mac[6]={0x00,0x08,0xdc,0x11,0x11,0x11};
uint8 lip[4]={192,168,10,111};
uint8 sub[4]={255,255,255,0};
uint8gw[4]={192,168,10,1};
setSHAR(mac);
setSUBR(sub);
setGAR(gw);
setSIPR(lip);
硬件中有关服务器5、6、7流程的代码:
charsec_ws_key[32]={0x00,};
characcept_key[32]={0x00,};
//get Sec-WebSocket-Key:
if(strstr((charconst*)wsRxBuf,"Sec-WebSocket-Key: "))
{
mid((char*)wsRxBuf,"Sec-WebSocket-Key: ","\r\n",sec_ws_key);//截取sec_key
calc_accept_key(sec_ws_key,accept_key);//编码函数
sprintf((char*)wsTxBuf,"HTTP/1.1 101 SwitchingProtocols\r\nUpgrade: WebSocket\r\nConnection:Upgrade\r\nSec-WebSocket-Accept: %s\r\n\r\n",accept_key);//生成握手消息
send(s,wsTxBuf,strlen((char*)wsTxBuf));//发送给客户端
}
handshaked=1;
这样看起来可能有点抽象,我们看看实际的数据包吧,上边红色字体为浏览器页面的握手请求,Sec-websoket-Key后即为我们截取的sec_key,后边的蓝色字体为服务器端的握手回复,Sec-websoket-Accept后为我们编码后的accept_key,怎么样,一目了然了吧。
图5握手过程抓包信息
在握手成功后,在硬件端就可以将每隔一段时间采集来的温湿度数据发送给浏览器页面。WebSocket协议的数据包非常轻量,下面介绍数据包的帧格式:
图6WebSocket数据帧格式
上图是官方提供的结构图,第一个字节,第一位是FIN,后面三位是RSV1到3。RSV是预留的空间,用 0填充,那么前4位只有第一位的FIN需要设置。接着后面的四位是储存opcode的值,opcode定义负载数据的解释。FIN用来指示消息的最后片段,如果只有一条消息,那么FIN就是1;这里我们用opcode定义数据是文本-0x1,这样第一个字的二进制是1000001(0x81),第一个1是FIN的值,最后一个1是opcode的值。
接着是第二个字节的数据,它由1位的MASK和7位的PayloadLen组成,MASK标识这个数据帧的数据是否使用掩码,PayloadLen表示数据部分的长度。但是PayloadLen只有7位,换成无符号整型的话只有0到127的取值,这么小的数值当然无法描述较大的数据,因此规定当数据长度小于或等于125时候它才作为数据长度的描述,如果这个值为126,则时候后面的两个字节来储存储存数据长度,如果为127则用后面八个字节来储存数据长度。这里我们每次发送的温湿度数据只有5个字节,并且不使用掩码,所以配置为0x05。
再接着是上面图表中的MaskingKey,它占四个字节,储存掩码的实体部分。但是只有在前面的MASK被设置为1时候才存在这个数据,否则不使用掩码也就没有这个数据了。
最后是数据部分,如果掩码存在,那么所有数据都需要与掩码做一次异或运算。如果不存在掩码,那么后面的数据就可以直接使用。
看看我们数据发送的代码是如何实现的吧:
wsTxBuf[0]=0x81;
wsTxBuf[1]=0x05;
wsTxBuf[2]= Temp/10+0x30;
wsTxBuf[3]= Temp%10+0x30;
wsTxBuf[1]=0x2E;//分隔符‘.’
wsTxBuf[2]=Humi/10+0x30;
wsTxBuf[3]= Humi%10+0x30;
send(s,wsTxBuf,strlen((char*)wsTxBuf));
是不是代码很easy!
数据采集
那么另外简述一下数据的采集过程。
我们选用的是温湿度传感器DHT11,进行对室内温湿度数据的实时采集与上传。这里就用DHT11与单片机连接(W5500),它与单片机的通信只需要一个I/O口,使用很简单。
具体DHT11与单片机的连接 与相关调试,这里就不详细讲解了。可以搜索相关资料。
相信随着HTML5的不断成熟,它带来的不仅仅是PC环境的Web革命。对于嵌入式领域来说,也能够带来更好的客户体验及产品性能。当然,我们仍然还需要借助W5500这个颇具特色的以太网芯片。其全硬件TCP/IP协议栈不仅大大节约了颇为珍贵的嵌入式资源,而且节省了很多开发步骤及难度,从而能让我们能够更多的资源与精力去实现更为精彩的Web功能。
如果你感兴趣的话,赶快来做一个属于你的在线实时采集系统吧。
完整的程序代码程序请参看附件。
|