跳转至

实验展示

DHT11温湿度数码管显示.MP4 download:https://cdn.jsdelivr.net/gh/zikwq/Blog_Pic/4c7607b1dc9ab6b2cfc246a2fffc6624.mp4

DHT11相关文档

DHT11数据格式

时序交互

信号持续时间

程序框图

状态机部分的状态转移图

整体波形图绘制

时钟的绘制,采用clk_us

程序部分

顶层模块:

```verilog dht11.v module dht11( input wire sys_clk, input wire sys_rst_n, inout wire dht11, input wire key,

output wire [7:0]segdata,
output wire [2:0]segcs

); wire key_flag; wire [19:0] data_out;

key_filter

(

.CNT_MAX(20'd999_999)

) key_filter_inst ( .sys_clk (sys_clk) , .sys_rst_n (sys_rst_n) , .key_in (key) , .led_out(), .key_flag(key_flag) ); dht11_ctrl dht11_ctrl_inst ( .sys_clk(sys_clk), .sys_rst_n(sys_rst_n), .key_flag(key_flag), .dht11(dht11), .data_out(data_out), .sign() );

seg seg_inst ( .clk(sys_clk), .rst_n(sys_rst_n), .tenvalue(data_out), // 这里连接没有问题 .segdata(segdata), .segcs(segcs) );

endmodule




6位数码管驱动模块:

```verilog seg.v
/*
数码管显示驱动,目前是直接设置固定数据
通过将tenvalue设置到输入端口,可以作为子模块,通过传入数据显示在数码管上面
*/
module seg(
    input clk,
    input rst_n,
    input  [19:0]tenvalue,
    output reg [7:0]segdata,
    output reg [2:0]segcs
);



reg[31:0] count;
reg[24:0]count1ms;

reg[2:0]number;

reg clk1ms;

parameter sample=2'b00,
          display=2'b01;

