此文章已刊登在《无线电》杂志2014年1月刊
- 社交网络与物联网
近年来,随着Twitter和Facebook的大热,社交网络这个名词红遍了大街小巷。截至2012年,全球社交网络的使用人数超过了14亿!不管是明星大腕,还是草根百姓,还是权贵政要,都拥有自己的社交网络的账号,而且关注者众多,动辄数以千万计。在2012年美国总统竞选时,奥巴马的Twitter更是发挥了前所未有的影响力,竞选当时奥巴马的跟随者(粉丝)已超过了850万名,排名全美第三,仅次于美国歌星ladygaga和加拿大小天王贾斯汀·比伯。国内社交网络也不甘落后,各大门户网站紧急跟进,类Twitter和Facebook网站如雨后春笋,争相破土而出。新浪更是抢到了weibo.com!个人认为新浪的微博相对来讲和Twitter更接近,使用起来较为方便。与此同时,各类人物也都争相开通了自己的微博,例如知名的李开复先生、演员姚晨等等,粉丝都超过了几千万。试想一下,他们的每一条微博都将可能被几千万人看到,受众人群如此之众,社交网络的信息传播方式又一次改变了人们对互联网的认识。
然而,硬件也不甘心落后,物联网融合传统的传感器网络和互联网,使每个硬件设备都有机会连接互联网。微电子技术的发展,尤其是单片机发展的突飞猛进,价格下降的同时,运算能力大幅上升,使得一些传统的白色家电,诸如电视、空调以及冰箱等设备连接网络成为现实。更有一些公司为了方便开发者和使用者,推出了物联网云平台,例如国内比较知名的就有YeeLink还有乐为物联等,用户可以同过这些平台随时随地了解自己设备的状态并且能远程控制。
早在2011年底,就有浙大的学生开发出了会发微博的饮水机(如下图1所示),来方便自己随时知道饮水机的状态。不过他这个做法相对原始,并没有实现饮水机连网,而是通过一个设备把饮水机的状态传送给电脑,由电脑来完成连网发微博的功能。
图1. 会发微博的饮水机(图片源自:http://info.js.hc360.com/2012/04/0908545081.shtml)
今天我们要介绍主要内容是让设备自己发微博,不需像上面饮水机那样还需要电脑辅助;也就是说如何实现给饮水机一根网线就能让她发微博。
- 开发环境
工欲善其事,必先利其器。我们先来看一下开发环境。开发板如图2所示。
1. 开发板基本情况
a) 单片机:STM32F103RC,256K字节Flash,48K字节SRAM,2K字节EEPROM
b) 以太网控制器:W5500,SPI接口与单片机相连
c) 电源:USB供电
2. 开发工具: IAR for ARM v5.41,这是我们工程所使用的版本。如果使用不同版本的IAR,请对STM的库稍作调整。
3. 其他
a) 新浪微博用户名和密码;如若没有,就赶快给你的设备申请一个吧!
b) 一根Mini接口的USB线,如图2所示。
c) 一根网线。
d) STM32芯片的串口程序烧录工具,STM官方提供的程序名为:Flash Loader Demo,运行界面如图3所示。
图2. USB线示例
图3. 程序烧录工具运行界面
- 程序开发
看代码之前,我们还是先来了解一下整个的程序流程,如下图所示。在硬件初始化完成之后,将进行网络参数配置,这是要根据自己网络的情况来配置W5500的IP地址等网络参数,确保W5500能连接外网;然后初始化W5500的一个Socket,再连接服务器,等待连接成功后,直接发送微博内容。就这么简单,下面还是详细看一下代码吧。
图4 程序流程图
熟悉完了开发环境,我们就来看一下具体的代码实现,在此我们无法贴出全部代码,这里只贴出发送微博实现部分的代码(请查找weibo.c),想要全部代码的话,到http://wizwiki.net/forum/download/file.php?id=48下载。
-
CODE:
SELECT ALL
-
1 #include "w5500/socket.h"
2 #include "w5500/w5500.h"
#include <stdio.h>
#include <string.h>
3 #define SOCK_WEIBO 2 //the socket number is used for weibo; it can be a number between 0~7
4 #define WEIBO_SERVER "61.109.255.136" //weibo server IP address string
5 #define HTTP_PATH "/wiznet/" //HTTP path
6 #define WEIBO_ID "xxxx@xxxx.xxx" //your sina weibo ID
7 #define WEIBO_PWD "******" //your sina weibo password
char tmp_buf[512]={0x00,}; //a temp buffer to store weibo content and HTTP header
unsigned char post_weibo(char* weibo)
{
8 unsigned char weibo_server_ip[4] = {61,109,255,136}; //Weibo server IP address
9 static unsigned int any_local_port = 1000; //TCP socket local port nubmer
10 char post_data[385]={0x00,};
//weibo content (140 characters, but one Chinese character will be 2 Bytes!) + ID & Password information. If your sina weibo ID & Password are too long, please define a bigger buffer
unsigned char ret=0;
unsigned int len=0;
11 if(socket(SOCK_WEIBO,Sn_MR_TCP,any_local_port++,0)!=1) //to initialize a TCP socket
{
printf("Socket initialization failed.\r\n");
return 0;
}
else
{
12 ret=connect(SOCK_WEIBO,weibo_server_ip,80); //connect to the weibo server, default TCP port is 80
if(ret!=1)
{
printf("Connect Weibo server failed.\r\n");
return 0;
}
else
{
13 while(getSn_SR(SOCK_WEIBO)!=SOCK_ESTABLISHED); //wait for the TCP connection established!
printf("Connected with Weibo server.\r\n");
14 sprintf(post_data,"id=%s&pw=%s&cmd=update&status=%s",(char*)WEIBO_ID,(char*)WEIBO_PWD,weibo);
15 sprintf(tmp_buf,"POST %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: w5500\r\nContent-Type: application/x-www-form-urlencoded; charset=gb2312\r\nContent-Length: %d\r\n\r\n%s",(char*)HTTP_PATH,(char*)WEIBO_SERVER,strlen(post_data),post_data);
16 len=send(SOCK_WEIBO,(unsigned char*)tmp_buf,strlen(tmp_buf)); //upload your weibo content
while(1)
{
17 len=getSn_RX_RSR(SOCK_WEIBO);
if(len>0)
{
memset(tmp_buf,0x00,512);
18 len=recv(SOCK_WEIBO, (unsigned char*)tmp_buf, len); //receive the return result from weibo server
char* p=strstr(tmp_buf,(char*)"\r\n\r\n")+4; //get http payload without http header: return value
printf("%s\r\n",p);
19 disconnect(SOCK_WEIBO); //disconnect with weibo server
20 close(SOCK_WEIBO); //close the socket
21 return 1; //sucess! return 1
}
}
}
}
}
我们从头看起,第1,2行,把W5500的库和Socket库文件引用过来。第3~7行为宏定义部分,第3行是给微博选一个Socket,鉴于W5500共有8个Socket可以同时通信,这里随便选取一个没有用到的Socket就可以了,这里选的是2。第4、5行定义的是要访问的服务器地址和具体的HTTP路径,请不要更改!注意: 第6、7行需要填写设备的新浪微博用户名和密码,请注意,我们仅支持新浪微博!这里要填写正确的新浪微博用户名和密码,否则无法发送。另外请放心,我们绝不会在后台保存你设备的微博密码!
第8行还是要连接的服务器IP地址,放到了一个数组里面;第9行为该Socket定义了一个本地端口号,这个数值0~65535中任取。这里我们所采用的服务器接受HTTP格式提交的数据,第10行定义的数组就是为了临时保存该格式的微博内容;你也许会问,微博最多能够接受140个字符,为什么这里要定义一个385字节的数组呢?因为这个数组不仅要保存微博内容,还有微博的账号和密码,还有,如果微博内容是汉字的话,那么一个汉字将占用2个字节,一个全是汉字的微博最大的长度将是280个字节,因此,如微博账号和密码过长的话,请适当调整该数组长度。
下面就是Socket的操作了,第11行初始化一个Socket,接着12行对服务器发出连接请求,第13行一直等待连接的建立,与服务器成功建立连接后,第14、15行负责组建带有微博的HTTP数据包,第16行负责发送。
然后接收服务器返回,第17行是读取W5500接收到的数据长度,当该长度大于零时,第18行从W5500的接收缓存中把接收到的数据读到tmp_buf中,由于接收到的数据包含了HTTP头,接下来的一行是把HTTP头去掉,我们只关心服务器的返回结果。收到了服务器的返回,说明我们和服务器的通信是成功的!但是,通信虽然成功,但是微博并不一定是百分之百发出去的,请看一下服务器返回结果的类型,如表1所示。
表1. 服务器返回值说明
最后,第19行断开与服务器的连接,之后第20行关闭Socket。与服务器通信成功,第21行返回1。
另:微博发送内容编辑请查找main.c中语句进行更改(例):
post_weibo_update("《为您的设备添加社交网络功能》-- 成功实现W5500开发板发微博应用!");
好了,代码就这么多。赶快编译,烧到单片机里面,上电,看串口调试信息:255: ok。大功告成!登陆到微博看看,刚才写进程序里面的那句话果然出现在了微博上面,如下图所示。
图5. 微博发送成功
怎么样,是不是很简单?整合应用到饮水机上是不是更强大了?赶快连接到自己的设备上试一下吧!
看完这段代码,你也许会有疑问,为什么要用一个代理服务器?而不是用单片机直接与新浪微博的服务器通信发微博呢?这要从新浪微博开发平台的变化说起。刚开始的时候,新浪微博和Twitter一样,都有一个基于Basic Auth的用户认证开放接口,但是由于安全原因,新浪关闭了这个接口。对现有第三方应用,只能使用OAuth2.0这个接口来开发应用。然而,OAuth2.0是基于SSL的,安全性是提高了,但是要在单片机上实现似乎有点困难。鉴于此,我们做了一个简单的代理,让代理来做OAuth2.0这些授权和认证,单片机只需把自己微博账号和密码,以及要发的微博内容提交给代理即可。这样一来,单片机只要能联网,就能发微博了。
另外,我们提供的参考代码是基于全硬件TCP/IP芯片的,如果使用软件协议栈,如lwIP或Microchip提供的协议栈,由于我们使用的库函数基本上和BSD的标准Socket操作类似,因此也能很轻松地移植到其他的平台上去。但对于初学者来讲,搞懂单片机已经不容易了,再学习复杂的TCP/IP协议栈的话,会觉得困难多多,很容易被吓到。因此,我们建议使用带有协议栈的网络芯片,在减轻单片机负载的同时,也给自己减轻点开发负担,多增加些自信。
- 后记
在社交网络应用上做文章,已经不再是凤毛麟角。当微博在大陆应用泛开涟漪后,各种古怪新奇的idea层出不穷。你甚至不知道正在跟你对话的是家用电器还是玩具,饮水机能发微博,电冰箱可以发信息…当然这一切都离不开网络,设备上远程控制的实现都在网络中得以实现。我们通过对W5500的控制实现设备的社交网络功能,旨在跟大家分享它在网络中发挥的作用----更轻松简易的实现物联网功能。谨以此小小的制作,望获取和大家更多交流的机会,在开源硬件运动中同行。