资讯详情

温湿度复合传感器

文章目录

  • 1. DHT11简介
    • 1.1 数据格式
    • 1.2 数据时序
  • 2. 程序设计

1. DHT11简介

DHT11是一种温湿度复合传感器,包括电容式感湿元件和一个NTC与高性能8位单片机连接的测温元件。 在这里插入图片描述

1.1 数据格式

DHT11采用单总线通信,一次传输40位数据,高位先出。 前四个字节之和的节之和的最后8位: 00110101 00000000 00011000 00000100=01010001 小数温度的最高位为1,表示负温度,否则表示正温度。

1.2 数据时序

用户主机(FPGA)发送信号后,DHT11从低功耗模式到高速模式,主机开始信号结束后,DHT11发送响应信号40bit数据,并触发信号采集。 注意: 1、DHT11上电后要等1s跳过不稳定状态,在此期间不能发送任何指令。 2、结束信号后,DHT内部重测环境温度数据,并记录数据,等待外部信号的到来。 3、主机从DHT读取的温湿度数据总是前一个测量值。如果两次测量时间长,请连续读取两次,以第二次获得的值为实时温湿度值。 4.不建议连续多次读取传感器次读取传感器间隔大于2秒即可获得更准确的数据。

2. 程序设计

使用FPGA开发板完成对DHT采集11温湿度数据,在数码管上切换显示按钮控制温湿度。

module top_dht11(     input          sys_clk  ,  //系统时钟      input          sys_rst_n,  //系统复位          inout          dht11    ,  //DHT11总线     input          key      ,  //按键     output  [5:0]  sel      ,  ///数字管位选择信号     output  [7:0]  seg_led     ///数字管段选择信号 ); //wire define wire  [31:0]  data_valid; wire  [19:0]  data      ; wire  [5:0]   point     ;  //***************************************************** //** main code //*****************************************************  //dht11驱动模块 dht11_drive u_dht11_drive (     .sys_clk        (sys_clk),     .rst_n          (sys_rst_n),          .dht11          (dht11),     .data_valid     (data_valid)     
       
        )
        ; 
        //按键消抖模块 key_debounce 
        u_key_debounce
        ( 
        .sys_clk 
        (sys_clk
        )
        , 
        .sys_rst_n 
        (sys_rst_n
        )
        , 
        .key 
        (key
        )
        , 
        .key_flag 
        (key_flag
        )
        , 
        .key_value 
        (key_value
        ) 
        )
        ; 
        //按键控制温/湿度显示 dht11_key 
        u_dht11_key
        ( 
        .sys_clk 
        (sys_clk
        )
        , 
        .sys_rst_n 
        (sys_rst_n
        )
        , 
        .key_flag 
        (key_flag
        )
        , 
        .key_value 
        (key_value
        )
        , 
        .data_valid 
        (data_valid
        )
        , 
        .data 
        (data
        )
        , 
        .sign 
        (sign
        )
        , 
        .en 
        (en
        )
        , 
        .point 
        (point
        ) 
        )
        ; 
        //动态数码管显示模块 seg_led u_seg_led 
        ( 
        .clk 
        (sys_clk
        )
        , 
        .rst_n 
        (sys_rst_n
        )
        , 
        .seg_sel 
        (sel
        )
        , 
        .seg_led 
        (seg_led
        )
        , 
        .data 
        (data
        )
        , 
        .point 
        (point
        )
        , 
        .en 
        (en
        )
        , 
        .sign 
        (sign
        ) 
        )
        ; endmodule 
       
module dht11_drive (
    input                sys_clk    ,   //系统时钟
    input                rst_n      ,   //系统复位
                                        
    inout                dht11      ,   //dht11温湿度传感器单总线
    output  reg  [31:0]  data_valid     //有效输出数据
);                                      
                                        
