设为首页收藏本站帮助中心
查看: 54|回复: 0
收起左侧

Quartus Verilog HDL/FPGA 实现驱动 DHT11 数字温湿度传感器模块 并通过频率输出信号

[复制链接]
发表于 2023-12-23 10:03:38 | 显示全部楼层 |阅读模式
main.png
  1. module clk_div(                        //时钟分频模块 输出频率=输入频率/分频系数/2
  2.         input clk,                                //时钟输入
  3.         input [15:0] div,                //[16位宽]分频系数
  4.         output reg out                        //分频输出
  5. );
  6. initial out = 1'd0;
  7. reg [15:0] i = 0;
  8. always @(posedge clk) begin
  9.         i = i + 16'd1;
  10.         if(i >= div) begin
  11.                 i = 0;
  12.                 out <= !out;
  13.         end
  14. end
  15. endmodule

  16. module edge_detect(              //边沿检测模块
  17.         input clk,                                        //时钟 (上升沿触发)
  18.         input dat,                                        //待检测单比特信号
  19.         output pos                                        //dat上升沿发出高电平 (单脉冲,下一个时钟恢复低电平)
  20. );
  21. reg a,b;
  22. assign pos = ({a,b} == 2'b10) ? 1'b1 : 1'b0;
  23. always @(posedge clk) begin
  24.         a <= dat;
  25.         b <= a;
  26. end
  27. endmodule

  28. module dht11_count(                        //DHT11电平时间计数模块
  29.         input clk,                                        //1Mhz 时钟输入
  30.         input start,                                //上升沿开始计数
  31.         input dht11,                                //DHT11数据脚
  32.         input signal,                                //1:计数高电平时间 0:低电平
  33.         output reg stop,                        //电平翻转或超时发出上升沿 计数完成
  34.         output reg [7:0] count         //[8位宽] 计数微秒 (超时255)
  35. );
  36. initial count = 8'd0;
  37. reg run = 1'b0;
  38. initial stop = 1'b0;

  39. always @(posedge start or posedge stop) begin
  40.         if(stop) begin
  41.                 run <= 1'b0;
  42.         end else if(start) begin
  43.                 run <= 1'b1;
  44.         end
  45. end

  46. always @(posedge clk) begin
  47.         stop <= 1'b0;
  48.         if(run) begin
  49.                 if(dht11 == signal && !(&count)) begin
  50.                         count <= count + 8'd1;
  51.                 end else begin
  52.                         stop <= 1'b1;
  53.                 end
  54.         end else begin
  55.                 count <= 8'd0;
  56.         end
  57. end
  58. endmodule

  59. module dht11_decode(                        //DHT11数据解码模块
  60.         //[39:32]:湿度高8位 [31:24]:湿度低8位 [23:16]:温度高8位 [15:8]:温度低8位 [7:0] 校验位
  61.         input [39:0] dat,                        //[40位宽] DHT11接收到的数据输入
  62.         output check,                                //数据校验是否正确 1:正确 0:错误
  63.         output reg signed [11:0] temperature,        //[12位宽] 温度
  64.         output reg [9:0] humidity                                        //[10位宽] 湿度
  65. );

  66. wire [7:0] sum = dat[39:32] + dat[31:24] + dat[23:16] + dat[15:8];        //校验和
  67. assign check = (dat[7:0] == sum) ? 1'b1 : 1'b0;
  68. wire sign = dat[15];                //符号位 0:零上温度 1:零下温度 (摄氏度)
  69. wire [11:0] humi = dat[39:32]*10'd10 + dat[31:24];
  70. always @(*) begin
  71.         if(humi > 12'd1000) begin
  72.                 humidity = 10'd1000;
  73.         end else begin
  74.                 humidity = humi[9:0];
  75.         end
  76.         temperature = dat[23:16]*12'd10 + dat[14:8];
  77.         if(sign) begin
  78.                 temperature = 12'd0-temperature;
  79.         end
  80. end
  81. endmodule

  82. module dht11(                                        //DHT11 数字温湿度传感器模块驱动
  83.         input clk,                                        //1Mhz时钟输入
  84.         input run,                                        //上升沿开始采集 0.5HZ则2秒采一次
  85.         inout data,                                        //[双向IO] DHT11数据脚
  86.         output reg error,                        //是否发生错误
  87.         output reg interrupt,        //上升沿中断 (温湿度采集完成后触发)
  88.         output signed [11:0] temperature,        //[12位宽] 温度 范围:-200~600 精度:0.1℃ (输出234则为23.4摄氏度)
  89.         output [9:0] humidity                                        //[10位宽] 湿度 范围:5~95% 精度:0.1% (输出456则湿度为45.6%)
  90. );

  91. reg dat = 1'b0;                        //1:输出高电平(由上拉电阻拉高,可以被拉低) 0:低电平(不能被拉高)
  92. assign data = dat ? 1'bz : 1'b0;
  93. reg [3:0] state = 4'd0;        //[4位宽] 状态寄存器
  94. reg [14:0] delay;                        //[15位宽] 延时时钟寄存器
  95. reg start;
  96. reg signal;
  97. wire stop;
  98. wire [7:0] us;                //[8位宽] 电平计数微秒数 范围:0~255
  99. reg [39:0] ram;        //[40位宽] DHT11接收到的数据
  100. reg [5:0] pc;                //[6位宽] 数据指针 范围:0~39
  101. wire check;
  102. wire pos;

  103. edge_detect edge_detect(
  104.         .clk(!clk),
  105.         .dat(run),
  106.         .pos(pos)
  107. );

  108. dht11_decode dht11_decode(
  109.         .dat(ram),
  110.         .check(check),
  111.         .temperature(temperature),
  112.         .humidity(humidity)
  113. );

  114. dht11_count dht11_count(
  115.         .clk(!clk),
  116.         .start(start),
  117.         .dht11(data),
  118.         .signal(signal),
  119.         .stop(stop),
  120.         .count(us)
  121. );

  122. always @(posedge clk) begin
  123.         if(|delay) begin
  124.                 delay <= delay - 15'd1;
  125.         end else begin
  126.                 case(state)
  127.                         4'd0:begin
  128.                                 dat <= 1'b1;
  129.                                 state <= pos ? 4'd1 : 4'd0;
  130.                         end
  131.                                
  132.                         4'd1:begin
  133.                                 dat <= 1'b0;                //主动拉低18ms (不能主动拉高)
  134.                                 delay <= 15'd18000;
  135.                                 state <= 4'd2;
  136.                         end
  137.                                
  138.                         4'd2:begin
  139.                                 dat <= 1'b1;                //输入模式等待被DHT11拉低
  140.                                 signal <= 1'b1;
  141.                                 start <= 1'b1;
  142.                                 state <= 4'd3;
  143.                         end
  144.                                
  145.                         4'd3:begin
  146.                                 start <= 1'b0;
  147.                                 if(stop) begin
  148.                                                 if(&us) begin                        //超时则没有检测到DHT11
  149.                                                         error <= 1'b1;
  150.                                                         state <= 4'd13;
  151.                                                 end else begin
  152.                                                         error <= 1'b0;
  153.                                                         state <= 4'd4;
  154.                                                 end
  155.                                 end else begin
  156.                                         state <= 4'd3;
  157.                                 end
  158.                         end
  159.                                
  160.                         4'd4:begin
  161.                                 signal <= 1'b0;
  162.                                 start <= 1'b1;
  163.                                 state <= 4'd5;
  164.                         end
  165.                                
  166.                         4'd5:begin
  167.                                 start <= 1'b0;
  168.                                 if(stop) begin
  169.                                         if(us < 8'd78 || us > 8'd88) begin                //收到83微秒低电平应答信号 小于78或大于88则无效
  170.                                                 error <= 1'b1;
  171.                                                 state <= 4'd13;
  172.                                         end else begin
  173.                                                 error <= 1'b0;
  174.                                                 state <= 4'd6;
  175.                                         end
  176.                                 end else begin
  177.                                         state <= 4'd5;
  178.                                 end
  179.                         end
  180.                        
  181.                         4'd6:begin
  182.                                 signal <= 1'b1;
  183.                                 start <= 1'b1;
  184.                                 state <= 4'd7;
  185.                         end
  186.                        
  187.                         4'd7:begin
  188.                                 start <= 1'b0;
  189.                                 if(stop) begin
  190.                                         if(us < 8'd82 || us > 8'd92) begin        //87微秒高电平应答
  191.                                                 error <= 1'b1;
  192.                                                 state <= 4'd13;
  193.                                         end else begin
  194.                                                 error <= 1'b0;
  195.                                                 pc <= 6'd39;
  196.                                                 state <= 4'd8;
  197.                                         end
  198.                                 end else begin
  199.                                         state <= 4'd7;
  200.                                 end
  201.                         end
  202.                                
  203.                         4'd8:begin
  204.                                 signal <= 1'b0;
  205.                                 start <= 1'b1;
  206.                                 state <= 4'd9;
  207.                                
  208.                         end
  209.                                
  210.                         4'd9:begin
  211.                                 start <= 1'b0;
  212.                                 if(stop) begin
  213.                                         if(us < 49 || us > 59) begin                //54us低电平应答
  214.                                                 error <= 1'b1;
  215.                                                 state <= 4'd13;
  216.                                         end else begin
  217.                                                 error <= 1'b0;
  218.                                                 state <= 4'd10;
  219.                                         end
  220.                                 end else begin
  221.                                         state <= 4'd9;
  222.                                 end
  223.                         end
  224.                                
  225.                         4'd10:begin
  226.                                 signal <= 1'b1;
  227.                                 start <= 1'b1;
  228.                                 state <= 4'd11;
  229.                         end
  230.                                
  231.                         4'd11:begin
  232.                                 start <= 1'b0;
  233.                                 if(stop) begin
  234.                                         error = 1'b0;
  235.                                                 if(us >= 8'd18 && us <= 8'd32) begin                        //位0:54us低电平与23~27us高电平
  236.                                                         ram[pc] <= 1'b0;
  237.                                                 end else if(us >= 8'd63 && us <= 8'd79) begin        //位1:54us低电平与68~74us高电平
  238.                                                         ram[pc] <= 1'b1;
  239.                                                 end else begin
  240.                                                         error = 1'b1;
  241.                                                         state <= 4'd13;
  242.                                                 end
  243.                                                 if(!error) begin
  244.                                                         if(pc == 6'd0) begin
  245.                                                                 state <= 4'd12;
  246.                                                         end else begin
  247.                                                                 pc <= pc - 6'd1;
  248.                                                                 state <= 4'd8;
  249.                                                         end
  250.                                                 end
  251.                                 end else begin
  252.                                         state <= 4'd11;
  253.                                 end
  254.                         end
  255.                        
  256.                         4'd12:begin
  257.                                 error <= !check;
  258.                                 state <= 4'd13;
  259.                         end
  260.                        
  261.                         4'd13:begin
  262.                                 interrupt <= 1'b1;
  263.                                 state <= 4'd14;
  264.                         end
  265.                        
  266.                         4'd14:begin
  267.                                 state <= 4'd15;
  268.                         end
  269.                        
  270.                         4'd15:begin
  271.                                 interrupt <= 1'b0;
  272.                                 state <= 0;
  273.                         end
  274.                 endcase
  275.         end
  276. end
  277. endmodule

  278. module main(
  279.         input clk,                        //50Mhz Pin17
  280.         output reg led,        //接LED 低电平点亮 Pin3
  281.         //接示波器或逻辑分析仪 成功输出频率 失败输出10HZ
  282.         output temp,                //温度频率输出 温度:(500000/频率-300)/10 Pin43
  283.         output humi,                //湿度频率输出 湿度:50000/频率 Pin45
  284.         inout data                        //接DHT11 Pin40 (请配置该IO口上拉电阻:Weak Pull-Up Resistor)
  285. );
  286. wire clk_1Mhz;
  287. wire clk_10hz;                        //10HZ
  288. wire run;                //0.5HZ

  289. clk_div clk_50Mhz_1Mhz(                //50Mhz分频1Mhz
  290.         .clk(clk),
  291.         .div(16'd25),
  292.         .out(clk_1Mhz)
  293. );

  294. clk_div clk_1Mhz_to_10hz(                //1Mhz分频10Hz
  295.         .clk(clk_1Mhz),
  296.         .div(16'd50000),
  297.         .out(clk_10hz)
  298. );

  299. clk_div clk_10hz_500mhz(                //10Hz分频0.5Hz
  300.         .clk(clk_10hz),
  301.         .div(16'd10),
  302.         .out(run)
  303. );

  304. wire error;
  305. wire interrupt;
  306. wire signed [11:0] temperature;
  307. wire [9:0] humidity;
  308. reg signed [11:0] temperature2;
  309. reg [9:0] humidity2;

  310. dht11 dht11(
  311.         .clk(clk_1Mhz),
  312.         .run(run),
  313.         .data(data),
  314.         .error(error),
  315.         .interrupt(interrupt),
  316.         .temperature(temperature),
  317.         .humidity(humidity)
  318. );

  319. reg init = 1'b0;

  320. wire temp2;
  321. wire humi2;
  322. assign temp = (|{error,!init}) ? clk_10hz : temp2;
  323. assign humi = (|{error,!init}) ? clk_10hz : humi2;

  324. clk_div A(
  325.         .clk(clk_1Mhz),
  326.         .div(temperature2+300),
  327.         .out(temp2)
  328. );

  329. clk_div B(
  330.         .clk(clk_1Mhz),
  331.         .div(humidity2),
  332.         .out(humi2)
  333. );

  334. always @(posedge interrupt) begin
  335.         init <= 1'b1;
  336.         led <= error;
  337.         temperature2 <= temperature;
  338.         humidity2 <= humidity;       
  339. end
  340. endmodule
复制代码

相关帖子

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入我们

本版积分规则