一、说明书主要内容
1、产品概述
2、接口说明
串行接口:
3、通讯过程
从通讯时序可以看出,读取一帧传感器数据的时序为:
主机将data线拉低至少18ms,然后拉高20-40us。然后主机释放data线给dht11,dht11将data线拉低80us作为响应信号,再拉高80us,若主机检测到正确的响应信号,读操作即可开始。
读操作:
dht11将data线拉低50us,然后拉高,如果这一位表示‘0’,则拉高时间为26-28us,若表示‘1’,则拉高时间为70us
Verilog驱动
//作者:杨成煜
//日期:2020/4/6
//==================defines=====================
//`define SIM
module dht11(
//================System Signal================
input clk,
input rst_n,
//================Interface====================
inout data,
input rd_req,
output reg[39:0] data_rd
);
//================parameters===================
`ifndef SIM
localparam CNT_30US = 1499;
localparam CNT_20MS = 999_999;
localparam CNT_80US = 3999;
localparam CNT_50US = 2499;
localparam CNT_70US = 3499;
localparam CNT_28US = 1399;
`else
`endif
//state
localparam S_IDLE = 5'b00001;
localparam S_START= 5'b00010;
localparam S_DHT_ACK=5'b00100;
localparam S_DHT_SEND_DATA = 5'b01000;
localparam S_CHECK_DATA_BIT = 5'b10000;
//================System regs==================
reg DATA;
reg[19:0] cnt_20ms;
reg[10:0] cnt_30us;
reg[11:0] cnt_80us;
reg[11:0] cnt_50us;
reg[11:0] cnt_70us;
reg cnt_dht_ack_bit;
reg flag_rd;
reg[3:0] state;
reg rd_req_t0;
reg rd_req_t1;
wire trig_rd_rq;
reg data_t0;
reg data_t1;
wire data_pedge;
wire data_nedge;
wire flag_check_data_bit;
reg flag_check_data_done;
reg[5:0] cnt_data_bit;
reg flag_cnt_30us_en;
//================Main Codes===================
//flag_cnt_30us_en
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
flag_cnt_30us_en <= 1'b0;
else if(state==S_START&&cnt_20ms==CNT_20MS)
flag_cnt_30us_en <= 1'b1;
else if(state==S_START&&cnt_30us==CNT_30US)
flag_cnt_30us_en <= 1'b0;
end
//cnt_data_bit
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_data_bit <= 'd0;
else if(cnt_data_bit==6'd39&&flag_check_data_done==1'b1)
cnt_data_bit <= 'd0;
else if(flag_check_data_done==1'b1)
cnt_data_bit <= cnt_data_bit + 1'b1;
end
//flag_check_data_done
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
flag_check_data_done <= 1'b0;
else if(state==S_CHECK_DATA_BIT&&data_nedge==1'b1)
flag_check_data_done <= 1'b1;
else
flag_check_data_done <= 1'b0;
end
//flag_check_data_bit
assign flag_check_data_bit = (state==S_CHECK_DATA_BIT&&flag_check_data_done==1'b0)?1'b1:1'b0;
//data_rd
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
data_rd <= 'd0;
else if(state==S_CHECK_DATA_BIT)
if(cnt_70us<=CNT_28US&&flag_check_data_done==1'b1)
data_rd <= {data_rd[38:0],1'b0};
else if(cnt_70us<=CNT_80US&&flag_check_data_done==1'b1)
data_rd <= {data_rd[38:0],1'b1};
end
// DATA;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
DATA <= 1'b1;
else if(state==S_IDLE||state==S_START)
if(trig_rd_rq==1'b1&&flag_rd==1'b0)
DATA <= 1'b0;
else if(cnt_20ms==CNT_20MS)
DATA <= 1'b1;
end
//cnt_20ms
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_20ms <= 'd0;
else if(state==S_START)
if(cnt_20ms==CNT_20MS)
cnt_20ms <= 'd0;
else
cnt_20ms <= cnt_20ms + 1'b1;
else
cnt_20ms <= 'd0;
end
//cnt_30us
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_30us <= 'd0;
else if(state==S_START&&flag_cnt_30us_en==1'b1)
if(cnt_30us==CNT_30US)
cnt_30us <= 'd0;
else
cnt_30us <= cnt_30us + 1'b1;
else
cnt_30us <= 'd0;
end
//cnt_80us
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_80us <= 'd0;
else if(state==S_DHT_ACK)
if(cnt_80us==CNT_80US)
cnt_80us <= 'd0;
else
cnt_80us <= cnt_80us + 1'b1;
else
cnt_80us <= 'd0;
end
//cnt_50us
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_50us <= 'd0;
else if(state==S_DHT_SEND_DATA)
if(cnt_50us==CNT_50US)
cnt_50us <= 'd0;
else
cnt_50us <= cnt_50us + 1'b1;
else
cnt_50us <= 'd0;
end
//cnt_70us
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_70us <= 'd0;
else if(state==S_CHECK_DATA_BIT)
if(cnt_70us==CNT_70US)
cnt_70us <= 'd0;
else
cnt_70us <= cnt_70us + 1'b1;
else
cnt_70us <= 'd0;
end
//cnt_dht_ack_bit
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_dht_ack_bit <= 'd0;
else if(state==S_DHT_ACK)
if(cnt_dht_ack_bit==1'b0&&cnt_80us==CNT_80US)
cnt_dht_ack_bit <= 1'b1;
else if(cnt_dht_ack_bit==1'b1&&cnt_80us==CNT_80US)
cnt_dht_ack_bit <= 1'b0;
end
//flag_rd
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
flag_rd <= 1'b0;
else if(state==S_IDLE)
if(trig_rd_rq==1'b1)
flag_rd <= 1'b1;
else
flag_rd <= 1'b0;
else if(state==S_CHECK_DATA_BIT)
if(cnt_data_bit==6'd39&&flag_check_data_done==1'b1)
flag_rd <= 1'b0;
else
flag_rd <= 1'b1;
end
assign data = (state==S_IDLE||state==S_START&&cnt_30us<=CNT_30US)?DATA:1'bz;
//rd_req_temp
always @(posedge clk)begin
rd_req_t0 <= rd_req;
rd_req_t1 <= rd_req_t0;
end
assign trig_rd_rq = rd_req_t0&(~rd_req_t1);
//data_temp
always @(posedge clk)begin
if(state==S_CHECK_DATA_BIT)
data_t0 <= data;
data_t1 <= data_t0;
end
assign data_nedge = (~data_t0)&data_t1;
assign data_pedge = data_t0&(~data_t1);
//state machine
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
state <= S_IDLE;
else case(state)
S_IDLE:begin
if(trig_rd_rq==1'b1)
state <= S_START;
else
state <= S_IDLE;
end
S_START:begin
if(cnt_30us==CNT_30US&&cnt_20ms==20'd0)
state <= S_DHT_ACK;
else
state <= S_START;
end
S_DHT_ACK:begin
if(cnt_80us==1999&&data==1'b0&&cnt_dht_ack_bit==1'b0)
state <= S_DHT_ACK;
else if(cnt_80us==1999&&cnt_dht_ack_bit==1'b1)
state <= S_DHT_SEND_DATA;
else if(cnt_80us==1999&&data==1'b1&&cnt_dht_ack_bit==1'b0)
state <= S_IDLE;
end
S_DHT_SEND_DATA:begin
if(cnt_50us==CNT_50US)
state <= S_CHECK_DATA_BIT;
else
state <= S_DHT_SEND_DATA;
end
S_CHECK_DATA_BIT:begin
if(cnt_data_bit==6'd39&&flag_check_data_bit==1'b1&&flag_check_data_done==1'b1)
state <= S_IDLE;
else if(flag_check_data_bit==1'b1&&flag_check_data_done==1'b1)
state <= S_DHT_SEND_DATA;
else
state <= S_CHECK_DATA_BIT;
end
default:state <= S_IDLE;
endcase
end
endmodule