再谈Arduino和DDWRT直接交互
这两天在做一个已经做烂的在线的温度发布系统。就是Arduino采集数据,然后发布到网页上去。很多的方案都是使用以太网的shield连路由,但是我没有shield,所以参考了国内外一些网站,最终做成了现在的这个方案。
简单来说,就是Arduino通过串口直接将数据传给路由器,路由器端运行一个小程序再把数据传给网页服务器。
下面解释几个问题:
1,路由器怎么选?
一般选择能运行开源固件的openWRT或DDWRT的路由,当然,本身要有(或者能引出)串口或者USB接口。我选的是DDWRT,觉得更方便,原因后面再详细说。
2,Arduino跟路由串口怎么连?
一般有2种吧。第一种是直接TTL对TTL,这个最好搞定,但是你要把路由器的TTL事先引出来,还有一个问题就是一般这种带登录的TTL在由启动的时候会输出大量启动记录,如果你打算控制Arduino的话要小心了,自定义通讯协议的时候要能避开这些信息,防止误触发。
第二种是借助一个TTL转USB的适配器,通过路由的USB口连接,很多Arduino都自带TTL转USB芯片,没有的话另外找一个。这种稍微麻烦一点,因为不是所有的适配器都行,要先选好驱动再找适配器。不过现在openWRT和DDWRT两个驱动都挺全的,问题也不大。
3,路由端怎么运行自制小程序?
这个是我想说的重点。一般想编译路由器程序要在PC上面搭建交叉编译环境。然后编译完成以后再拷贝回路由器测试。我选择DDWRT的原因是DD可以装GCC,直接在路由器上编译C程序,软件包是:buildroot_4.1.1-13_mipsel.ipk (39MB),目前GCC版本是4.1.1。编译了之后就可以直接运行了,很方便。openWRT我没有找到可以直接装的GCC。当然编译的话只适合编译小程序,大程序还得用PC。
4,小程序怎么把数据传给网页服务器?
方法应该很多吧。我暂时只想到2种。第一种是小程序把读到的数据写到文件里面,然后网页服务器直接读取文件。如果要这样弄,最好把文件放到 /tmp下吧。因为对于DDWRT来说/tmp在RAM里,频繁读写文件不伤Flash。
第二种是通过socket来发布,网页服务器那边用JS,JSP,PHP来读相应端口,从而获取数据。
然后说一说我的方案:
我的Arduino MEGA(兼容版,TTL转USB用的是FT232BM芯片)。上面连了2个传感器,一个是GL5528光敏电阻,还有一个是DHT11温湿度传感器(代码参考Arduino.cn)。
我的路由器是Asus WL-500G Premium v2,运行lighttpd和PHP。Arduino直接插到路由USB接口。路由器上运行程序sensor,接收从Arduino传过来的数据帧,帧格式定义都在附件的代码里面,代码写的很烂,看看差不多就行了。然后sensor把数据写到/tmp/sensorData.txt文件里(这里我把数据以字符串的形式写到文件里了,本来想直接按照相应数据类型存储的,但是在PHP处理字节流的方面遇到点问题),PHP直接读取这个文件再显示到网页上。小程序的编译命令是:gcc sensor.c -static -s -o sensor。我的路由每天早上4:30重启,所以把小程序加到自动启动列表里面了。
最后是网页的截图,因为PHP没学好,不会画图像,之后还可以直接绘制气温图。
结束以后可以通过DDNS发布到外网去,这样不管在哪里都可以看到温度了。如果不方便DDNS的话可以用Yeelink。
欢迎交流经验。
更新2:对于把传感器信息信息送到网页这点,我还有2个方法要补充一下,第一个就是5楼讲的方法,直接用cat直接打印,优点是不不要编译小程序了,但是这样做对数据做处理要全部交给网页服务器,如果数据一多,比如显示一个礼拜的平均温度,处理起来会不会麻烦?。如果自己写小程序,完全可以每天算好平均温度什么的。如果想法再多一点,还可以跟路由本地的mysql交互(DDWRT可以装mysql)。
第二个方法其实是我最先用的方法,就是用PHP直接读取路由端的串口,代码如下:
<?php
ini_set('display_errors', 'On');
//exec("mode /dev/usb/tts/0: BAUD=9600 PARITY=N data=8 stop=1 xon=off"); //调波特率,如果是默认的9600可以不要
$fp = fopen("/dev/usb/tts/0", "r");
$read = fread($fp, 1000);
echo $read."</br>";
fclose($fp);
?>
<?php
ini_set('display_errors', 'On');
//exec("mode /dev/usb/tts/0: BAUD=9600 PARITY=N data=8 stop=1 xon=off"); //调波特率,如果是默认的9600可以不要
$fp = fopen("/dev/usb/tts/0", "r");
$read = fread($fp, 1000);
echo $read."</br>";
fclose($fp);
?>
我遇到的问题就是貌似只能读字符串形式的字节数据,如果是数据帧形式的字节数据,不知道怎么提取各个数据。希望有高人相助。然后这个缺点也是不能处理数据,但是这种方法对于单次查询Arduino串口非常方便。
更新1:之前Arduino的代码发错了,现在改好了
via - 极客工坊