// Humidity & Temperature Sensor data read & write, FSM
module dht11_cntr (
input clk, reset_p,
inout dht11_data, // Input + Output, reg Declaration Not Possible
output reg [7:0] humidity, temperature, // Output Measurement
output [15:0] led // for Debugging
);
// Change State Using Shift
localparam S_IDLE = 6'b00_0001; // Standby State
localparam S_LOW_18MS = 6'b00_0010; // MCU Sends Out Start Signal
localparam S_HIGH_20US = 6'b00_0100; // MCU Pull Up & Wait for Sensor Response
localparam S_LOW_80US = 6'b00_1000; // DHT Sends Out Response Signal
localparam S_HIGH_80US = 6'b01_0000; // DHT Pull Up & Get Ready Data
localparam S_READ_DATA = 6'b10_0000; // DHT Data Read
localparam S_WAIT_PEDGE = 2'b01; // Start to Transmit 1-bit Data
localparam S_WAIT_NEDGE = 2'b10; // Voltage Length Measurement
// Clock Divide 100, 10ns x 100 = 1us
wire clk_usec_nedge; // Divide Clock 1us
clock_div_100 us_clk (.clk(clk), .reset_p(reset_p), .nedge_div_100(clk_usec_nedge));
// us Unit Count
reg [21:0] cnt_usec; // us Count
reg cnt_usec_e; // us Count Enable
always @(negedge clk, posedge reset_p) begin
if (reset_p) cnt_usec = 0; // Count Clear
else if (clk_usec_nedge && cnt_usec_e) begin // Count Start when Enable & us Negative Edge
cnt_usec = cnt_usec + 1; // Count During Enable
end
else if (!cnt_usec_e) cnt_usec = 0; // Count Clear when Disable
end
// Edge Detection of DHT Signal
wire dht_nedge, dht_pedge;
edge_detector_pos btn_ed (.clk(clk), .reset_p(reset_p),
.cp(dht11_data), .p_edge(dht_pedge), .n_edge(dht_nedge));
// Input Cannot be Declared as reg, Use Buffer
reg dht11_buffer; // Buffer
reg dht11_data_out_e; // Write Mode Enable Output, Disable Input
assign dht11_data = dht11_data_out_e ? dht11_buffer : 'bz; // Output dout, Input Impedance Value
reg [5:0] state, next_state; // Current & Next State
assign led [5:0] = state; // State LED Output
reg [1:0] read_state; // Data Read State
// Change State in Negative Edge
always @(negedge clk, posedge reset_p) begin
if (reset_p) state = S_IDLE; // Basic Standby State
else state = next_state; // Change State in Negative Edge
end
reg [39:0] temp_data; // DHT Output Data 40-bit
reg [5:0] data_cnt; // Counting to 40
assign led [11:6] = data_cnt;
// Set Next State in Positive Edge
always @(posedge clk, posedge reset_p) begin
if (reset_p) begin
next_state = S_IDLE; // Basic Stanby State
temp_data = 0; // DHT Data Reset
data_cnt = 0; // DHT Data Count Reset
dht11_data_out_e = 0; // DHT Write Disable, Input
read_state = S_WAIT_PEDGE; // Data Read Pull-Up High
end
else begin
case (state)
S_IDLE : begin // Standby State
if (cnt_usec < 22'd3_000_000) begin // Real 3_000_000, Test 3_000
cnt_usec_e = 1; // us Count Enable
dht11_data_out_e = 0; // DHT Input Mode
end
else begin
cnt_usec_e = 0; // Count Clear
next_state = S_LOW_18MS;// Change State S_LOW_18MS
end
end
S_LOW_18MS : begin // MCU Sends Out Start Signal
if (cnt_usec < 22'd18_000) begin // Real 18_000, Test 18
cnt_usec_e = 1; // us Count Enable
dht11_data_out_e = 1; // DHT Output Mode
dht11_buffer = 0; // Buffer Reset
end
else begin
cnt_usec_e = 0; // us Count Disable, Clear
next_state = S_HIGH_20US; // Change State S_HIGH_20US
dht11_data_out_e = 0; // DHT Input Mode
end
end
// It is Supposed to Respond after 20us, but in Reality, Response Occurs before that.
// Remove 20us Waiting Part
S_HIGH_20US : begin // MCU Pull Up & Wait for Sensor Response
cnt_usec_e = 1; // Count for Checking Response Time
if (cnt_usec > 22'd100_000) begin // No Response 100ms, Comunication Error, Etc..
cnt_usec_e = 0; // us Count Disable, Clear
next_state = S_IDLE; // Change State S_IDLE
end
if (dht_nedge) begin // DHT Response, No Count
cnt_usec_e = 0; // us Count Disable, Clear
next_state = S_LOW_80US; // Change State S_LOW_80US
end
end
S_LOW_80US : begin // DHT Sends Out Response Signal
cnt_usec_e = 1; // Count for Checking Response Time
if (cnt_usec > 22'd100_000) begin // No Response 100ms, Comunication Error, Etc..
cnt_usec_e = 0; // us Count Disable, Clear
next_state = S_IDLE; // Change State S_IDLE
end
if (dht_pedge) begin
cnt_usec_e = 0; // us Count Disable, Clear
next_state = S_HIGH_80US; // No Need to Count, Change State
end
end
S_HIGH_80US : begin // DHT Pull Up & Get Ready Data
cnt_usec_e = 1; // Count for Checking Response Time
if (cnt_usec > 22'd100_000) begin // No Response 100ms, Comunication Error, Etc..
cnt_usec_e = 0; // us Count Disable, Clear
next_state = S_IDLE; // Change State S_IDLE
end
if (dht_nedge) begin
cnt_usec_e = 0; // us Count Disable, Clear
next_state = S_READ_DATA; // No Need to Count, Change State
end
end
S_READ_DATA : begin // DHT Data Read
case (read_state)
S_WAIT_PEDGE : begin // Current Low, Wait High
// High Signal Generation
if (dht_pedge) read_state = S_WAIT_NEDGE; // Change State
cnt_usec_e = 0; // us Count Disable, Clear
end
S_WAIT_NEDGE : begin // Current High, Wait Low
// Low Signal Generation
if (dht_nedge) begin
read_state = S_WAIT_PEDGE; // Change State
data_cnt = data_cnt + 1; // Counting to 40
if (cnt_usec < 50) begin // Distinguish by Signal Length
temp_data = {temp_data[38:0], 1'b0}; // Shift Left & Enter Value in LSM
end
else begin
temp_data = {temp_data[38:0], 1'b1};
end
end
else begin
cnt_usec_e = 1; // us Count Enable
if (cnt_usec > 22'd100_000) begin // No Response 100ms, Comunication Error, Etc..
cnt_usec_e = 0; // us Count Disable, Clear
next_state = S_IDLE;
data_cnt = 0; // DHT Data Count Reset
read_state = S_WAIT_PEDGE;
end
end
end
endcase
if (data_cnt >= 40) begin // 40-bit Read Completed
next_state = S_IDLE; // Basic Stanby State
data_cnt = 0; // DHT Data Count Reset
// DHT11 Data = Humidity Integral 8-bit + Decimal 8-bit + Temperature Integral 8-bit + Decimal 8-bit + Check Sum 8-bit
// Compare Upper 32-bits of Sum with Checksum
if ((temp_data[39:32] + temp_data[31:24] + temp_data[23:16] + temp_data[15:8]) == temp_data[7:0]) begin
humidity = temp_data[39:32]; // Use only Integer Values
temperature = temp_data[23:16];
end
end
end
default : next_state = S_IDLE; // Basic Stanby State
endcase
end
end
endmodule