OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 677|回复: 0

[国产FPGA] 《ATK-DFPGL22G 之FPGA开发指南》第二十八章 DHT11数字温湿度传感器实验

[复制链接]

1070

主题

1081

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4443
金钱
4443
注册时间
2019-5-8
在线时间
1199 小时
发表于 2023-11-30 15:32:24 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2023-11-30 15:32 编辑

第二十八章 DHT11数字温湿度传感器实验

1)实验平台:正点原子 ATK-DFPGL22G开发板

2) 章节摘自【正点原子】ATK-DFPGL22G之FPGA开发指南_V1.0


4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz-PGL22G.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)FPGA技术交流QQ群:435699340

155537c2odj87vz1z9vj6l.jpg

155537nfqovl2gg9faaol9.png

DHT11是奥松(AoSong)公司生产的一款数字温湿度复合传感器。该传感器用途广泛、抗干扰能力强、可靠性高,在家电、汽车、医疗等方面有广泛的应用。本章我们将使用FPGA开发板实现对DHT11数据的采集,并将温湿度数据显示在数码管上。
本章包括以下几个部分:
1.1简介
1.2实验任务
1.3硬件设计
1.4程序设计
1.5下载验证

1.1 简介
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它使用专用的数字模块采集技术和温湿度传感技术,具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC(负温度系数热敏电阻器)测温元件,并与一个高性能8位MCU相连接。每个DHT11传感器都在湿度校验室中校准过,校准系数以程序的形式储存在OTP(一次性可编程)内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。DHT11使用单线制串行接口,4针单排引脚封装,信号传输距离可达20米以上,在各类应用甚至很苛刻的环境中都能正常工作。                             
image001.jpg
图 28.1.1 DHT11内部原理图
上图为DHT11的内部原理图,可以看出感湿原件、感温元件和OTP内存直接连接在内部一个八位MCU上,该MCU通过计算得出测量数值。
DATA用于FPGA与DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分为整数部分和小数部分,数据格式如下:
一次完整的数据传输为40bit,高位在前。
数据格式:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和数据。
数据传送正确时校验和数据等于“8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据”所得结果的末8位)。
接下来我们介绍一下DHT11的传输时序,DHT11的数据发送流程如图 28.1.2 DHT11数据发送流程所示。
image003.png
图 28.1.2 DHT11数据发送流程
主机(此处指FPGA)首先发送一次开始信号,即:拉低数据线,保持t1(至少18ms)时间;然后拉高数据线保持t2(20~40us)时间,随后开始读取DHT11的响应;如果操作正确的话,DHT11会拉低数据线,保持t3(80us)时间,作为响应信号;接下来DHT11会拉高数据线,保持t4(80us)时间,随后开始输出有效数据。
DHT11共输出40bit有效数据,每1bit数据都是以50us低电平开始,高电平的持续时间作为判断数据位的条件。当数据位为0时,高电平的持续时间为26~28us;当数据位为1时,高电平的持续时间为70us。
DHT11数据位“0”时序图和数据位“1”时序图如图 28.1.3和图 28.1.4所示。
image005.png
图 28.1.3 DHT11数据位“0”时序图
image007.png
图 28.1.4 DHT11数据位“1”时序图
需要注意的是,DHT11的温度和湿度转换较慢,如果读取速度过快会导致DHT11无法响应的情况。本次实验每100ms读取一次,如果DHT11长时间未响应,则重新发起开始信号。

1.2 实验任务
本节实验任务是使用ATK-DFPGL22G开发板完成对DHT11温湿度数据的采集,并通过按键KEY0控制温度和湿度在数码管上的切换显示。

1.3 硬件设计
我们的ATK-DFPGL22G开发板上有一个DS18B20/DTH11的扩展接口,该接口可以用来连接DS18B20或DHT11。其原理图如图 28.3.1所示。
image009.png
图 28.3.1 DHT11/DS18B20扩展接口原理图
DHT11通过4个排针与外部连接,如图 28.3.2所示,将DHT11直接插在开发板上即可,接插之前注意正负极的方向,以免短路。
image011.png
图 28.3.2 DHT11连接实物图
本次实验的管脚分配如下表所示:
QQ截图20231129101744.png
表 28.3.1 管脚分配

