|
- module clk_div( //时钟分频模块 输出频率=输入频率/分频系数/2
- input clk, //时钟输入
- input [15:0] div, //[16位宽]分频系数
- output reg out //分频输出
- );
- initial out = 1'd0;
- reg [15:0] i = 0;
- always @(posedge clk) begin
- i = i + 16'd1;
- if(i >= div) begin
- i = 0;
- out <= !out;
- end
- end
- endmodule
- module edge_detect( //边沿检测模块
- input clk, //时钟 (上升沿触发)
- input dat, //待检测单比特信号
- output pos //dat上升沿发出高电平 (单脉冲,下一个时钟恢复低电平)
- );
- reg a,b;
- assign pos = ({a,b} == 2'b10) ? 1'b1 : 1'b0;
- always @(posedge clk) begin
- a <= dat;
- b <= a;
- end
- endmodule
- module dht11_count( //DHT11电平时间计数模块
- input clk, //1Mhz 时钟输入
- input start, //上升沿开始计数
- input dht11, //DHT11数据脚
- input signal, //1:计数高电平时间 0:低电平
- output reg stop, //电平翻转或超时发出上升沿 计数完成
- output reg [7:0] count //[8位宽] 计数微秒 (超时255)
- );
- initial count = 8'd0;
- reg run = 1'b0;
- initial stop = 1'b0;
- always @(posedge start or posedge stop) begin
- if(stop) begin
- run <= 1'b0;
- end else if(start) begin
- run <= 1'b1;
- end
- end
- always @(posedge clk) begin
- stop <= 1'b0;
- if(run) begin
- if(dht11 == signal && !(&count)) begin
- count <= count + 8'd1;
- end else begin
- stop <= 1'b1;
- end
- end else begin
- count <= 8'd0;
- end
- end
- endmodule
- module dht11_decode( //DHT11数据解码模块
- //[39:32]:湿度高8位 [31:24]:湿度低8位 [23:16]:温度高8位 [15:8]:温度低8位 [7:0] 校验位
- input [39:0] dat, //[40位宽] DHT11接收到的数据输入
- output check, //数据校验是否正确 1:正确 0:错误
- output reg signed [11:0] temperature, //[12位宽] 温度
- output reg [9:0] humidity //[10位宽] 湿度
- );
- wire [7:0] sum = dat[39:32] + dat[31:24] + dat[23:16] + dat[15:8]; //校验和
- assign check = (dat[7:0] == sum) ? 1'b1 : 1'b0;
- wire sign = dat[15]; //符号位 0:零上温度 1:零下温度 (摄氏度)
- wire [11:0] humi = dat[39:32]*10'd10 + dat[31:24];
- always @(*) begin
- if(humi > 12'd1000) begin
- humidity = 10'd1000;
- end else begin
- humidity = humi[9:0];
- end
- temperature = dat[23:16]*12'd10 + dat[14:8];
- if(sign) begin
- temperature = 12'd0-temperature;
- end
- end
- endmodule
- module dht11( //DHT11 数字温湿度传感器模块驱动
- input clk, //1Mhz时钟输入
- input run, //上升沿开始采集 0.5HZ则2秒采一次
- inout data, //[双向IO] DHT11数据脚
- output reg error, //是否发生错误
- output reg interrupt, //上升沿中断 (温湿度采集完成后触发)
- output signed [11:0] temperature, //[12位宽] 温度 范围:-200~600 精度:0.1℃ (输出234则为23.4摄氏度)
- output [9:0] humidity //[10位宽] 湿度 范围:5~95% 精度:0.1% (输出456则湿度为45.6%)
- );
- reg dat = 1'b0; //1:输出高电平(由上拉电阻拉高,可以被拉低) 0:低电平(不能被拉高)
- assign data = dat ? 1'bz : 1'b0;
- reg [3:0] state = 4'd0; //[4位宽] 状态寄存器
- reg [14:0] delay; //[15位宽] 延时时钟寄存器
- reg start;
- reg signal;
- wire stop;
- wire [7:0] us; //[8位宽] 电平计数微秒数 范围:0~255
- reg [39:0] ram; //[40位宽] DHT11接收到的数据
- reg [5:0] pc; //[6位宽] 数据指针 范围:0~39
- wire check;
- wire pos;
- edge_detect edge_detect(
- .clk(!clk),
- .dat(run),
- .pos(pos)
- );
- dht11_decode dht11_decode(
- .dat(ram),
- .check(check),
- .temperature(temperature),
- .humidity(humidity)
- );
- dht11_count dht11_count(
- .clk(!clk),
- .start(start),
- .dht11(data),
- .signal(signal),
- .stop(stop),
- .count(us)
- );
- always @(posedge clk) begin
- if(|delay) begin
- delay <= delay - 15'd1;
- end else begin
- case(state)
- 4'd0:begin
- dat <= 1'b1;
- state <= pos ? 4'd1 : 4'd0;
- end
-
- 4'd1:begin
- dat <= 1'b0; //主动拉低18ms (不能主动拉高)
- delay <= 15'd18000;
- state <= 4'd2;
- end
-
- 4'd2:begin
- dat <= 1'b1; //输入模式等待被DHT11拉低
- signal <= 1'b1;
- start <= 1'b1;
- state <= 4'd3;
- end
-
- 4'd3:begin
- start <= 1'b0;
- if(stop) begin
- if(&us) begin //超时则没有检测到DHT11
- error <= 1'b1;
- state <= 4'd13;
- end else begin
- error <= 1'b0;
- state <= 4'd4;
- end
- end else begin
- state <= 4'd3;
- end
- end
-
- 4'd4:begin
- signal <= 1'b0;
- start <= 1'b1;
- state <= 4'd5;
- end
-
- 4'd5:begin
- start <= 1'b0;
- if(stop) begin
- if(us < 8'd78 || us > 8'd88) begin //收到83微秒低电平应答信号 小于78或大于88则无效
- error <= 1'b1;
- state <= 4'd13;
- end else begin
- error <= 1'b0;
- state <= 4'd6;
- end
- end else begin
- state <= 4'd5;
- end
- end
-
- 4'd6:begin
- signal <= 1'b1;
- start <= 1'b1;
- state <= 4'd7;
- end
-
- 4'd7:begin
- start <= 1'b0;
- if(stop) begin
- if(us < 8'd82 || us > 8'd92) begin //87微秒高电平应答
- error <= 1'b1;
- state <= 4'd13;
- end else begin
- error <= 1'b0;
- pc <= 6'd39;
- state <= 4'd8;
- end
- end else begin
- state <= 4'd7;
- end
- end
-
- 4'd8:begin
- signal <= 1'b0;
- start <= 1'b1;
- state <= 4'd9;
-
- end
-
- 4'd9:begin
- start <= 1'b0;
- if(stop) begin
- if(us < 49 || us > 59) begin //54us低电平应答
- error <= 1'b1;
- state <= 4'd13;
- end else begin
- error <= 1'b0;
- state <= 4'd10;
- end
- end else begin
- state <= 4'd9;
- end
- end
-
- 4'd10:begin
- signal <= 1'b1;
- start <= 1'b1;
- state <= 4'd11;
- end
-
- 4'd11:begin
- start <= 1'b0;
- if(stop) begin
- error = 1'b0;
- if(us >= 8'd18 && us <= 8'd32) begin //位0:54us低电平与23~27us高电平
- ram[pc] <= 1'b0;
- end else if(us >= 8'd63 && us <= 8'd79) begin //位1:54us低电平与68~74us高电平
- ram[pc] <= 1'b1;
- end else begin
- error = 1'b1;
- state <= 4'd13;
- end
- if(!error) begin
- if(pc == 6'd0) begin
- state <= 4'd12;
- end else begin
- pc <= pc - 6'd1;
- state <= 4'd8;
- end
- end
- end else begin
- state <= 4'd11;
- end
- end
-
- 4'd12:begin
- error <= !check;
- state <= 4'd13;
- end
-
- 4'd13:begin
- interrupt <= 1'b1;
- state <= 4'd14;
- end
-
- 4'd14:begin
- state <= 4'd15;
- end
-
- 4'd15:begin
- interrupt <= 1'b0;
- state <= 0;
- end
- endcase
- end
- end
- endmodule
- module main(
- input clk, //50Mhz Pin17
- output reg led, //接LED 低电平点亮 Pin3
- //接示波器或逻辑分析仪 成功输出频率 失败输出10HZ
- output temp, //温度频率输出 温度:(500000/频率-300)/10 Pin43
- output humi, //湿度频率输出 湿度:50000/频率 Pin45
- inout data //接DHT11 Pin40 (请配置该IO口上拉电阻:Weak Pull-Up Resistor)
- );
- wire clk_1Mhz;
- wire clk_10hz; //10HZ
- wire run; //0.5HZ
- clk_div clk_50Mhz_1Mhz( //50Mhz分频1Mhz
- .clk(clk),
- .div(16'd25),
- .out(clk_1Mhz)
- );
- clk_div clk_1Mhz_to_10hz( //1Mhz分频10Hz
- .clk(clk_1Mhz),
- .div(16'd50000),
- .out(clk_10hz)
- );
- clk_div clk_10hz_500mhz( //10Hz分频0.5Hz
- .clk(clk_10hz),
- .div(16'd10),
- .out(run)
- );
- wire error;
- wire interrupt;
- wire signed [11:0] temperature;
- wire [9:0] humidity;
- reg signed [11:0] temperature2;
- reg [9:0] humidity2;
- dht11 dht11(
- .clk(clk_1Mhz),
- .run(run),
- .data(data),
- .error(error),
- .interrupt(interrupt),
- .temperature(temperature),
- .humidity(humidity)
- );
- reg init = 1'b0;
- wire temp2;
- wire humi2;
- assign temp = (|{error,!init}) ? clk_10hz : temp2;
- assign humi = (|{error,!init}) ? clk_10hz : humi2;
- clk_div A(
- .clk(clk_1Mhz),
- .div(temperature2+300),
- .out(temp2)
- );
- clk_div B(
- .clk(clk_1Mhz),
- .div(humidity2),
- .out(humi2)
- );
- always @(posedge interrupt) begin
- init <= 1'b1;
- led <= error;
- temperature2 <= temperature;
- humidity2 <= humidity;
- end
- endmodule
复制代码 |
|