测试平台: Vivado 2018.3+Xilinx XC7A35TFGG484-2
关于DHT11时序,优缺点网上很多,就不说了.
话不多说了,直接上代码:
代码有不懂的地方欢迎与我交流.微信1247652780
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2020 All rights reserved
// -----------------------------------------------------------------------------
// Author : zhufu.liang e-mail:1247652780@qq.com
// File : dht11.v
// Create : 2020-12-12 21:04:12
// Revise : 2020-12-13 10:45:10
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
module dht11(
input wire clk,//100MHz
input wire rst,
input wire start,
inout wire data_io,
output reg vld_falg,
output reg [7:0] himi,
output reg [7:0] temp
);
parameter START_MAX =2000000-1;
parameter RESP_MAX =8200-1;
parameter LOW_MIN =2200-1;
parameter LOW_MAX =2800-1;
parameter HIGH_MIN =6700-1;
parameter HIGH_MAX =7500-1;
parameter END_MAX =5300-1;
parameter IDLE =5'b00_001;
parameter START =5'b00_010;
parameter RESP =5'b00_100;
parameter RECE =5'b01_000;
parameter END =5'b10_000;
reg [4:0] state;
reg [1:0] data_dly;
reg pos_flag;
reg neg_flag;
reg [21:0] level_cnt;
reg [5:0] bit_cnt;
reg [42:0] data_temp;
reg oe;
reg data_o;
reg check_ok;
always @(posedge clk) begin
if (rst) begin
oe<=1'b0;
end
else if(state==START)begin
oe<=1'b1;
end
else begin
oe<=1'b0;
end
end
assign data_io = (oe==1'b1)?data_o:1'bz;
always @(posedge clk) begin
if (rst) begin
data_o<=1'b1;
end
else if (state==START && level_cnt==START_MAX) begin
data_o<=1'b1;
end
else if (state==START) begin
data_o<=1'b0;
end
end
always @(posedge clk) begin
data_dly<={data_dly[0],data_io};
end
always @(*) begin
if(data_dly==2'b10)begin
neg_flag =1'b1;
end
else begin
neg_flag =1'b0;
end
end
always @(*) begin
if(data_dly==2'b01)begin
pos_flag =1'b1;
end
else begin
pos_flag =1'b0;
end
end
//state
always @(posedge clk) begin
if (rst) begin
state<=IDLE;
end
else begin
case(state)
IDLE:begin
if(start==1'b1)begin
state<=START;
end
end
START:begin
if(level_cnt == START_MAX)begin
state<=RESP;
end
end
RESP:begin
if(pos_flag==1'b1 && level_cnt > RESP_MAX)begin
state<=RECE;
end
end
RECE:begin
if(bit_cnt=='d41)begin
state<=END;
end
end
END:begin
if(pos_flag==1'b1 && level_cnt > END_MAX)begin
state<=IDLE;
end
end
default:state<=IDLE;
endcase
end
end
//low_cnt
always @(posedge clk) begin
if (rst) begin
level_cnt<='d0;
end
else begin
case(state)
START:begin
if(level_cnt==START_MAX)begin
level_cnt<='d0;
end
else if(data_o==1'b0)begin
level_cnt<=level_cnt+1'b1;
end
end
RESP:begin
if(pos_flag==1'b1)begin
level_cnt<='d0;
end
else if(data_dly[1]==1'b0)begin
level_cnt<=level_cnt+1'b1;
end
end
RECE:begin
if(neg_flag==1'b1)begin
level_cnt<='d0;
end
else if(data_dly[1]==1'b1)begin
level_cnt<=level_cnt+1'b1;
end
end
END:begin
if(pos_flag==1'b1)begin
level_cnt<='d0;
end
else if(data_dly[1]==1'b0)begin
level_cnt<=level_cnt+1'b1;
end
end
default:level_cnt<='d0;
endcase
end
end
//bit_cnt
always @(posedge clk) begin
if (rst) begin
bit_cnt<='d0;
end
else if(state!=RECE)begin
bit_cnt<='d0;
end
else if (state==RECE && neg_flag==1'b1 && level_cnt > LOW_MIN) begin
bit_cnt<= bit_cnt+1'b1;
end
end
//data_temp
always @(posedge clk) begin
if (rst) begin
data_temp<='d0;
end
else if(state==RECE && neg_flag==1'b1 && level_cnt > LOW_MIN && level_cnt < LOW_MAX ) begin
data_temp<={data_temp[38:0],1'b0};
end
else if(state==RECE && neg_flag==1'b1 && level_cnt > HIGH_MIN && level_cnt < HIGH_MAX )begin
data_temp<={data_temp[38:0],1'b1};
end
end
//check_ok
always @(posedge clk) begin
if (rst) begin
check_ok<=1'b0;
end
else if (state==END) begin
check_ok<=({data_temp[39:32]+data_temp[15:8]+data_temp[23:16]+data_temp[31:24]}==data_temp[7:0])?1'b1:1'b0;
end
else begin
check_ok<=1'b0;
end
end
//himi
always @(posedge clk) begin
if (rst) begin
himi<='d0;
end
else if (state==END && pos_flag==1'b1) begin
himi<= (data_temp[42:36]<<3) +(data_temp[40:36]<<1)+data_temp[35:32];
end
end
//temp
always @(posedge clk) begin
if (rst) begin
temp<='d0;
end
else if (state==END && pos_flag==1'b1 && data_temp[15]==1'b0) begin
temp<= (data_temp[26:20]<<3)+(data_temp[24:20]<<1)+data_temp[19:16];
end
else if (state==END && pos_flag==1'b1 && data_temp[15]==1'b1) begin
temp[6:0] <= ~((data_temp[26:20]<<3)+(data_temp[24:20]<<1)+data_temp[19:16])+1'b1;
temp[7] <= 1'b1;
end
end
//vld_falg
always @(posedge clk) begin
if (rst) begin
vld_falg<=1'b0;
end
else if (state==END && pos_flag==1'b1) begin
vld_falg<=1'b1;
end
else begin
vld_falg<=1'b0;
end
end
endmodule
下面为顶层:
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2020 All rights reserved
// -----------------------------------------------------------------------------
// Author : zhufu.liang e-mail:1247652780@qq.com
// File : top_dht11.v
// Create : 2020-12-12 21:03:56
// Revise : 2020-12-12 22:54:08
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
module top_dht11(
input wire clk,//50MHz
input wire rst_n,//active low
inout wire data_io//data input/output
);
parameter TIME_MAX = 200000000-1;//2s ==need more than 2s
reg start;//signal of start =2s
wire vld_falg;//valid data flag
wire[7:0] himi;//data of humidity
wire[7:0] temp;//data of temperature
reg [31:0] time_cnt;//timer for 2s
wire sclk;
wire rst;
assign rst = ~rst_n;
gen_clk100 inst_gen_clk100(
// Clock out ports
.clk_100m(sclk), // output clk_100m
// Clock in ports
.clk_in1(clk)
); // input clk_in1
always @(posedge sclk) begin
if (rst) begin
time_cnt<='d0;
end
else if (time_cnt==TIME_MAX) begin
time_cnt<='d0;
end
else begin
time_cnt<=time_cnt+1'b1;
end
end
always @(posedge sclk) begin
if (rst) begin
start<=1'b0;
end
else if (time_cnt==TIME_MAX) begin
start<=1'b1;
end
else begin
start<=1'b0;
end
end
dht11 inst_dht11 (
.clk (sclk),
.rst (rst),//active high
.start (start),
.data_io (data_io),
.vld_falg (vld_falg),
.himi (himi),
.temp (temp)
);
wire [127:0] probe0;
assign probe0 ={
start,
time_cnt,
vld_falg,
himi,
temp
} ;
ila_0 ila_0_inst (
.clk(sclk), // input wire sclk
.probe0(probe0) // input wire [31:0] probe0
);
endmodule
最后为testbench:
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2020 All rights reserved
// -----------------------------------------------------------------------------
// Author : zhufu.liang e-mail:1247652780@qq.com
// File : tb_dht11.v
// Create : 2020-12-12 21:04:19
// Revise : 2020-12-12 21:04:21
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
`timescale 1ns/1ns
module tb_dht11 (); /* this is automatically generated */
reg clk;
reg start;
reg data_io_r;
wand data_io;
wire vld_falg;
wire [7:0] himi;
wire [7:0] temp;
// clock
initial begin
clk = 0;
forever #(5) clk = ~clk;
end
// synchronous reset
reg rst;
initial begin
start=0;
data_io_r=1;
rst <= 1;
repeat(100)@(posedge clk)
rst <= 0;
#100;
gen_data(32'h33005500);
@(negedge vld_falg);
#1000;
gen_data(32'h77004480);
@(negedge vld_falg);
#1000;
gen_data(32'h88006680);
@(negedge vld_falg);
#10000;
$stop;
end
assign data_io = data_io_r;
dht11 inst_dht11(
.clk (clk),
.rst (rst),
.start (start),
.data_io (data_io),
.vld_falg (vld_falg),
.himi (himi),
.temp (temp)
);
task gen_data;
input [31:0] data;
integer i;
reg [7:0] check_sum;
reg [39:0] temp;
reg [21:0] tiem_cnt;
begin
check_sum={data[7:0]+data[15:8]+data[23:16]+data[31:24]};
temp={data,check_sum};
start=0;
tiem_cnt=0;
#10;
start=1;
#10;
start=0;
@(negedge data_io)
@(posedge data_io)
data_io_r=1;
#13_000;
data_io_r=0;
#83_000;
data_io_r=1;
#87_000;
for(i=0;i<40;i=i+1)begin
data_io_r=0;
#54_000;
if(temp[39])begin
data_io_r=1;
#71_000;
end
else begin
data_io_r=1;
#24_000;
end
temp=temp<<1;
end
data_io_r=0;
#54_000;
data_io_r=1;
end
endtask
endmodule
板级验证: