【FPGA】温湿度センサーDHT11を実現するVerilogコード

#今日は塩漬けの日でもあります〜

ロベイカップに参加するのはロボットなので、ロボットの具体的な機械的な方法については話さないでくださいが、外界と通信するセンサーは絶対に必要です。外部環境データを取得して処理し、実行することができます。さまざまな機能。

簡単なモジュール、温度と湿度のセンサー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. 電源投入後、不安定な状態を通過するまで1秒待ちます。
  2. IOは信号出力モードであり、低レベルは18ms以上持続します。(20ms推奨)
  3. IOレベルは20〜40usの間高くなります。(30us推奨)
  4. IOは信号入力モードであり、DHT応答時間に入ります。(つまり、モジュールはマスターコントロールの情報を受信し、データの送信前信号を返します)
  5. 低レベルは80usを遅延させ、レベルは80usに引き上げられ、DHT応答を完了します。
  6. 送信するデータロジック0/1を入力し、40ビット持続します。
  7. ロジック0、レベルは50usでプルダウンされ、レベルは25usでプルアップされます。
  8. ロジック1、レベルは50usでプルダウンされ、レベルは80usでプルアップされます。
  9. データ送信が終了した後、バスはハイにプルアップされます。(ここでは、少なくとも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で実装できるか試してみます。

おすすめ

転載: blog.csdn.net/Ninquelote/article/details/105824323