首页
社区
课程
招聘
[原创]初玩树莓派B 7物联网温湿度监控
2016-10-8 23:19 10725

[原创]初玩树莓派B 7物联网温湿度监控

2016-10-8 23:19
10725
初玩树莓派 B 7物联网温湿度监控

bbs.pediy.com

        这一节用温湿度传感器接入中移动物联网上报家中的温湿度。

1 dht11传感器使用简介
        DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。我购买的dht11只有三个针脚分别是 VCC  DATA GND,(有些是四阵脚的,多一个NC空脚)。

常用电路图。

        前面我们已经玩了一些常用模块,接线都比较熟悉了。正极接3.3V,负极接GND,DATA(OUT)针脚我接了物理的11号针脚,对应于WiringPi标号是0,同时为DATA针脚接入一个5K欧姆的上拉电阻,使得空闲状态的时候为高电平。


        对于之前使用的一些模块,我们只需要知道高低电平就可以了,现在要得到的是温度和湿度的具体数据,那么如何通过DATA针脚得到温度和湿度呢?通过DATA针脚采用单总线格式进行数据通讯。依次完整的数据传输为40bit,先读出来的是高位的数据。40bit数据的格式是:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和。如果数据是准确的,那么8bit湿度整 8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据的结果的末8位等于8bit校验和。
        通讯过程如下,主机首先向传感器发送开始信号,等开始信号发送完毕以后。dht11发送响应信号,依次传回40bit的数据,随后进入空闲状态。
        沟通握手过程如下,初始空闲状态DATA为高电平,主机将DATA拉低等待DHT11响应,拉低的时间必须大于18ms保证DHT11可以检测到这个状态。随后dht11等待开始信号结束,主机可以通过拉高电平20-40us表明信号结束。以后就可以准备读取dht11的响应信号了。dht11会发送80us的低电平来响应然后dht11再次将电平拉高持续80us表示后面的数据传输要开始了。


通讯过程如下:dht11每次传输1bit数据的过程是先拉低电平50us。随后拉高电平,高电平的时间长短决定了这1bit的数据是0还是1。当最后一个bit的数据传输完毕以后,dht11拉低电平50ms。随后上拉电阻拉高进入空闲状态。一次数据传输过程完毕。

传输0的过程:

传输1的过程:

关键部分代码如下。

/*
当检测到的状态不是state的时候就返回。
如果参数state是HIGH,那么需要等到检测到LOW的时候返回。
返回值代表了状态改变所用的时间计数。
返回值如果是-1 表明和设备通讯出现了错误,需要重新开始通讯。
*/
int loopCheckUntilStateChange(int state)
{
	//初始时间计数为0
	int count=0;
	//读取针脚的状态
	while(digitalRead(DHT11PIN)==state)
	{
		//如果状态没变那么计数加1
		count++;
		//如果计数超过了最大的计数,表明通讯错误,需要重新开始
		if(count>MAX_COUNT)
			return -1;
		//延时1微秒。
		delayMicroseconds(1);
	} 
	return count;
}


