DHT11

news2024/11/17 19:50:36

第一个传感----DHT11

通过前面的学习,你已经学会了控制IO口、延时函数、串口的收发。接下来,你就可以借助以上的知识点完成自己的第一个传感器--DHT11啦!

img

DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。应用非常广泛,并且具有长期的稳定性。

1.引脚说明

VDD------电源 3.3-5v

GND------接地

DATA-----数据

2.数据格式

DHT11采用的是单总线进行通信,即只有一条数据线,一次传送40位的数据,高位先出。

“8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 + 8bit 校验位”。其中,8bit的校验位是由前32位的位分别相加所得。

注:其中湿度小数部分为 0。

3.数据时序图:

注:主机从 DHT11 读取的温湿度数据总是前一次的测量值,如两次测间隔时间很长,请连续读两次以第二次获得的值为实时温湿度值。

4.读取步骤:(假设DATA 数据线的引脚接入到P22)

首先让接DHT11 中 P22空闲时保持一段时间的高电平越过不稳定状态。

(1)起始信号:

拉低P22端口22ms(这里只要在18ms-30ms就行),然后再拉高P22

(2)响应信号:

DHT11传感器会将P22引脚拉低83us,再拉高87us。

(3)40位数据:

接着DHT11传感器会连续发送40位数据,高位先出。

其中:54us低电平和23-27us的高电平表示位数据“1”

54us的低电平加上68-74us的高电平表示数据“0”

这里,我们如何用代码来实现这个操作呢?

我们可以在上升沿开始计数>40(最好是40-60之间),计数完成后判断此时P22的引脚是高电平还是低电平,若是高电平则为数据“1”,若低电平则为数据“0”。

(4)结束信号

将P22拉高即可,这里我们在前面使用空闲状态去代替了结束信号

(5)数据转换

我们所得到的初数据是八位的二进制,范围是0-255,为了能够在串口发送,我们需要将它转换为字符型,方便显示。

(6)校验位+串口发送

判断 8bit 校验位是否等于“8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 ”,如果不相等则说明此时接收的数据有问题。如果没问题的话,就用之前UART发送字符串的方法发送给电脑,以供显示。

5.案例工程代码:(建议用逻辑分析仪看波形)

main.c

/****************************数据类型******************************
unsigned char   uchar   8   0~255
signed   char   char    8   -128~127
unsignec int    uint    16  0~65535
signed   int    int     16  -32768~32767
******************************************************************/
#include "main.h"
/************************函数声明*************************************/
void STC8H_IOinit(void);            //STC15W单片机引脚初始化函数
/*===========================================================*/
/*函数:void STC32G_IOinit(void)
/*功能:STC18H单片机引脚初始化函数
/*说明:统一将单片机所有引脚初始化为准双向口工作模式
/*修改日期:2023.10.16
/*===========================================================*/
void STC8H_IOinit(void)
{
    P0M1 = 0;   P0M0 = 0;   //设置为准双向口   参考用户手册387页
    P1M1 = 0;   P1M0 = 0;   //设置为准双向口   参考用户手册387页
    P2M1 = 0;   P2M0 = 0;   //设置为准双向口   参考用户手册387页
    P3M1 = 0;   P3M0 = 0;   //设置为准双向口   参考用户手册387页
    P4M1 = 0;   P4M0 = 0;   //设置为准双向口   参考用户手册387页
    P5M1 = 0;   P5M0 = 0;   //设置为准双向口   参考用户手册387页
    P6M1 = 0;   P6M0 = 0;   //设置为准双向口   参考用户手册387页
    P7M1 = 0;   P7M0 = 0;   //设置为准双向口   参考用户手册387页  
    P0 = 0XFF;  P1 = 0XFF;  P2 = 0XFF; 
    P3 = 0XFF;  P4 = 0XFF;  P5 = 0XFF; 
    P6 = 0XFF;  P7 = 0XFF;                      //设置P0~P7所有I/O口为高电平
}
​
​
​
/****************************************************************************************************
/*函数:void main()
/*功能:40MHZ
/*说明:主函数
/*修改日期:
/****************************************************************************************************/
void main() 
{
        DHT11_ObjectTypedef hDHT11; 
    
    STC8H_IOinit();
    DHT11_Init(hDHT11.rdata);
    while(1) 
        {
        if(DHT11_Read(hDHT11.rdata))
                {
            if (hDHT11.rdata[0]+hDHT11.rdata[1]+hDHT11.rdata[2]+hDHT11.rdata[3]==hDHT11.rdata[4]) 
                        {
                SendString("湿度:");
                SendString(intToStr(hDHT11.rdata[0]));
                SendString(".");
                SendString(intToStr(hDHT11.rdata[1]));
                SendString("% ");
                SendString("温度:");
                SendString(intToStr(hDHT11.rdata[2]));
                SendString(".");
                SendString(intToStr(hDHT11.rdata[3]));
                SendString("C");
            }
        }
        Delay_ms(500);//40MHZ
    }
}

