Linux内核实践(一)驱动DS18B20传感器的完整流程解析(涵盖字符设备、单总线、设备树等)
本文目录
- 一、单总线知识点及概念
- 1. 特点
- 2. 常见应用
- 3. Linux 中的支持
- 二、ds18b20温度传感器
- 1. 详情
- 2. 工作原理
- 三、本节驱动涉及知识点
- 四、编写流程
- 1. 编写字符设备驱动框架,并完成平台总线驱动的注册。
一、单总线知识点及概念
在 Linux 中,“单总线”(One-Wire Bus)指的是一种串行通信总线标准,通常被用于与具有低数据速率需求的设备进行通信。它是一种由 Dallas Semiconductor(现在是 Maxim Integrated 的一部分)开发的通信协议。
1. 特点
(1)单线通信: 单总线协议只使用一条数据线(再加上一个地线)进行通信,既可以用来传输数据,也可以用来提供电源。这使得它非常适合于需要低成本和简单布线的应用场合。
(2)设备地址唯一性: 每个连接到单总线上的设备都有一个唯一的 64 位序列号,便于总线上挂载多个设备而不会发生冲突。
(3)半双工通信: 数据传输是半双工的,即同一时间数据只能在一个方向上传输。
(4)低速通信: 单总线的传输速率较低,通常在 16 kbps 左右。这适合传输速率要求不高的应用场景,如温度传感器数据传输。
(5)多设备连接: 单总线可以支持在同一条线上连接多个设备,这种特性非常适合需要监控多个传感器的应用。
2. 常见应用
温度传感器: 最著名的单总线设备可能是 DS18B20,它是一个数字温度传感器,广泛应用于各种温度监控系统。
电子标签: 单总线还常用于简单的电子标签和其他需要低数据速率、简单连接的设备。
3. Linux 中的支持
在 Linux 系统中,One-Wire 总线设备通常通过 w1 子系统进行管理。w1 子系统提供了对 One-Wire 总线的内核支持,用户可以通过 /sys/bus/w1/devices/ 目录访问 One-Wire 设备。
Linux 内核模块如 w1-gpio 提供了对使用 GPIO 引脚的 One-Wire 总线的支持,而 w1-therm 模块则提供对温度传感器如 DS18B20 的支持。
二、ds18b20温度传感器
1. 详情
DS18B20 是一种数字温度传感器,广泛应用于各种温度监测场合。它的主要特点包括高精度、易用性和低成本,适用于嵌入式系统、物联网设备等场景。
DS18B20 使用 One-Wire(单总线)通信协议,直接输出数字温度数据,而无需模数转换(ADC),这简化了与微控制器的接口设计。
该传感器可以提供 9 到 12 位分辨率的温度数据,默认分辨率为 12 位,可通过配置更改。它的测量范围为 -55°C 到 +125°C,在 -10°C 到 +85°C 范围内的精度为 ±0.5°C。
2. 工作原理
DS18B20 通过单总线与主控设备(如微控制器或单板计算机)通信。它的工作流程一般如下:
(1)总线复位: 主控设备发送一个复位信号,复位所有连接在总线上的 DS18B20 设备。
(2)设备检测: DS18B20 响应复位信号,表明其存在。主控设备可以读取设备的唯一序列号。
(3)温度转换: 主控设备发送温度转换命令,DS18B20 开始测量温度并存储测量值。
(4)数据读取: 主控设备读取 DS18B20 的温度数据,数据以 9 至 12 位的格式提供,主控设备可以根据需要处理这些数据。
三、本节驱动涉及知识点
- 字符设备驱动
- 平台总线
- 设备树
- 解析设备树
- gpio子系统
- pinctrl子系统
- 单总线协议
四、编写流程
1. 编写字符设备驱动框架,并完成平台总线驱动的注册。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/kernel.h> //内核
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <asm/uaccess.h>ssize_t my_read (struct file *fp, char __user *ubuf, size_t, loff_t * offset)
{}int my_open (struct inode *node, struct file *fp)
{return 0;
}ssize_t my_write(struct file *fp, const char __user *ubuf, size_t, loff_t *offset)
{}static const struct file_operations myfops={.read=my_read ,.write =my_write ,.open=my_open,
};struct miscdevice my_misc={.minor=MISC_DYNAMIC_MINOR,.fops=myfops,.name ="ds18b20_misc"
};int ds18b20_probe(struct platform_device *dev)
{int ret;ret=misc_register(&my_misc);if(ret <0){pr_err("misc_register error\n");return -1;}
}struct acpi_device_id ds18b20_id_table[]={{.compatible="ds18b20"},{NULL}
};struct platform_driver ds18b20_driver={.driver={.name="ds18b20",.owner=THIS_MODULE,.of_match_table= ds18b20_id_table,},.probe =ds18b20_probe};static int __init ds18b20_init(void)
{int ret;ret=platform_driver_register(&ds18b20_driver); if (ret < 0) {pr_err("platform_device_register error\n");return -1;}return 0;
}static void __exit ds18b20_exit(void)
{platform_driver_unregister(&ds18b20_driver);}module__init(ds18b20_init);
module__exit(ds18b20_exit);MODULE_LICENSE("GPL");