//parameter define 
parameter  POWER_ON_NUM     = 1000_000; //上电延时等待时间,单位us
//状态机各个状态 
parameter  st_power_on_wait = 3'd0;     //上电延时等待
parameter  st_low_20ms      = 3'd1;     //主机发送20ms低电平
parameter  st_high_13us     = 3'd2;     //主机释放总线13us
parameter  st_rec_low_83us  = 3'd3;     //接收83us低电平响应
parameter  st_rec_high_87us = 3'd4;     //等待87us高电平(准备接收数据)
parameter  st_rec_data      = 3'd5;     //接收40位数据
parameter  st_delay         = 3'd6;     //延时等待,延时完成后重新操作DHT11

//reg define
reg    [2:0]   cur_state   ;        //当前状态
reg    [2:0]   next_state  ;        //下一个状态
                                    
reg    [4:0]   clk_cnt     ;        //分频计数器
reg            clk_1m      ;        //1Mhz时钟
reg    [20:0]  us_cnt      ;        //1微秒计数器
reg            us_cnt_clr  ;        //1微秒计数器清零信号
                                    
reg    [39:0]  data_temp   ;        //缓存接收到的数据
reg            step        ;        //数据采集状态
reg    [5:0]   data_cnt    ;        //接收数据用计数器

reg            dht11_buffer;        //DHT11输出信号
reg            dht11_d0    ;        //DHT11输入信号寄存器0
reg            dht11_d1    ;        //DHT11输入信号寄存器1

//wire define 
wire        dht11_pos      ;        //DHT11上升沿
wire        dht11_neg      ;        //DHT11下降沿

//*****************************************************
//** main code
//*****************************************************

assign dht11     = dht11_buffer;
assign dht11_pos = ~dht11_d1 & dht11_d0; //采集上升沿
assign dht11_neg = dht11_d1 & ~dht11_d0; //采集下降沿

