初始化部分就不过多赘述,我会给出对应的文件,我只说明这部分里面涉及到使用的代码部分
1、数据的读取和校验
数据的读取和检验代码如下
always @ (posedge clk_us)
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;
在这个代码之前,我们已经用data_temp存储了温湿度传感器传输的数据
数据组成
温湿度传感器传过来的是一个四十位的数据,具体的意义对应如下
(1)data_temp[39:32]——湿度整数部分
(2)data_temp[31:24]——湿度小数部分
(3)data_temp[23:16]——温度整数部分
(4)data_temp[15:8]——温度小数部分
(5)data_temp[7:0]——校验和
校验思路
校验思路根据数据本身的意义进行,如果数据正确
则数据的校验和部分等于其他所有部分的相加
数据读取
数据的读取基于校验进行
若校验通过,则将温湿度传感器传回数据的前32位赋值给data[](后八位校验和只用于校验)
若校验不通过,则将data本身的值赋值给data[]
2、数据输出部分
代码部分如下
always @ (posedge clk_us)
begin
data_out[11:4] <= data[15:8]; // 输出温度的整数部分
data_out[3:0] <= data[3:0]; // 输出温度的小数部分
data_out[19:12] <= data[31:24]; // 输出湿度的整数部分
end
在之前我们已经介绍了温湿度传过来数据的组成,也说了数据读取的部分,所以这里就不再介绍为什么数据的部分的实际意义
3、按键标志位控制数据标志
always @ (posedge sys_clk)
if (key_flag == 1'b1)
data_flag <= ~data_flag;
else
data_flag <= data_flag;
data_flag
是一个标志位,用来选择要显示的是湿度数据还是温度数据。当data_flag
为1时,表示选择的是温度数据。
4、符号输出
温度的数据是带有符号的,也根据温湿度传输过来的数据确定
温度的符号根据温度数据的最高有效位确定
always @ (posedge clk_us)
if (data_flag == 1'b1 && data[7] == 1'b1)
sign <= 1'b1;
else
sign <= 1'b0;
5、状态机
状态机状态转换图
状态机部分代码
always @(posedge clk_us)
case (state)
WAIT_1S:
if (cnt_us == WAIT1S_MAX)
state <= START;
else
state <= WAIT_1S;
START:
if (cnt_us == LOW_18MS_MSX)
state <= DLY_1;
else
state <= START;
DLY_1:
if (cnt_us == 20'd10)
state <= REPLY;
else
state <= DLY_1;
REPLY:
if (dht11_rise == 1'b1 && cnt_low > 80)
state <= DLY_2;
else if (cnt_us > 1000)
state <= START;
else
state <= REPLY;
DLY_2:
if (dht11_fall == 1'b1 && cnt_us > 80)
state <= RD_DATA;
else
state <= DLY_2;
RD_DATA:
if (bit_cnt == 40 && dht11_rise == 1'b1)
state <= START;
else
state <= RD_DATA;
default: state <= WAIT_1S;
endcase
always @(posedge clk_us)
case(state)
WAIT_1S:
if (cnt_us == WAIT1S_MAX)
cnt_us <= 20'd0;
else
cnt_us <= cnt_us + 1'b1;
START:
if (cnt_us == LOW_18MS_MSX)
cnt_us <= 20'd0;
else
cnt_us <= cnt_us + 1'b1;
DLY_1:
if (cnt_us == 10)
cnt_us <= 20'd0;
else
cnt_us <= cnt_us + 1'b1;
REPLY:
if (dht11_rise == 1'b1 && cnt_low > 80)
begin
cnt_low <= 20'd0;
cnt_us <= 20'd0;
end
else if (dht11 == 1'b0)
begin
cnt_low <= cnt_low + 1'b1;
cnt_us <= cnt_us + 1'b1;
end
else if (cnt_us > 1000)
begin
cnt_low <= 20'd0;
cnt_us <= 20'd0;
end
else
begin
cnt_low <= cnt_low;
cnt_us <= cnt_us + 1'b1;
end
DLY_2:
if (dht11_fall == 1'b1 && cnt_us > 80)
cnt_us <= 20'd0;
else
cnt_us <= cnt_us + 1'b1;
RD_DATA:
if (dht11_fall == 1'b1 || dht11_rise == 1'b1)
cnt_us <= 20'd0;
else
cnt_us <= cnt_us + 1'b1;
default:
begin
cnt_low <= 20'd0;
cnt_us <= 20'd0;
end
endcase
6、模块完整代码
module dht11
(
input wire sys_clk ,
input wire key_flag,
inout wire dht11,
output reg [19:0] data_out ,
output reg sign
);
parameter WAIT_1S = 6'b000_001,
START = 6'b000_010,
DLY_1 = 6'b000_100,
REPLY = 6'b001_000,
DLY_2 = 6'b010_000,
RD_DATA = 6'b100_000;
parameter WAIT1S_MAX = 20'd999_999 ;
parameter LOW_18MS_MSX = 20'd17_999 ;
wire dht11_rise ;
wire dht11_fall ;
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 ;
reg [5:0] bit_cnt ;
reg [39:0] data_temp ;
reg [31:0] data ;
reg data_flag ;
reg dht11_en ;
reg dht11_out ;
always @(posedge sys_clk)
if (cnt == 5'd24)
cnt <=5'd0;
else
cnt <=cnt+ 1'b1;
always @(posedge sys_clk)
if (cnt == 5'd24)
clk_us <= ~clk_us ;
else
clk_us <=clk_us;
always @(posedge clk_us)
case (state)
WAIT_1S :
if (cnt_us == WAIT1S_MAX)
state <= START;
else
state <=WAIT_1S ;
START :
if (cnt_us == LOW_18MS_MSX)
state <= DLY_1;
else
state <=START ;
DLY_1 :
if (cnt_us ==20'd10)
state <= REPLY ;
else
state <=DLY_1 ;
REPLY :
if (dht11_rise == 1'b1&&cnt_low> 80 )
state <= DLY_2;
else if (cnt_us >1000)
state <=START ;
else
state <= REPLY;
DLY_2 :
if (dht11_fall == 1'b1 &&cnt_us > 80 )
state <= RD_DATA ;
else
state <= DLY_2 ;
RD_DATA :
if (bit_cnt == 40 && dht11_rise == 1'b1)
state <= START;
else
state <= RD_DATA;
default : state <= WAIT_1S ;
endcase
//转换时钟
always @(posedge clk_us)
case(state)
WAIT_1S :
if (cnt_us==WAIT1S_MAX)
cnt_us <=20'd 0;
else
cnt_us <= cnt_us+1'b1 ;
START :
if (cnt_us==LOW_18MS_MSX)
cnt_us <=20'd 0;
else
cnt_us <= cnt_us+1'b1 ;
DLY_1 :
if (cnt_us== 10)
cnt_us <=20'd 0;
else
cnt_us <= cnt_us+1'b1 ;
REPLY :
if (dht11_rise == 1'b1&&cnt_low> 80 )
begin
cnt_low <= 20'd0 ;
cnt_us <= 20'd0 ;
end
else if (dht11 == 1'b0)
begin
cnt_low <= cnt_low +1'b1;
cnt_us <= cnt_us + 1'b1;
end
else if (cnt_us >1000)
begin
cnt_low <= 20'd0;
cnt_us <= 20'd0 ;
end
else
begin
cnt_low <= cnt_low ;
cnt_us <= cnt_us + 1'b1;
end
DLY_2 :
if (dht11_fall == 1'b1 &&cnt_us > 80 )
cnt_us <= 20'd0 ;
else
cnt_us <= cnt_us +1'b1 ;
RD_DATA :
if (dht11_fall ==1'b1||dht11_rise==1'b1 )
cnt_us <= 20'd0 ;
else
cnt_us<= cnt_us +1'b1 ;
default :
begin
cnt_low <= 20'd0;
cnt_us <= 20'd0 ;
end
endcase
always @(posedge clk_us)
begin
dht11_reg1 <= dht11 ;
dht11_reg2 <= dht11_reg1 ;
end
assign dht11_rise = (~dht11_reg2)&&(dht11_reg1);
assign dht11_fall = (dht11_reg2)&&(~dht11_reg1);
always @ (posedge clk_us)
if (bit_cnt==40 && dht11_rise == 1'b1 )
bit_cnt <= 6'b0 ;
else if (state ==RD_DATA && dht11_fall==1'b1)
bit_cnt <= bit_cnt +1'b1 ;
else
bit_cnt <= bit_cnt;
always @ (posedge clk_us)
if (state ==RD_DATA && dht11_fall==1'b1&& cnt_us <= 50 )
data_temp[39-bit_cnt] <= 1'b0 ;
else if (state ==RD_DATA && dht11_fall==1'b1&& cnt_us >50 )
data_temp[39-bit_cnt] <= 1'b1 ;
else
data_temp <= data_temp ;
//数据校验部分data_temp[39:32]温度整数部分;data_temp[31:24]湿度小数部分;data_temp[23:16]温度整数部分;
always @ (posedge clk_us)
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 ;
always @ (posedge clk_us)
if (state ==START)
dht11_en <= 1'b1;
else
dht11_en <= 1'b0;
always @ (posedge clk_us)
dht11_out <=1'b0 ;
always @ (posedge sys_clk)
if (key_flag == 1'b1)
data_flag <= ~ data_flag;
else
data_flag <= data_flag;
always @ (posedge clk_us)
begin
data_out[11:4] <= data[15:8];
data_out[3:0] <= data[3:0];
data_out[19:12] <= data[31:24] ;
end
always@(posedge clk_us )
// if(data_flag == 1'b0 ) //湿度小数位为0
// data_out <= data[31:24] * 10; //为了兼容温度显示的小数,将湿度的个
// //位与十位扩大10倍,小数位为零
// else if(data_flag == 1'b1) //温度低四位显示温度小数数据
// data_out <= data[15:8] * 10 + data[3:0];
always @ (posedge clk_us)
if (data_flag==1'b1 && data[7] == 1'b1)
sign <= 1'b1 ;
else
sign <= 1'b0 ;
assign dht11 = (dht11_en == 1) ? 1'b0 : 1'bz ;
endmodule