[单片机芯片]CH32V307驱动单总线温湿度传感器DHT22

2023-05-16

手头有一个DHT22温湿度传感器和CH32V307开发板,可玩性极强。DHT22是已校准的数字温湿度传感器,用于检测环境温湿度,采用DHT22(AM2302),标准单总线接口。拥有比常见的DHT11更高的精度和更大的量程。

DHT22产品主要特性如下:
工作电压:        3.3V-5.5V
湿度分辨率:        0.1%RH
湿度测量范围:        0%RH ~ 99.9%RH
湿度测量误差:        ±2%RH (25°C)
温度分辨率:        0.1°C
温度测量范围:        -40°C ~ 80°C
温度测量误差:        ±0.5℃



DHT22传感器有3个引脚,功能如下:
VCC:电源正(3.3V-5.5V)
GND:电源地
DOUT:通信端口


DHT22器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由数据线完成。单总线通常要求外接一个约 5.1kΩ的上拉电阻,这样,当总线闲置时,其状态为高电平。SDA 用于微处理器与 AM2302 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先出。具体通信时序如图所示:


DHT22通信格式说明:
起始信号: 微处理器把数据总线(SDA)拉低一段时间(至少800μs)[1],通知传感器准备数据。
响应信号: 传感器把数据总线(SDA)拉低80μs,再接高80μs以响应主机的起始信号。
数据格式: 收到主机起始信号后,传感器一次性从数据总线(SDA)串出40位数据,高位先出。
湿度: 湿度分辨率是16Bit,高位在前;传感器串出的湿度值是实际湿度值的10倍。
温度: 温度分辨率是16Bit,高位在前;传感器串出的温度值是实际温度值的10倍;温度最高位(Bit15)等于1表示负温度,温度最高位(Bit15)等
于0表示正温度;温度除了最高位(Bit14~Bit0)表示温度值。
校验位=湿度高位+湿度低位+温度高位+温度低位。

单总线通信时序
用户主机(MCU)发送一次起始信号(把数据总线 SDA 拉低至少 800µs)后, DHT22从休眠模式转换到高速模式。待主机开始信号结束后,DHT22发送响应信号,从数据总线 SDA 串行送出 40Bit的数据,先发送字节的高位;发送的数据依次为湿度高位、湿度低位、温度高位、 温度低位、校验位,发送数据结束触发一次信息采集,采集结束传感器自动转入休眠模式,直到下一次通信来临。

设计一个结构体用来存放温湿度数据:

typedef struct

{

    float hum;

    float temp;

} DHT_data;



typedef struct {

    GPIO_TypeDef *DHT_Port; 

    uint16_t DHT_Pin;       

} DHT_sensor;



外设读取步骤
主机和传感器之间的通信可通过如下三个步骤完成读取数据。
步骤一:
DHT22上电后( DHT22上电后要等待 2S 以越过不稳定状态,在此期间读取设备不能发送任何指令),测试环境温湿度数据,并记录数据,此后传感器自动转入休眠状态。 DHT22的 SDA 数据线由上拉电阻拉高一直保持高电平,此时 AM2302 的 SDA 引脚处于输入状态,时刻检测外部信号。
设置CH32V307 IO为输出模式的代码如下:

static void goToOutput(DHT_sensor *sensor)

{

   GPIO_InitTypeDef GPIO_InitStruct = {0};

   lineUp();



  GPIO_InitStruct.GPIO_Pin = sensor->DHT_Pin;

  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;



  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(sensor->DHT_Port, &GPIO_InitStruct);

}

设置CH32V307 IO为上拉输入模式的代码如下:

static void goToInput(DHT_sensor *sensor)

{

  GPIO_InitTypeDef GPIO_InitStruct = {0};



  GPIO_InitStruct.GPIO_Pin = sensor->DHT_Pin;

  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;

  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(sensor->DHT_Port, &GPIO_InitStruct);

}


