当前位置: 首页 > news >正文

dht11传感器总结

设备树规定GPIO

在设备树规定使用的IO口

	/*DT11 gpio4 23*/
/{	dht11 {compatible = "imx6ull,dht11";pinctrl-names = "default";pinctrl-0 = <&pinctrl_dht11>;dht11-gpios = <&gpio4 23 GPIO_ACTIVE_HIGH>; // 新添加的 GPIO,用于 DHT11 数据status = "okay";};
}&iomuxc{pinctrl_dht11: dht11grp {fsl,pins = <MX6UL_PAD_CSI_DATA02__GPIO4_IO23 0x10B0 >;};
}

驱动程序

dth11协议
在这里插入图片描述

判断dht11的响应信号(低脉冲持续 80us,高脉冲持续 80us)

static int dht11_wait_for_ready(void)
{int timeout_us = 20000;// 检查 GPIO 描述符是否有效if (!is_dht11_gpio_valid()) {printk(KERN_ERR "DHT11: dht11_gpio invalid in dht11_wait_for_ready (start)\n");return -EFAULT;}// 等待低电平(主机开始信号)while (gpiod_get_value(dht11_gpio) && --timeout_us){udelay(1);}if (!timeout_us){printk("%s %s line %d timeout waiting for low\n", __FILE__, __FUNCTION__, __LINE__);return -1;}// 等待高电平(DHT11响应信号开始)timeout_us = 80;  // 高电平持续时间为 80uswhile (!gpiod_get_value(dht11_gpio) && --timeout_us){udelay(1);}if (!timeout_us){printk("%s %s line %d timeout waiting for high\n", __FILE__, __FUNCTION__, __LINE__);return -1;}// 等待低电平(DHT11响应信号结束)timeout_us = 80;  // 低电平持续时间为 80uswhile (gpiod_get_value(dht11_gpio) && --timeout_us){udelay(1);}if (!timeout_us){printk("%s %s line %d timeout waiting for low after high\n", __FILE__, __FUNCTION__, __LINE__);return -1;}return 0;   
}

判断dht11接受到的字节是0或1

/* 读取 DHT11 一个字节的数据 */
static int dht11_read_byte(unsigned char *buf)
{int i;int us = 0;unsigned char data = 0;// 检查 GPIO 描述符是否有效if (!is_dht11_gpio_valid()) {printk(KERN_ERR "DHT11: dht11_gpio invalid in dht11_read_byte (start)\n");return -EFAULT;}for (i = 0; i < 8; i++){int timeout_us = 400; // 重置超时us = 0;// 等待高电平while (!gpiod_get_value(dht11_gpio) && --timeout_us){udelay(1);us++;}if (!timeout_us){printk("%s %s line %d timeout waiting for high in bit %d\n", __FILE__, __FUNCTION__, __LINE__, i);return -1;}udelay(40); // 高电平持续时间,用于判断位是 0 还是 1// 检查 GPIO 值,判断是 0 还是 1if (gpiod_get_value(dht11_gpio)){data = (data << 1) | 1; // 获取 bit 1timeout_us = 400; // 重置超时us = 0;while (gpiod_get_value(dht11_gpio) && --timeout_us){udelay(1);us++;}if (!timeout_us){printk("%s %s line %d timeout waiting for low after bit 1 in bit %d\n", __FILE__, __FUNCTION__, __LINE__, i);return -1;}}else{data = (data << 1) | 0; // 获取 bit 0}}*buf = data; // 返回读取的字节数据return 0;
}

与用户空间交互

严格执行协议的a到e步骤

static ssize_t dht11_read(struct file *file, char __user *buf, size_t size, loff_t *offset){int i;int re;unsigned char data[5];unsigned long flags;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);// 检查读取的数据大小if(size != 4){printk(KERN_ERR "DHT11: Read size must be 4 bytes, got %zu\n", size);return -EINVAL;}// 检查 dht11_gpio 是否有效if (!is_dht11_gpio_valid()) {printk(KERN_ERR "DHT11: dht11_gpio invalid in dht11_read (top)\n");return -EFAULT;}local_irq_save(flags);    // 关中断,保护时序敏感操作// 设置 GPIO 引脚方向为输出并拉高gpiod_direction_output(dht11_gpio, 1); mdelay(30); // 等待传感器准备gpiod_set_value(dht11_gpio, 0); // 拉低总线,发送启动信号mdelay(20); // 延时 20msgpiod_set_value(dht11_gpio, 1); // 拉高总线udelay(40); // 延时 40usgpiod_direction_input(dht11_gpio); // 切换为输入模式udelay(2); // 稍作延时if (dht11_wait_for_ready()) {local_irq_restore(flags); // 恢复中断printk("%s %s line %d dht11_wait_for_ready failed\n", __FILE__, __FUNCTION__, __LINE__);return -EAGAIN;}// 读取 5 字节数据for (i = 0; i < 5; i++){if (dht11_read_byte(&data[i])) {local_irq_restore(flags); // 恢复中断printk("%s %s line %d dht11_read_byte failed for byte %d\n", __FILE__, __FUNCTION__, __LINE__, i);return -EAGAIN;}}// 校验码验证if (data[4] != (data[0] + data[1] + data[2] + data[3])) {printk(KERN_WARNING "DHT11: Checksum mismatch! Data: %d %d %d %d, Checksum: %d, Expected: %d\n",data[0], data[1], data[2], data[3], data[4], (data[0] + data[1] + data[2] + data[3]));}printk("data %d %d\n", data[0], data[2]); // 打印湿度和温度数据// 将数据拷贝到用户空间re = copy_to_user(buf, data, 4);if (re != 0) {printk(KERN_ERR "DHT11: Failed to copy data to user space: %d\n", re);return -EFAULT;}return 4; // 返回读取的字节数
}

