这个项目基于51单片机、ESP8266WiFi模块、温湿度DHT11传感器、阿里云来完成。
目录
DHT11温湿度传感器采集数据后发送给单片机,单片机在经过简单的数据处理后把数据发送给esp8266WiFi模块,WiFi模块再把数据发送到阿里云上。

根据淘宝客服给的dht11模块资料,我们可以得出DHT11的供电电压为 3-5.5V这个信息以及dht11与单片机之间通过单总线的数据格式(即通信只需要用到data这一根引脚),因此关于dht11的引脚接线就是:
VCC接单片机上的上的5v引脚
DATA引脚接单片机任意一个IO引脚
GND接地
单片机与dht11一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和
通讯过程如下图所示:

接收到数据后,数据分为数据0和数据1
数字0信号表示方法如下图所示

数据 1信号表示方法如下图所示

由此,我们可以编写出dht11检测温湿度的代码(dht11.c)
#include "main.h"
//DHT11起始信号
void DHT11_start()
{
Temp_data=1;
delay_us(2);
Temp_data=0;
delay_ms(20);
Temp_data=1;
delay_us(13);
}
//接收一个字节
unsigned char DHT11_rec_byte()
{
unsigned char i,dat;
for(i=0;i<8;i++)
{
while(!Temp_data);
delay_us(8);
dat<<=1;
if(Temp_data==1)
{
dat+=1;
}
while(Temp_data);
}
return dat;
}
//接收温湿度数据
void DHT11_receive()
{
unsigned int R_H,R_L,T_H,T_L;
unsigned char RH,RL,TH,TL,revise;
DHT11_start();
Temp_data=1;
if(Temp_data==0)
{
while(Temp_data==0); //等待拉高
delay_us(40); //拉高后延时80us
R_H=DHT11_rec_byte(); //接收湿度高八位
R_L=DHT11_rec_byte(); //接收湿度低八位
T_H=DHT11_rec_byte(); //接收温度高八位
T_L=DHT11_rec_byte(); //接收温度低八位
revise=DHT11_rec_byte(); //接收校正位
delay_us(25); //结束
if((R_H+R_L+T_H+T_L)==revise) //校正
{
RH=R_H;
RL=R_L;
TH=T_H;
TL=T_L;
}
rec_dat[0]=RH;
rec_dat[1]=RL;
rec_dat[2]=TH;
rec_dat[3]=TL;
}
}
博主所使用的是8引脚的esp8266-01s,在拿到WIFI模块后,首先要进行的是使用esp8266的出厂固件库(AT指令集)来检查,ESP8266的接线方式如下:
EN引脚接高电平(3.3V或者5V都可以,5V可能会发烫)
GND引脚接地
VCC:接3.3V的高电平
RX:接TXD
TX:接RXD
接完之后在串口调试助手中输入AT来验证模块是否正常,如果正常模块会返回一个ok,检查完成之后我们要顺便配置一下ESP8266的波特率,把他从原来的115200改为9600,AT+CIOBAUD=9600。
完成这些步骤之后,就要为ESP8266模块编写代码了。
代码编写分为两个部分,一个是在keil软件上编写的,与单片机连接的串口模块。此模块十分简单,就配置一个串口来给单片机与ESP8266进行通信即可,博主使用的单片机晶振是11.0592MHZ的,因此串口的配置(usart.c)如下:
#include "main.h"
bit uart_busy = 0;
void usart_init(void)//4800bps@12.000MHZ
{
SCON=0x40; //串口通信工作方式1
REN=1; //允许接收
TMOD=0x20; //定时器1的工作方式2
TH1=0xFd,TL1=0xFd;
TI=1; //这里一定要注意
TR1=1;
EA =1; //开总中断
ES =1; //开串口1中断
}
void Uart_SendByteData(unsigned char msg)
{
while(uart_busy); //等待上一个数据发送完成
SBUF=msg;
uart_busy = 1; //串口发送置忙
}
void Uart_SendStrData(unsigned char *msg)
{
while(*msg)
{
Uart_SendByteData(*msg++);
}
}
void USART_IRQHandler() interrupt 4
{
unsigned char one_char;
if(RI)
{
one_char = SBUF;
RI=0; //清空接收标志位
}
if(TI)
{
TI=0;
uart_busy = 0;
}
}
keil软件的代码编写完之后,就是arduino软件上的代码编写,此代码编写需用到配置阿里云中得到的信息,这待会在阿里云的部分在介绍。
安装Arduino软件。
链接:https://pan.baidu.com/s/1OWmn4ei7JENqGbAFIylMxg
提取码:hcwa
安装CP210x驱动,安装了这个驱动之后才能下载程序到ESP8266中。这里要把网盘中整个文件夹进行下载,之后才能正常安装。
链接:https://pan.baidu.com/s/1e9-uI2qscRPam-OQ7csttw
提取码:dh8c
使用arduino软件时需要先下载各种需要使用的固件库,如果下载安装成功会显示浅绿色的“INSTALLED”字样。