/*
读取DHT11。如果读取成功,返回true,否则false。将温度放到 ptemp,将湿度放到
phumi
*/
bool readDHT11(float* ptemp,float* phumi)
{

	int count=0,ibit=0;
	bool bret=false;
	//保存电平改变所用的时间计数
	int bitsz[40]={0};
	//保存读取到的4个温湿度数据和1个校验码
	int data[5]={0};

	//首先设置为输出模式
	pinMode(DHT11PIN,OUTPUT);
	//写入低电平
        digitalWrite(DHT11PIN,LOW);
	//低电平至少持续18ms。保证能够DHT检测到这个初始信号
	delay(20);
	//随后主机将电平拉高,通知DHT信号结束
	digitalWrite(DHT11PIN,HIGH);
	//将针脚转为输入模式,等待DHT的响应。
	pinMode(DHT11PIN,INPUT);
	//经过20-40us,我们需要等待DHT将电平从高电平拉低
	if(loopCheckUntilStateChange(HIGH)<0)
	{
	
		return bret;
	}
	//DHT的响应信号低电平持续80us,等待DHT再次由低拉高
	if(loopCheckUntilStateChange(LOW)<0)
	{
		return bret;
	}
	//高电平将持续80us,等待DHT将高电平拉低。开始传输数据
	if(loopCheckUntilStateChange(HIGH)<0)
	{
		return bret;
	}
	
	//数据传输开始。每次传输一个bit。一共40bit。5字节
	for(ibit=0;ibit<40;ibit++)
	{
		//每个bit传输由50us的低电平开始。变为高电平就是开始传输0或者1了。
		if(loopCheckUntilStateChange(LOW)<0)
		{

			return bret;
		}
		//这次我们要检测高电平到低电平经过了多少个计数的count
		//以此来决定这一bit是0还是1
		count=loopCheckUntilStateChange(HIGH);
		//如果小于0,出错了
		if(count<0)
		{

			return bret;
		}
		//将高电平持续的count保存在bitsz里面。
		bitsz[ibit]=count;
	}

/*
定义了区别 0 和1 的count 阈值。这个阈值要根据实际情况和你写的函数调整。
比如 loopCheckUntilStateChange里面如果没有delayMicroseconds(1);完全跑CPU,那么count值会比较大。
如果有delayMicroseconds(1)那么这个值会小一些。
*/
#define THRESHOLD 20
	for(ibit=0;ibit<40;ibit++)
	{
		/*
		将data左移1位,因为ibit的传输是从高位到低位
		每次填充后就要移动一次。
		ibit/8 确定是第几个data
		*/
		data[ibit/8]<<=1;
		/*
		根据传输时高电平占用时间的count来确定这个bit是0还是1
		THRESHOLD阈值根据不同的情况来确定,1的时间长,count大。0的时间短。count小。确定
		一个中间的值即可	
		*/
		if(bitsz[ibit]>THRESHOLD)
		{
			//如果超过了阈值。说明这一位是1。否则什么都不做。默认就是0了
			data[ibit/8]|=1;
		}
		
	}
	//检查校验码。查看整个数据是否传输准确了
	if(data[4]!=(data[3]+data[2]+data[1]+data[0])&0xff)
	{

		return bret;
	}
	
	/*
	由于dht11设备默认小数位为0,没有小数位.所以这里小数位就不要了。只有整数位的温度和湿度。
	否则就是(%d.%d data[0].data[1])湿度 (%d.%d data[2].data[3])温度
	*/
	*ptemp=data[2]*1.0;
	*phumi=data[0]*1.0;
	

	return true;
}


THRESHOLD和 MAX_COUNT的确定要根据实际的代码来修改。
比如THRESHOLD,如果loopCheckUntilStateChange 没有delayMicroseconds(1)。
count=loopCheckUntilStateChange(HIGH);打印40次
得到的count结果如下。


可以看到count基本分为两类。一类是120-130左右,一类是370-380左右。
因此代表0的26-28us的高电平时间对应的count就是120-130 ,代表1的70us的高电平count就是370-380。所以阈值可以设置为200。超过200就是1。小于200就是0。

如果加上了delayMicroseconds(1)。那么40次count的结果如下,前面指令都是跑CPU,因此count比较大,这里延时了1us,count就变小了。


明显看到一类是 10 左右,代表传输0。一类是30左右,代表传输1。
因此阈值设置为20。大于20是1,小于20是0。

这一部分代码的数据读取准确度不是很高,可能还需要稍作调整使得读取准确率更高,我是按照最好理解的方式写的。

2接入中移动的物联网开放平台

http://open.iot.10086.cn/ 是中移动推出的物联网平台,开放一些免费的接口可以开发应用,具体可以去官网查看更多资料,篇幅有限就不多介绍了,http://open.iot.10086.cn/doc/里面有详细文档文档。下面简单介绍一下使用步骤。

主要步骤参考http://open.iot.10086.cn/doc/art190.html#43

1注册账号并登陆。
2 页面中进入开发者中心,并创建一个产品。



创建产品。

填写简单资料。


其他的默认,并且使用http传输协议数据。

3添加一个设备


4为设备添加数据流

点开设备。

操作栏中点击添加数据流。

注意数据流的id用英文比较好。后续我们post数据需要用这个英文的id,中文容易出各种编码问题。
我们添加两个。一个是humi 湿度。一个是temp温度。

5添加一个应用