步骤二:
微处理器的 I/O 设置为输出, 同时输出低电平,且低电平保持时间不能小于 800us,典型值是拉低 1MS,然后微处理器的 I/O 设置为输入状态,释放总线,由于上拉电阻,微处理器的 I/O 即DHT22的 SDA 数据线也随之变高,等主机释放总线后,DHT22发送响应信号,即输出 80 微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据,信号传输如图所示:

 步骤三:
DHT22 发送完响应后,随后由数据总线 SDA 连续串行输出 40 位数据,微处理器根据 I/O 电平的变化接收 40 位数据。 位数据“0”的格式为: 50 微秒的低电平加 26-28 微秒的高电平; 位数据“1”的格式为: 50 微秒的低电平加 70 微秒的高电平; 位数据“0”、位数据“1”格式信号如图 所示:



DHT22的数据总线 SDA 输出 40 位数据后,继续输出低电平 50 微秒后转为输入状态,由于上拉电阻随之变为高电平。同时 DHT22内部重测环境温湿度数据,并记录数据,测试记录结束,单片机自动进入休眠状态。单片机只有收到主机的起始信号后,才重新唤醒传感器,进入工作状态。
温湿度数据读取函数设计如下:

DHT_data DHT_getData(DHT_sensor *sensor)

{

    DHT_data data = {-128.0f, -128.0f};



    goToOutput(sensor);

    lineDown();

    Delay(18);

    lineUp();

    goToInput(sensor);



    uint16_t timeout = 0;

    while(getLine())

    {

        timeout++;

        if (timeout > DHT_TIMEOUT)

        {

            return data;

        }

    }

    timeout = 0;



    while(!getLine())

    {

        timeout++;

        if (timeout > DHT_TIMEOUT)

        {

            return data;

        }

    }

    timeout = 0;

    while(getLine())

    {

        timeout++;

        if (timeout > DHT_TIMEOUT)

        {

            return data;

        }

    }



    uint8_t rawData[5] = {0,0,0,0,0};

    for(uint8_t a = 0; a < 5; a++)

    {

        for(uint8_t b = 7; b != 255; b--)

        {

            uint16_t hT = 0, lT = 0;

            while(!getLine() && lT != 65535) lT++;

            timeout = 0;

            while(getLine()&& hT != 65535) hT++;

            if(hT > lT) rawData[a] |= (1<<b);

        }

    }



    if((uint8_t)(rawData[0] + rawData[1] + rawData[2] + rawData[3]) == rawData[4])

    {

        data.hum = (float)(((uint16_t)rawData[0]<<8) | rawData[1])*0.1f;

        if(!(rawData[2] & (1<<7)))

        {

            data.temp = (float)(((uint16_t)rawData[2]<<8) | rawData[3])*0.1f;

        }

        else

        {

            rawData[2] &= ~(1<<7);

            data.temp = (float)(((uint16_t)rawData[2]<<8) | rawData[3])*-0.1f;

        }

    }



    return data;

}



DHT22传感器读单总线的流程图示意图如图所示:

 



主程序设计,初始化串口打印,初始化IO结构体:

int main(void)

