ARDUINO时钟项目-4

没有评论

2016年5月21日 at 下午2:41分类:硬件 阅读: 318 次

当前进展(0521):

本地温度、湿度、亮度、空气质量(PM2.5)指示

NTP自动对时、时钟显示

网络历史数据存储、历史数据展示

框图及连线:

传感器gp2y1010au的D2、A0脚接Arduino的D2、A1脚,Arduino读取pm2.5数据并上报

传感器输出电压与空气质量关系图:

拟合图:

所有传感器数据显示:

 

在Arduino程序中对上报数据进行了平滑处理,将一分钟内的数据取平均值上报。另外增加对ESP8266的死机检测和复位(D8)控制:

ALL0521

 

关于ESP8266稳定性问题及规避方法

没有评论

2016年5月21日 at 上午11:29分类:硬件 阅读: 543 次

问题:

ESP8266(固件v0.9.5.0 AT Firmware)如果操作不慎,长时间运行会经常出现复位或者卡死现象,卡死时对任何AT命令只回应“busy p...",包括复位命令:

AT+CIPMODE=0
busy p...
AT+RST
busy p...
AT+RST
busy p...

此状态下只能通过复位ESP8266恢复。

另ESP8266在IP报文收发时容易出现复位现象,需要确保串口响应了上一条命令后再发送下一条命令。

 

规避方法:

1、增加AT命令发送函数,确保串口响应了上一条命令后再发送下一条命令

arduino函数:

/**
 * 执行一个AT命令,等待OK或ready再返回,或者超时返回
 */
String execATCommand(String cmd, int timeout, boolean norst){
  //执行AT命令前,先把缓存内的数据都读完,防止影响命令结果
 
  if(1){
    while( Serial.available() > 0) {
      Serial.read();
    }
 
  }
  Serial.print(cmd);
  Serial.print("\r\n");
  String data = "";
  if(timeout > 0){
    long t1 = millis();
    do{
 
        char r = Serial.read();
 
 
        if(r < 0){
          continue;
        }
        if(r == '\n' || r == '\r') {
          data="";
 
        } else {
            data += r;  
        }
 
        if(norst)
        {
         if(data == "OK") 
           return data;
        }
        else
        {
         //复位命令时返回ready为成功
         if(data == "ready") 
            return data;
         }
 
    }while((millis() - t1) < timeout);
  }
  data="ERR";
  return data;
}

2、增加死机检测,死机时硬件复位

arduino发送串口AT命令给ESP8266,如果连续几次没有得到正确返回(超时返回),就通过数字管脚对ESP8266进行复位。如ESP8266-01的复位脚通过电阻分压(5V转3.3)接arduino D8引脚:

//ESP8266复位管脚
#define ESP_RESET_PIN 8
 
//ESP8266复位函数
void ESP_Reset()
{
  digitalWrite(ESP_RESET_PIN, LOW);    
  delay(1000);              
  digitalWrite(ESP_RESET_PIN, HIGH);   
  delay(1000);  
}
 
 
//判断语句
...
  cmd = "AT+CIPMODE=1";
  respMessage = execATCommand(cmd, 5000, true);
  if(respMessage=="ERR")
  {
    //判断ESP8266是否死机,连续3次以上无正确响应即复位
    ESP_ErrNum++;
    if(ESP_ErrNum>3)
    {
     ESP_Reset();
     ESP_ErrNum=0;
    }
    return;
  }
  else
  {
   ESP_ErrNum=0;
  } 
...

 

参考:
玩转ESP8266测试板(一):基本操作
玩转ESP8266测试板(二):程序烧写
玩转ESP8266测试板(三):远程控制测试板
玩转ESP8266测试板(四):SDK编程
关于ESP8266稳定性问题及规避方法

ARDUINO时钟项目-3

没有评论

2016年5月20日 at 下午7:19分类:硬件 阅读: 306 次

当前进展(0520):

本地温度、湿度、亮度指示

NTP自动对时、时钟显示

网络历史数据存储、历史数据展示

手机查看展示页面:

2016-05-20

数据展示采用HighCharts控件。通过ajax调用PHP来获取MySQL中存储的历史数据,然后通过HighCharts显示出来。