添加两个仪表盘。设备选择raspberry,数据流一个选择humi,一个选择temp。

保存应用。
web端的设置基本上就完毕了。

参看http://open.iot.10086.cn/doc/art190.html#43的协议文档。
为了上传温度和湿度,我们需要几个关键的数据。
1 设备id。这个从设备详情页可以拿到。
2appkey 。这个可以从appkey页面使用默认的

3数据的id。也就是之前添加数据流的时候使用的humi和temp。

我们需要post的数据类似于
POST /devices/YOURDEVICEID/datapoints?type=3 HTTP/1.1
Host:api.heclouds.com
api-key:YOURAPIKEY
content-type:application/json
{
        “temp”:25,“humi”:60
}

使用libcurl关键部分代码如下(记得替换YOURDEVICEID 以及YOURAPPKEY )。
#define POST_URL "http://api.heclouds.com/devices/YOURDEVICEID/datapoints?type=3"
void postData(float temp,float humi)
{
	CURL *curl;
	char jsonData[512];
	struct curl_slist* header=NULL;
	printf("humi=%.2f temp=%.2f\n",humi,temp);
	curl = curl_easy_init();  
	curl_easy_setopt(curl, CURLOPT_URL, POST_URL);  
	header=curl_slist_append(NULL,"api-key:YOURAPPKEY");
	curl_slist_append(header,"content-type:application/json");
	sprintf(jsonData,"{\"temp\":\"%.2f\",\"humi\":\"%.2f\"}",temp,humi);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData); 
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, showResponse); 
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);  
	curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/iotpost.cookie");  
	curl_easy_perform(curl); 
	curl_slist_free_all(header);
	curl_easy_cleanup(curl);
};
//如果将上传的结果打印出来
size_t showResponse(void *buffer, size_t size, size_t nmemb, void *userp)
{
	char* response=NULL;
	if(!buffer||!size||!nmemb)
	{
		printf("no response\n");
		return;
	}
	response=(char*)malloc(size*nmemb+1);
	memcpy(response,buffer,size*nmemb);
	response[size*nmemb]=0;
	printf("response: %s\n\n",response);
	free((void*)response);
};


如果成功会输出:
{
"errno": 0,
"error":“succ”,
}

使用libcurl发送post请求。
首先需要安装libcurl
sudo apt-get install libcurl4-gnutls-dev
编译的时候也要加上-lcurl
gcc -o dht11 dht11.c -lwiringPi -lcurl
具体的代码参看dht11.c

如果成功提交post数据。可以在应用的页面看到你家庭的温度和湿度。将发布链接转给别人,人家就能看到你家庭的温度湿度了。

每隔10s POST一次数据,webapp也会自动更新数据。

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
免费 3
打赏
分享
最新回复 (7)
雪    币: 288
活跃值: (212)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
mozha 2 2016-10-9 10:11
2
0
写得很好,搞得我也想买板树霉来玩玩。
雪    币: 6782
活跃值: (4441)
能力值: (RANK:600 )
在线值:
发帖
回帖
粉丝
gjden 14 2016-10-9 13:05
3
0
写得非常不错,感谢分享
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
我爱你的吻 2016-10-16 12:14
4
0
写的非常不错。既有硬件的相关通信协议,又有软件APPKEY申请应用。希望再多出一些这样实用性的文章!
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Dvive 2017-2-13 21:36
5
0
祝您生活愉快,同时谢谢您
雪    币: 33
活跃值: (58)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
psr 2017-2-14 15:51
6
0
请教一下为啥要为DATA针脚加个5K欧姆的上拉电阻?Data针脚保持高电平干嘛?
雪    币: 77
活跃值: (795)
能力值: ( LV7,RANK:150 )
在线值:
发帖
回帖
粉丝
shuozhang 2 2017-2-16 09:17
7
0
为了让Data端口空闲状态的时候为高电平,这样当mcu端口为低电平时,可以把Data端口拉低,这样DHT11就能检测到这个电平的变换,就明白了要开始传送湿度和温度的信息。
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yangfabin 2017-2-23 17:25
8
0

请教大神,你.c文件里面的#include <curl/curl.h>头文件是什么来的?我编译了一下提示没有这个头文件,求回答,感谢!

游客
登录 | 注册 方可回帖
返回