初始化部分就不过多赘述,我会给出对应的文件,我只说明这部分里面涉及到使用的代码部分
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)begindata_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;elsedata_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;elsestate <= RD_DATA;default: state <= WAIT_1S;endcasealways @(posedge clk_us)case(state)WAIT_1S:if (cnt_us == WAIT1S_MAX)cnt_us <= 20'd0;elsecnt_us <= cnt_us + 1'b1;START:if (cnt_us == LOW_18MS_MSX)cnt_us <= 20'd0;elsecnt_us <= cnt_us + 1'b1;DLY_1:if (cnt_us == 10)cnt_us <= 20'd0;elsecnt_us <= cnt_us + 1'b1;REPLY:if (dht11_rise == 1'b1 && cnt_low > 80)begincnt_low <= 20'd0;cnt_us <= 20'd0;end else if (dht11 == 1'b0)begincnt_low <= cnt_low + 1'b1;cnt_us <= cnt_us + 1'b1;end else if (cnt_us > 1000)begincnt_low <= 20'd0;cnt_us <= 20'd0;end elsebegincnt_low <= cnt_low;cnt_us <= cnt_us + 1'b1;endDLY_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:begincnt_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;elsestate <= 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;elsecnt_us <= cnt_us+1'b1 ;START :if (cnt_us==LOW_18MS_MSX)cnt_us <=20'd 0;elsecnt_us <= cnt_us+1'b1 ;DLY_1 :if (cnt_us== 10)cnt_us <=20'd 0;elsecnt_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)begincnt_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 :begincnt_low <= 20'd0;cnt_us <= 20'd0 ;end endcasealways @(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 ;elsedata_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;elsedht11_en <= 1'b0;always @ (posedge clk_us)dht11_out <=1'b0 ;always @ (posedge sys_clk)if (key_flag == 1'b1)data_flag <= ~ data_flag;elsedata_flag <= data_flag;always @ (posedge clk_us)begindata_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