getDatas.php代码:

<?php
$db_name = "idata";
$table_name="data";
$db_host = "localhost";
$db_user = "root";
$db_pass = "PASSWD";
 
$select="";
 
$index = 0;
if(isset($_GET['index'])) {
$index = (int)$_GET['index'];
} 
 
@$nowtime=strtotime("now");
if($index == 0)
$starttime=$nowtime-3600;
else if($index == 1)
$starttime=$nowtime-10800;
else if($index == 2)
$starttime=$nowtime-86400;
else if($index == 3)
$starttime=$nowtime-604800;
else
$starttime=$nowtime-2592000;
 
 
$link = mysql_connect($db_host,$db_user,$db_pass) or die("Can't connect DB");
$db = mysql_select_db($db_name);
mysql_query("set names utf8");
 
$select="";
if($index<2)
$select = "select `index`,UNIX_TIMESTAMP(`time`),`wen`,`shi`,`guang`,`pm25`,`other` from ".$table_name." where UNIX_TIMESTAMP(`time`)>".$starttime;
else if($index==2)
$select = "select `index`,UNIX_TIMESTAMP(`time`),`wen`,`shi`,`guang`,`pm25`,`other` from ".$table_name." where (UNIX_TIMESTAMP(`time`)>".$starttime.") and (`index` mod 5)=0" ;
else if($index==3)
$select = "select `index`,UNIX_TIMESTAMP(`time`),`wen`,`shi`,`guang`,`pm25`,`other` from ".$table_name." where (UNIX_TIMESTAMP(`time`)>".$starttime.") and (`index` mod 30)=0" ;
else 
$select = "select `index`,UNIX_TIMESTAMP(`time`),`wen`,`shi`,`guang`,`pm25`,`other` from ".$table_name." where (UNIX_TIMESTAMP(`time`)>".$starttime.") and (`index` mod 60)=0" ;
 
$result = mysql_query($select);
 
$datas = array();
 
while($row = mysql_fetch_row($result)) {
$datas[] = $row;
}
 
echo json_encode($datas);
?>

HTML代码:

<!DOCTYPE html>
<html>
 <head> 
  <style type="text/css">
li {
float: left;
line-height: 34px;
width: 126px;
list-style: none;
}
 li a {
display: block;
text-align: center;
font-family: 微软雅黑;
color: #666;
}
a:link {
outline: none;
text-decoration: none;
}
li a.cur {
background: url(./images/filter_cur.png) no-repeat;
}
.pic {
width: 1200px;
height: 429px;
background: url(./images/box2.png) no-repeat;
}
ul,li,div {margin: 0;padding: 0;outline: 0;}
.clear {
clear: both;
}
</style> 
  <title>环境监控数据</title> 
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
  <script type="text/javascript" src="js/jquery-1.8.3.min.js"></script> 
  <script type="text/javascript" src="js/highcharts.js"></script> 
  <script>
 
//图表属性,不包含数据
var options = {
    credits: {
        enabled: false // 禁用版权信息
    },
 
    chart: {
        renderTo: 'container1',
        type: 'spline',
        zoomType: 'x',
        spacingRight: 20
    },
    title: {
        text: '温度曲线',
        style: {
                fontWeight: 'bold',
                               fontFamily: '微软雅黑'
            },
        x: -20 //center
    },
 
    xAxis: {
        type: 'datetime',
 
 
 
    },
    yAxis: {
        title: {
            text: 'Temperature (°C)'
        },
        plotLines: [{
            value: 0,
            width: 1,
            color: '#808080'
        }]
    },
    series: [{
        name: '温度',
 
 
 
    }],
    tooltip: {
 
        formatter: function() {
            return '<b>' + this.series.name + ':' + this.y +'</b><br/>' + Highcharts.dateFormat('%Y-%m-%d %H:%M', this.x);
        }
    },
 
    plotOptions: {
        spline: {
            dataLabels: {
                enabled: false
            },
            animation: false,
            marker: {
                enabled: false
            },
        },
    },
};
 
 
 
//初始函数,设置定时器,定时取数据
$(function() {
     queryData(0, 0);
     queryData(1, 0);
     queryData(2, 0);
    var i = 0;
 
 
});
 
