Day72 传感器分类、关键参数、工作原理与Linux驱动开发(GPIO/I²C/Platform/Misc框架)

day72 传感器分类、关键参数、工作原理与Linux驱动开发(GPIO/I²C/Platform/Misc框架)


一、传感器分类与关键参数

(一)按通信协议分类

通信协议 对应传感器 功能
GPIO(单总线) dht11、dht22、ds18b20 dht11/dht22:温湿度检测;ds18b20:温度检测
GPIO hcsr-04 超声波测距
I²C LM75、BH1750、MPU6050、MAX30100/30102 LM75:温度;BH1750:光照强度;MPU6050:六轴姿态;MAX30100/30102:心率、血氧
SPI ADXL345 三轴加速度检测
ADC MQ系列(MQ-2、MQ-135、MQ-7) MQ-2:烟雾浓度;MQ-135、MQ-7:气体浓度
UART GPS传感器、GY-35 GPS:定位(经度、纬度、海拔);GY-35:红外测距

✅ 面试重点:必须清楚所用传感器的接口类型、通信协议(如I²C地址、SPI模式)、引脚连接方式。


(二)核心传感器关键参数表

传感器 功能 连接方式 量程(测量范围) 精度 分辨率 工作电压
dht11 温湿度 GPIO(单总线) 温度:0--50℃;湿度:20--90%RH 温度:±2℃;湿度:±5%RH 1 3.3V--5.5V
dht22 温湿度 GPIO(单总线) 温度:-40--80℃;湿度:0--99.9%RH 温度:±0.5℃;湿度:±2%RH 0.1℃ / 0.1%RH 3.3V--5.5V
ds18b20 温度 GPIO(单总线) -55--125℃ 0--85℃:±0.5℃(典型);全范围:±2℃ 9位:0.5℃;10位:0.25℃;11位:0.125℃;12位:0.0625℃ 3V--5V
hcsr-04 超声波测距 GPIO 2cm--450cm ±0.3cm 1 5V
MAX30102 心率、血氧 I²C 心率:30--240 BPM;血氧:70--100% ±2% - 1.8V--5.5V

⚠️ 选型建议:根据项目场景(如工业设备高温环境)选择合适量程的传感器。


二、典型传感器工作原理与时序

(一)dht11温湿度传感器

  1. 电路图:VCC接电源,通过4.7K电阻R1连接DATA引脚,GND接地,NC为空脚。
  2. 数据格式:共40bit(5字节),顺序为湿度整数+湿度小数+温度整数+温度小数+校验和,高位先行。
  3. 工作时序
    • 主机发送起始信号:DHT11引脚默认高电平,主机拉低至少18ms,再拉高20--40μs。
    • 从机回复应答:拉低80μs,再拉高80μs。
    • 传输bit'0':从机拉低50μs,再拉高26--28μs。
    • 传输bit'1':从机拉低50μs,再拉高70μs。
    • 结束信号:主机将引脚从低电平拉为高电平。

(二)hcsr-04超声波测距传感器

  1. 引脚定义:VCC(5V)、GND(地)、Trig(控制端/发射端)、Echo(接收端)。

  2. 工作原理/时序

    • Trig引脚默认低电平,拉高 ≥10μs 后拉低 → 传感器内部发送8个40kHz超声波脉冲。

    • Echo引脚默认低电平,检测到高电平时记录开始时间,检测到低电平时记录结束时间。

    • 距离计算公式:

      复制代码
      距离(cm) = (高电平时间 μs × 340 m/s) / (2 × 10000) = 高电平时间(μs) / 58
  3. IMX6ULL硬件连接

    • VCC → P4.46(5V)
    • GND → P4.47(地)
    • Trig → SNVS_TAMPER4(P4.1,即GPIO5_IO04)
    • Echo → SNVS_TAMPER5(P4.6,即GPIO5_IO05)

🔧 注意:必须使用5V供电,3.3V可能导致工作异常。


(三)MAX30102心率血氧传感器

  1. 引脚说明