//-----------数码管驱动时钟-----------
always@(posedge clk)
begin 
    if(count1ms >= 25'd50000) // 1ms的计数器
    begin
        clk1ms <= ~clk1ms;
        count1ms <= 1'd0;
    end
    else
        count1ms <= count1ms + 1'd1;
end

//-----------从0开始显示数字-----------
//assign tenvalue = 20'd99999; //固定显示999

//-----------数码管译码-----------
function [7:0] leddata;
input [3:0] datain;
begin
    case(datain)
        4'd0: leddata = 8'b11000000; // 0
        4'd1: leddata = 8'b11111001; // 1
        4'd2: leddata = 8'b10100100; // 2
        4'd3: leddata = 8'b10110000; // 3
        4'd4: leddata = 8'b10011001; // 4
        4'd5: leddata = 8'b10010010; // 5
        4'd6: leddata = 8'b10000010; // 6
        4'd7: leddata = 8'b11111000; // 7
        4'd8: leddata = 8'b10000000; // 8
        4'd9: leddata = 8'b10010000; // 9
        4'd10: leddata = 8'b10111111; // -
        4'd11: leddata = 8'b01111111; // .
        default: leddata = 8'b11111111;
    endcase
end
endfunction

//-----------数码管扫描-----------
always@(posedge clk1ms or negedge rst_n)
begin
    if(!rst_n)
        number <= 3'd0;
    else if(number == 3'd5)
        number <= 3'd0;
    else
        number <= number + 1;

    case(number)
        3'd0:
        begin
            segdata <= leddata(tenvalue % 10); // 个位
            segcs <= 3'b101;
        end
        3'd1:
        begin
            segdata <= leddata((tenvalue / 10) % 10); // 十位
            segcs <= 3'b100;
        end
        3'd2:
        begin
            segdata <= leddata((tenvalue / 100) % 10); // 百位
            segcs <= 3'b011;
        end
         4'd3:
            begin
                segdata<=leddata((tenvalue/1000)%10);//千位          
                segcs<=3'b010;
            end
          4'd4:
            begin
                segdata<=leddata((tenvalue/10000)%10);//万位         
                segcs<=3'b001;
            end
          4'd5:
            begin
                segdata<=leddata((tenvalue/100000)%10);//十万位           
                segcs<=3'b000;
            end
          default: 
              begin
                segdata <= 8'b11111111; // 或者其他默认值
               segcs <= 3'b111; // 或者其他默认值
                end
        endcase
end    

endmodule

dht11驱动模块

```verilog dht11_ctrl.v module dht11_ctrl( input wire sys_clk, input wire sys_rst_n, input wire key_flag, inout wire dht11,

output reg   [19:0]  data_out,
output reg     sign

); // 状态转移变量的赋值 parameter S_WAIT_1S = 3'd1 , //上电等待1s状态 S_LOW_18MS = 3'd2 , //主机拉低18ms,发送开始信号状态 S_DLY1 = 3'd3 , //等待20-40us状态 S_REPLY = 3'd4 , //DHT11响应80us状态 S_DLY2 = 3'd5 , //拉高等待80us状态 S_RD_DATA = 3'd6 ; //接收数据状态

parameter T_1S_DATA = 999999 ; //1s时间计数值 parameter T_18MS_DATA = 17999 ; //18ms时间计数值 // 内部参数的定义 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; // wire dht11_rise; // wire dht11_fall; // reg [5:0] bit_cnt; // 发送的bit计数,总共发送40bit的数据 reg [39:0] data_temp; reg [31:0] data; reg data_flag; // 数据发送的标志信号 reg dht11_en; // dht11使能信号 wire dht11_out; //

// 生成us时钟信号 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) cnt <= 5'd0; else if(cnt == 5'd24) cnt <= 5'd0; else cnt <= cnt+1'd1; end always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) clk_us <= 1'd0; else if(cnt == 5'd24) clk_us <= ~clk_us; else clk_us <= clk_us; end

//状态机状态跳转 always@(posedge clk_us or negedge sys_rst_n) if(sys_rst_n == 1'b0) state <= S_WAIT_1S ; else case(state) S_WAIT_1S: if(cnt_us == T_1S_DATA) //上电1s后跳入起始状态 state <= S_LOW_18MS ; else state <= S_WAIT_1S ; S_LOW_18MS: if(cnt_us == T_18MS_DATA) state <= S_DLY1 ; else state <= S_LOW_18MS ; S_DLY1: if(cnt_us == 10) //等待10us后进入下一状态 state <= S_REPLY ; else state <= S_DLY1 ; S_REPLY: //上升沿到来且低电平保持时间大于70us,则跳转到下一状态 if(dht11_rise == 1'b1 && cnt_low >= 70) state <= S_DLY2 ; //若1ms后,dht11还没响应,则回去继续发送起始信号 else if(cnt_us >= 1000) state <= S_LOW_18MS ; else state <= S_REPLY ; S_DLY2: //下降沿到来且计数器值大于70us,则跳转到下一状态 if(dht11_fall == 1'b1 && cnt_us >= 70) state <= S_RD_DATA ; else state <= S_DLY2 ; S_RD_DATA: //读完数据后,回到起始状态 if(bit_cnt == 40 && dht11_rise == 1'b1) state <= S_LOW_18MS ; else state <= S_RD_DATA ; default: state <= S_WAIT_1S ; endcase

//各状态下的计数器赋值 //cnt_us:每到一个新的状态就让该计数器重新计数 always@(posedge clk_us or negedge sys_rst_n) if(sys_rst_n == 1'b0) begin cnt_low <= 7'd0 ; cnt_us <= 21'd0 ; end else case(state) S_WAIT_1S: if(cnt_us == T_1S_DATA) cnt_us <= 21'd0 ; else cnt_us <= cnt_us + 1'b1; S_LOW_18MS: if(cnt_us == T_18MS_DATA) cnt_us <= 21'd0 ; else cnt_us <= cnt_us + 1'b1; S_DLY1: if(cnt_us == 10) cnt_us <= 21'd0 ; else cnt_us <= cnt_us + 1'b1; S_REPLY: if(dht11_rise == 1'b1 && cnt_low >= 70) begin cnt_low <= 7'd0 ; cnt_us <= 21'd0 ; end //当dht11发送低电平回应时,计算其低电平的持续时间 else if(dht11 == 1'b0) begin cnt_low <= cnt_low + 1'b1 ; cnt_us <= cnt_us + 1'b1 ; end //若1ms后,dht11还没响应,则回去继续发送起始信号 else if(cnt_us >= 1000) begin cnt_low <= 7'd0 ; cnt_us <= 21'd0 ; end else begin cnt_low <= cnt_low ; cnt_us <= cnt_us + 1'b1 ; end S_DLY2: if(dht11_fall == 1'b1 && cnt_us >= 70) cnt_us <= 21'd0 ; else cnt_us <= cnt_us + 1'b1; S_RD_DATA: if(dht11_fall == 1'b1 || dht11_rise == 1'b1) cnt_us <= 21'd0 ; else cnt_us <= cnt_us + 1'b1; default: begin cnt_low <= 7'd0 ; cnt_us <= 21'd0 ; end endcase

// 打两拍,提取dht11的输入信号的上升沿和下降沿 always @(posedge clk_us or negedge sys_rst_n) begin if(!sys_rst_n) begin dht11_reg1 <= 1'd1; dht11_reg2 <= 1'd1; end else begin dht11_reg1 <= dht11; dht11_reg2 <= dht11_reg1; end end assign dht11_rise = (~dht11_reg2) && (dht11_reg1) ; assign dht11_fall = (dht11_reg2) && (~dht11_reg1) ;

// bit_cnt的搭建 always @(posedge clk_us or negedge sys_rst_n) begin if(!sys_rst_n) bit_cnt <= 6'd0; else if(bit_cnt == 6'd40 && dht11_rise == 1'd1) bit_cnt <= 6'd0; else if(state == S_RD_DATA && dht11_fall == 1'd1) bit_cnt <= bit_cnt + 1'd1; else bit_cnt <= bit_cnt; end

// data_temp always @(posedge clk_us or negedge sys_rst_n) begin if(!sys_rst_n) data_temp <= 40'd0; else if(state == S_RD_DATA && dht11_fall == 1'd1 && cnt_us <=50) data_temp[39-bit_cnt] <= 1'd0; else if(state == S_RD_DATA && dht11_fall == 1'd1 && cnt_us >50) data_temp[39-bit_cnt] <= 1'd1; else data_temp <= data_temp; end //数据校验和赋值 always@(posedge clk_us or negedge sys_rst_n) begin if(!sys_rst_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

// dht11_en 的赋值 always @(posedge clk_us or negedge sys_rst_n) begin if(!sys_rst_n) dht11_en <= 1'd0; else if(state == S_LOW_18MS) dht11_en <= 1'd1; else dht11_en <= 1'd0; end

// dht11_out 的赋值 assign dht11_out = 1'd0 ;

// data_flag 的赋值 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) data_flag <= 1'd0; else if(key_flag == 1'd0) data_flag <= ~data_flag; else data_flag <= data_flag; end

// 输出信号 always @(posedge clk_us or negedge sys_rst_n) begin if(!sys_rst_n) data_out <= 20'd0; else if(data_flag == 1'd0) data_out <= data[31:24]10; else if(data_flag == 1'd1) data_out <= (data[15:8]10) + data[3:0]; end

// 符号位 always @(posedge clk_us or negedge sys_rst_n) begin if(!sys_rst_n) sign <= 1'd0; else if(data_flag == 1'd1 && data[7] == 1'd1) sign <= 1'd1; else sign <= 1'd0; end

// 如果使能是高电平,则吧dht11_out赋值给dht11输出端口。否则dht11端口作为输入端口为高阻态状态 assign dht11 = (dht11_en == 1'd1) ? dht11_out : 1'bz;

endmodule




按键消抖模块

```verilog key_filter.v
module key_filter
#(
    parameter   CNT_MAX     =   32'd99999
)

(
    input           wire            sys_clk         ,
    input           wire            sys_rst_n       ,
    input           wire            key_in          ,

    output          reg             key_flag             ,
     output           reg                  led_out
);
reg         [31:0]      cnt_20ms;
always @(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        cnt_20ms<=20'd0;
     else if(key_in == 1'b1)
        cnt_20ms<=20'd0;
    else if(cnt_20ms == CNT_MAX)
        cnt_20ms<=CNT_MAX;

    else
        cnt_20ms<=cnt_20ms+20'd1;


always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        key_flag<=1'b0;
    else if(cnt_20ms == (CNT_MAX-20'd1))
        key_flag<=1'b1;
    else
        key_flag<=1'b0;
end
always @(*) begin
    if(!sys_rst_n)
        led_out<=1'b0;
    else if(cnt_20ms == CNT_MAX)
        led_out<=1'b0;
    else
        led_out<=1'b1;
end

endmodule

引脚配置

参考链接

[1] ChatGPT3.5

[2] 128-第三十九讲-DHT11数字温湿度传感器(一)_哔哩哔哩_bilibili