温湿度传感器

前言

&常见型号类型:DS18B20、DHT11

DHT11概述

DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。产品为4 针单排引脚封装。连接方便,特殊封装形式可根据用户需求而提供。

概述解读

  • 校准系数OTP内存
    • OTP内存——One Time Programable 一次可编程
    • 传感器是经过校准的,数据误差比较小,使用的一次可编程内存,属于ROM。
  • 单线制串行接口
    • 单线:半双工通信
    • 串行:比特流形式进行数据传输,所以需要判断是高位先出(MSB)还是低位先出(LSB)大端小端(待完善)
  • 4 针单排引脚
    • 有单排引脚,有VCC和GND,之外还有两根排线引脚,查看数据手册通过半双工,判断存在悬空引脚

测量精度

image.png
传感器的湿度阈值范围为15%RH95%RH,温度阈值范围为-2℃52℃

电路说明

image.png

传输要求

DATA 用于微处理器与DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数部分用于以后扩展,现读出为零.操作流程如下:
一次完整的数据传输为40bit,高位先出
数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和
数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”所得结果的末8位。

image.png

数字0和数字1的不同表示
image.png

代码

/**
   ******************************************************************************
   * @file    main.c 
   * @author  
   * @version 
   * @date    2024.07.12
   * @brief   实现利用DHT11温湿度模块进行数据采集
				
   ******************************************************************************
**/

#include "stm32f4xx.h"  //必须包含
#include <stdio.h>
#include "delay.h"   //包含延时函数


GPIO_InitTypeDef  GPIO_InitStructure;

//前台程序就是中断服务程序,该程序是不需要手动调用的,当中断触发之后CPU会自动跳转过来执行该函数
void USART1_IRQHandler(void)
{
	uint8_t data;
  //判断中断是否发生
  if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
  {   
		//从USART1中接收一个字节
		data = USART_ReceiveData(USART1);  //一次只能接收一个字节   
		
		//把接收到的数据转发出去
		USART_SendData(USART1,data);
  }
}


void USART1_Config(u32 baud)
{
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//打开了GPIO端口时钟  PA9和PA10
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	//打开USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//选择GPIO引脚的复用功能
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 , GPIO_AF_USART1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
	
	//配置GPIO引脚 注意:复用模式
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_9|GPIO_Pin_10;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	//配置串口参数+对串口初始化
	USART_InitStructure.USART_BaudRate = baud;	//波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;	//数据位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;	//停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;	//无校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无流控
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
	USART_Init(USART1, &USART_InitStructure);

	//配置NVIC参数 + 对NVIC初始化
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	//选择USART1的中断源,接收到数据则触发中断
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	//打开串口
	USART_Cmd(USART1, ENABLE);
}


struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;

int fputc(int ch, FILE *f)
{
	USART_SendData(USART1,ch);	
	while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );
		
	return ch;
}

//利用串口发送一个字符串
void  USART1_SendString(const char *str)
{
	while(*str)
	{
		while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );
		 USART_SendData(USART1,*str++);
		 		
	}
}


 //PG9串口初始化
void DHT11_Init()
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);	
    //PG9配置为开漏输出模式 
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType   = GPIO_OType_OD;//open drain,开漏输出
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_9;
	GPIO_Init(GPIOG, &GPIO_InitStructure);	
    
    GPIO_SetBits( GPIOG, GPIO_Pin_9);
}

//发送开始信号给温度传感器
void DHT11_Master_Send()
{
    //PG9配置为开漏输出模式
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//open drain,开漏输出
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_9;
	GPIO_Init(GPIOG, &GPIO_InitStructure);


    //2.主机至少先拉低18ms,再拉高20-40ms
    GPIO_ResetBits(GPIOG, GPIO_Pin_9);
    delay_ms(20);
    GPIO_SetBits(GPIOG, GPIO_Pin_9);
    delay_us(30);
    
    //3.设置主机为输入模式
    GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_IN;
	GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_9;
	GPIO_Init(GPIOG, &GPIO_InitStructure);	
    
   
}




//开始接收温度传感器的返回数据
int32_t DHT11_Salve_return(uint8_t *buf)
{
    uint8_t cnt = 0;
    uint8_t data = 0;    
    
    //首先判断温度传感器的响应信号,先等待高电平结束
    cnt = 0;
    while(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_9) == Bit_SET){
        delay_us(1);
        cnt++;
        if(cnt > 90) return -1;
    }
    
    cnt = 0;
    while(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_9) == Bit_RESET){ 
        delay_us(1);
        cnt++;
        if(cnt > 90) return -2;
    }   

    
    cnt = 0;
    while(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_9) == Bit_SET){
        delay_us(1);
        cnt++;
        if(cnt > 90) return -3;
    }   

    //开始接收数据  
    for(uint8_t i = 0 ; i < 5 ; i++){
        data = 0;        
        for(int32_t j = 7 ; j >=0 ; j--){           
            cnt = 0;
            while(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_9) == Bit_RESET){
                delay_us(1);
                cnt++;
                if(cnt > 60) return -4;
            }
            
            //延时等待查看高电平持续时间
            delay_us(40);
         
            if(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_9) == Bit_SET){
               data |= 1<<j;
               cnt = 0;
               while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9)==Bit_SET)
               {
                    delay_us(1);
                    cnt++;
                    if(cnt > 60) return -5;
				}		
            }
        }
        buf[i] = data;
    }
    //校验数据
	//if(buf[4]==((buf[0]+ buf[1]+buf[2]+buf[3])&0xFF))
		return 0;
    //return -6;
}



int main(void)
{
	uint8_t buf[5];
	int32_t rt;
    
	//1.硬件的初始化
	USART1_Config(9600);
	DHT11_Init();
	
	
	while(1)
	{
        DHT11_Master_Send();
		rt = DHT11_Salve_return(buf);
		
		if(rt == 0)
		{
			printf("H:%d.%d T:%d.%d\r\n",buf[0],buf[1],buf[2],buf[3]);
		}
		else
		{
			printf("dht11 read error code %d\r\n",rt);
		}
        delay_ms(6000);
	}
}






posted @ 2024-07-13 17:36  banon  阅读(3)  评论(0编辑  收藏  举报