引脚 功能
VIN 电源输入(1.8V--5.5V)
SCL I²C时钟线
SDA I²C数据线
INT 中断引脚
IRD 红外LED_DRIVER
RD 红色LED_DRIVER
GND
  1. 核心特性

    • 集成红外LED(940nm)、红光LED(660nm)、光电探测器;
    • 基于PPG(Photoplethysmography,光电容积图)原理;
    • 16位ADC;
    • I²C接口(默认地址0x57);
    • 可配置LED电流、采样率、FIFO阈值。
  2. PPG采集原理

    • 光线照射人体组织,动脉血随心脏搏动膨胀收缩,导致吸收光强变化;
    • 光电探测器捕捉光强变化并转化为电信号;
    • 红光与红外光配合用于SpO₂计算和心率检测。
  3. 信号处理流程

    • 光发射:控制红/红外LED发射特定波长光;
    • 光信号采集:光电探测器 → AFE放大/滤波 → ADC转换;
    • 数字信号处理:
      • 带通滤波(0.5--5Hz)去噪;
      • AC/DC分量分离;
      • 峰值检测 → 计算心率;
      • AC/DC比值 → 查表得血氧值。

三、Linux驱动开发框架

(一)Linux驱动分类

  1. 字符型设备驱动

    • 以1字节为单位读写,无缓存;
    • 适用于鼠标、键盘、传感器等;
    • 需实现 cdev 结构体(设备号、名称)和 file_operations(open/read等)。
  2. 块设备驱动

    • 以固定块(如512B)为单位,带缓存;
    • 适用于硬盘、Flash。
  3. 网络设备驱动

    • 基于TCP/IP协议栈。

(二)字符型设备驱动框架

  1. 手动创建设备节点

    bash 复制代码
    mknod /dev/hcsr04 c 250 0  # c=字符设备,250=主设备号,0=次设备号
  2. 自动创建设备节点

    • 使用 class_create() 创建类;
    • 使用 device_create() 创建设备节点。
  3. init函数(insmod触发)

    • 注册字符设备:alloc_chrdev_region()(动态)或 register_chrdev_region()(静态);
    • 初始化 cdevcdev_init() + cdev_add()
    • 自动创建设备节点;
    • 硬件初始化(如 request_irq)。
  4. exit函数(rmmod触发)

    • 注销字符设备:unregister_chrdev_region()
    • 删除cdev:cdev_del()
    • 销毁类/设备:class_destroy() + device_destroy()
    • 释放资源:free_irq()

(三)杂项设备驱动(Misc Device)

  1. 特点

    • 主设备号固定为10;
    • 自动生成 /dev/xxx 节点;
    • 使用 miscdevice 结构体(含次设备号、设备名)和 file_operations
  2. init函数

    c 复制代码
    misc_register(&misc_dev);  // 自动创建 /dev/misc_max30102
    request_irq(...);          // 申请中断
  3. exit函数

    c 复制代码
    misc_deregister(&misc_dev);
    free_irq(...);

(四)Platform驱动(设备与驱动分离)

1. 设备树配置(以hcsr-04为例)

(1) 引脚复用配置

dts 复制代码
pinctrl_hcsr04: hcsr04grp {
    fsl,pins = <
        MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04  0x10b0  /* Trigger */
        MX6UL_PAD_SNVS_TAMPER5__GPIO5_IO05  0x10b0  /* Echo */
    >;
};

(2) 设备节点

dts 复制代码
hcsr04 {
    compatible = "imx6ull,hcsr04";
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_hcsr04>;
    gpios = <&gpio5 4 GPIO_ACTIVE_LOW>,   /* Trigger */
            <&gpio5 5 GPIO_ACTIVE_LOW>;   /* Echo */
    status = "okay";
};

(3) 编译并更新设备树

bash 复制代码
make dtbs
cp arch/arm/boot/dts/imx6ull-14x14-evk.dtb /tftpboot/
2. 驱动实现
  • init函数platform_driver_register()
  • exit函数platform_driver_unregister()
  • probe函数 (设备匹配成功后执行):
    • 解析设备树GPIO:of_get_named_gpio()
    • 申请GPIO:devm_gpio_request_one()
    • 设置方向:gpio_direction_output() / gpio_direction_input()
    • 注册杂项设备:misc_register()

✅ 行业趋势:现代Linux驱动开发普遍采用 Platform + Device Tree 架构。


(五)I²C子系统驱动(以MAX30102为例)

1. I²C子系统架构分层
层级 功能
物理硬件层 具体I²C设备(如MAX30102)
适配器层 开发板I²C控制器,厂商实现,提供 i2c_adapteri2c_algorithm
核心层 提供设备/驱动注册、匹配方法,数据传输API(i2c_master_send等)
设备驱动层 手动实现 i2c_driveri2c_client
用户层 调用 openread 等函数操作设备
2. 驱动实现要点

