zcbzjx 发表于 2013-5-13 21:10:06

【翻译教程】enc28J60 和 Arduino (14)——获取数据存储到服务器并显示图表

终于等到原作者出第14篇教程了,我又可以来挣极客工坊淘宝杂货铺的¥5元的消费劵了,很多人还不知道吧,这儿帮极客工坊论坛宣传下吧,发表高质量文章就有可能获取金币的哦,而这个金币就可以在极客工坊的淘宝杂货铺当钱用哦,1金币=¥1元。hoho,看看你们有多少金币吧。好了,言归正传,原文在这儿,英文好的帮我校正下。。。多谢!


在本教程中,我将介绍如何开发一个小网站从Arduino的(使用Enc28j60盾)获取数据,存储并显示出图标曲线。

逻辑架构

您的网站将会由两页:


[*]saveTemp.php,从Arduino获取数据,并将其存储在文本文件;
[*]displayTemp.php,读取文本文件,并显示数据。




在这个例子中,Arduino使用SD18B20传感器获取房间的温度,我已经在博客的这篇文章介绍了该传感器。

对于网页编程,我选择了在网络上广泛使用PHP。

注意:为了保持简单的例子,数据被存储在一个CSV(逗号分隔值)文件,在实际应用中,最好使用一个数据库,例如MySQL。

发送数据

我使用的HTTP协议的GET方法将数据发送到Web服务器。这种方法请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连,如:login.php?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII。



为了防止其他用户发送数据,除了温度参数,你也必须发送到该网页的密码,使用pwd参数。

我的代码读取温度传感器,将其转换成字符串类型,并把它“print”到一个Stash对象:sensors.requestTemperatures();
float float_temp = sensors.getTempCByIndex(0);

char string_temp;
dtostrf(float_temp, 4, 2, string_temp);

Stash stash;
byte sd = stash.create();
stash.print(string_temp);
stash.save();然后在另外一个Stash对象中准备请求(Http Get 请求),并用tcpSend()方法发送到服务器:Stash::prepare(PSTR("GET /demo/saveTemp.php?temp=$H&pwd=$F HTTP/1.0" "\r\n"
    "Host: $F" "\r\n" "\r\n"),
    sd, password, website);
session_id = ether.tcpSend();由于会话标识符(SESSION_ID),你可以得到一个来自服务器的响应,并检查它是否包含错误消息(“KO”):const char* reply = ether.tcpReply(session_id);
[...]
if(strstr(reply, "KO - ") != 0) Serial.println(strstr(reply, "KO - "));在PHP中,你可以通过关联数组$_GET获得这些HTTP GET发送过来的数据:$temp = $_GET["temp"];
$pwd = $_GET["pwd"];验证密码后,温度值以及对应的时间戳一起存储在文件中:define("LOG_FILE", "./temperatures.csv");
[...]
$file_handler = fopen(LOG_FILE, "a+");
fwrite($file_handler, time() . "," . $temp . "\n");旁白请忽略,版主如果觉得不合适可以删除:哎要不要给我的维基拉点流量嘞。。。算了,还是让各位看官直接在这儿爽完吧。。。因为我饱受那样的痛苦。。。从此直接忽略掉这类文章。。。

数据显示

为了使这个例子更有趣,我决定把这些数据显示在图表上。

对于PHP,有一个很好的开源的图表库可供选择:JpGraph。要使用它,你必须把库文件上传到您的网站的子文件夹中,通常为“/JpGraph”:



在PHP代码中,你就必须包括需要的库,这取决于你要创建的图表类型:require_once('jpgraph/jpgraph.php');
require_once('jpgraph/jpgraph_line.php');
JpGraph库不负责获取图表所需的数据而是通过PHP代码,打开文件 - 按行 - 把数据保存到两个数组中:$file_lines = file(LOG_FILE, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
foreach($file_lines as $line_num => $line_value) {
      $line_elements = explode(",", $line_value);
      $times[] = date("H:i:s", $line_elements);
      $values[] = $line_elements;
}JpGraph可以为每组数据创建许多不同类型的图表, 你可以做很多的自定义:有关使用该库的例子和教程,请参考官方手册。

运行

Arduino的草图和PHP网页的源代码可以在GitHub上我的存储库中下载,这里有两个截图显示运行状态:




翻译结束!

下面是我的验证过程:

软件准备

1.php服务站点,托破砖的福。。帮我建了一个——demo.microduino.net;
2.下载JpGraph库,下载地址在这儿;
为保持完整也可直接从下面下载

3.解压缩后,将文件夹内的src文件夹更名为JpGraph,并上传到demo.microduino.net对应的根目录下;
4.下载例程所需文件,下载地址在这儿;
也可直接从这儿下载

5.将displayTemp.php,saveTemp.php 2个文件拷贝到demo.microduino.net对应的根目录下;
可以更改saveTemp.php中的password。define("PASSWORD", "password");比如可更改为:define("PASSWORD", "xxxxxxx");硬件准备

1.microduino-core(也可用uno 或者nano);
2.Microduino-FT232R(如果用uno或者nano就不用这个了);
3.Microduino-ENC28J60和-RJ45(也可用别的ENC28J60盾或者模块);
4.Test-Microduino;
5.自制的18B20温度传感器(当然你也可以用现成的18B20温度传感器模块)。

开始试验

各个模块叠加,并插入Test-Microduino实验底板,并在底板上连接传感器:



恩,大家可以看到ENC28J60模块的片选是连接到D8,温度传感器模块数据端口是连接到A0的。
恩,如果用别的模块的请注意连线别连接错了哦。

我先休息10分钟,等大家连线,抽根烟,泡杯茶。。。。。

恩,大家连好了吧,我们继续:

插入网线和usb线:



下载代码:

#include <EtherCard.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define SEND_INTERVAL5000
#define TIMEOUT      5000
#define ONE_WIRE_BUS   A0
#define STATUS_IDLE    0
#define STATUS_SENT    1

// ethernet interface mac address
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
// ethernet interface ip address
static byte myip[] = { 10,21,0,195 };
// gateway ip address
static byte gwip[] = { 10,21,0,1 };
// dns ip address
static byte mydns[] = { 10,11,5,25 };

byte Ethernet::buffer;

char website[] PROGMEM = "demo.microduino.net";
char password[] PROGMEM = "xxxxxxxx";

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

unsigned long previousMillis = 0;
static byte session_id;
byte actual_status;

void setup () {

Serial.begin(57600);
Serial.println("WebTemperature demo");
Serial.println();

if (!ether.begin(sizeof Ethernet::buffer, mymac)) {
    Serial.println( "Failed to access Ethernet controller");
    while(1);
} else Serial.println("Ethernet controller initialized");

if (!ether.staticSetup(myip, gwip,mydns)) {
    Serial.println("Failed to get configuration from DHCP");
    while(1);
} else Serial.println("DHCP configuration done");

if (!ether.dnsLookup(website)) {
    Serial.print("Unable to resolve Website IP");
    while(1);
} else Serial.println("Website IP resolved");

Serial.println();
ether.printIp("IP Address:\t", ether.myip);
ether.printIp("Netmask:\t", ether.mymask);
ether.printIp("Gateway:\t", ether.gwip);
ether.printIp("Website IP:\t", ether.hisip);
Serial.println();
}

void loop() {

ether.packetLoop(ether.packetReceive());
unsigned long currentMillis = millis();

switch(actual_status) {
    case STATUS_IDLE:
      if(currentMillis - previousMillis > SEND_INTERVAL) {
      previousMillis = currentMillis;
      sendTemperature();      
      }
      break;
    case STATUS_SENT:
      if(currentMillis - previousMillis > TIMEOUT) {
      Serial.println("No response");
      previousMillis = currentMillis;
      actual_status = STATUS_IDLE;
      }
      checkResponse();
}
}   

void sendTemperature() {

sensors.requestTemperatures();
float float_temp = sensors.getTempCByIndex(0);

char string_temp;
dtostrf(float_temp, 4, 2, string_temp);

Stash stash;
byte sd = stash.create();
stash.print(string_temp);
stash.save();

Stash::prepare(PSTR("GET /saveTemp.php?temp=$H&pwd=$F HTTP/1.0" "\r\n"
    "Host: $F" "\r\n" "\r\n"),
    sd, password, website);
session_id = ether.tcpSend();
Serial.print("Temperature ");
Serial.print(string_temp);
Serial.print(" sent to website... ");
actual_status = STATUS_SENT;
}

void checkResponse() {

const char* reply = ether.tcpReply(session_id);
if(reply > 0) {
    if(strstr(reply, "KO - ") != 0) Serial.println(strstr(reply, "KO - "));
    else Serial.println("OK");
    actual_status = STATUS_IDLE;
}
}


上传后,成功显示曲线。

你们的成功了么?什么?还在接线啊。。。

返回目录

幻生幻灭 发表于 2013-5-13 21:32:39

越来越难了啊:dizzy:

Tiki 发表于 2013-5-13 21:59:23

6点40分和7点40分,气温突然升高了5度,请问张老师当时在干什么?;P

zcbzjx 发表于 2013-5-13 22:03:40

Tiki 发表于 2013-5-13 21:59 static/image/common/back.gif
6点40分和7点40分,气温突然升高了5度,请问张老师当时在干什么?

用手摸了下

wasdpkj 发表于 2013-5-13 22:49:57

php页面曲线是张图,不是很理想。不过这篇教程是个好的开始,这样利用服务器相对节省了Arduino的资源

darkorigin 发表于 2013-5-13 22:56:21

Tiki 发表于 2013-5-13 21:59 static/image/common/back.gif
6点40分和7点40分,气温突然升高了5度,请问张老师当时在干什么?

...你是暗示我们张老师在做什么热血沸腾的事情么?

哈哈~~~~ 气温五度 如果不是直接触摸或者是在附近用热源,让大范围(比如一个房间)空气上升短时间上升五度需要很大能量的

darkorigin 发表于 2013-5-13 22:57:17

张老师。 帖子不错啊~~~ 精品啊~~

Tiki 发表于 2013-5-13 22:59:20

darkorigin 发表于 2013-5-13 22:56 static/image/common/back.gif
...你是暗示我们张老师在做什么热血沸腾的事情么?

哈哈~~~~ 气温五度 如果不是直接触摸或者是在附近用 ...

说的这么具体。。。

Tiki 发表于 2013-5-13 23:00:26

城砖君好像正在开放 demo.microduino.net 的开放注册啊,是不是大家都可以试一试这个玩法了?

darkorigin 发表于 2013-5-13 23:01:09

其实,感觉这个WEB服务器给的图比YEELINK看的舒服多了。而且这个算是私有传感器的服务端了。
话说YEELINK的话,很多人用摄像头传感器。。。万一在家里做点少儿不宜的运动。。。(宅男都懂的)被人看到了,就贻笑大方了哈哈
私有的服务器架设的传感器,首先限制少(不会数据间隔>15S 否则就.406 Err) 而且安全性好

弘毅 发表于 2013-5-13 23:04:43

本帖最后由 弘毅 于 2013-5-13 23:08 编辑

{:soso_e129:}新的一篇出来了。。。。果断加精。。。

zcbzjx 发表于 2013-5-13 23:12:20

弘毅 发表于 2013-5-13 23:04 static/image/common/back.gif
新的一篇出来了。。。。果断加精。。。

多谢郝老板

darkorigin 发表于 2013-5-13 23:13:17

wasdpkj 发表于 2013-5-13 22:49 static/image/common/back.gif
php页面曲线是张图,不是很理想。不过这篇教程是个好的开始,这样利用服务器相对节省了Arduino的资源

最好是个FLASH。但是那个涉及的东西又多了。 呵呵

可以再HTML里面加刷新的代码,每2S自动刷新。这样浏览起来图片就在跟着数据动了

zcbzjx 发表于 2013-5-13 23:15:50

darkorigin 发表于 2013-5-13 23:01 static/image/common/back.gif
其实,感觉这个WEB服务器给的图比YEELINK看的舒服多了。而且这个算是私有传感器的服务端了。
话说YEELINK的 ...

但是私有服务器成本会比较高,对个人来说难度会比较大,相对来说yeelink等物联网服务提供商让忘记能更快更容易上手,至于私密性,我想付费会员应该可以解决这个问题,其实给空间费域名费和给会员费道理是一样的。

zcbzjx 发表于 2013-5-13 23:18:59

Tiki 发表于 2013-5-13 23:00 static/image/common/back.gif
城砖君好像正在开放 demo.microduino.net 的开放注册啊,是不是大家都可以试一试这个玩法了?

开放这个其实应该是可以实现的,开放ftp注册,每人限定一定的空间量。hoho。具体得看破砖这个专家了。。
页: [1] 2 3 4
查看完整版本: 【翻译教程】enc28J60 和 Arduino (14)——获取数据存储到服务器并显示图表