ds18b20-温度传感器-linux驱动-混杂设备

news2024/9/17 7:28:45

文章目录

  • ds18b20读取温度数据步骤
  • ds18b20时序图:
    • 初始化时序
      • DS18B20初始化时序的步骤:
    • 读/写时序
      • DS18B20写步骤:
      • DS18B20读步骤:
  • DS18B20驱动实现
      • 结果如下:
      • 参考:

ds18b20读取温度数据步骤

  1. 初始化:将总线拉低至少480μs,然后释放总线并等待15μs。
  2. 发送“跳过ROM”命令(0xCC):该命令用于跳过在总线上连接的所有设备的唯一地址,直接定位到DS18B20。
  3. 发送“温度转换”命令(0x44):该命令告诉DS18B20开始进行温度转换,并将其存储在内部寄存器中。转换时间取决于DS18B20的分辨率设置,通常在750ms左右。
  4. 等待温度转换结束:可以使用忙等待方式,不断地向DS18B20发送“读取状态”命令(0xBE),当DS18B20返回0xFF时,表明温度转换已经完成。
  5. 发送“读取数据”命令(0xBE):该命令用于从DS18B20的内部寄存器中读取转换后的温度值。
  6. 读取温度值:从总线上读取9个字节的数据,其中第一个字节是温度的低8位,第二个字节是温度的高8位,第三个字节是温度的符号位(0代表正数,1代表负数),后面6个字节是校验位。
  7. 计算温度值:将低8位和高8位按照二进制拼接成16位的原始温度值,然后按照符号位进行判断,将原始温度值转换为实际温度值。

ds18b20时序图:

初始化时序

在这里插入图片描述

DS18B20初始化时序的步骤:

  1. 必须要拉低至少480us,这是复位信号;
  2. 然后拉高释放总线,等待15~60us之后,
  3. 若存在DS18B20,其会拉低总线60~240us表示DS18B20初始化复位成功。

读/写时序

在这里插入图片描述

DS18B20写步骤:

  • 写0,拉低至少60us,写周期为60-120us
  • 写1,拉低1us,写周期至少60us

DS18B20读步骤:

  • 整个读周期需要在15us内完成
  • 主机拉低总线至少1us,接着读取总线电平,为0表示读到的bit数据为0,若为1则表示读到数据是1

DS18B20驱动实现

使用混杂设备驱动框架

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/ioctl.h>
#include <cfg_type.h>
#include <linux/miscdevice.h>
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/ktime.h>


// DS18B20设备节点名称
#define DS18B20_DEV_NAME    "ds18b20"
// DS18B20设备资源定义
#define DS18B20_GPIO_PIN 	(PAD_GPIO_C + 17)


static void ds18b20_delay_us(int us)
{
	ktime_t kt;
	u64 pre,last;
	kt = ktime_get();
	pre = ktime_to_ns(kt);
	while(1)
	{
		kt = ktime_get();
		last = ktime_to_ns(kt);
		if(last-pre >= us*1000)
		{
			break;
		}
	}
}
static int ds18b20_pulse_init(void) {
    /* 设置引脚为输出模式 */
    gpio_direction_output(DS18B20_GPIO_PIN, 0);
    ds18b20_delay_us(500);  // 拉低至少480微秒
    gpio_direction_input(DS18B20_GPIO_PIN);
    ds18b20_delay_us(80);   // 等待传感器拉低
    if (gpio_get_value(DS18B20_GPIO_PIN) == 0) {  // 如果传感器存在
        ds18b20_delay_us(120);  // 等待传感器完成初始化
        return 1;
    }
    return 0;
}

static void ds18b20_write_bit(int bit) {
    gpio_direction_output(DS18B20_GPIO_PIN, 0);
    if (bit)
        ds18b20_delay_us(10);
    else
        ds18b20_delay_us(60);
    gpio_direction_input(DS18B20_GPIO_PIN);
    ds18b20_delay_us(10);
}

static void ds18b20_write_byte(uint8_t data) {
    int i;
    for (i = 0; i < 8; i++) {
        ds18b20_write_bit(data & 0x01);
        data >>= 1;
    }
}