分别下载AliyunIoTSDK,ArduinoJson,PubSubClient,Crypto,AWS-SDK-ESP8266这几个库。并且点开文件中的首选项,把附加开发板管理器网址设置成以下:
开发板管理器网址:http://arduino.esp8266.com/stable/package_esp8266com_index.json
然后再进行以下配置:


安装完所有的固件库后,还要进行以下文件的修改 ,修改刚刚下载库中的PubSubClient.h文件,此步是关键步骤,不修改将导致无法连接上阿里云平台。


然后就是进行arduino代码的编写:
// 引入 wifi 模块,并实例化,不同的芯片这里的依赖可能不同
#include <ESP8266WiFi.h>
static WiFiClient espClient;
// 引入阿里云 IoT SDK
#include <AliyunIoTSDK.h>
// 设置产品和设备的信息,从阿里云设备信息里查看
#define PRODUCT_KEY "xxxx" //此信息在阿里云部分PRODUCT_KEY
#define DEVICE_NAME "xxxxx" //同上DEVICE_NAME
#define DEVICE_SECRET "xxx" //同上DEVICE_SECRET
#define REGION_ID "cn-shanghai" //对应阿里云华东2(上海)服务器
// 设置 wifi 信息
#define WIFI_SSID "xxx" //自己的手机热点WiFi名字(此处为自己手机开出的热点给esp8266
//连接)
#define WIFI_PASSWD "xxxxxxx" //自己的手机热点WiFi密码
char Serial_Buf[50]; //可根据自己定义的数据长度自行修改
unsigned int Rx_Cnt = 0;
char Temp[20];
char Hum[20];
void setup()
{
Serial.begin(9600);
// 初始化 wifi
wifiInit(WIFI_SSID, WIFI_PASSWD);
// 初始化 iot,需传入 wifi 的 client,和设备产品信息
AliyunIoTSDK::begin(espClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET, REGION_ID);
//AliyunIoTSDK::send("temperature", 11.8); //修改阿里云平台上对应设备的Tempature属性
}
void loop()
{
AliyunIoTSDK::loop();
Serial_Rece_Process(); //串口接收数据与数据处理
AliyunIoTSDK::send("temperature",atof(Temp));
AliyunIoTSDK::send("Humidity",atof(Hum));
}
// 初始化 wifi 连接
void wifiInit(const char *ssid, const char *passphrase)
{
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, passphrase);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.println("WiFi not Connect");
}
Serial.println("Connected to AP");
}
//ESP8266串口接收数据与数据处理函数
void Serial_Rece_Process(void)
{
unsigned char i =0;
unsigned char sg = 0;
while (Serial.available())
{
Serial_Buf[Rx_Cnt] = Serial.read();
Rx_Cnt++;
delay(3);
}
if (Rx_Cnt != 0)
for(int i=0;i<Rx_Cnt;i++)
{
/*此段代码是因为博主从串口接收到的数据格式是t:%d.%d,h=%d.%d\r\n这种格式*/
if(i>1&&i<6)
{
Temp[i-2]=Serial_Buf[i];
}
else if(i>8&&i<13)
{
Hum[i-9]=Serial_Buf[i];
}
}
Rx_Cnt = 0;
//此处放置串口数据处理等代码
}
代码写完之后,再设置端口以及开发板的型号

点击左上角的箭头进行编译。
编译的接线也是十分重要的,因为博主手中的esp8266模块根据IO0引脚来区分下载模式还是运行模式,当IO0引脚接低电平的时候为下载模式,悬空的时候为运行模式,所以我们在使用arduino来下载esp8266的代码时需要把IO0引脚,以及RST复位引脚接地。当编译过程中出现connecting字样的时候,让RST复位引脚悬空,当出现Hard resetting via RTS pin...字样的时候,插上RST引脚复位后,拔掉IO0引脚以及RST引脚,这时候,arduino的代码就已经烧录到ESP8266当中。
此处是讲解阿里云的配置
1.登录阿里云平台账号
2.进入阿里云物联网平台(点击左上角的产品,然后点击物联网IOT,选择企业物联网平台)就会出现这个界面:



然后就是创建自定义产品


定义产品功能属性




添加刚刚创建的产品类别的设备。

这一步很关键,复制设备三元组信息到文本文件中保存好,arduino软件编写esp8266代码部分会依靠这个信息才能连接上阿里云物联网平台。

至此,阿里云配置完成。

我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
我目前正在使用带有Carrierwavegem的Rails3.2将文件上传到AmazonS3。现在我需要能够处理用户提交的大于5GB的文件,同时仍然使用Carrierwavegem。Carrierwave或Fog是否有任何其他gem或分支可以处理5GB以上的文件上传到S3?编辑:我不想重写一个完整的Rails上传解决方案,所以像这样的链接没有帮助:https://gist.github.com/908875. 最佳答案 我想出了如何做到这一点,并且现在可以正常工作了。在正确的config/environment文件中,添加以下内容以
这段代码没有像我预期的那样执行:casewhen->{false}then"why?"else"ThisiswhatIexpect"end#=>"why?"这也不是casewhen->(x){false}then"why?"else"ThisiswhatIexpect"end#=>"why?"第一个then子句在两种情况下都被执行,这意味着我提供给when子句的lambda没有被调用。我知道无论when子句的主题是什么,都应该调用大小写相等运算符===。我想知道当没有为case提供参数时,===的另一边会发生什么。我在想它可能是nil,但它不可能是:->{false}===nil#=>
我想知道我的代码是否在rspec下运行。这可能吗?原因是我正在加载一些错误记录器,这些记录器在测试期间会被故意错误(expect{x}.toraise_error)弄得乱七八糟。我查看了我的ENV变量,没有(明显的)测试环境变量的迹象。 最佳答案 在spec_helper.rb的开头添加:ENV['RACK_ENV']='test'现在您可以在代码中检查RACK_ENV是否经过测试。 关于ruby-检测由RSpec、Ruby运行的代码,我们在StackOverflow上找到一个类似的问题
我正在使用rubydaemongem。想知道如何向停止操作添加一些额外的步骤?希望我能检测到停止被调用,并向其添加一些额外的代码。任何人都知道我如何才能做到这一点? 最佳答案 查看守护程序gem代码,它似乎没有用于此目的的明显扩展点。但是,我想知道(在守护进程中)您是否可以捕获守护进程在发生“停止”时发送的KILL/TERM信号...?trap("TERM")do#executeyourextracodehereend或者你可以安装一个at_exit钩子(Hook):-at_exitdo#executeyourextracodehe
我正在尝试上传文件。一个简单的hello.txt。我正在关注文档,但无法将其上传到我的存储桶。#STARTAWSCLIENTs3=Aws::S3::Resource.newbucket=s3.bucket(BUCKET_NAME)begins3.buckets[BUCKET_NAME].objects[KEY].write(:file=>FILE_NAME)puts"Uploadingfile#{FILE_NAME}tobucket#{BUCKET_NAME}."bucket.objects.eachdo|obj|puts"#{obj.key}=>#{obj.etag}"endresc
我正在运行rspec测试以确保两个模型通过has_many和belongs_to相互关联。下面是我的测试。describe"testingforhasmanylinks"dobeforedo@post=Post.new(day:"Day1",content:"Test")@link=Link.new(post_id:@post.id,title:"google",url:"google.com")endit"inthepostmodel"do@post.links.first.url.should=="google.com"endend测试告诉我url是一个未定义的方法。我的测试有什么
我有一个定义类的Ruby脚本。我希望脚本执行语句BoolParser.generate:file_base=>'bool_parser'仅当脚本作为可执行文件被调用时,而不是当它被irbrequire(或通过-r在命令行上传递)时。我可以用什么来包装上面的语句,以防止它在我的Ruby文件加载时执行? 最佳答案 条件$0==__FILE__...!/usr/bin/ruby1.8classBoolParserdefself.generate(args)p['BoolParser.generate',args]endendif$0==_
我有以下字符串,我想检测那里的换行符。但是Ruby的字符串方法include?检测不到它。我正在运行Ruby1.9.2p290。我哪里出错了?"/'ædres/\nYour".include?('\n')=>false 最佳答案 \n需要在双引号内,否则无法转义。>>"\n".include?'\n'=>false>>"\n".include?"\n"=>true 关于Ruby无法检测字符串中的换行符,我们在StackOverflow上找到一个类似的问题: h