main.h

#ifndef __MAIN_H__
#define __MAIN_H__
​
#include "STC8H.h"  //单片机头文件(包含单片机的特殊功能寄存器的定义)  
#include "intrins.h"//nop头文件
#include "DHT11.h"  
#include "UART.h"   
#include "Delay.h"  
​
​
typedef unsigned char u8;
typedef unsigned int    u16;
typedef unsigned long u32;
​
#endif

DHT11.C

#include "main.h"
​
void DHT11_Init(unsigned char* arr)
{   
    unsigned char i;
    for(i=0;i<5;i++)
    {
            arr[i]=0;
    }
}
//该DHT11在40MHZ运行
unsigned char DHT11_Read(unsigned char* arr)
{
   unsigned char out,i=0,j=0,rdata=0;
​
        //空闲状态
        P22 = 1;
        Delay_us(2);
    
    // 起始信号    
    P22 = 0;//拉低P22
    Delay_ms(22); //延时22ms               
    P22 = 1;   
​
    // 应答信号
    Delay_30us(1);
        out=0;
    while(!P22)//等待传感器拉低P22
        {
        Delay_us(1);        
        if(out++ > 100) //while内部用于计时,如果超过100us则判断应答失败,应该重新发送起始信号
                        return 0;
    }
    out = 0;
    while(P22) //等待传感器拉高P22
        {
        Delay_us(1);        
        if(out++>100) //while内部用于计时,如果超过100us则判断应答失败,应该重新发送起始信号
                    return 0;
    }
​
    // 读取数据
    for(j=0;j<5;j++)//读取5个字节
        {
        rdata=0;//暂存8位的变量
        for(i=0;i<8;i++)//读取8位 
            {      
            out=0;
            while(!P22)//等待P22拉高
                        {
                Delay_us(1);        
                if (out++>100)//while内部用于计时,如果超过100us则判断应答失败,应该重新发送起始信号
                                    return 0;
            }
            Delay_us(40);
            rdata<<=1;    
            if(P22)//如果此时P22为高电平,则判断为数据为“1” 
                        {
                                rdata|=0x01;
                        }
            out=0;
            while(P22)//等待P22拉低,以读取下一个位 
                        {
                Delay_us(1);        
                if(out++ > 100)//while内部用于计时,如果超过100us则判断应答失败,应该重新发送起始信号
                                        return 0;
            }
        }
        arr[j]=rdata;//将暂存的(1字节)数据分别放入数组中
    }
    return 1;
}
​
char* intToStr(unsigned char num) {
    static char str[4]; 
    int i=3;
    str[i]='\0';//结尾符
    i--;
​
    if (num==0) 
        {
        str[i]='0';
        i--;
    } 
        else 
        {
        while (num>0) 
                {
            str[i]='0'+(num%10);
            num/=10;
            i--;
        }
    }
    return &str[i+1];//从下标0开始
}

DHT11.h

#ifndef __DHT11_H__
#define __DHT11_H__
​
typedef struct Dht11
{
    unsigned char rdata[5];//数据位+校验位40位数据
    
}DHT11_ObjectTypedef;
​
void DHT11_Init(unsigned char* rdata);
//该DHT11在40MHZ运行
unsigned char DHT11_Read(unsigned char* rdata);
char* intToStr(unsigned char num);
​
#endif

UART.C

#include "main.h"
​
//串口发送一个字符
void SendChar(char dat)
{
    unsigned char i;
    //起始信号
    P31=0;
    Pote(1);
​
    //发送8bit
    for(i=0; i<8; i++) 
        {
        P31 = dat & 0x01;
        Pote(1);
        dat >>= 1;
    }
        
    //结束信号
    P31=1;
    Pote(1);
}
​
//串口发送字符串
void SendString(char *s)
{
    while (*s) 
        {
        SendChar(*s);  
        s++;                            
    }
}

UART.H

#ifndef __UART_H__
#define __UART_H__
​
​
​
//串口发送一个字符
void SendChar(char dat);
//串口发送字符串
void SendString(char *s);
#endif

Delay.c