static uint8_t ds18b20_read_bit() {
    uint8_t bit;
    gpio_direction_output(DS18B20_GPIO_PIN, 0);
    ds18b20_delay_us(2);
    gpio_direction_input(DS18B20_GPIO_PIN);
    ds18b20_delay_us(10);
    bit = gpio_get_value(DS18B20_GPIO_PIN);
    ds18b20_delay_us(48);
    return bit;
}

static uint8_t ds18b20_read_byte() {
    uint8_t data = 0;
    int i;
    for (i = 0; i < 8; i++) {
        data |= ds18b20_read_bit() << i;
    }
    return data;
}

static float ds18b20_read_temperature() {
    uint8_t temp_l, temp_h;
    float temp;
    if (!ds18b20_pulse_init()) {
        printk(KERN_ERR "DS18B20 sensor not found\n");
        return -1.0;
    }
    ds18b20_write_byte(0xCC);  // 跳过ROM指令
    ds18b20_write_byte(0x44);  // 温度转换命令
    mdelay(800);  				// 等待转换完成 至少750ms
    if (!ds18b20_pulse_init()) {
        printk(KERN_ERR "DS18B20 sensor not found\n");
        return -1.0;
    }
    ds18b20_write_byte(0xCC);  // 跳过ROM指令
    ds18b20_write_byte(0xBE);  // 读取scratchpad命令
    temp_l = ds18b20_read_byte();
    temp_h = ds18b20_read_byte();
    temp = ((temp_h << 8) | temp_l) / 16.0;
    return temp;
}


static ssize_t ds18b20_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{

	float temp = ds18b20_read_temperature();
    if (copy_to_user(buf, &temp, sizeof(temp)))
    {
        printk(KERN_ERR "ds18b20: failed to copy data to user\n");
        return -EFAULT;
    }

    *f_pos += sizeof(temp);
    return sizeof(temp);
}


static struct file_operations ds18b20_fops = {
	.owner          =   THIS_MODULE,
	.read           =   ds18b20_read,
};

static struct miscdevice gec6818_adc_miscdev = {
	.minor		= MISC_DYNAMIC_MINOR,	//MISC_DYNAMIC_MINOR,动态分配次设备号
	.name		= "ds18b20",		//设备名称,/dev/ds18b20	
	.fops		= &ds18b20_fops,	//文件操作集
};

static int __init ds18b20_init(void)
{
	int ret = -1;
	//混杂设备的注册
	ret = misc_register(&gec6818_adc_miscdev);
	if (ret) {
		printk("7""misc_register fail\n");
		goto err_misc_register;
	}

	gpio_free(DS18B20_GPIO_PIN);	//防止gpio驱动有冲突先释放
	ret = gpio_request(DS18B20_GPIO_PIN, "ds18b20");
	if(ret < 0) {
		printk(KERN_ERR"gpio_request fail\n");
		goto err_gpio_request;
	}

	printk(KERN_INFO "ds18b20: ds18b20 init.\n");
	return 0;

err_gpio_request:
	misc_deregister(&gec6818_adc_miscdev);
err_misc_register:
	return ret;
}

static void __exit ds18b20_exit(void)
{
	misc_deregister(&gec6818_adc_miscdev);
	gpio_free(DS18B20_GPIO_PIN);
	printk(KERN_INFO "ds18b20: ds18b20 exit.\n");
}

module_init(ds18b20_init);
module_exit(ds18b20_exit);
MODULE_LICENSE("GPL");

test.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#define DS18B20_DEV_NAME            "/dev/ds18b20"

int main(int argc, char **argv)
{
    int fd;
    int ret;
    float temp;
    // 打开设备节点
    fd = open(DS18B20_DEV_NAME, O_RDWR);
    if (fd < 0) {
        perror("open");
        exit(1);
    }

    while(1) {

	    // 读取温度值
	    ret = read(fd, &temp, sizeof(temp));
	    if (ret < 0) {
	        perror("read");
	        close(fd);
	        exit(1);
	    }
        printf("tmp = %f\n",temp);
	    sleep(1);
    }

    // 关闭设备节点
    close(fd);

    return 0;
}

