FPGA之DHT11温湿度传感器

FPGA之DHT11温湿度传感器学习笔记

一.DHT

DHT11作为一款低价、入门级的温湿度传感器,常用于单片机设计实例中;它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。DHT11为 4 针单排引脚封装,如下图,采用单线制串行接口,只需加适当的上拉电阻,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。

二、工作总结

1.RTL图:
基于ISE

其中消抖模块和数码管模块之前已完成编写,直接例化就可。

2.如上图所示,DHT11共有四个接线,1(接3-5.5V电源),2(40位data数据位),3(无效线,不接或接地),4(接地线)
3.串行接口
(单线双向)
DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次
通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数
部分用于以后扩展,现读出为零.操作流程如下:
一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据(湿度小数一般为0)
+8bi温度整数数据+8bit温度小数数据
+8bit校验和
数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据
+8bi温度整数数据+8bit温度小数数据”所得结果的末8位。

用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主
机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,
用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集,
如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集.采集数据后
转换到低速模式。
1.通讯过程如图1所示
在这里插入图片描述

总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必
须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后,
等待主机开始信号结束,然后发送80us低电平响应信号.主机发送开始信号结束
后,延时等待20-40us后, 读取DHT11的响应信号,主机发送开始信号后,可以切换
到输入模式,或者输出高电平均可,
总线由上拉电阻拉高

总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉
高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定
了数据位是0还是1.格式见下面图示.如果读取响应信号为高电平,则DHT11没有
响应,请检查线路是否连接正常.当最后一bit数据传送完毕后,DHT11拉低总线
50us,随后总线由上拉电阻拉高进入空闲状态。

4.数据0,1表示方法:
(1)0的表示方法:在这里插入图片描述

当状态到了读取数据时,数据线拉高26us-28us即为0
(2)1的表示方法:在这里插入图片描述

当状态到了读取数据时,数据线拉高70us即为1
在实际代码中,为了好判断结果为0还是1,可以取一个中间数50进行判断。
例如:cnt_us <= 50表示为0,反之则为1
5.工作频率为2S一个周期,动态刷新的时间为2S。

三.代码

顶层模块

module dht11_top(sys_clk,sys_rst_n,key,dht11,stcp,shcp,ds,oe);

	input  		wire		sys_clk;
	input 		wire		sys_rst_n;
	input 		wire		key;
	inout 		wire		dht11;
				
	output  	wire        stcp        ; 
	output 		wire        shcp        ; 
	output  	wire        ds          ; 
	output  	wire        oe          ; 
			
	wire  				key_flag;
	wire	[19:0]		data_out;
	wire 				sign;
	

		
/*key_filter
#(
	.CNT_MAX(20'd999_999)
)*/		
key_filter key_filter 
(
    .sys_clk(sys_clk), 
    .sys_rst_n(sys_rst_n), 
    .key_in(key), 
    .key_flag(key_flag)
);

dth11_ctrl dth11_ctrl 
(
    .sys_clk(sys_clk), 
    .sys_rsy_n(sys_rsy_n), 
    .key_flag(key_flag), 
    .dht11(dht11), 
    .data_out(data_out), 
    .sign(sign)
);

