lvxinn2006 发表于 2019-1-17 10:54

【 ST NUCLEO-G071RB测评】_06_DHT11温湿度传感器实验

<div class='showpostmsg'> 本帖最后由 lvxinn2006 于 2019-1-17 11:00 编辑

本次活动测评开发板ST NUCLEO-G071RB由ST意法半导体提供,感谢意法半导体对EEWorld测评的支持!https://www.stmcu.com.cn/Product/pro_detail/cat_code/STM32G0/family/81/sub_family/261/layout/product【实验目的】· 掌握DHT11的通信时序· 掌握使用GPIO处理通信时序
【实验环境】· NUCLEO-G071RB开发板· DHT11温湿度模块· Keil MDK-ARM(Keil uVision 5.25.2.0)· Keil.STM32G0xx_DFP.1.0.0.pack· 串口调试助手
【实验资料】· NUCLEO-G071RB开发板原理图· STM32G071x8/xB Data Sheet· STM32G071芯片用户参考手册· DHT11用户手册 【实验分析】原理图:

连接如图所示,灰色线连接到电源的负极,黑色线连接到3.3V正极,白色是数据线,连接到了PC10引脚。DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。DATA 用于微处理器与 DHT11 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先出。数据格式::8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据+8bit 校验位。校验位数据定义:“8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据”8bit 校验位等于所得结果的末 8 位。
数据时序图用户主机(MCU)发送一次开始信号后,DHT11 从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11 发送响应信号,送出 40bit 的数据,幵触发一次信采集。信号发送如图所示:外设读取步骤主机和从机之间的通信可通过如下几个步骤完成(外设(如微处理器)读取 DHT11 的数据的步骤)。步骤一:DHT11 上电后(DHT11 上电后要等待 1S 以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,幵记录数据,同时 DHT11 的 DATA 数据线由上拉电阻拉高一直保持高电平;此时 DHT11 的DATA 引脚处于输入状态,时刻检测外部信号。步骤二:微处理器的 I/O 设置为输出同时输出低电平,且低电平保持时间不能小于 18ms,然后微处理器的 I/O设置为输入状态,由于上拉电阻,微处理器的 I/O 即 DHT11 的 DATA 数据线也随之变高,等待 DHT11 作出回答信号,发送信号如图所示:
步骤三:DHT11 的 DATA 引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后 DHT11 的 DATA引脚处于输出状态,输出 80 微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据,微处理器的 I/O 此时处于输入状态,检测到 I/O 有低电平(DHT11 回应信号)后,等待 80 微秒的高电平后的数据接收,发送信号如图所示:步骤四:由 DHT11 的 DATA 引脚输出 40 位数据,微处理器根据 I/O 电平的变化接收 40 位数据,位数据“0”的格式为: 50 微秒的低电平和 26-28 微秒的高电平,位数据“1”的格式为: 50 微秒的低电平加 70微秒的高电平。位数据“0”、“1”格式信号如图所示:
结束信号:DHT11 的 DATA 引脚输出 40 位数据后,继续输出低电平 50 微秒后转为输入状态,由于上拉电阻随之变为高电平。但 DHT11 内部重测环境温湿度数据,幵记录数据,等待外部信号的到来。
【实验代码】#include "stm32g0xx.h"                  // Device header
#include "uart.h"
#include <stdio.h>

void mdelay(int ms)
{
      RCC->APBENR1 |= RCC_APBENR1_TIM6EN;      //使能TIM6
      TIM6->PSC = SystemCoreClock / 1000 - 1;      //预分频 定时器时钟为1000Hz
      TIM6->ARR = ms;      //周期数
      TIM6->CR1 |= TIM_CR1_OPM;      //One Pulse mode
      TIM6->CR1 |= TIM_CR1_CEN;      //启动定时器
      while(TIM6->CR1 & TIM_CR1_CEN);      //等待定时器结束
}

void GPIOSetDir(GPIO_TypeDef *GPIO, int pin, int dir)
{
      if (dir == 0){
                GPIO->MODER      &= ~(0x3UL<<(pin * 2));
                GPIO->OTYPER &= ~(1<<pin);
      }else{
                GPIO->MODER      &= ~(0x3UL<<(pin * 2));
                GPIO->MODER      |= (0x1UL<<(pin * 2));
                GPIO->OSPEEDR |= 0x3UL<<(pin * 2);
                GPIO->OTYPER &= ~(1<<pin);
      }
}

void GPIOSetValue(GPIO_TypeDef *GPIO, int pin, int value)
{
      if (value == 0){
                GPIO->ODR &= ~(1<<pin);
      }else{
                GPIO->ODR |= (1<<pin);
      }
}

void GPIOSetToggle(GPIO_TypeDef *GPIO, int pin)
{
      GPIO->ODR ^= (1<<pin);
}

int GPIOGetValue(GPIO_TypeDef *GPIO, int pin)
{
      return GPIO->IDR & (1<<pin);
}

int DHT11_Read(char *temp, char *humd)
{
      int i;
      int timeout = 0;
      volatile int low_count, high_count;
      char data;      //接收40位数据
      
      //步骤二
      GPIOSetDir(GPIOC, 10, 1);
      GPIOSetValue(GPIOC, 10, 0);      //输出低电平
      mdelay(30);
      GPIOSetDir(GPIOC, 10, 0);      //设置成输入模式
      //步骤三
      while(GPIOGetValue(GPIOC, 10)){ //等待响应信号
                timeout ++;
                if (timeout > 10000) return -1;
      }
      while(GPIOGetValue(GPIOC, 10) == 0);      //等待高电平
      while(GPIOGetValue(GPIOC, 10) != 0);      //等待高电平结束
      //步骤四
      for (i = 0; i < 40; i ++){
                low_count = 0;
                high_count = 0;
                while(GPIOGetValue(GPIOC, 10) == 0){      //记录低电平
                        low_count ++;
                }
                while(GPIOGetValue(GPIOC, 10) != 0){      //记录高电平
                        high_count ++;
                }
                if (low_count > high_count){ //数据0
                        data &= ~(1<<(7-i%8));
                }else{//数据1
                        data |= (1<<(7-i%8));
                }
      }
      //步骤五
      while(GPIOGetValue(GPIOC, 10) == 0);      //等待低电平结束
      
      if((data+data+data+data) == data){//校验数据
                humd=data;
                humd=data;
                temp=data;
                temp=data;
                return 1;
      }else{      //数据校验失败
                return 0;
      }
}

/* 配置64MHz系统时钟 */
void SystemClockConfig(void)
{
      //Fvco1 * 32 / 4 = 128
      RCC->PLLCFGR = (0x2<<0)      //HSI16
                        | (1<<4)                //M=1+1=2
                        | (16<<8)                //N=16
                        | (1<<28)                //使能PLLRCLK
                        | (1<<29);      //R=1      PLLRCLK分频系数为2
      RCC->CR |= (1<<24);      //使能PLL
      while(!(RCC->CR & (1<<25)));      //等待PLL锁定
      
      FLASH->ACR |= (0x1<<0);      //设置Flash访问延迟
      RCC->CFGR |= (0x2<<0);      //切换时钟源为PLLRCLK
      while(!(RCC->CFGR & (0x2<<3)));      //等待时钟源切换完成
      SystemCoreClockUpdate();      //更新SystemCoreClock全局变量
}

int main(void)
{
      int ret;
      char temp={0};      //保存温度数据
      char humd={0};      //保存湿度数据
      SystemClockConfig();
      RCC->IOPENR |= RCC_IOPENR_GPIOCEN;      //使能GPIOC
      UART2_Init(115200);

      GPIOSetDir(GPIOC, 13, 0);
      GPIOSetDir(GPIOA, 5, 1);
      while(1){
                ret = DHT11_Read(temp, humd);
                switch (ret){
                        case -1:
                              printf("Timeout\n");
                        break;
                        case 0:
                              printf("Data Error\n");
                        break;
                        case 1:
                              printf("humd:%d.%d temp:%d.%d\n", humd, humd
                                                      , temp, temp);
                        break;
                }
                mdelay(1000);
      }
}

【实验现象】连接开发板,并打开串口调试工具,并使用115200的波特率连接开发板的串口,显示如下:



此内容由EEWORLD论坛网友lvxinn2006原创,如需转载或用于商业用途需征得作者同意并注明出处

</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>
页: [1]
查看完整版本: 【 ST NUCLEO-G071RB测评】_06_DHT11温湿度传感器实验