(1) 使用宏简化注册

c 复制代码
module_i2c_driver(max30102_driver);  // 自动调用 i2c_add_driver/i2c_del_driver

(2) i2c_driver结构体

c 复制代码
static const struct of_device_id max30102_of_match[] = {
    { .compatible = "imx6ull,max30102" },
    { }
};

static struct i2c_driver max30102_driver = {
    .probe = max30102_probe,
    .remove = max30102_remove,
    .driver = {
        .name = "max30102",
        .of_match_table = max30102_of_match,
    },
};

(3) I²C寄存器读写封装

c 复制代码
// 写寄存器:向指定寄存器写入1字节
static int max30102_write_reg(struct i2c_client *client, u8 reg, u8 val) {
    u8 buf[2] = {reg, val};  // buf[0]=寄存器地址, buf[1]=写入值
    struct i2c_msg msg = {
        .addr = client->addr,   // I2C设备地址(0x57)
        .flags = 0,             // 写操作
        .len = 2,               // 发送2字节
        .buf = buf,             // 数据缓冲区
    };
    return i2c_transfer(client->adapter, &msg, 1);  // 返回传输消息数
}
// 理想结果:返回1表示成功传输1条消息
// 功能:通过I²C总线向MAX30102的指定寄存器写入配置值
c 复制代码
// 读寄存器:先写地址,再读数据(两段式)
static int max30102_read_reg(struct i2c_client *client, u8 reg, u8 *val) {
    struct i2c_msg msgs[2] = {
        { .addr = client->addr, .flags = 0, .len = 1, .buf = &reg },      // 写地址
        { .addr = client->addr, .flags = I2C_M_RD, .len = 1, .buf = val } // 读数据
    };
    return i2c_transfer(client->adapter, msgs, 2);
}
// 理想结果:返回2表示成功完成两段传输
// 功能:从MAX30102指定寄存器读取1字节数据到val指针

(4) probe函数关键步骤

  • 注册杂项设备:misc_register()
  • 解析中断:irq_of_parse_and_map()
  • 申请中断:request_threaded_irq()(下降沿触发)
  • 初始化等待队列(用于阻塞read)
  • 配置传感器寄存器(设置工作模式、LED电流、采样率等)

(5) read函数逻辑

  • 进程在等待队列中阻塞;
  • FIFO满时触发INT中断;
  • 中断服务函数唤醒进程;
  • 驱动读取FIFO原始数据(红光/红外ADC值);
  • copy_to_user() 返回给应用层。

四、应用程序开发

(一)hcsr-04应用程序(main.c)

功能 :打开 /dev/misc_hcsr04,读取Echo高电平时间,计算并打印距离。

c 复制代码
int fd = open("/dev/misc_hcsr04", O_RDWR);        // 打开设备节点
read(fd, &time_us, sizeof(time_us));              // 读取高电平持续时间(微秒)
distence = (340.0 / 10000.0 * time_us) / 2;       // 距离 = (声速 × 时间) / 2
printf("time_us = %d, distence = %.2lf cm\n", time_us, distence); // 打印结果
usleep(250000);                                   // 延时250ms
close(fd);                                        // 关闭设备

理想运行结果
time_us = 580, distence = 10.00 cm
功能说明:应用层通过标准文件操作接口与驱动交互,获取测距原始数据并换算为厘米。


(二)MAX30102应用程序(max30102_app.c)

功能 :打开 /dev/misc_max30102,读取FIFO数据,调用算法计算心率、血氧。

关键步骤

  1. 读取500个样本初始化缓冲区,确定信号范围(max/min);
  2. 调用 maxim_heart_rate_and_oxygen_saturation() 计算心率和血氧;
  3. 循环更新缓冲区(舍去前100组,添加新100组),重新计算并打印。

(三)MAX30102算法(max30102_algorithm.c/.h)

核心函数maxim_heart_rate_and_oxygen_saturation

  • 去噪滤波:对IR信号去除DC分量,进行4点移动平均、差分、汉明窗滤波;
  • 峰值检测:计算相邻峰值间隔,心率 = 6000 / 平均间隔(单位:BPM);
  • 血氧计算 :计算红光/红外信号AC/DC比值,通过 uch_spo2_table 查表得SpO₂。

