实验展示
DHT11相关文档
程序部分
顶层模块:
module dht11(
input wire sys_clk,
input wire sys_rst_n,
inout wire dht11,
input wire key,
output wire [7:0]segdata,
output wire [2:0]segcs
);
wire key_flag;
wire [19:0] data_out;
key_filter
#(
.CNT_MAX(20'd999_999)
)
key_filter_inst
(
.sys_clk (sys_clk) ,
.sys_rst_n (sys_rst_n) ,
.key_in (key) ,
.led_out(),
.key_flag(key_flag)
);
dht11_ctrl dht11_ctrl_inst (
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.key_flag(key_flag),
.dht11(dht11),
.data_out(data_out),
.sign()
);
seg seg_inst (
.clk(sys_clk),
.rst_n(sys_rst_n),
.tenvalue(data_out), // 这里连接没有问题
.segdata(segdata),
.segcs(segcs)
);
endmodule
6位数码管驱动模块:
/*
数码管显示驱动,目前是直接设置固定数据
通过将tenvalue设置到输入端口,可以作为子模块,通过传入数据显示在数码管上面
*/
module seg(
input clk,
input rst_n,
input [19:0]tenvalue,
output reg [7:0]segdata,
output reg [2:0]segcs
);
reg[31:0] count;
reg[24:0]count1ms;
reg[2:0]number;
reg clk1ms;
parameter sample=2'b00,
display=2'b01;
//-----------数码管驱动时钟-----------
always@(posedge clk)
begin
if(count1ms >= 25'd50000) // 1ms的计数器
begin
clk1ms <= ~clk1ms;
count1ms <= 1'd0;
end
else
count1ms <= count1ms + 1'd1;
end
//-----------从0开始显示数字-----------
//assign tenvalue = 20'd99999; //固定显示999
//-----------数码管译码-----------
function [7:0] leddata;
input [3:0] datain;
begin
case(datain)
4'd0: leddata = 8'b11000000; // 0
4'd1: leddata = 8'b11111001; // 1
4'd2: leddata = 8'b10100100; // 2
4'd3: leddata = 8'b10110000; // 3
4'd4: leddata = 8'b10011001; // 4
4'd5: leddata = 8'b10010010; // 5
4'd6: leddata = 8'b10000010; // 6
4'd7: leddata = 8'b11111000; // 7
4'd8: leddata = 8'b10000000; // 8
4'd9: leddata = 8'b10010000; // 9
4'd10: leddata = 8'b10111111; // -
4'd11: leddata = 8'b01111111; // .
default: leddata = 8'b11111111;
endcase
end
endfunction
//-----------数码管扫描-----------
always@(posedge clk1ms or negedge rst_n)
begin
if(!rst_n)
number <= 3'd0;
else if(number == 3'd5)
number <= 3'd0;
else
number <= number + 1;
case(number)
3'd0:
begin
segdata <= leddata(tenvalue % 10); // 个位
segcs <= 3'b101;
end
3'd1:
begin
segdata <= leddata((tenvalue / 10) % 10); // 十位
segcs <= 3'b100;
end
3'd2:
begin
segdata <= leddata((tenvalue / 100) % 10); // 百位
segcs <= 3'b011;
end
4'd3:
begin
segdata<=leddata((tenvalue/1000)%10);//千位
segcs<=3'b010;
end
4'd4:
begin
segdata<=leddata((tenvalue/10000)%10);//万位
segcs<=3'b001;
end
4'd5:
begin
segdata<=leddata((tenvalue/100000)%10);//十万位
segcs<=3'b000;
end
default:
begin
segdata <= 8'b11111111; // 或者其他默认值
segcs <= 3'b111; // 或者其他默认值
end
endcase
end
endmodule
dht11驱动模块
module dht11_ctrl(
input wire sys_clk,
input wire sys_rst_n,
input wire key_flag,
inout wire dht11,
output reg [19:0] data_out,
output reg sign
);
// 状态转移变量的赋值
parameter S_WAIT_1S = 3'd1 , //上电等待1s状态
S_LOW_18MS = 3'd2 , //主机拉低18ms,发送开始信号状态
S_DLY1 = 3'd3 , //等待20-40us状态
S_REPLY = 3'd4 , //DHT11响应80us状态
S_DLY2 = 3'd5 , //拉高等待80us状态
S_RD_DATA = 3'd6 ; //接收数据状态
parameter T_1S_DATA = 999999 ; //1s时间计数值
parameter T_18MS_DATA = 17999 ; //18ms时间计数值
// 内部参数的定义
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; //
wire dht11_rise; //
wire dht11_fall; //
reg [5:0] bit_cnt; // 发送的bit计数,总共发送40bit的数据
reg [39:0] data_temp;
reg [31:0] data;
reg data_flag; // 数据发送的标志信号
reg dht11_en; // dht11使能信号
wire dht11_out; //
// 生成us时钟信号
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 5'd0;
else if(cnt == 5'd24)
cnt <= 5'd0;
else
cnt <= cnt+1'd1;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
clk_us <= 1'd0;
else if(cnt == 5'd24)
clk_us <= ~clk_us;
else
clk_us <= clk_us;
end
//状态机状态跳转
always@(posedge clk_us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= S_WAIT_1S ;
else
case(state)
S_WAIT_1S:
if(cnt_us == T_1S_DATA) //上电1s后跳入起始状态
state <= S_LOW_18MS ;
else
state <= S_WAIT_1S ;
S_LOW_18MS:
if(cnt_us == T_18MS_DATA)
state <= S_DLY1 ;
else
state <= S_LOW_18MS ;
S_DLY1:
if(cnt_us == 10) //等待10us后进入下一状态
state <= S_REPLY ;
else
state <= S_DLY1 ;
S_REPLY: //上升沿到来且低电平保持时间大于70us,则跳转到下一状态
if(dht11_rise == 1'b1 && cnt_low >= 70)
state <= S_DLY2 ;
//若1ms后,dht11还没响应,则回去继续发送起始信号
else if(cnt_us >= 1000)
state <= S_LOW_18MS ;
else
state <= S_REPLY ;
S_DLY2: //下降沿到来且计数器值大于70us,则跳转到下一状态
if(dht11_fall == 1'b1 && cnt_us >= 70)
state <= S_RD_DATA ;
else
state <= S_DLY2 ;
S_RD_DATA: //读完数据后,回到起始状态
if(bit_cnt == 40 && dht11_rise == 1'b1)
state <= S_LOW_18MS ;
else
state <= S_RD_DATA ;
default:
state <= S_WAIT_1S ;
endcase
//各状态下的计数器赋值
//cnt_us:每到一个新的状态就让该计数器重新计数
always@(posedge clk_us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
else
case(state)
S_WAIT_1S:
if(cnt_us == T_1S_DATA)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_LOW_18MS:
if(cnt_us == T_18MS_DATA)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_DLY1:
if(cnt_us == 10)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_REPLY:
if(dht11_rise == 1'b1 && cnt_low >= 70)
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
//当dht11发送低电平回应时,计算其低电平的持续时间
else if(dht11 == 1'b0)
begin
cnt_low <= cnt_low + 1'b1 ;
cnt_us <= cnt_us + 1'b1 ;
end
//若1ms后,dht11还没响应,则回去继续发送起始信号
else if(cnt_us >= 1000)
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
else
begin
cnt_low <= cnt_low ;
cnt_us <= cnt_us + 1'b1 ;
end
S_DLY2:
if(dht11_fall == 1'b1 && cnt_us >= 70)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_RD_DATA:
if(dht11_fall == 1'b1 || dht11_rise == 1'b1)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
default:
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
endcase
// 打两拍,提取dht11的输入信号的上升沿和下降沿
always @(posedge clk_us or negedge sys_rst_n) begin
if(!sys_rst_n)
begin
dht11_reg1 <= 1'd1;
dht11_reg2 <= 1'd1;
end
else
begin
dht11_reg1 <= dht11;
dht11_reg2 <= dht11_reg1;
end
end
assign dht11_rise = (~dht11_reg2) && (dht11_reg1) ;
assign dht11_fall = (dht11_reg2) && (~dht11_reg1) ;
// bit_cnt的搭建
always @(posedge clk_us or negedge sys_rst_n) begin
if(!sys_rst_n)
bit_cnt <= 6'd0;
else if(bit_cnt == 6'd40 && dht11_rise == 1'd1)
bit_cnt <= 6'd0;
else if(state == S_RD_DATA && dht11_fall == 1'd1)
bit_cnt <= bit_cnt + 1'd1;
else
bit_cnt <= bit_cnt;
end
// data_temp
always @(posedge clk_us or negedge sys_rst_n) begin
if(!sys_rst_n)
data_temp <= 40'd0;
else if(state == S_RD_DATA && dht11_fall == 1'd1 && cnt_us <=50)
data_temp[39-bit_cnt] <= 1'd0;
else if(state == S_RD_DATA && dht11_fall == 1'd1 && cnt_us >50)
data_temp[39-bit_cnt] <= 1'd1;
else
data_temp <= data_temp;
end
//数据校验和赋值
always@(posedge clk_us or negedge sys_rst_n)
begin
if(!sys_rst_n)
data <= 32'd0;
else 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;
end
// dht11_en 的赋值
always @(posedge clk_us or negedge sys_rst_n) begin
if(!sys_rst_n)
dht11_en <= 1'd0;
else if(state == S_LOW_18MS)
dht11_en <= 1'd1;
else
dht11_en <= 1'd0;
end
// dht11_out 的赋值
assign dht11_out = 1'd0 ;
// data_flag 的赋值
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
data_flag <= 1'd0;
else if(key_flag == 1'd0)
data_flag <= ~data_flag;
else
data_flag <= data_flag;
end
// 输出信号
always @(posedge clk_us or negedge sys_rst_n) begin
if(!sys_rst_n)
data_out <= 20'd0;
else if(data_flag == 1'd0)
data_out <= data[31:24]*10;
else if(data_flag == 1'd1)
data_out <= (data[15:8]*10) + data[3:0];
end
// 符号位
always @(posedge clk_us or negedge sys_rst_n) begin
if(!sys_rst_n)
sign <= 1'd0;
else if(data_flag == 1'd1 && data[7] == 1'd1)
sign <= 1'd1;
else
sign <= 1'd0;
end
// 如果使能是高电平,则吧dht11_out赋值给dht11输出端口。否则dht11端口作为输入端口为高阻态状态
assign dht11 = (dht11_en == 1'd1) ? dht11_out : 1'bz;
endmodule
按键消抖模块
module key_filter
#(
parameter CNT_MAX = 32'd99999
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire key_in ,
output reg key_flag ,
output reg led_out
);
reg [31:0] cnt_20ms;
always @(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_20ms<=20'd0;
else if(key_in == 1'b1)
cnt_20ms<=20'd0;
else if(cnt_20ms == CNT_MAX)
cnt_20ms<=CNT_MAX;
else
cnt_20ms<=cnt_20ms+20'd1;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
key_flag<=1'b0;
else if(cnt_20ms == (CNT_MAX-20'd1))
key_flag<=1'b1;
else
key_flag<=1'b0;
end
always @(*) begin
if(!sys_rst_n)
led_out<=1'b0;
else if(cnt_20ms == CNT_MAX)
led_out<=1'b0;
else
led_out<=1'b1;
end
endmodule
引脚配置
参考链接
[1] ChatGPT3.5