//Ajax 获取数据并解析创建Highcharts图表
function queryData(num, index) {
    $.ajax({
        url: 'getDatas.php?index=' + index,
        type: 'get',
        dataType: "json",
        success: function(data) {
            var categories = [];
            var val = [];
                        var test= [];
            var count = 0;
            $.each(data,
            function(i, n) {
 
                //加8个时区
                categories[i] = n[1] * 1000 + 28800000;
                                if (num == 0) {
                val[i] = n[2] * 1;
                                } else if(num == 1) {
                val[i] = n[3] * 1;
                } else  {
                                 val[i] = n[4] * 1;
                                 }
                                  test[i]=[categories[i],val[i]];
 
                count++;
            });
            if (num == 0) {
                $(".ts a").removeClass('cur');
                $("#t" + "_" + index).addClass('cur');
                options.chart.renderTo = "container1";
                options.title.text = "温度曲线";
                options.yAxis.title.text = "温度(°C)";
                options.series[0].name = "温度";
 
            } else if (num == 1) {
                $(".ss a").removeClass('cur');
                $("#s" + "_" + index).addClass('cur');
                options.chart.renderTo = "container2";
                options.title.text = "湿度曲线";
                options.yAxis.title.text = "湿度(%)";
                options.series[0].name = "湿度";
 
            } else  {
                $(".gs a").removeClass('cur');
                $("#g" + "_" + index).addClass('cur');
                options.chart.renderTo = "container3";
                options.title.text = "光照强度曲线";
                options.yAxis.title.text = "光照度(LUX)";
                options.series[0].name = "光照度";
 
            }
            options.series[0].data = test;
 
 
            if (count <= 30) options.plotOptions.spline.dataLabels.enabled = true;
            else options.plotOptions.spline.dataLabels.enabled = false;
            chart = new Highcharts.Chart(options);
 
 
        }
    });
}
 
</script> 
 </head> 
 <body> 
  <div class="index"> 
   <ul class="ts" style="margin-left:5px;"> 
    <li><a id="t_0" href="javascript:queryData(0,0)" class="cur">最近1小时</a></li> 
    <li><a id="t_1" href="javascript:queryData(0,1)" class="">最近3小时</a></li> 
    <li><a id="t_2" href="javascript:queryData(0,2)" class="">最近1天</a></li> 
    <li><a id="t_3" href="javascript:queryData(0,3)" class="">最近1周</a></li> 
    <li><a id="t_4" href="javascript:queryData(0,4)" class="">最近1月</a></li> 
    <div class="clear"></div> 
   </ul> 
  </div> 
  <div class="pic"> 
   <br /> 
   <div id="container1" style="min-width:800px;width:1100px;height:400px;margin-top:5px; margin: 0 auto;"></div> 
  </div> 
 
  <br /> 
  <div class="index"> 
   <ul class="ss" style="margin-left:5px;"> 
    <li><a id="s_0" href="javascript:queryData(1,0)" class="cur">最近1小时</a></li> 
    <li><a id="s_1" href="javascript:queryData(1,1)" class="">最近3小时</a></li> 
    <li><a id="s_2" href="javascript:queryData(1,2)" class="">最近1天</a></li> 
    <li><a id="s_3" href="javascript:queryData(1,3)" class="">最近1周</a></li> 
    <li><a id="s_4" href="javascript:queryData(1,4)" class="">最近1月</a></li> 
    <div class="clear"></div> 
   </ul> 
  </div> 
  <div class="pic"> 
   <br /> 
   <div id="container2" style="min-width:800px;width:1100px;height:400px;margin-top:5px; margin: 0 auto;"></div> 
  </div>  
 
  <br /> 
  <div class="index"> 
   <ul class="gs" style="margin-left:5px;"> 
    <li><a id="g_0" href="javascript:queryData(2,0)" class="cur">最近1小时</a></li> 
    <li><a id="g_1" href="javascript:queryData(2,1)" class="">最近3小时</a></li> 
    <li><a id="g_2" href="javascript:queryData(2,2)" class="">最近1天</a></li> 
    <li><a id="g_3" href="javascript:queryData(2,3)" class="">最近1周</a></li> 
    <li><a id="g_4" href="javascript:queryData(2,4)" class="">最近1月</a></li> 
    <div class="clear"></div> 
   </ul> 
  </div> 
  <div class="pic"> 
   <br /> 
   <div id="container3" style="min-width:800px;width:1100px;height:400px;margin-top:5px; margin: 0 auto;"></div> 
  </div>  
 
 </body>
