FPGA-DHT11:温湿度传感器

1.DHT11基本知识

(1)单总线

DHT11器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。设备(主机或从机)通过一个漏极开路或三态端口连至该数据线,以允许设备在不发送数据时能够释放总线,而让其它设备使用总线;单总线通常要求外接一个约4.7kΩ的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结构,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。
DATA用于微处理器与DHT11之间的通讯和同步,采用单总线数据格式,一次传送40位数据,高位先出

(2)数据格式

8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验位
data[39:32]+data[31:24]+data[23:16]+data[15:8]=data[7:0]
在这里插入图片描述

2.画时序图

在这里插入图片描述
在这里插入图片描述

由datasheet可知,一次完整的读取过程大致分为:INIT(初始化,即主机唤醒从机,从机响应),READ(40个bit数据的读取),WAIT(每次读取时间间隔需大于2秒,同时这两秒也包含了数据处理)。

首先在INIT初始状态时,主机需要先主动拉低约18ms,因此传输data的i/o口应该定义为inout;
在这里插入图片描述
模块框图如下:
在这里插入图片描述

在这里插入图片描述
首先,因为datasheet里最低的处理时间单位是us,而fpga使用了50MHz时钟,所以要先定义出时间计数器:
在这里插入图片描述
当计数到相应的时间主机开始拉低,
在这里插入图片描述

拉低的时间要求根据datasheet设定
在这里插入图片描述

在主机释放总线后,之后总线被从机接管,从机按照规定时序向主机发送数据;
在这里插入图片描述
从机的响应时间应根据datasheet设定;

如何从INIT状态跳转到READ状态呢?
我选择的条件是:cnt_ms==Tbe + 1 && cnt_us == Tgo+Trel+Treh 时,图中其实多计数了1us,但是不影响,而且这些数值也不是绝对的,需要不断去调试才能确定选哪个数值最好,一切以实际测试为主。
在这里插入图片描述
根据个人习惯,我先定义了一个读使能信号 read_en,用来协助cnt_h信号,cnt_h是在READ状态下对data的高电平计数,目的就是来区分数据“0”和‘“1”,
在这里插入图片描述
当cnt_h计数了23-27us表示“0”’,计数了68us-74us表示“1”;为什么要对data的高电平计数,而不是直接对单个bit数据计数呢,因为“0”和“1”不等长,所以 无法判断单个bit的长度。
那如何取出cnt_h的数值呢,因为无法去定义一个数使得cnt_h等于这个数时将数值取出。
我选择将信号打一拍然后做对比:
在这里插入图片描述
这样取出来的数就可以判断是落在23us-27us之间还是68us-74us之间,从而判断出0和1;
将这样的步骤完成40次,基本上就完成了数据的读取;
如何从READ状态跳转到WAIT状态呢?那就可以定义一个cnt_bit信号,当cnt_bit完成计数40次后转到WAIT状态;
在这里插入图片描述

3.总结

WAIT状态至少要2秒,这两秒可以用来检查校验码,并且完成温湿度输出或者其他操作,我的很多信号其实没必要生成,我只是为了自己过段时间不忘,不过定义了也并不会占用很多资源,因为不定义这些综合器也会有可能生成类似的资源,一切以实际为主,我的并不是最优解。

资料以及代码:https://pan.baidu.com/s/1_j2y37xk94G0EmKF-rAfjw 提取码:8z0r