FPGADHT11温度および湿度センサーの研究ノート
1. DHT
低コストのエントリーレベルの温度および湿度センサーとして、DHT11はシングルチップの設計例でよく使用されます。専用のデジタルモジュール取得技術と温度および湿度検出技術を使用して、製品の信頼性が非常に高く、長持ちすることを保証します。 -期間安定性。センサーは、抵抗湿度検知素子とNTC温度測定素子を含み、高性能8ビットシングルチップマイクロコンピューターと接続されています。DHT11は、下図に示すように、4ピン単列ピンパッケージです。単線シリアルインターフェースを使用し、適切なプルアップ抵抗を追加するだけで済みます。信号伝送距離は20メートル以上に達する可能性があります。さまざまなアプリケーション、さらには最も要求の厳しいアプリケーションになります。最良の選択です。
2.作業概要
1. RTL図:
防振モジュールとデジタル真空管モジュールは以前に作成されているため、直接インスタンス化できます。
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開発チュートリアルビデオによって作成されましたが、ボード上でまだ検証されていません。来週ボード上で検証される予定です。
初心者の方は、研究ノートや経験を共有してください。何か提案があれば、ありがたいです!