#include "main.h"
​
void Pote(unsigned int time)//40mhz
{
    unsigned int i;
    unsigned int j;
    for(j=0;j<time;j++)
    {
        for(i=0;i<462;i++)
        {
            _nop_();
        }
  }
}
​
void Delay_ms(unsigned int time)//40mhz
{
    unsigned int i;
    unsigned int j;
    for(j=0;j<time;j++)
    {
        for(i=0;i<4973;i++)
        {
            _nop_();
        }
  }
}
​
​
void Delay_us(unsigned int time)//40mhz
​
{
    unsigned int i;
    unsigned int j;
    for(j=0;j<time;j++)
    {
        for(i=0;i<1;i++)
        {
            _nop_();
        }
  }
}
​
void Delay_30us(unsigned int time)//40mhz
{
    unsigned int i;
    unsigned int j;
    for(j=0;j<time;j++)
    {
        for(i=0;i<107;i++)
        {
            _nop_();
        }
  }
}
​

Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__
​
void Pote(unsigned int time);//40mhz
void Delay_ms(unsigned int time);//40mhz
void Delay_us(unsigned int time);//40mhz
void Delay_30us(unsigned int time);//40mhz
​
#endif
​
6.结果展示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1864366.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《Three.JS零基础入门教程》第九篇:环境详解

往期回顾&#xff1a; 《Three.JS零基础入门教程》第一篇&#xff1a;搭建开发环境 《Three.JS零基础入门教程》第二篇&#xff1a;起步案例 《Three.JS零基础入门教程》第三篇&#xff1a;开发辅助 《Three.JS零基础入门教程》第四篇&#xff1a;基础变换 《Three.JS零基…

数据处理神器Elasticsearch_Pipeline:原理、配置与实战指南

文章目录 &#x1f4d1;引言一、Elasticsearch Pipeline的原理二、Elasticsearch Pipeline的使用2.1 创建 Pipeline2.2 使用 Pipeline 进行索引2.3 常用的 Processor 三、实际应用场景3.1 日志数据处理3.2 数据清洗和标准化3.3 数据增强 四、最佳实践4.1 性能优化4.2 错误处理4…

【CPP】类 -- class 使用思想

目录 3 类 -- class3.1 什么是类3.2 类的定义3.3 类内参数的使用3.4 类与结构体 -- class VS struct3.5 类的实操 -- log类(日志类)3.6 类定义 与 static 3 类 – class 3.1 什么是类 类是面向对象的一种设计,其中封装了我们对对象的"描述",或者说对象的"特征…

生命在于学习——Python人工智能原理(4.6)

在这里插一句话&#xff0c;我有两个好兄弟的github项目&#xff0c;感兴趣的可以去看一下&#xff0c;star一下&#xff0c;谢谢。 https://github.com/fliggyaa/fscanpoc https://github.com/R0A1NG/Botgate_bypass 四、Python的程序结构与函数 4.1 Python的分支结构 &…

C语言——链表专题

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 点击主页&#xff1a;optimistic_chen和专栏&#xff1a;c语言&#xff0c; 创作不易&#xff0c;大佬们点赞鼓…

国产操作系统上多种压缩和解压命令详解 _ 统信 _ 麒麟 _ 中科方德

原文链接&#xff1a;国产操作系统上多种压缩和解压命令详解 | 统信 | 麒麟 | 中科方德 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在国产操作系统上多种压缩和解压命令详解的文章。压缩和解压缩是我们在日常工作中经常需要进行的操作&#xff0c;尤其是在处理大…

49-2 内网渗透 - 使用UACME Bypass UAC

靶场准备: 1. 使用已有的 Windows 2012 虚拟机 确保你的虚拟机正在运行,并且可以正常访问。2. 添加 test 用户到管理员组(如上篇文件添加过了就跳过这一步) 具体命令如下: net localgroup administrators test /add 3. 切换用户登录 注销当前会话,并使用 test 用户登录。…

理解MySQL索引:提升查询性能的关键

一、前言 在众多数据库中&#xff0c;MySQL以其高效、稳定和跨平台的特点成为许多开发者的首选。然而&#xff0c;随着数据量的不断增加&#xff0c;查询性能可能会成为一个瓶颈。这时&#xff0c;索引&#xff08;Index&#xff09;便成为了提升查询速度的关键工具。本篇文章…

ajax请求接口不设置请求头可以请求成功,但是设置请求头之后就跨域,已解决

遇到这个问题我们不要着急找后端&#xff0c;先通过控制台看看有没有报错&#xff0c;控制台的列表是不会有这个红色报错的&#xff0c;所以我们要看下图&#xff1a; 点击这个红色&#xff0c;然后在下面会出现一些信息 很明显是这个请求头timestamp的请求头被屏蔽了&#xff…