</html>

 

在线演示:

http://blog.iytc.net/iot/iot.html

 

ARDUINO时钟项目-2

没有评论

2016年5月19日 at 下午8:22分类:硬件 阅读: 316 次

当前进展:

本地温度、湿度、亮度指示

NTP自动对时、时钟显示

网络历史数据存储

框图及连线:

通过ESP8266 wifi连接网络,自动进行NTP对时及传感器数据上报。

arduino与ESP8266通过串口相连,注意ESP8266的供电电源为3.3V,需要5V到3.3V的电源转换,并且ESP8266-01需将CH_PD脚接VCC。

GPIO16管脚也是复位(reset)管脚。

ESP8266工作在AT模式,arduino通过AT命令控制ESP8266,包括wifi配置、NTP UDP数据收发、HTTP传感器数据上报等。

说明:

ESP8266工作在模式3状态(AP+STA),作为AP可以接收近端用户配置,作为STA连接家里的路由器,接入网络。

ESP8266的IP报文传输分透传和非透传两种,非透传模式下无法发送回车、换行符,因此在发送http数据时需将IP发送模式设置为透传(AT+CIPMODE=1),透传模式退出发送需输入“+++”字符串。

NTP为UDP报文,发送48字节请求报文,然后对接收的48字节进行分析,提取时间数据。

传感器数据采用http get的方式上传至网站,在网站上用PHP对get数据进行提取,并写入mysql数据库:

PHP文件:

<?php
@$wen=$_GET['wen'];
@$shi=$_GET['shi'];
@$guang=$_GET['guang'];
@$pm25=$_GET['pm25'];
@$other=$_GET['other'];

if($wen)
{
$conn=mysql_connect("localhost", "root", "XXXX");
mysql_query("set names 'utf8' ");
mysql_query("set character_set_client=utf8");
mysql_query("set character_set_results=utf8");

$insert="INSERT INTO `idata`.`data` (`wen`, `shi`, `guang`, `pm25`, `other`) VALUES ( '".$wen."', '".$shi."', '".$guang."', '".$pm25."', '".$other."')";
if(mysql_db_query("idata",$insert, $conn))
echo "OK";
else
echo "err";

}

?>

数据库密码为XXXX,数据库名为idata,表名为data,字段结构

插入记录时自动记录系统时间。

arduino源码:

ALL0519

arduino时钟项目-1

没有评论

2016年5月18日 at 上午11:23分类:硬件 阅读: 265 次

目标功能:

本地温度、湿度、PM2.5、亮度指示

NTP自动对时、时钟显示

网络历史数据存储

手机APP

语音控制

 

当前进展:

本地温度、湿度、亮度指示

框图及连线:

 

说明:

arduino通过模拟A0脚连接温湿度传感器;通过I2C(A4、A5脚)连接光传感器;通过SPI接口驱动OLED

OLED的驱动用的是U8gLib,需把库文件拷入C:\Program Files (x86)\Arduino\libraries

OLED与arduino的连线:

OLED屏     arduino板
GND         GND
VCC          5V
D0           10
D1            9
RES         13
DC          11
CS          12

arduino程序:

ALL

汉字取字模用的是PCtoLCD2002,设置如下:

比如显示“天”字:

const uint8_t rook_bitmap1[] PROGMEM = {

//“天”字的字模:
0x00,0x00,0x3F,0xF8,0x01,0x00,0x01,0x00,
0x01,0x00,0x01,0x00,0xFF,0xFE,0x01,0x00,
0x02,0x80,0x02,0x80,0x04,0x40,0x04,0x40,
0x08,0x20,0x10,0x10,0x20,0x08,0xC0,0x06
};

u8g.drawBitmap( 33, 42, 2,16, rook_bitmap1);