结果如下:

在这里插入图片描述

参考:

https://cloud.tencent.com/developer/article/1974916

https://blog.csdn.net/qq_36413982/article/details/122674749

https://blog.csdn.net/qq_45661238/article/details/114002415

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

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

相关文章

对话ChatGPT:Prompt是普通人“魔法”吗?

在ChatGPT、Midjourney、Stable Diffusion等新事物的作用下&#xff0c;不少人或多或少听说过Prompt的概念。 虽然OpenAI掀起的大模型浪潮再度刷新了人们对AI的认知&#xff0c;但现阶段的AI终归还不是强人工智能&#xff0c;大模型里的“知识”存储在一个隐性空间里&#xff0…

工地高空作业安全带穿戴识别 python

工地高空作业安全带穿戴识别系统通过pythonopencv网络模型分析技术&#xff0c;工地高空作业安全带穿戴识别算法模型对现场监控画面中人员安全绳安全带穿戴进行检测&#xff0c;不需人为干预立即触发告警存档。OpenCV的全称是Open Source Computer Vision Library&#xff0c;是…

【Ruby 2D】【unity learn】抬头显示血条

说起游戏开发&#xff0c;大家一般会觉得控制角色移动和制作血条哪个难呢&#xff1f; 或许都会觉得血条比较难吧。 是的&#xff0c;正是如此。 那么我们让我们来看看血条该怎么做吧 这是效果图 受伤后是这样的 首先是创建一张Canvas画布 这个画布会很大 相比之下我们的小…

【redis】BigKey

【redis】BigKey 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章…

ChatGPT云桌面:无需科技挂载,即点即用

ChatGPT是一个由OpenAI开发的人工智能对话语言模型。它被设计为对话式人工智能代理&#xff0c;用于客户服务、个人助理和文娱等任务。它可以理解并生成多种语言的文本&#xff0c;包括中文、英语、西班牙语、德语等。但从某些地方访问ChatGPT可能很困难&#xff0c;特别是在注…

实验4 Matplotlib数据可视化

1. 实验目的 ①掌握Matplotlib绘图基础&#xff1b; ②运用Matplotlib&#xff0c;实现数据集的可视化&#xff1b; ③运用Pandas访问csv数据集。 2. 实验内容 ①绘制散点图、直方图和折线图&#xff0c;对数据进行可视化&#xff1b; ②下载波士顿数房价据集&#xff0c;并…

机器学习 -- 过拟合与欠拟合以及应对过拟合的方法 神经网络中的超参数如何选择

前言 在学习机器学习的过程中&#xff0c;训练模型时常遇到的问题就是模型的过拟合和欠拟合&#xff0c;下文我将解释过拟合和欠拟合的概念&#xff0c;并且学习应对过拟合以及神经网络中的超参数如何选择的方法。 过拟合和与欠拟合 过拟合&#xff1a;是指学习时选择的模型…

基于 Git 的开发工作流——主干开发特性总结

在参与开发的过程&#xff0c;得益与平台提供便捷的开发流程&#xff0c;简化很多开发过程操作分支的步骤&#xff1b;也就很好奇&#xff0c;为什么研发平台怎么设计&#xff0c;考虑的点是为什么&#xff0c;便有了这次对主干研发的学习与记录。当我们是构建软件项目的唯一开…

【计算机网络-传输层】TCP 协议

文章目录1 传输层概述1.1 传输层的功能1.2 端口号2 TCP 报文段2.1 TCP 报文段首部格式2.2 TCP 数据传送的过程3 TCP 连接管理3.1 TCP 连接的建立——三次握手3.1.1 客户机向服务器发送 TCP 连接请求报文段3.1.2 服务器向客户机发送 TCP 连接请求确认报文段3.1.3 客户机向服务器…

python数据可视化玩转Matplotlib subplot子图操作,四个子图(一包四),三个子图,子图拉伸