网约车停运损失费:1、事故经过

目录 &#x1f345;点击这里查看所有博文 随着自己工作的进行&#xff0c;接触到的技术栈也越来越多。给我一个很直观的感受就是&#xff0c;某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了&#xff0c;只有经常会用到的东西才有可能真正记…

IT入门知识第八部分《云计算》(8/10)

目录 云计算&#xff1a;现代技术的新篇章 1. 云计算基础 1.1 云计算的起源和发展 云计算的早期概念 云计算的发展历程 1.2 云计算的核心特点 按需自助服务 广泛的网络访问 资源池化 快速弹性 按使用量付费 1.3 云计算的优势和挑战 成本效益 灵活性和可扩展性 维…

Matlab进阶绘图第61期—滑珠散点图

滑珠散点图也是一种在《Nature》中常见的数据图。 其功能类似于柱状图&#xff0c;但更加简洁易读。 由于Matlab中没有现成的函数绘制滑珠散点图&#xff0c;因此需要大家自行解决。 本文利用自己制作的BubbleScatter工具&#xff0c;进行滑珠散点图的绘制&#xff0c;先来看…

验证码技术 easy-captcha

依赖 <!-- easy-captcha用来生成验证码&#xff0c;由于jdk9以后&#xff0c;内置JavaScript去掉了&#xff0c;所以需要导入这个org.openjdk.nashorn --> <dependency><groupId>com.github.whvcse</groupId><artifactId>easy-captcha</arti…

Redis数据库(四):Redis数据库事务

经过前面的学习&#xff0c;我们就对于Redis数据库可以进行基本的操作&#xff0c;从这一节开始&#xff0c;我们就正式学习Redis数据库的相关知识&#xff0c;为以后工作打下坚实的基础。 目录 一、事务&#xff08;了解&#xff09; 1.1 Redis的事务概念 1.2 Redis事务…

黑马程序员——Spring框架——day09——linux初级

目录&#xff1a; 前言 什么是Linux&#xff1f;为什么要学Linux 企业用人要求个人发展需要学完Linux能干什么 1).环境搭建2).常用命令3).安装软件4).项目部署小结2.Linux简介 主流操作系统Linux发展历史Linux系统版本Linux安装 安装方式介绍安装VMware安装Linux网卡设置安装S…

我用过最好的GPT,NewspaceGPT使用心得

记住网址&#xff1a;https://newspace.ai0.cn 前言 只要你能表达明白&#xff0c;NewspaceGPT就不会让你失望。 Gpt4o预测GPT5 IT之家6月22日消息&#xff0c;在美国达特茅斯工程学院周四公布的采访中&#xff0c;OpenAI首席技术官米拉穆拉蒂被问及GPT-5是否会在明年发布&…

Beyond Compare不能比较Selinux te文件的解决方案

Beyond Compare不能比较Selinux te文件的解决方案 Beyond Compare默认不能比较te文件&#xff0c;现象如下&#xff1a; 问题原因&#xff1a; 是Beyond Compare将*.te文件识别为一个可执行文件&#xff0c;但是*.te不是一个可执行文件&#xff0c;所以打不开&#xff1b;即使…

微信群聊不见了?掌握这4个技巧轻松找回,简直太爽了

微信&#xff0c;作为国内最受欢迎的社交应用之一&#xff0c;其群聊功能极大地方便了人们的工作与生活。然而&#xff0c;随着加入的群聊数量日益增多&#xff0c;如何快速找到并管理这些群聊成为了一个难题。 幸运的是&#xff0c;微信提供了一些实用的技巧&#xff0c;帮助…

Vue原生写全选反选框

效果 场景&#xff1a;Vue全选框在头部&#xff0c;子框在v-for循环内部。 实现&#xff1a;点击全选框&#xff0c;所有子项选中&#xff0c;再次点击取消&#xff1b;子项全选中&#xff0c;全选框自动勾选&#xff0c;子项并未全选&#xff0c;全选框不勾选&#xff1b;已选…

2024全国大学生信息安全竞赛(ciscn)半决赛(华中赛区)Pwn题解

简介 前段时间赛前准备把ciscn东北赛区、华南赛区、西南赛区半决赛的题都复现完了。 可惜遇到了华东北赛区的离谱平台和离谱pwn出题人&#xff1a; 假的awdp&#xff08;直接传&#x1f40e;到靶机&#xff0c;然后连上去cat /flag.txt即可&#xff09;题型分布不合理&#…