如何为编程爱好者设计一款好玩的智能硬件(四)——初尝试·把温湿度给收集了(上)!
一、我的构想:如何为编程爱好者设计一款好玩的智能硬件(一)——即插即用、积木化、功能重组的智能硬件模块构想
二、别人家的孩子:如何为编程爱好者设计一款好玩的智能硬件(二)——别人是如何设计硬件积木的!
三、MCU选型:如何为编程爱好者设计一款好玩的智能硬件(三)——该选什么样的MCU呢?
四、温湿度传感器DHT11驱动封装:
万事开头难,昨晚睡太晚!每天一篇确实有点累,不过能鞭策自己不偷懒努力向前!前三篇我们已经将“X-积木”大致轮廓(第一篇)、同类产品(第二篇)、MCU选型及大致计划(第三篇最后)介绍了一下。前几篇属于宏观把控,本篇将实施第三篇最后的三步计划中的第一步——“暂选CC2541作为核心块,先实现几个简单的功能块(如温湿度模块、光照模块、显示屏模块、超声波模块、继电器模块、人体红外线模块等),并分别对各个外设模块封装成可以通过蓝牙获取其使用说明和通信方式的API,然后尝试开发一个手机demo来通过蓝牙搜集这些信息并展示。”
包括本篇在内的接下来几篇都是针对各种常见外设进行和平台无关性封装,在每篇中会详细介绍每个外设的特性及封装思路,并且在各种平台上进行验证。本篇介绍智能家居领域总是少不了的一款传感器——温湿度传感器
买买买:
有些朋友建议我“你讲软件我们能够下载找到,你讲硬件我们很难找到,如果方便给个链接吧”。因此今后我会在必要的地方插入如何购买这些元件的链接(不是广告植入哦!)。对于该款DHT11传感器只要在淘宝上输入关键词,便可搜到一片(我建议大家买那些销量比较高的,如果您不想跟风的话,可以深入了解下所给的资料等是否齐全)。不过目前我不建议大家盲目地买过来,今后我会针对具体的小应用给大家一些采购方案~
传感器资料:
datasheet:http://akizukidenshi.com/download/ds/aosong/DHT11.pdf
DHT11 ①:是一个包含湿度测量电阻、NTC温度测量装置和一个8-bit的微处理器的温湿度采集模块。②:典型应用在加湿器、空调还有部分传感器网络中的气象采集等。③:特别说明其输出的是相对温湿度,需要校准!
Relative humidity Resolution: 16Bit Repeatability: ±1% RH Accuracy: At 25℃ ±5% RH Interchangeability: fully interchangeable Response time: 1 / e (63%) of 25℃ 6s 1m / s air 6s Hysteresis: <± 0.3% RH Long-term stability: <± 0.5% RH / yr in Temperature Resolution: 16Bit Repeatability: ±0.2℃ Range: At 25℃ ±2℃ Response time: 1 / e (63%) 10S
下面是其一个典型的小系统的电路图,其四个引脚的典型电器特性为:1, the VDD power supply 3.5~5.5V DC 2 DATA serial data, a single bus 3, NC, empty pin 4, GND ground, the negative power
从上面可以看出,其和MCU进行通信的I/O引脚只有引脚2一根,所以要想正确从其中获取温湿度数据就必须了解其单线的通信协议了!我们的任务就是根据其通信协议,编写一个平台无关的底层驱动!
通信协议:
数据在DHT11和MCU之间采用单总线传输,一次传输40个bit,高位先出。
数据格式:
8bit湿度数据整数部分+8bit湿度数据小数部分+8bit温度数据整数部分+8bit温度数据小数部分+8bit奇偶校验
@这里的8bit奇偶校验=8bit湿度数据整数部分+8bit湿度数据小数部分+8bit温度数据整数部分+8bit温度数据小数部分
数据时序图:
上面我们知道DHT11通过单总线将温湿度数据和奇偶校验总共40bit发送给主设备(一般是MCU),那么MCU如何发起、读取、并结束读数据这一过程的呢?要想知道这一过程最简单的方式便是看数据时序图(很多人讨厌看、胆怯看,是因为不了解它,其实它展示了整个通信的详细过程,很美!)下面我们就根据一个写好的DHT11的驱动程序,来反推这个时序图的精巧与美!
Step 1:系统上电启动后一秒DHT11趋于稳定,可以进行数据读取操作(所以系统刚启动时最好不要立刻调用DHT11驱动函数读取数据
Step 2:初看该时序图,可以看出host设备置单总线一个凹槽型电平,形成开始读的初始信号!对于细节——置低一定要大于18ms。
Step 3:在主设备发起开始信号后便进入等待从设备应答模式,接下来当从设备将数据总线拉低持续80us然后又拉高80us后就准备发送40bit的数据了。
Step 4:接下来40bit的数据均是采用下面的格式发送过来,那么这40bit如何区分是1还是0呢?如下:根据高电平持续的时间——当高电平持续30us以下表示该bit为0,若维持50-70us表明为1.这样就能准确获得这40bit的数据情况了,再加上最后8bit的奇偶校验,便更加增强了其可靠性!
Step 5:结束通信,在40bit数据输出完毕低电平持续50us后置主设备为输出模式,置总线为高电平,结束本次通信。
数据时序图对应的DHT11的驱动程序(只是从网上找的针对CC2541的):
从下面代码容易看出:step2阶段的代码和上面的时序图凹槽型几乎一样;step3阶段用while循环统计低电平和高电平持续时间(不过这里的驱动并没有用这个持续时间);读8bit数据函数下面讲;step5阶段在52行端口属性设置为输出时真正生效,虽然上面27行已经将DATA_PIN置高,但是到52行才会生效,所以也满足40bit数据传输结束后50us后拉高电平结束本次数据传输。
1 void DHT11(void) //温湿传感启动 2 { 3 DATA_PIN=0; //启动阶段step2 4 Delay_ms(19); //>18MS 5 DATA_PIN=1; 6 P0DIR &= ~0x01; //重新配置IO口方向 7 Delay_10us(); 8 Delay_10us(); 9 Delay_10us(); 10 Delay_10us(); 11 if(!DATA_PIN) 12 { 13 ucharFLAG=2; //从设备应答阶段step3 14 while((!DATA_PIN)&&ucharFLAG++); 15 ucharFLAG=2; 16 while((DATA_PIN)&&ucharFLAG++); 17 COM(); //读取40bit阶段step4 18 ucharRH_data_H_temp=ucharcomdata; 19 COM(); 20 ucharRH_data_L_temp=ucharcomdata; 21 COM(); 22 ucharT_data_H_temp=ucharcomdata; 23 COM(); 24 ucharT_data_L_temp=ucharcomdata; 25 COM(); 26 ucharcheckdata_temp=ucharcomdata; 27 DATA_PIN=1; //和最后的52行组成end阶段step5 28 uchartemp=(ucharT_data_H_temp+ucharT_data_L_temp+ucharRH_data_H_temp+ucharRH_data_L_temp);//奇偶校验 29 if(uchartemp==ucharcheckdata_temp) 30 { 31 ucharRH_data_H=ucharRH_data_H_temp; 32 ucharRH_data_L=ucharRH_data_L_temp; 33 ucharT_data_H=ucharT_data_H_temp; 34 ucharT_data_L=ucharT_data_L_temp; 35 ucharcheckdata=ucharcheckdata_temp; 36 } 37 wendu_shi=ucharT_data_H/10; 38 wendu_ge=ucharT_data_H%10; 39 40 shidu_shi=ucharRH_data_H/10; 41 shidu_ge=ucharRH_data_H%10; 42 } 43 else //没用成功读取,返回0 44 { 45 wendu_shi=0; 46 wendu_ge=0; 47 48 shidu_shi=0; 49 shidu_ge=0; 50 } 51 52 P0DIR |= 0x01; //IO口需要重新配置 53 }
对于COM函数连续读8bit数据的细节如下:参照step4两种表示当前bit位为1还是0的方法——第7行是用while循环过掉低电平状态(同样这里ucharFLAG作为统计低电平持续的时间并没有用,这也体现了该驱动的不严谨性!),之后故意延时30us并检测当前是低电平还是高电平,这里用的很机智!因为step4中两个时序图可以看出表示当前bit位为0的时序图高电平持续时间没有超过30us,表示1的时序图高电平持续了近70us,所以延时30us后再检测当前电平就能判断该bit位是0还是1了!很机智吧!
1 void COM(void) // 温湿写入 2 { 3 uchar i; 4 for(i=0;i<8;i++) 5 { 6 ucharFLAG=2; 7 while((!DATA_PIN)&&ucharFLAG++); 8 Delay_10us(); 9 Delay_10us(); 10 Delay_10us(); 11 uchartemp=0; 12 if(DATA_PIN)uchartemp=1; 13 ucharFLAG=2; 14 while((DATA_PIN)&&ucharFLAG++); 15 if(ucharFLAG==1)break; 16 ucharcomdata<<=1; 17 ucharcomdata|=uchartemp; 18 } 19 }
小结&接下来计划:
本节将一款常用的DHT11温湿度传感器的购买、资料查找、datasheet阅读、时序图的理解和驱动代码的之所以这样写的原因给大家展示出来。虽然是一款简单的单总线传感器,但是这种分析流程和方法和比较复杂的模块基本都是相似的。今天时间也有点晚了,我准备将该传感器和平台无关的驱动封装放在下一篇介绍,今天得早点休息啦~晚安,各位!明天同一时间、同一地点ヾ( ̄▽ ̄)再见~
@beautifulzzzz
2015-9-8 持续更新中~