probe函数获取硬件资源

/* 5.1 实现 probe 函数 */
static int dht11_probe(struct platform_device *dev)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);/* 获取硬件资源 */dht11_gpio = gpiod_get(&dev->dev, "dht11", GPIOD_OUT_HIGH);if (IS_ERR(dht11_gpio)) {int err = PTR_ERR(dht11_gpio);dev_err(&dev->dev, "Failed to get dht11 GPIO: %d\n", err);return err;}dev_info(&dev->dev, "Successfully got dht11 GPIO\n");/* 创建设备节点,用户空间可以访问 */device_create(dht11_class, NULL, MKDEV(major, 0), NULL, "querydht11");return 0;
}

入口函数与出口函数

注册字符设备、创建类、注册平台驱动
注销字符设备、注销类、注销平台驱动

应用函数

open打开设备节点,然后再用read读传感器的信息

#include "dht11.h"
#include <QFile>temper::temper()
{}temper::~temper()
{}void temper::run()
{QFile file;QString fileName = "/dev/querydht11";file.setFileName(fileName);file.open(QIODevice::ReadWrite | QIODevice::Unbuffered);    //非缓冲读取while(!stop){file.read(reinterpret_cast<char*>(databuf), sizeof(databuf));if(databuf[0] > 0 && databuf[0] < 100 && databuf[1] > 0 && databuf[1]){     //判断数据是否正确for(int i = 0; i < 100; i++){if(!stop){msleep(100);    //每10s读一次数据}}}else{      //数据不对重读msleep(1000);continue;}}file.close();
}void temper::getData(int delay)
{//获取一次数据后退出while(1){QFile file;QString fileName = "/dev/dth11";file.setFileName(fileName);file.open(QIODevice::ReadWrite | QIODevice::Unbuffered);file.read(reinterpret_cast<char*>(databuf), sizeof(databuf));file.close();if(databuf[0] > 0 && databuf[0] < 100 && databuf[1] > 0 && databuf[1]){break;}msleep(delay);}
}void temper::temperStop()
{stop = 1;
}

QT中

启动线程,并且设计定时器定时更新界面

    // 启动温湿度读取线程myTemper = new temper();  // 创建温湿度线程对象myTemper->getData(500);  // 启动线程进行温湿度数据获取myTemper->start();  // 启动线程ui->lineEdit->setText("湿度:" + QString::number(myTemper->databuf[0]) + "%");  // 显示湿度ui->lineEdit_2->setText("温度:" + QString::number(myTemper->databuf[1]) + "℃");  // 显示温度
    // 每60秒更新一次温湿度数据if(timerNums > 600){    // 60s测一次myTimer->stop();  // 停止定时器myTemper->getData(500);  // 获取温湿度数据if(myTemper->databuf[0] > 0 && myTemper->databuf[0] < 100 && myTemper->databuf[1] > 0 && myTemper->databuf[1]){ui->lineEdit->setText("湿度:" + QString::number(myTemper->databuf[0]) + "%");  // 更新湿度显示ui->lineEdit_2->setText("温度:" + QString::number(myTemper->databuf[1]) + "℃");  // 更新温度显示}timerNums = 0;  // 重置计时器计数myTimer->start();  // 重启定时器
http://www.dtcms.com/a/355538.html

相关文章:

  • [灵动微电子 MM32BIN560CN MM32SPIN0280]读懂电机MCU之串口DMA
  • 【C++游记】子承父业——乃继承也
  • 91美剧网官网入口 - 最新美剧资源在线观看网站
  • 保姆级教程 | 在Ubuntu上部署Claude Code Plan Mode全过程
  • 【论文阅读】MotionXpert:基于肌电信号的优化下肢运动检测分类
  • Spring事务管理机制深度解析:从JDBC基础到Spring高级实现
  • [灵动微电子MM32SPIN0280]从灵动微电子看电机专用MCU
  • Deeplizard 深度学习课程(五)—— 模型训练
  • 数据结构01:顺序表
  • react Antd Table 多选大数据量 UI渲染很慢的解决方案
  • 每日五个pyecharts可视化图表日历图和箱线图:从入门到精通
  • ChatGPT登录,拒绝访问,错误1020解决办法
  • THM Whats Your Name WP
  • QT .pro文件的常见用法
  • 与trae携手,构建owtb一体化物流平台之--需求文档V0.3
  • RTL8198E SDK温控机制
  • 家电公司跨界造车,追觅能否造出“电动时代的布加迪”
  • 【架构师干货】软件工程
  • 从卡顿到丝滑:大型前端项目 CSS 优化全攻略
  • Agent实战教程:Langgraph的StateGraph以及State怎么用
  • 如何安装InfluxDB 1.7.0 Windows版(influxdb-1.7.0_windows_amd64.exe使用方法附安装包下载)​
  • 群晖 DS225+ 和绿联 DXP2800:企业文件备份方案对比
  • 仿生纺织飞行模块专利拆解:螺旋旋转结构的空气动力学与升力产生机制
  • curl打印信息实现
  • 如何将yolo训练图像数据库的某个分类的图像取出来
  • Step-by-Step: 接入淘宝商品详情 API 并解析返回数据
  • 无人机+AI光伏热斑检测技术
  • 大模型训练中对SFT和DPO的魔改——PROXIMAL SUPERVISED FINE-TUNING和Semi-online DPO论文阅读笔记
  • 锁的种类都有什么
  • Vue3 + Rsbuild 完全指南:10倍构建速度的现代前端开发方案