//得到1Mhz分频时钟
always @ (posedge sys_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

//对DHT11输入信号连续寄存两次,用于边沿检测
always @ (posedge clk_1m or negedge rst_n) begin
    if (!rst_n) begin
        dht11_d0 <= 1'b1;
        dht11_d1 <= 1'b1;
    end 
    else begin
        dht11_d0 <= dht11;
        dht11_d1 <= dht11_d0;
    end 
end 

//1微秒计数器
always @ (posedge clk_1m or negedge rst_n) begin
    if (!rst_n)
        us_cnt <= 21'd0;
    else if (us_cnt_clr)
        us_cnt <= 21'd0;
    else 
        us_cnt <= us_cnt + 1'b1;
end 

//状态跳转
always @ (posedge clk_1m or negedge rst_n) begin
    if (!rst_n)
        cur_state <= st_power_on_wait;
    else 
        cur_state <= next_state;
end 

//状态机读取DHT11数据
always @ (posedge clk_1m or negedge rst_n) begin
    if(!rst_n) begin
        next_state   <= st_power_on_wait;
        data_temp    <= 40'd0;
        step         <= 1'b0; 
        us_cnt_clr   <= 1'b0;
        data_cnt     <= 6'd0;
        dht11_buffer <= 1'bz;   
    end 
    else begin
        case (cur_state)
                //上电后延时1秒等待DHT11稳定
            st_power_on_wait : begin                
                if(us_cnt < POWER_ON_NUM) begin
                    dht11_buffer <= 1'bz; //空闲状态释放总线
                    us_cnt_clr   <= 1'b0;
                end
                else begin            
                    next_state   <= st_low_20ms;
                    us_cnt_clr   <= 1'b1;
                end
            end
                //FPGA发送起始信号(20ms的低电平) 
            st_low_20ms: begin
                if(us_cnt < 20000) begin
                    dht11_buffer <= 1'b0; //起始信号为低电平 
                    us_cnt_clr   <= 1'b0;
                end
                else begin
                    dht11_buffer <= 1'bz; //起始信号结束后释放总线
                    next_state   <= st_high_13us;
                    us_cnt_clr   <= 1'b1;
                end    
            end 
                //等待DHT11的响应信号(等待10~20us)
            st_high_13us:begin                      
                if (us_cnt < 20) begin
                    us_cnt_clr   <= 1'b0;
                    if(dht11_neg) begin   //检测到DHT11响应信号
                        next_state <= st_rec_low_83us;
                        us_cnt_clr <= 1'b1; 
                    end
                end
                else                      //超过20us未响应
                    next_state <= st_delay;
            end 
                //等待DHT11的83us低电平响应信号结束
            st_rec_low_83us: begin                  
                if(dht11_pos)                   
                    next_state <= st_rec_high_87us;  
            end 
                //DHT11拉高87us通知FPGA准备接收数据
            st_rec_high_87us: begin
                if(dht11_neg) begin       //准备时间结束 
                    next_state <= st_rec_data; 
                    us_cnt_clr <= 1'b1;
                end
                else begin                //高电平准备接收数据
                    data_cnt  <= 6'd0;
                    data_temp <= 40'd0;
                    step  <= 1'b0;
                end
            end 
                //连续接收40位数据 
            st_rec_data: begin                                
                case(step)
                    0: begin              //接收数据低电平
                        if(dht11_pos) begin 
                            step   <= 1'b1;
                            us_cnt_clr <= 1'b1;
                        end            
                        else              //等待数据低电平结束
                            us_cnt_clr <= 1'b0;
                    end
                    1: begin              //接收数据高电平
                        if(dht11_neg) begin 
                            data_cnt <= data_cnt + 1'b1;
                                          //判断接收数据为0/1
                            if(us_cnt < 60)
                                data_temp <= { 
        data_temp[38:0],1'b0};
                            else                
                                data_temp <= { 
        data_temp[38:0],1'b1};
                            step <= 1'b0;
                            us_cnt_clr <= 1'b1;
                        end 
                        else              //等待数据高电平结束
                            us_cnt_clr <= 1'b0;
                    end
                endcase
                
                if(data_cnt == 40) 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 
                //完成一次数据采集后延时2s
            st_delay:begin
                if(us_cnt < 2000_000)
                    us_cnt_clr <= 1'b0;
                else begin                //延时结束后重新发送起始信号
                    next_state <= st_low_20ms;      
                    us_cnt_clr <= 1'b1;
                end
            end
            default : ;
        endcase
    end 
end

endmodule
module dht11_key(
    input             sys_clk,
    input             sys_rst_n,
    
    input             key_flag,
    input             key_value,
    input      [31:0] data_valid,
    
    output     [31:0] data,
    output reg        sign,
    output            en,                     
    output     [ 5:0] point
);

//reg define 
reg       flag ; // 温/湿度标志信号
reg [7:0] data0; // 小数部分
reg [7:0] data1; // 整数部分

//*****************************************************
//** main code
//*****************************************************

//数码管使能信号
assign en    = 1'b1;

//显示的数值为 (整数 + 0.1*小数)*100
assign data  = data1 * 100 + data0*10;

//小数点左移两位
assign point = 6'b000100;

//检测到按键按下时,切换温/湿度标志信号
always @ (posedge sys_clk or negedge sys_rst_n) begin 
    if(!sys_rst_n)                                    
        flag <= 1'b0;
    else if (key_flag & (~key_value))
        flag <= ~flag;
end 

//flag为“0”时显示温度,为“1”时显示湿度
always @ (posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        data0 <= 8'd0;
        data1 <= 8'd0;
        sign  <= 1'b0;
    end
    else if(flag == 1'b0) begin
        data0 <= data_valid[6:0];  //温度小数部分最高位为符号位
        data1 <= data_valid[15:8];
        if(data_valid[7])
            sign <= 1'b1;          //bit7为1表示负温度
        else
            sign <= 1'b0;
    end
    else begin
        data0 <= data_valid[23:16];
        data1 <= data_valid[31:24];
        sign  <= 1'b0;
    end
end

endmodule 

标签: cnt传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台