DHT11 数字温湿度传感器,是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC 测温元件,并与一个高性能8 位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11 传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在OTP 内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20 米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。产品为4 针单排引脚封装。连接方便,特殊封装形式可根据用户需求而提供。
DHT11信号分析:
DHT11是通过单总线与单片机进行通信的,这样做的好处就是占用资源少,编程实现简单,发送数据的具体格式为 8bit 湿度整数数据+8bit 湿度小数数据+8bi 温度整数数据+8bit 温度小数数据+8bit校验和。主机先要给DHT11发送一个启动新号,等待DHT11做出响应,然后再进行检测温湿度的发送及传输,下面通过一张图来了解一下DHT11的传输过程。
从图上我们可以看出,主机要先把应答线拉低,因为空闲的时候是高状态,然后再次拉高,等待DHT11的响应,也就是等待数据线被拉低,当DHT11准备输出数据时,再把数据线拉低,输出数据给单片机,单片机可以根据高电平时间的长短来判别输出的数据是0还是1,最后在进行校验位的检查,从而成传输。
这个传感器有三个脚,分别是VCC、GND、DATA。这是一个单数据口的传感器,数据口做双向传输使用,这个管脚在FPGA上要设置为inout。
工作原理: 看这张信号图,就可以知道模块和主控之间的通信方式。- 上电后等待1s,以越过不稳定状态。
- IO为信号输出模式,低电平持续18ms以上。(建议20ms)
- IO电平拉高,持续20~40us。(建议30us)
- IO为信号输入模式,进入DHT响应时间。(就是模块受到了主控的信息,返回一个数据预发送信号)
- 低电平延时80us,电平拉高80us,完成DHT响应。
- 进入数据逻辑0/1发送,持续40位。
- 逻辑0,电平拉低持续50us,电平拉高持续25us。
- 逻辑1,电平拉低持续50us,电平拉高持续80us。
- 数据发送结束后,总线拉高。(此处可以至少延时1s,然后再进行下一次数据采集)
FPGA代码:
// dht11// made by 00 //time 2020.4.28 module dht11( input clk, input rst_n, inout dht11, output reg [31:0] data_valid ); /**************parameter********************/ parameter POWER_ON_NUM = 1000_000; parameter S_POWER_ON = 3'd0; parameter S_LOW_20MS = 3'd1; parameter S_HIGH_13US = 3'd2; parameter S_LOW_83US = 3'd3; parameter S_HIGH_87US = 3'd4; parameter S_SEND_DATA = 3'd5; parameter S_DEALY = 3'd6; //reg define reg[2:0] cur_state; reg[2:0] next_state; reg[20:0] count_1us; reg[5:0] data_count; reg[39:0] data_temp; reg[4:0] clk_cnt; reg clk_1M; reg us_clear; reg state; reg dht_buffer; reg dht_d0; reg dht_d1; wire dht_podge; //data posedge wire dht_nedge; //data negedge /*********************main codes*********************/ assign dht11 = dht_buffer; assign dht_podge = ~dht_d1 & dht_d0; // catch posedge assign dht_nedge = dht_d1 & (~dht_d0); // catch negedge /*********************counters*****************************/ //clock with 1MHz always @ (posedge clk or negedge rst_n) begin if (!rst_n) begin clk_cnt <= 5'd0; clk_1M <= 1'b0; end else if (clk_cnt < 5'd24) clk_cnt <= clk_cnt + 1'b1; else begin clk_cnt <= 5'd0; clk_1M <= ~ clk_1M; end end //counter 1 us always @ (posedge clk_1M or negedge rst_n) begin if (!rst_n) count_1us <= 21'd0; else if (us_clear) count_1us <= 21'd0; else count_1us <= count_1us + 1'b1; end //change state always @ (posedge clk_1M or negedge rst_n) begin if (!rst_n) cur_state <= S_POWER_ON; else cur_state <= next_state; end // state machine always @ (posedge clk_1M or negedge rst_n) begin if(!rst_n) begin next_state <= S_POWER_ON; dht_buffer <= 1'bz; state <= 1'b0; us_clear <= 1'b0; data_temp <= 40'd0; data_count <= 6'd0; end else begin case (cur_state) S_POWER_ON : //wait begin if(count_1us < POWER_ON_NUM) begin dht_buffer <= 1'bz; us_clear <= 1'b0; end else begin next_state <= S_LOW_20MS; us_clear <= 1'b1; end end S_LOW_20MS: // send 20 ms begin if(count_1us < 20000) begin dht_buffer <= 1'b0; us_clear <= 1'b0; end else begin next_state <= S_HIGH_13US; dht_buffer <= 1'bz; us_clear <= 1'b1; end end S_HIGH_13US: // Hign 13 us begin if (count_1us < 20) begin us_clear <= 1'b0; if(dht_nedge) begin next_state <= S_LOW_83US; us_clear <= 1'b1; end end else next_state <= st_delay; end S_LOW_83US: begin if(dht_podge) next_state <= S_HIGH_87US; end S_HIGH_87US: // ready to receive data signal begin if(dht_nedge) begin next_state <= S_SEND_DATA; us_clear <= 1'b1; end else begin data_count <= 6'd0; data_temp <= 40'd0; state <= 1'b0; end end S_SEND_DATA: // have 40 bit begin case(state) 0: begin if(dht_podge) begin state <= 1'b1; us_clear <= 1'b1; end else us_clear <= 1'b0; end 1: begin if(dht_nedge) begin data_count <= data_count + 1'b1; state <= 1'b0; us_clear <= 1'b1; if(count_1us < 60) data_temp <= {data_temp[38:0],1'b0}; //0 else data_temp <= {data_temp[38:0],1'b1}; //1 end else //wait for high end us_clear <= 1'b0; end endcase if(data_cnt == 40) //check data bit begin next_state <= st_delay; if(data_temp[7:0] == data_temp[39:32] + data_temp[31:24] + data_temp[23:16] + data_temp[15:8]) data_valid <= data_temp[39:8]; end end S_DELAY: // after data received delay 2s begin if(count_1us < 2000_000) us_cnt_clr <= 1'b0; else begin next_state <= S_LOW_20MS; // send signal again us_cnt_clr <= 1'b1; end end default : cur_state <= cur_state; endcase end end //edge always @ (posedge clk_1M or negedge rst_n) begin if (!rst_n) begin dht_d0 <= 1'b1; dht_d1 <= 1'b1; end else begin dht_d0 <= dht11; dht_d1 <= dht_d0; end end endmodule
复制代码