{

    Delay_Init();

    USART_Printf_Init(115200);

    printf("SystemClk:%d\r\n",SystemCoreClock);



    DHT_sensor dht = {GPIOE, GPIO_Pin_6};

    while(1)

    {

      DHT_data d = DHT_getData(&dht);

      printf("Temp %2.1f°C, Hum %2.1f%%\r\n", d.temp, d.hum);

      Delay_Ms(1000);

    }


线路连接,将DHT22数据线连接到PE6管脚:



运行结果:


完整dht.h代码:

#ifndef DHT_H_

#define DHT_H_



#include "debug.h"



#define DHT_TIMEOUT                 100000



typedef struct

{

    float hum;

    float temp;

} DHT_data;



typedef struct {

    GPIO_TypeDef *DHT_Port; 

    uint16_t DHT_Pin;       

} DHT_sensor;



DHT_data DHT_getData(DHT_sensor *sensor);



#endif



完整dht.c代码:

#include "dht.h"



#define lineDown()      GPIO_ResetBits(sensor->DHT_Port, sensor->DHT_Pin)

#define lineUp()        GPIO_SetBits(sensor->DHT_Port, sensor->DHT_Pin)

#define getLine()       GPIO_ReadInputDataBit(sensor->DHT_Port, sensor->DHT_Pin)

#define Delay(d)        Delay_Ms(d)



static void goToOutput(DHT_sensor *sensor)

{

   GPIO_InitTypeDef GPIO_InitStruct = {0};

   lineUp();



  GPIO_InitStruct.GPIO_Pin = sensor->DHT_Pin;

  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;



  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(sensor->DHT_Port, &GPIO_InitStruct);

}



static void goToInput(DHT_sensor *sensor)

{

  GPIO_InitTypeDef GPIO_InitStruct = {0};



  GPIO_InitStruct.GPIO_Pin = sensor->DHT_Pin;

  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;

  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(sensor->DHT_Port, &GPIO_InitStruct);

}



DHT_data DHT_getData(DHT_sensor *sensor)

{

    DHT_data data = {-128.0f, -128.0f};



    goToOutput(sensor);

    lineDown();

    Delay(18);

    lineUp();

    goToInput(sensor);



    uint16_t timeout = 0;

    while(getLine())

    {

        timeout++;

        if (timeout > DHT_TIMEOUT)

        {

            return data;

        }

    }

    timeout = 0;



    while(!getLine())

    {

        timeout++;

        if (timeout > DHT_TIMEOUT)

        {

            return data;

        }

    }

    timeout = 0;

    while(getLine())

    {

        timeout++;

        if (timeout > DHT_TIMEOUT)

        {

            return data;

        }

    }



    uint8_t rawData[5] = {0,0,0,0,0};

    for(uint8_t a = 0; a < 5; a++)

    {

        for(uint8_t b = 7; b != 255; b--)

        {

            uint16_t hT = 0, lT = 0;

            while(!getLine() && lT != 65535) lT++;

            timeout = 0;

            while(getLine()&& hT != 65535) hT++;

            if(hT > lT) rawData[a] |= (1<<b);

        }

    }



    if((uint8_t)(rawData[0] + rawData[1] + rawData[2] + rawData[3]) == rawData[4])

    {

        data.hum = (float)(((uint16_t)rawData[0]<<8) | rawData[1])*0.1f;

        if(!(rawData[2] & (1<<7)))

        {

            data.temp = (float)(((uint16_t)rawData[2]<<8) | rawData[3])*0.1f;

        }

        else

        {

            rawData[2] &= ~(1<<7);

            data.temp = (float)(((uint16_t)rawData[2]<<8) | rawData[3])*-0.1f;

        }

    }



    return data;

}

 ---------------------
作者:dql2015
链接:https://bbs.21ic.com/icview-3272628-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[单片机芯片]CH32V307驱动单总线温湿度传感器DHT22 的相关文章

  • 树莓派4b连接RealSense T265

    使用的是树莓派4 8G版本 准备连接RealSense T265的双目相机 T265目前官方编译好的的只有Ubuntu16和18 其他的系统版本需要自己编译realsense驱动 安装ubuntu20 10 https ubuntu com
  • Dockerfile文件解释

    一 先来看一个简单的 Dockerfile 这个Dockerfile作用是打一个python3项目环境 FROM python 3 alpine WORKDIR app ADD app RUN pip3 install r requirem
  • 一文读懂BLOB算法

    算法执行效果 相关参考资料 看着玩的 BLOB算法简述 https blog csdn net icyrat article details 6594574 话说这老哥写的也太 简 了吧 完全口水话 把blob算法说的很神秘 说什么把blo
  • Sobel算法优化 AVX2与GPU

    国庆假期 一口气肝了10篇博客 基本上把最近的成果都做了遍总结 假期最后一天 以一个比较轻松的博客主题结束吧 这次是Sobel算法的AVX2优化 执行效果 sobel算法的原理 使用如下的卷积核 c 硬写 span class token
  • 随机Hough直线算法的改进

    背景介绍 随机Hough直线算法相比Hough直线算法 xff0c 算法效率会有提高 xff0c 但仍不能满足工程需求 因此提出使用生长的随机Hough直线算法 该算法对随机Hough直线算法进行改造 xff0c 在随机选点转到Hough空
  • MATLAB编写的读取.mat文件数据并画曲线图的gui程序

    matlab编写的读取sd卡数据的gui程序 界面截图 xff1a 打开文件界面 xff1a 导入数据后截图 xff1a 是不是高端大气上档次 xff0c 不要急 xff0c 慢慢往下看 xff0c 后面更精彩 xff0c 代码会贴出来的
  • px4飞控位置估计lpe移植到vs

    本文主要内容 px4飞控的位置估计有两种方式 xff0c 一是inav xff0c 二是lpe xff0c 用到的传感器用加速度计 xff0c 磁场传感器 xff0c gps xff0c 超声 xff0c 激光 xff0c 气压 xff0c
  • 常见的信号平滑处理方法

    本文介绍了常见的信号平滑处理方法 xff1a xff08 一阶滤波 xff0c 互补滤波 xff0c 卡尔曼滤波 xff09
  • PX4代码学习系列博客(1)——开发环境配置

    写在前面 虽然有很多关于px4博客 xff0c 但还是想自己亲手写 xff0c 一来记录自己的学习过程 xff0c 以备将来复习 xff0c 二来方便后来者参考学习 xff0c 好多西当然要大家分享 关于px4飞控程序的博客 xff0c 我
  • PX4代码学习系列博客(3)——px4固件目录结构和代码风格

    写在前面 px4不是普通的单片机程序 xff0c 其中没有main函数 它实际上是一个操作系统 xff0c 上面运行着很多应用程序 xff08 类比windows xff09 xff0c 比如姿态解算 xff0c 位置解算 xff0c 姿态
  • PX4代码学习系列博客(5)——在px4中添加自己的模块

    怎么在px4中添加自己的模块 在 px4固件目录结构和代码风格 这一节 xff0c 曾经说过NuttX是一个实时的嵌入式系统 xff0c 上面可以像windows那样运行程序 那既然是应用程序 xff0c 那我们应该也能写一些可以在Nutt
  • PX4代码学习系列博客(6)——offboard模式位置控制代码分析

    分析offboard模式的代码需要用到以下几个模块 local position estimator mavlink mc pos control mc att control mixer 程序数据走向 mavlink 一般的offboar
  • selenium安装

    一 安装webdriver 1 下载安装包 下载地址 xff1a CNPM Binaries Mirror 注意 xff1a 下载版本应与自己的chrome的大版本一致 chrome版本查看 xff0c 设置 gt 关于chrome xff
  • 基于惯性轮倒立摆原理的自行车

    背景 自平衡车有很多种 xff0c 其中一种是利用惯性轮倒立摆原理 xff0c 早在2003年 xff0c 日本的村田顽童就已经问世 xff0c 它采用的就是惯性轮倒立摆原理 后来其他研究组织和个人纷纷效仿 xff0c 制作出了五花八门的基
  • 二维码的特征定位和信息识别

    二维码的特征定位和信息识别 背景介绍 视觉的方法可以用来估计位置和姿态 最容易想到的是在目标上布置多个容易识别的特征 xff0c 这样使用opencv相机标定和 相机畸变矫正 轮廓提取 solvepnp来获取目标相对于相机的位姿 在实际使用
  • 学生作业信息管理系统

    一 xff0e 引言 1 1编写目的 首先 xff0c 软件系统的设计报告可以出用户提出的模糊需求分析出具体的工程需求 xff0c 并转化为数据流图 xff0c 程序流程图 xff0c 模块图 xff0c 数据库设计等软件设计必要的底层步骤
  • NVIDIA显卡驱动版本,CUDA版本,cudnn版本之间关系及如何选择

    要配置NVIDIA显卡的CUDA和cudnn xff0c 各种版本之间的依赖关系以及与其他使用GPU的库版本兼容一直没有弄明白 xff0c 最近经过多次卸载重装 xff0c 终于成功配置好了显卡计算环境 xff0c 于是把各个驱动程序和库之
  • 机器人定位误差标定模型

    概述 以工业机器人为基础 xff0c 构建柔性制造单元或柔性生产线 xff0c 实现产品自动化 柔性化 智能化生产必将成为现代制造发展的重点 新型产业环境下 xff0c 工业机器人的应用范围将越来越广泛 作业任务也将越来越精细复杂 xff0
  • 觉得C/C++难懂的、面临找工作面试笔试的,速来看这本书!

    如果你是C C 43 43 的初学者 xff0c 请看这本书 xff0c 因为其他的书也许你看了还不如不看 xff0c 一定要选一本好书 xff1b 如果你正准备求职 xff0c 那么请认真看这本书 xff0c 因为这本书会教会你工作中必备
  • rosdep update错误失败一直timeout解决方法

    更新rosdep 终端输入 rosdep update 失败1 The read operation timed out xff08 包括ERROR unable to process source xff0c ERROR error lo

随机推荐

  • bat, shell脚本ssh自动输入密码

    我电脑是win11 xff0c 并且自带ubuntu系统 xff0c 打开cmd xff0c 然后输入ubuntu xff0c 可以直接进入ubuntu系统 xff0c 然后执行简单的linux命令 我在两个系统下都写了自动连接远程服务的脚
  • FreeRtos 文件结构

    最核心的三个文件 1 xff09 tasks c 2 xff09 list c 3 xff09 queue c tasks c 任务相关 list c 为一个双向链表 queue c 队列 xff0c 信号量用于任务间通讯 4 xff09
  • 论文超详细精读:SMPL: A Skinned Multi-Person Linear Model

    文章目录 前言总览一 Introduction二 Related WorkBlend Skinning xff08 混合蒙皮 xff09 Blend shapes xff08 混合变形 xff09 Learning pose and sha
  • 1、列表推导式、字典推导式

    34 34 34 1 列表推导式 xff1a 作用 快速生成列表 需求1 xff1a 如何快速生成一个 34 data0 34 34 data1 34 34 data99 34 的列表 语法 xff1a y for x in xxx 实现
  • pwm超详细解读,大佬细说pwm的控制方式

    pwm xff0c 也就是常说的脉冲宽度调制脉冲宽度调制技术 目前 xff0c pwm技术的应用是非常多的 为了增进大家对pwm的认识 xff0c 本文将对pwm 的几种控制方法进行详细的阐述 xff0c 保证大家彻底理解 如果你对pwm
  • WiFi信号覆盖面积小?如何扩大Wifi信号覆盖范围?

    WiFi已是现代生活不可缺少的组成之一 xff0c 在WiFi的帮助下 xff0c 一个家庭网络或办公网络 xff0c 能够通过无线的方法连接诸多设备 为增进大家对WiFi的认识 xff0c 本文将对WiFi以及扩大WiFi信号覆盖范围的方
  • 数据存储方式有哪些?这3种数据存储方式了解吗?

    数据存储具有很强的现实意义 xff0c 只有采取合理的数据存储方式 xff0c 才能够有利于数据的管理 检索等 为增进大家对数据存储方式的认识 xff0c 本文将对三种数据存储方式予以介绍 如果你对数据存储方式具有兴趣 xff0c 不妨继续
  • 这里带你了解IR2104驱动电路

    Ir2014驱动电路及自举电容的应用 以前做智能车的时候用H桥驱动电路 xff0c 驱动芯片就是用的IR2104 xff0c MOS管用的IR7843 xff0c 想把以前的知识总结一下 1 为什么需要H桥电路 因为驱动电机正反转 xff0
  • 什么是神经网络模型,常见神经网络模型有哪些?

    神经网络模型是机器学习 深度学习的核心 xff0c 针对不同的问题 xff0c 我们需要搭建不同的神经网络模型 为增进大家对神经网络模型的认识 xff0c 本文将对常见的神经网络模型予以介绍 如果你对神经网络模型具有兴趣 xff0c 不妨继
  • STM32L431使用TencentOS tiny操作系统连接腾讯物联网开发平台

    去年腾讯为了宣传自己针对物联网的开源操作系统TencentOS tiny xff0c 举办了一场试用活动 xff0c 当时幸运获得一块 板子实物就这样 xff0c 没啥好介绍的 xff0c 都是基础的外设 xff0c 如今闲来无事 xff0
  • [总线技术]汽车ECU网络传输-诊断协议测试-基于Canoe软件CAPL脚本编写

    一 xff0e 汽车电子电控结构 先介绍一下汽车电子电控的结构 xff0c 汽车并不像电脑一样 xff0c 只有一个CPU xff0c 而是分为多个 CPU 独立工作 xff0c 就是由很多很多个控制器组成的 xff0c 比如 xff1a
  • [STM32F1]关于STM32F103芯片按钮机制串口发送程序

    就是目前遇到一个项目 xff0c 是监视各个按钮状态并将各个按钮的状态发送至上位机 xff0c 上位机进行整体程序逻辑动作 一般情况下串口发送可以直接一直发送给上位机 xff0c 通过解析不同数据位0和1的状态可以知道具体哪个按钮按下 xf
  • [uCOS/RTOS]freertos——创建任务(一)

    FreeRTOS操作系统学习 前言 FreeRTOS操作系统的学习正式开始 一 了解FreeRTOS FreeRTOS共有32个优先级 xff08 0 31 xff09 使用时0和31不使用 优先级规则 xff1a 数字越大优先级越高 任务
  • 基于FreeRTOS的UART空闲中断框架设计

    设计背景 xff1a 针对大部分国产低端MCU ARM CortexM0 来说 xff0c 并没有空闲中断 xff0c 此时就需要一个定时器Timer配合来完成此任务 对于UART接受不定长数据 xff0c 空闲中断还是非常实用的 xff0
  • 2、可迭代对象与迭代器

    1 Iterable 可迭代对象 概念 xff1a python中能够使用for循环遍历的都是可迭代对象 1 常见的可迭代对象 1 1 序列如 xff1a list str tuple range 1 2 非序列 xff1a dict se
  • 帮你分清嵌入式与单片机

    从事计算机和或电子行业相关领域工作的朋友 xff0c 一般都听说过单片机和嵌入式 但是要问单片机和嵌入式两者之间有什么联系 xff0c 大多数人都不能很好的解释清楚 想要弄清楚嵌入式和单片机有什么联系 xff0c 首先就要弄明白什么是嵌入式
  • [MM32生态]Python,让嵌入式应用开发更便捷、更高效、更专注

    前言 前面分享了基于PikaScript如何在MM32平台上部署Python开发环境的帖子 xff0c 实现了Python基础开发环境的部署 xff0c 可以通过串口终端软件在线编写Python xff0c 然后直接运行得到结果 通过Pyt
  • [STM32]STM32移植freemodbus实现modbusTCP

    上次说到采用STM32F1移植了FreeModbus协议栈进行开发实现ModBus RTU协议来进行一些线圈寄存器的控制 xff08 继电器开关 xff09 和一些保持寄存器的读写 xff08 参数配置灯 xff09 xff0c 这次说一下
  • FR8012HAQ利用ADC实现检测电池电压检测的解决方案

    今天要跟大家分享的是FR8012HAQ利用ADC实现检测电池电压检测的解决方案 FR8012HAQ是富芮坤的一款通用蓝牙芯片 特性介绍如下图 xff1a 我们再来看FR8012HAQ的PMU xff0c 它强大的地方还在于内置了充电模块 F
  • [单片机芯片]CH32V307驱动单总线温湿度传感器DHT22

    手头有一个DHT22温湿度传感器和CH32V307开发板 xff0c 可玩性极强 DHT22是已校准的数字温湿度传感器 xff0c 用于检测环境温湿度 xff0c 采用DHT22 AM2302 xff0c 标准单总线接口 拥有比常见的DHT