目录 一、创建子图 1.1 下图是绘制的子图&#xff1a; 1.2 代码释义&#xff1a; 二、绘制子图 2.1 代码引入 2.2 图形绘制 三、子图布局 3.1 子图布局说明 四、子图大小 4.1 子图大小调整 五、子图间距 5.1 子图代码调整 六、子图位置 6.1 代码引入 6.2 完整代码…

如何在 Windows10 下运行 Tensorflow 的目标检测?

前言 看过很多博主通过 Object Detection 实现了一些皮卡丘捕捉&#xff0c;二维码检测等诸多特定项的目标检测。而我跟着他们的案例来运行的时候&#xff0c;不是 Tensorflow 版本冲突&#xff0c;就是缺少什么包&#xff0c;还有是运行官方 object_detection_tutorial 不展示…

算法记录 | Day30 回溯算法

332.重新安排行程 思路&#xff1a; 1.确定回溯函数参数&#xff1a;定义全局遍历存放path&#xff0c; 2.终止条件&#xff1a;遍历完所有路径&#xff0c;机场个数&#xff0c;如果达到了&#xff08;航班数量1&#xff09;&#xff0c;即path的长度应当为字符串二维数组长…

教程 | 多通道fNIRS数据的预处理和平均(下)

前言 前文近红外数据的预处理和平均&#xff08;上&#xff09;提到fNIRS是一种评估氧和脱氧血红蛋白浓度变化的方法&#xff0c;可与fMRI相媲美。fNIRS的不足是它的空间分辨率比fMRI差&#xff0c;但其优点是有更高的时间分辨率&#xff0c;并允许测量无法通过fMRI扫描仪测试…

GPT-4 API 接口调用及价格分析

GPT-4 API 接口调用及价格分析 15日凌晨&#xff0c;OpenAI发布了万众期待的GPT-4&#xff01;新模型支持多模态&#xff0c;具备强大的识图能力&#xff0c;并且推理能力和回答准确性显著提高。在各种专业和学术基准测试上的表现都媲美甚至超过人类。难怪OpenAI CEO Sam Altm…

动态规划专题(明天继续)

动态规划求最大值&#xff1a; 题目描述 小蓝在一个 nn 行 mm 列的方格图中玩一个游戏。 开始时&#xff0c;小蓝站在方格图的左上角&#xff0c;即第 11 行第 11 列。 小蓝可以在方格图上走动&#xff0c;走动时&#xff0c;如果当前在第 rr 行第 cc 列&#xff0c;他不能…

ASIC-WORLD Verilog(3)第一个Verilog代码

写在前面 在自己准备写一些简单的verilog教程之前&#xff0c;参考了许多资料----asic-world网站的Verilog教程即是其一。这套教程写得极好&#xff0c;奈何没有中文&#xff0c;在下只好斗胆翻译过来&#xff08;加了自己的理解&#xff09;分享给大家。 这是网站原文&#xf…

Windows应急响应 -Windows日志排查,系统日志,Web应用日志,

「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 Windows日志分析一、查看日志二、日志分类三、筛选日志四、事件ID1、安全日志1.1、登录类…

基于Java+SSM+Vue的旅游资源网站设计与实现【源码(完整源码请私聊)+论文+演示视频+包运行成功】

博主介绍&#xff1a;专注于Java技术领域和毕业项目实战 &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案例&#xff08;200套&#xff09; 目录 一、效果演示 二、…

【从零开始学Skynet】实战篇《球球大作战》(八):login代码设计

现在来编写我们的第二个服务——登录服务&#xff0c;在编写此服务时&#xff0c;建议大家对照着如下所示的流程图来看&#xff0c;知晓各个方法的作用&#xff0c;写起来会简单许多。 1、登录协议 定义如下图所示的登录协议&#xff1a; 客户端需要发送玩家账号和密码&#x…

MyBatis 源码解析 面试题总结

MyBatis源码学习环境下载 文章目录1、工作原理1.1 初始化1.1.1 系统启动的时候&#xff0c;加载解析全局配置文件和相应的映射文件1.1.2 建造者模式帮助我们解决复杂对象的创建&#xff1a;1.2 处理SQL请求的流程1.2.1 通过sqlSession中提供的API方法来操作数据库1.2.2 获取接口…