seg_595_dynamic seg_595_dynamic 
(
    .sys_clk(sys_clk), 
    .sys_rst_n(sys_rst_n), 
    .data(data_out), 
    .point(6'b000_010), 
    .seg_en(1'b1), 
    .sign(sign), 
	
    .stcp(stcp), 
    .shcp(shcp), 
    .ds(ds), 
    .oe(oe)
);


endmodule

DHT11驱动模块

module dth11_ctrl(sys_clk,sys_rsy_n,key_flag,dht11,data_out,sign);
	
	input  				sys_clk;
	input 				sys_rsy_n;
	input 				key_flag;
	inout 				dht11;
	
	output 	reg	 [19:0]	data_out;
	output 	reg			sign;
	
//状态定义
	parameter           WAIT_1S	 =  6'b000_001,上电等待1s状态
						START    =  6'b000_010,//主机拉低18ms,发送开始信号状态
						DLY_1    =  6'b000_100,//等待从机答应
						REPLY    =  6'b001_000,//从机对主机发出发送信号
						DLY_2    =  6'b010_000,//等待主机回应
						RD_DATA  =  6'b100_000;//开始传输数据
						
	parameter			WAIT_1S_MAX	= 20'd999_999,
						LOW_18MS_MAX = 20'd17_999;
		
	wire 				dht11_rise;
	wire				dht11_fall;
	
	
	
    reg 				clk_us;		
	reg 	  [4:0]		cnt;//微妙时钟计数器
	reg 	  [5:0]		state;
	reg 	  [19:0]	cnt_us;
	reg 	  [19:0]	cnt_low;
	reg 				dht11_reg1;
	reg 				dht11_reg2;
	reg 	  [5:0]		bit_cnt;
	reg  	  [39:0]	data_temp;
	reg 	  [39:0]	data;
	reg 				data_flag;
	reg 				dht11_en;
	reg 				dht11_out;
	

always@(posedge sys_clk or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		cnt <= 5'd0;
	else if(cnt == 5'd24)
		cnt <= 5'd0;
	else 
		cnt <= cnt + 1'b1;

end
//微妙时钟
always@(posedge sys_clk or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		clk_us <= 1'b0;
	else if(cnt_us == 5'd24)
		clk_us <= ~ clk_us;
	else 
		clk_us <= clk_us;
end

//状态机
always@(posedge clk_us or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		state <= WAIT_1S;
	else 
		case(state)
		 WAIT_1S:
		 	if(cnt_us == WAIT_1S_MAX)
		 		state <= START;
		 	else 
		 		state <= WAIT_1S;
		 START	:
		 	if(cnt_us ==  LOW_18MS_MAX)
		 		state <= DLY_1; 
		 	else 
		 		state <=  START;
		 DLY_1  :
		 	if(cnt_us == 20'd10)
		 		state <= REPLY;
		 	else
		 		state <= DLY_1;
		 REPLY  :
		 	if(dht11_rise == 1'b1 && (cnt_low > 80))
		 		state <= DLY_2;
		 	else if(cnt_us > 1000)//表示等待了1MS
		 		state <= START;
		 	else 
		 		state <= REPLY;
		 DLY_2  :
		 	if(dht11_fall == 1'b1 && cnt_us >80)
		 		state <= RD_DATA;
		 	else 
		 		state <= DLY_2;
		 RD_DATA:
		 	if(bit_cnt == 40 && dht11_rise == 1'b1)
		 		state <= START;
		    else 	
		 		state <= RD_DATA;
		default:state <= WAIT_1S;
		endcase
end
	
always@(posedge clk_us or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		begin
			cnt_low <= 20'd0;
			cnt_us  <= 20'd0;
		end
	else
		case(state)
			WAIT_1S:
				if(cnt_us == WAIT_1S_MAX)
					cnt_us <= 20'd0;
				else 
					cnt_us <= cnt_us + 1'b1;
            START  :
				if(cnt_us == LOW_18MS_MAX)
					cnt_us <= 20'd0;
				else 
					cnt_us <= cnt_us + 1'b1;
            DLY_1  :
				if(cnt_us == 10)
					cnt_us <= 20'd0;
				else 
					cnt_us <= cnt_us + 1'b1;
            REPLY  :
				if(dht11_rise == 1'b1 && (cnt_low > 80))
					begin
						cnt_low <= 20'd0;
						cnt_us  <= 20'd0;
					end
				else if(dht11 == 1'b0)
					begin
						cnt_low <= cnt_low + 1'b1;
						cnt_us  <= cnt_us + 1'b1;
					end
				else if(cnt_us > 1000)
					begin
						cnt_low <= 20'd0;
						cnt_us  <= 20'd0;
					end
				else 
					begin
						cnt_low <= cnt_low;
						cnt_us  <= cnt_us + 1'b1;
					end
            DLY_2  :
				if(dht11_fall == 1'b1 && (cnt_us > 80))
					cnt_us <= 20'd0;
				else 
					cnt_us  <= cnt_us + 1'b1;
            RD_DATA:
				if(dht11_fall == 1'b1 || dht11_rise == 1'b1)
					cnt_us  <= 1'b0;
				else 
					cnt_us <= cnt_us + 1'b1;
			default:
				begin
						cnt_low <= 20'd0;
						cnt_us  <= 20'd0;
				end
		endcase
end

always@(posedge clk_us or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		begin
			dht11_reg1 <= 1'b1;
			dht11_reg2 <= 1'b1;
		end
	else 
		begin
			dht11_reg1 <= dht11;
			dht11_reg2 <= dht11_reg1;
		end
end


assign dht11_rise = (dht11_reg1) && (~dht11_reg2);
assign dht11_fall = (~dht11_reg1) && (dht11_reg2);


always@(posedge clk_us or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		bit_cnt <= 6'd0;
	else if(bit_cnt == 40 && dht11_rise == 1'b1)
		bit_cnt <= 6'd0;
	else if((state == RD_DATA) && (dht11_fall == 1'b1))
		bit_cnt <= bit_cnt + 1'b1;
	else
		bit_cnt <= bit_cnt;
end

always@(posedge clk_us or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		data_temp <= 40'd0;
	else if(state == RD_DATA && dht11_fall == 1'b1 && )
		data_temp[39 - bit_cnt] <= 1'b0; //从高位向低位赋值
	else if(state == RD_DATA && dht11_fall == 1'b1 && cnt_us > 50)
		data_temp[39 - bit_cnt] <= 1'b1;
	else 
		data_temp <= data_temp;
end
//数据校验和赋值
always@(posedge clk_us or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		data <= 32'd0;
	else if(data_temp[7:0] == data_temp[39:32] + data_temp[31:24] + data_temp[23:16] + data_temp[15:8])
		data <= data_temp[39:8];
	else 
		data <= data;
end

always@(posedge clk_us or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		dht11_en <= 1'b0;
	else if(state <= START)
		dht11_en <= 1'b1;
	else 
		dht11_en <= 1'b0;	
end

always@(posedge clk_us or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		dht11_out <= 1'b0;
	else 
		dht11_out <= 1'b0;
end
//通过按键的key_flag信号,转换data_out输出的是湿度还是温度
always@(posedge sys_clk or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		data_flag <= 1'b0;
	else if(key_flag == 1'b1)
		data_flag <= ~data_flag;
	else 
		data_flag <= data_flag;
end

always@(posedge clk_us or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		data_out <= 20'd0;
	else if(data_flag == 1'b0)
		data_out <= data[31:24] * 10;//湿度的整数值
	else if(data_flag == 1'b1)
		data_out <= (data[15:8]*10) + data[3:0];
	else 
		data_out <= data_out;
end

always@(posedge clk_us or negedge sys_rsy_n)
begin
	if(!sys_rsy_n)
		sign <= 1'b0;
	else if(data_flag == 1'b1 && data[7] == 1'b1)//data[7]信号表示温度的正负,data[7]为1是负
		sign <= 1'b1;
	else 
		sign <= 1'b0;
end

assign dht11 = (dht11_en == 1'b1) ? dht11_out : 1'bz;


endmodule

数码管模块和按键消抖模块就不贴了,这两个模块网上会有很多资料。

上板验证结果来啦。
温度显示如下:
在这里插入图片描述湿度显示如下:
在这里插入图片描述

初学入门,分享学习笔记和心得,如有指教,感激不尽!

1. 系统概述 本系统主要由FPGA开发板和DHT11湿度传感器组成,通过FPGA开发板的GPIO口与DHT11传感器进行连接,实现环境湿度的检测和显示。其中,FPGA开发板负责控制传感器采集以及数据的处理和显示,DHT11传感器负责采集环境湿度数据并将数据传输给FPGA开发板。 2. 系统设计 系统设计主要分为硬件设计和软件设计两部分。 2.1 硬件设计 硬件设计主要包括FPGA开发板和DHT11传感器的连接和控制。 2.1.1 FPGA开发板 FPGA开发板主要由一个FPGA芯片、一组GPIO口和一块显示屏组成。其中,FPGA芯片主要负责数据的处理和控制,GPIO口主要用于与DHT11传感器进行连接,显示屏用于显示检测到的环境湿度数据。 2.1.2 DHT11传感器 DHT11传感器主要由一个湿度传感器和一个数据传输芯片组成。其中,湿度传感器负责采集环境湿度数据,数据传输芯片负责将采集到的数据通过单线数字信号传输给FPGA开发板。 2.2 软件设计 软件设计主要包括FPGA开发板程序的编写和数据处理算法的设计。 2.2.1 FPGA开发板程序 FPGA开发板程序主要负责控制GPIO口与DHT11传感器进行连接和数据的读取、处理和显示。具体实现过程为:首先通过GPIO口向DHT11传感器发送启动信号,然后等待DHT11传感器的响应,接着读取DHT11传感器传输的数据,最后将读取到的数据进行处理和显示。 2.2.2 数据处理算法 数据处理算法主要负责将读取到的原始数据进行解析和转换,得到环境湿度的实际值。具体实现过程为:首先将读取到的原始数据进行校验,确保数据的正确性,然后根据DHT11传感器的数据格式将数据进行解析,最后将解析出的数据进行转换,得到环境湿度的实际值。 3. 系统实现 系统实现主要包括硬件的连接和软件的编程实现两部分。 3.1 硬件连接 硬件连接主要包括FPGA开发板和DHT11传感器的连接。具体实现过程为:将DHT11传感器的VCC口连接到FPGA开发板的3.3V电源口,将DHT11传感器的GND口连接到FPGA开发板的GND口,将DHT11传感器的DATA口连接到FPGA开发板的GPIO口。 3.2 软件编程实现 软件编程实现主要包括FPGA开发板程序的编写和数据处理算法的设计。具体实现过程为:首先编写FPGA开发板程序,实现GPIO口与DHT11传感器的连接和数据的读取、处理和显示。然后设计数据处理算法,实现对读取到的原始数据进行解析和转换,得到环境湿度的实际值。 4. 系统测试 系统测试主要包括系统功能测试和性能测试两部分。 4.1 系统功能测试 系统功能测试主要测试系统能否正确地采集环境湿度数据并将数据显示在屏幕上。具体测试过程为:将DHT11传感器放置在不同的环境中,启动系统,观察系统是否能够正确地采集环境湿度数据并将数据显示在屏幕上。 4.2 系统性能测试 系统性能测试主要测试系统的性能指标,包括采样精度、采样速度等。具体测试过程为:通过对不同环境下的湿度数据进行采集和比对,测试系统的采样精度;通过测试系统在不同环境下的采样速度,测试系统的采样速度。
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值