1.4 程序设计
根据实验任务,我们可以大致规划出系统的工作流程:FPGA控制DHT11采集温度和湿度,并将收到的温度和湿度数据转换成十进制显示在数码管上。本次实验使用按键来控制数码管显示温度和湿度,所以还需要添加消抖模块来对按键进行消抖,以及按键控制模块控制数码管切换显示温度和湿度。由此画出的系统框图如下图所示。
image014.png
图 28.4.1 DHT11数字温湿度传感器系统框图
FPGA部分包括5个模块,顶层模块(top_dht11)、DHT11驱动模块(dht11_drive)、按键消抖模块(key_debounce)、按键控制模块(dht11_key)、数码管驱动模块(seg_led)。其中在顶层模块完成对其他模块的例化。
DHT11驱动模块(dht11_drive):dht11_drive模块通过单总线引脚读取DHT11的温度值和湿度值,并将读取到的数据输出至按键控制模块。
按键消抖模块(key_debounce):消除按键抖动,在检测到有按键按下或释放时对按键数据进行消抖处理。
按键控制模块(dht11_key):根据输入的按键控制信号,将温度数据和湿度数据选择输出至数码管显示模块。
数码管显示模块(seg_led):将输入的数据显示到数码管上。
顶层模块代码如下:
  1. 1  module top_dht11(
  2. 2       input         sys_clk  ,  //系统时钟
  3. 3       input         sys_rst_n,  //系统复位
  4. 4      
  5. 5       inout         dht11    ,  //DHT11总线
  6. 6       input         key      ,  //按键
  7. 7       output  [5:0  sel      ,  //数码管位选信号
  8. 8       output  [7:0  seg_led     //数码管段选信号
  9. 9  );
  10. 10 //wire define
  11. 11 wire  [31:0  data_valid;
  12. 12 wire  [19:0  data      ;
  13. 13 wire  [5:0   point    ;
  14. 14
  15. 15 //*****************************************************
  16. 16 //**                    main code
  17. 17 //*****************************************************
  18. 18
  19. 19 //dht11驱动模块
  20. 20 dht11_drive u_dht11_drive (
  21. 21      .sys_clk        (sys_clk),
  22. 22      .rst_n          (sys_rst_n),
  23. 23      
  24. 24      .dht11          (dht11),
  25. 25      .data_valid     (data_valid)
  26. 26      );
  27. 27
  28. 28
  29. 29 //按键消抖模块
  30. 30 key_debounce u_key_debounce(
  31. 31      .sys_clk        (sys_clk),
  32. 32      .sys_rst_n      (sys_rst_n),
  33. 33      
  34. 34      .key            (key),
  35. 35      .key_flag       (key_flag),
  36. 36      .key_value      (key_value)
  37. 37      );
  38. 38
  39. 39 //按键控制温/湿度显示
  40. 40 dht11_key u_dht11_key(
  41. 41      .sys_clk        (sys_clk),
  42. 42      .sys_rst_n      (sys_rst_n),
  43. 43      
  44. 44      .key_flag       (key_flag),
  45. 45      .key_value      (key_value),
  46. 46      .data_valid     (data_valid),
  47. 47      
  48. 48      .data           (data),
  49. 49      .sign           (sign),
  50. 50      .en             (en),                     
  51. 51      .point          (point)
  52. 52      );
  53. 53
  54. 54 //动态数码管显示模块
  55. 55 seg_led u_seg_led (
  56. 56      .clk            (sys_clk),
  57. 57      .rst_n          (sys_rst_n),
  58. 58      
  59. 59      .seg_sel        (sel),
  60. 60      .seg_led        (seg_led),
  61. 61      
  62. 62      .data           (data),
  63. 63      .point          (point),
  64. 64      .en             (en),
  65. 65      .sign           (sign)
  66. 66      );
  67. 67
  68. 68 endmodule
复制代码
顶层模块完成对其他模块的例化,dht11_drivr模块输出的数据信号(data_valid)和key_debounce模块输出的按键信号(key_flag和key_value)连接至dht11_key模块,dht11_key模块输出的温度/湿度数据(data)以及数码管控制信号连接至seg_led模块。
由本章简介部分介绍的DHT11传输时序可以发现,DHT11的传输时序适合用状态机来编写。DHT11驱动模块状态跳转图如下所示:
QQ截图20231129101800.png
图 28.4.2 DHT11驱动状态跳转图
DHT11驱动模块使用三段式状态机来读取DHT11的温度和湿度值,从上图可以比较直观的看到每个状态实现的功能以及跳转都下一个状态的条件。这里需要注意的一点是,由于DHT11温度和湿度转换较慢,如果读取速度过快会导致DHT11无法响应的情况,所以我们在每次读操作结束后延时两秒。
由于DHT11驱动模块的代码较长,我们仅贴出部分源代码。
  1. 131         case (cur_state)
  2. 132             //上电后延时1秒等待DHT11稳定
  3. 133             st_power_on_wait : begin               
  4. 134                 if(us_cnt < POWER_ON_NUM) begin
  5. 135                     dht11_buffer <= 1'bz; //空闲状态释放总线
  6. 136                     us_cnt_clr   <=1'b0;
  7. 137                 end
  8. 138                 else begin            
  9. 139                     next_state   <=st_low_20ms;
  10. 140                     us_cnt_clr   <=1'b1;
  11. 141                 end
  12. 142             end
  13. 143             //FPGA发送起始信号(20ms的低电平)   
  14. 144             st_low_20ms: begin
  15. 145                 if(us_cnt < 20000) begin
  16. 146                     dht11_buffer <= 1'b0; //起始信号为低电平
  17. 147                     us_cnt_clr   <=1'b0;
  18. 148                 end
  19. 149                 else begin
  20. 150                     dht11_buffer <= 1'bz; //起始信号结束后释放总线
  21. 151                     next_state   <=st_high_13us;
  22. 152                     us_cnt_clr   <=1'b1;
  23. 153                 end   
  24. 154             end
  25. 155             //等待DHT11的响应信号(等待10~20us)
  26. 156             st_high_13us:begin                     
  27. 157                 if (us_cnt < 20) begin
  28. 158                     us_cnt_clr   <=1'b0;
  29. 159                     if(dht11_neg) begin   //检测到DHT11响应信号
  30. 160                         next_state <= st_rec_low_83us;
  31. 161                         us_cnt_clr <= 1'b1;
  32. 162                     end
  33. 163                 end
  34. 164                 else                     //超过20us未响应
  35. 165                     next_state <= st_delay;
  36. 166             end
  37. 167             //等待DHT11的83us低电平响应信号结束
  38. 168             st_rec_low_83us: begin                  
  39. 169                 if(dht11_pos)                  
  40. 170                     next_state <= st_rec_high_87us;  
  41. 171             end
  42. 172             //DHT11拉高87us通知FPGA准备接收数据
  43. 173             st_rec_high_87us: begin
  44. 174                 if(dht11_neg) begin       //准备时间结束   
  45. 175                     next_state <= st_rec_data;
  46. 176                     us_cnt_clr <= 1'b1;
  47. 177                 end
  48. 178                 else begin                //高电平准备接收数据
  49. 179                     data_cnt  <= 6'd0;
  50. 180                     data_temp <= 40'd0;
  51. 181                     step  <= 1'b0;
  52. 182                 end
  53. 183             end
  54. 184             //连续接收40位数据
  55. 185             st_rec_data: begin                                
  56. 186                 case(step)
  57. 187                     0: begin              //接收数据低电平
  58. 188                         if(dht11_pos) begin
  59. 189                             step     <= 1'b1;
  60. 190                             us_cnt_clr <= 1'b1;
  61. 191                         end            
  62. 192                         else              //等待数据低电平结束
  63. 193                             us_cnt_clr <= 1'b0;
  64. 194                     end
  65. 195                     1: begin              //接收数据高电平
  66. 196                         if(dht11_neg) begin
  67. 197                             data_cnt <= data_cnt + 1'b1;
  68. 198                                           //判断接收数据为0/1
  69. 199                             if(us_cnt < 60)
  70. 200                                 data_temp <= {data_temp[38:0],1'b0};
  71. 201                             else               
  72. 202                                 data_temp <= {data_temp[38:0],1'b1};
  73. 203                             step <= 1'b0;
  74. 204                             us_cnt_clr <= 1'b1;
  75. 205                         end
  76. 206                         else             //等待数据高电平结束
  77. 207                             us_cnt_clr <= 1'b0;
  78. 208                     end
  79. 209                 endcase
  80. 210                 
  81. 211                 if(data_cnt == 40) begin  //数据传输结束,验证校验位
  82. 212                     next_state <= st_delay;
  83. 213                     if(data_temp[7:0 == data_temp[39:32 + data_temp[31:24
  84. 214                                          + data_temp[23:16 + data_temp[15:8])
  85. 215                         data_valid <= data_temp[39:8];  
  86. 216                 end
  87. 217             end
  88. 218             //完成一次数据采集后延时2s
  89. 219             st_delay:begin
  90. 220                 if(us_cnt < 2000_000)
  91. 221                     us_cnt_clr <= 1'b0;
  92. 222                 else begin                //延时结束后重新发送起始信号
  93. 223                     next_state <= st_low_20ms;      
  94. 224                     us_cnt_clr <= 1'b1;
  95. 225                 end
  96. 226             end
  97. 227             default : ;
  98. 228         endcase
复制代码
代码第143行FPGA发送20ms的起始信号,使dht11起始信号为低电平,起始信号结束后释放总线;进入st_high_13us状态(等待DHT11的响应信号),从代码的第156行可知,在st_high_13us状态下,当DHT11长时间未响应时(超时20us),则进入延时状态(st_delay),延时两秒后重新发起开始信号。检测到DHT11响应信号,则进入st_rec_low_83us。
代码第167行为st_rec_low_83us的状态为等待相应的时间,拉低数据线,作为响应信号。响应结束后,进入st_rec_high_87us(准备接收数据)状态,主要是为接收数据做准备。
代码第185行st_rec_data为解析数据的状态,数据解析完成之后,开始进入st_delay(延时)状态,延时状态结束之后,准备重新发起开始信号。
按键控制模块的代码如下所示:
  1. 1  module dht11_key(
  2. 2       input            sys_clk,
  3. 3       input            sys_rst_n,
  4. 4      
  5. 5       input            key_flag,
  6. 6       input            key_value,
  7. 7       input      [31:0 data_valid,
  8. 8      
  9. 9       output     [31:0 data,
  10. 10      output reg        sign,
  11. 11      output            en,                    
  12. 12      output     [ 5:0 point
  13. 13 );
  14. 14
  15. 15 //reg define                           
  16. 16 reg       flag ; // 温/湿度标志信号
  17. 17 reg [7:0 data0; // 小数部分
  18. 18 reg [7:0 data1; // 整数部分
  19. 19
  20. 20 //*****************************************************
  21. 21 //**                    main code
  22. 22 //*****************************************************
  23. 23
  24. 24 //数码管使能信号
  25. 25 assign en    = 1'b1;
  26. 26
  27. 27 //显示的数值为 (整数 + 0.1*小数)*100
  28. 28 assign data  = data1 * 100 + data0*10;
  29. 29
  30. 30 //小数点左移两位
  31. 31 assign point = 6'b000100;
  32. 32
  33. 33 //检测到按键按下时,切换温/湿度标志信号
  34. 34 always @ (posedge sys_clk or negedge sys_rst_n) begin
  35. 35      if(!sys_rst_n)                                    
  36. 36          flag <= 1'b0;
  37. 37      else if (key_flag &(~key_value))
  38. 38          flag <= ~flag;
  39. 39 end
  40. 40
  41. 41 //flag为“0”时显示温度,为“1”时显示湿度
  42. 42 always @ (posedge sys_clk or negedge sys_rst_n) begin
  43. 43      if(!sys_rst_n) begin
  44. 44          data0 <= 8'd0;
  45. 45          data1 <= 8'd0;
  46. 46          sign <= 1'b0;
  47. 47      end
  48. 48      else if(flag == 1'b0) begin
  49. 49          data0 <= data_valid[6:0];  //温度小数部分最高位为符号位
  50. 50          data1 <= data_valid[15:8];
  51. 51          if(data_valid[7])
  52. 52              sign <= 1'b1;          //bit7为1表示负温度
  53. 53          else
  54. 54              sign <= 1'b0;
  55. 55      end
  56. 56      else begin
  57. 57          data0 <= data_valid[23:16];
  58. 58          data1 <= data_valid[31:24];
  59. 59          sign <= 1'b0;
  60. 60      end
  61. 61 end
  62. 62
  63. 63 endmodule
复制代码
在代码的第34行开始的always中,每按下一次按键KEY0,flag的值会改变一次,当flag的值等于0时,输出的值为温度值;当flag的值等于1时,输出的值为湿度值。在代码的第28行中,我们将温湿度值的整数部分放大100倍,小数部分放大10倍,显示在数码管上。
按键消抖模块和数码管显示模块分别在“按键控制蜂鸣器实验”和“动态数码管显示实验”中有详细的介绍,如果需要了解可以参考上述两个相关的实验进行学习。

1.5 下载验证
首先将DHT11接插到ATK-DFPGL22G开发板上的单总线接口,如下图所示。然后将下载器一端连电脑,另一端与开发板上对应端口连接,最后连接电源线并打开电源开关。
image017.png
图 28.5.1 DHT11接插至ATK-DFPGL22G开发板
接下来我们下载程序,验证温湿度传感器数码管显示功能。下载完成后,数码管默认显示的是温度值,当按下KEY0按键后,数码管会显示湿度值,说明本次DHT11数字温湿度传感器实验验证成功。这里需要注意的是温度值的单位是:℃(摄氏度);湿度值的单位是:%RH(相对湿度),温度值和湿度值的单位在数码管上没有显示。
image019.png
图 28.5.2 开发板KEY0按键
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-6-9 22:17

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表