关键数据结构

  • aun_ir_buffer[]:红外光原始数据缓冲区;
  • aun_red_buffer[]:红光原始数据缓冲区;
  • uch_spo2_table[]:预校准的血氧查找表。

五、设备树配置(MAX30102完整示例)

  1. 禁用冲突设备(避免GPIO1_IO15被占用):
dts 复制代码
&sai2 {
    status = "disabled";  // 禁用SAI2,释放GPIO1_IO15
};
  1. 中断引脚配置
dts 复制代码
pinctrl_max30102: max30102grp {
    fsl,pins = <
        MX6UL_PAD_GPIO1_IO15__GPIO1_IO15  0x10b0  /* INT引脚 */
    >;
};
  1. I²C设备节点
dts 复制代码
&i2c1 {
    clock-frequency = <100000>;  // 100kHz
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c1>;
    status = "okay";

    max30102@57 {
        compatible = "imx6ull,max30102";
        reg = <0x57>;  // I²C地址
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_max30102>;
        interrupt-parent = <&gpio1>;
        interrupts = <15 IRQ_TYPE_EDGE_FALLING>;  // GPIO1_IO15,下降沿触发
        status = "okay";
    };
};

硬件连接(i.MX6ULL)

  • VCC → P4.48(3.3V)
  • GND → P4.47(地)
  • SCL → P4.43(I2C1_SCL)
  • SDA → P4.42(I2C1_SDA)
  • INT → P4.30(GPIO1_IO15)

六、开发环境与编译

交叉编译工具链配置(内核版本:4.1.15)

  1. 拷贝工具链:

    bash 复制代码
    cp gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz ~/rabbit/
  2. 解压:

    bash 复制代码
    cd ~/rabbit
    tar -xvf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz
  3. 配置环境变量(~/.bashrc):

    bash 复制代码
    export PATH=/home/用户名/rabbit/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin:$PATH
    source ~/.bashrc
  4. 验证:

    bash 复制代码
    arm-linux-gnueabihf-gcc -v  # 应显示 4.9.4

⚠️ 重要:内核与驱动必须使用同一版本编译器,否则 insmod 会报错。


应用程序Makefile示例

makefile 复制代码
CC := arm-linux-gnueabihf-gcc 
MODULE_NAME := max30102

all:
	${CC} $(wildcard *.c) -o ${MODULE_NAME}_app -lm  # -lm链接数学库
	cp ${MODULE_NAME}_app ~/nfs

.PHONY: clean
clean:
	rm -f ${MODULE_NAME}_app

distclean:
	rm -f ${MODULE_NAME}_app
	rm -f ~/nfs/${MODULE_NAME}_app

七、面试高频问题准备

  1. "你用的传感器是什么接口?如何连接?"
  2. "该传感器的量程、精度、分辨率是多少?"
  3. "请描述其工作时序。"
  4. "Linux下如何编写其驱动?用了什么框架?"
  5. "设备树中如何描述该设备?"

💡 建议:调试时务必记录参数、时序、代码逻辑,形成个人技术笔记。


总结:本日学习涵盖传感器分类选型、工作原理、Linux驱动四大框架(字符设备/Misc/Platform/I²C子系统)、设备树配置、应用层交互及交叉编译环境搭建,为嵌入式传感器项目开发奠定完整基础。

相关推荐
NextZeros3 小时前
基于CentOS安装LNMP
linux·centos
梁萌3 小时前
Linux安装mysql8.4.6
linux·运维·mysql安装·8.4.6
gtr20203 小时前
Ubuntu24.04 无法读取 U盘
linux
南棱笑笑生3 小时前
20251028在Ubuntu20.04.6上编译AIO-3576Q38开发板的Buildroot系统
大数据·linux·服务器·rockchip
FreeBuf_3 小时前
Ubuntu内核曝严重UAF漏洞,可致攻击者获取Root权限
linux·运维·ubuntu
Jason_zhao_MR3 小时前
RK3576机器人核心:三屏异显+八路摄像头,重塑机器人交互与感知
linux·人工智能·嵌入式硬件·计算机视觉·机器人·嵌入式·交互
☆璇3 小时前
【Linux】数据链路层
linux·服务器·网络
NEU-UUN5 小时前
C语言 . 第二章第二节 . 分支结构
c语言·开发语言
阿巴~阿巴~5 小时前
线程局部存储(Thread-Local Storage, TLS)
linux·服务器·开发语言·c++·线程·虚拟地址空间·线程局部存储