#今日は塩漬けの日でもあります〜
ロベイカップに参加するのはロボットなので、ロボットの具体的な機械的な方法については話さないでくださいが、外界と通信するセンサーは絶対に必要です。外部環境データを取得して処理し、実行することができます。さまざまな機能。
簡単なモジュール、温度と湿度のセンサーDHT11について話しましょう。
DHT11の紹介
DHT11は、温度と湿度を測定するための安価で使いやすいツーインワンセンサーです。超小型で消費電力が非常に少ないという特徴があります。シングルバスを使用してシングルチップコンピュータで双方向シリアルデータ伝送を実行し、信号伝送距離は20メートル以上に達する可能性があります。高精度でリアルタイムを必要としない温度・湿度測定に最適です。
この記事では、DFRobotオープンソースハードウェアプラットフォームのDHT11モジュールとDFRduino開発ボードを紹介し、DHT11のドライバーと使用法について説明します。
DHT11の電気的パラメータ
電源電圧:3〜5.5V (標準値:5V);
温度範囲:0〜50℃、誤差±2℃;
湿度範囲:20〜90%RH、誤差±5%RH;
サンプリング期間:より大きい1秒/時間以上。
このセンサーには、VCC、GND、およびDATAの3つのピンがあります。これは単一のデータポートを備えたセンサーです。データポートは双方向送信に使用されます。このピンはFPGAでに設定する必要がありますinout
。
動作原理
DHT11は、通信に単一のバスを使用します。これは、DATAピンとマイクロコントローラーを接続するラインです。バスは常にアイドル状態と通信状態の間にあります。
シングルチップマイクロコンピュータがDHT11と相互作用しない場合、バスはアイドル状態になり、プルアップ抵抗の作用下でハイレベル状態になります。
MCUとDHT11が通信しているとき、バスは通信状態にあり、完全な通信プロセスは次のとおりです。①MCUは、バス
を駆動するIOを出力モードとして構成します。DHT11にデータを送信する準備ができました。
②マイクロコントローラはバスを18ms以上プルダウンしてスタート信号を送信します。次に、バスをHighにプルし、20〜40us遅延して、開始信号の終了を表します。
③シングルチップマイクロコンピュータは、ドライブバスのIOを入力モードとして構成し、DHT11から返されたデータを受信できるようにします。
④DHT11は、マイクロコントローラから送信された初期信号を検出すると、応答を開始し、収集したセンサーデータを返します。DHT11は、マイクロコントローラーへの確認応答(ACK)として最初にバスを80us引き下げ、次にバスを80us引き上げて、収集された温度と湿度のデータを返す準備をします。温度と湿度のデータは、固定フレーム形式で送信されます。
フレームは40ビットで、各ビットの送信タイミングロジックは次のとおりです。各ビットは50usのローレベルによって導かれ(DHT11はバスをローにプルします)、次にDHT11はバスをハイにプルします。このハイレベルの場合期間が26〜28us、論理0を表し、70us続く場合は、論理1を表します。
この信号図を見ると、モジュールとマスター間の通信モードがわかります。
- 電源投入後、不安定な状態を通過するまで1秒待ちます。
- IOは信号出力モードであり、低レベルは18ms以上持続します。(20ms推奨)
- IOレベルは20〜40usの間高くなります。(30us推奨)
- IOは信号入力モードであり、DHT応答時間に入ります。(つまり、モジュールはマスターコントロールの情報を受信し、データの送信前信号を返します)
- 低レベルは80usを遅延させ、レベルは80usに引き上げられ、DHT応答を完了します。
- 送信するデータロジック0/1を入力し、40ビット持続します。
- ロジック0、レベルは50usでプルダウンされ、レベルは25usでプルアップされます。
- ロジック1、レベルは50usでプルダウンされ、レベルは80usでプルアップされます。
- データ送信が終了した後、バスはハイにプルアップされます。(ここでは、少なくとも1秒遅延してから、次のデータ収集を実行できます)
Verilogドライバーコード:
// 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
プロテストが可能です。コメントがすべて英語で書かれているのは、コードを書いたときに英語のキーボードを開いたのですが、中国語が書けなかったので、中国語の記号の間違いを避けることができました。
物理テスト
これはロベイカップ大会で使用される予定ですが、RISC-Vアーキテクチャを使用する場合は、ハードコアを調整するためにザイリンクスを使用する必要があるため、ザイリンクスとアルテラのボードのどちらを使用するかについてはまだ悩んでいます。まだ出来ないと感じているので、まずは構造を構築してから、RISC-Vで実装できるか試してみます。