FPGADHT11温度および湿度センサー

FPGADHT11温度および湿度センサーの研究ノート

1. DHT

低コストのエントリーレベルの温度および湿度センサーとして、DHT11はシングルチップの設計例でよく使用されます。専用のデジタルモジュール取得技術と温度および湿度検出技術を使用して、製品の信頼性が非常に高く、長持ちすることを保証します。 -期間安定性。センサーは、抵抗湿度検知素子とNTC温度測定素子を含み、高性能8ビットシングルチップマイクロコンピューターと接続されています。DHT11は、下図に示すように、4ピン単列ピンパッケージです。単線シリアルインターフェースを使用し、適切なプルアップ抵抗を追加するだけで済みます。信号伝送距離は20メートル以上に達する可能性があります。さまざまなアプリケーション、さらには最も要求の厳しいアプリケーションになります。最良の選択です。

2.作業概要

1. RTL図:
ISEに基づく

防振モジュールとデジタル真空管モジュールは以前に作成されているため、直接インスタンス化できます。

2.上の図に示すように、DHT11には、1(3〜5.5V電源に接続)、2(40ビットデータデータビット)、3(無効なライン、接続または接地されていない)、4(接地されている)の4つの配線があります。回線)
3。シリアルインターフェース
(単線双方向)
DATAはマイクロプロセッサとDHT11間の通信と同期に使用されます。シングルバスデータ形式を採用しています。
通信時間は約4msです。データは小数部と整数に分割されます。特定のフォーマットについて以下に説明します。現在の10進数の
一部は将来の拡張に使用され、現在はゼロとして読み取られます。操作フローは次のとおりです
。完全なデータ送信は40ビットで、上位が最初に出力されます。 。
データ形式:8ビット湿度整数データ+ 8ビット湿度10進データ(湿度10進は通常0)
+ 8bi温度整数データ+8ビット温度10進データ
+8ビットチェックサム
データ送信は正しく、チェックサムデータは「8ビット湿度整数データ+8ビット」に等しい湿度10進データ
+ 8bi温度整数データ+8ビット温度10進データ」結果の最後の8桁。

ユーザーMCUが開始信号を1回送信すると、DHT11は低電力モードから高速モードに切り替わり、ホスト
開始信号が終了するのを待った後、DHT11は応答信号を送信し、40ビットデータを送信して、信号取得をトリガーします。 。
ユーザーはデータの一部を読み取ることを選択できます。スレーブモードでは、DHT11は開始信号を受信して​​温度と湿度の取得をトリガーします。
ホストから送信された開始信号を受信しない場合、DHT11はアクティブに温度と湿度を実行しません湿度取得。データ収集後、
低速モードに切り替わります。
1.通信プロセスを図1に示します。
ここに画像の説明を挿入します

バスアイドル状態はハイです。ホストはバスをローにプルし、DHT11が応答するのを待ちます。ホストは
、DHT11が開始信号を検出できるように、バスを18ミリ秒以上ローにプルする必要がありますDHT11は、
ホストの開始信号を受信した後、ホストの開始信号の終了を待ってから、80usの低レベル応答信号を送信します。ホストが開始信号を送信した後、
20〜40us待機し、応答信号を読み取ります。 DHT11の場合、ホストは開始信号を送信します。その後
、入力モードに切り替えるか、高レベルを出力すると、
バスはプルアップ抵抗によってプルアップされます。

バスはローであり、DHT11が応答信号を送信することを示します。DHT11が応答信号を送信した後、バス
を80usの間ハイにプルして、データ送信の準備をします。データの各ビットは、50usのローレベルタイムスロットで始まり、ハイレベル
がデータを決定します。ビットは0または1です。フォーマットは次の図に示されています。読み取り応答信号がハイの場合、DHT11は
応答しません。ラインが正しく接続されているかどうかを確認してください。データが送信され、DHT11がバスを
50usプルダウンした後、プルアップ抵抗によってバスがHighにプルアップされ、アイドル状態になります。

4.データ0、1表現方法:
(1)0表現方法:ここに画像の説明を挿入します

ステータスがデータの読み取りである場合、データラインは26us〜28usにプルアップされます。これは、0
(2)1メソッドです。ここに画像の説明を挿入します

状態がデータを読み取る場合、データ行は
実際のコードでは1ある70usだけプルアップされます。結果が0か1かを判断するために、中間の数値50を使用して判断できます。
次に例を示します。cnt_us<= 50は0を意味し、それ以外の場合は1です
。5。動作周波数は1サイクルで2S、動的リフレッシュ時間は2Sです。

3.コード

トップレベルモジュール

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

デジタル真空管モジュールとキーデバウンスモジュールは掲載されません。これら2つのモジュールに関する多くの情報がオンラインで公開されます。

PS:コードはWildfire FPGA開発チュートリアルビデオによって作成されましたが、ボード上でまだ検証されていません。来週ボード上で検証される予定です。

初心者の方は、研究ノートや経験を共有してください。何か提案があれば、ありがたいです!

おすすめ

転載: blog.csdn.net/weixin_46628093/article/details/115055623