1. RK3506驱动超声波测距模块HC-SR04实战指南
在嵌入式开发中,超声波测距是一种常用的非接触式距离测量方案。HC-SR04作为经典的低成本超声波模块,通过GPIO接口即可实现2cm-4m范围内的距离检测。本文将详细介绍如何在RK3506平台上开发HC-SR04的Linux内核驱动,包含完整的驱动实现、交叉编译和测试方案。
注意:HC-SR04模块的VCC需接5V电源,而Trig和Echo信号线需接3.3V电平的GPIO,避免损坏RK3506的IO口。
2. HC-SR04工作原理与硬件连接
2.1 超声波测距原理
HC-SR04模块通过发射40kHz的超声波脉冲,并检测反射回波的时间差来计算距离。具体工作时序如下:
- 向Trig引脚发送至少10us的高电平脉冲
- 模块自动发射8个40kHz超声波脉冲
- 模块检测回波并通过Echo引脚输出高电平
- 高电平持续时间与距离成正比(每58us对应1cm)
距离计算公式:
code复制距离(cm) = 高电平时间(us) × 340m/s ÷ 2 ÷ 10000
2.2 RK3506硬件连接
RK3506开发板与HC-SR04的连接方式:
| HC-SR04引脚 | RK3506连接 | 说明 |
|---|---|---|
| VCC | 5V电源 | 模块工作电压 |
| Trig | GPIO1_D2 | 触发信号输出 |
| Echo | GPIO1_D3 | 回波信号输入 |
| GND | GND | 共地 |
在驱动代码中,我们使用以下GPIO编号:
c复制#define HC_SR04_TRIG_GPIO (1*32 + 3*8 + 2) // GPIO1_D2 = 58
#define HC_SR04_ECHO_GPIO (1*32 + 3*8 + 3) // GPIO1_D3 = 59
3. 驱动设计与实现详解
3.1 驱动架构设计
本驱动采用字符设备框架,主要功能模块:
- GPIO控制:管理Trig和Echo引脚
- 中断处理:捕获Echo信号的上升沿和下降沿
- 定时器:周期性触发测距
- 字符设备:提供用户空间访问接口
- Sysfs接口:通过/sys/class/hc_sr04/distance获取距离
3.2 核心代码解析
3.2.1 中断处理函数
c复制static irqreturn_t hc_sr04_echo_irq_handler(int irq, void *dev_id)
{
unsigned long duration=0;
if (gpio_get_value(HC_SR04_ECHO_GPIO)) {
// 上升沿:记录开始时间
echo_start_time = ktime_get_ns();
} else {
// 下降沿:记录结束时间,计算距离
echo_end_time = ktime_get_ns();
duration = echo_end_time - echo_start_time;
// 距离 = (时间(us) × 声速(340m/s)) / 2 → 转换为 cm
distance = (duration * 34) / 2000000;
measuring = false;
}
return IRQ_HANDLED;
}
3.2.2 定时器触发函数
c复制static void hc_sr04_trig_timer_func(struct timer_list *t)
{
if (measuring) {
printk(KERN_INFO "HC-SR04: triging\n");
return;
}
measuring = true;
// 发送10us高电平触发信号
gpio_set_value(HC_SR04_TRIG_GPIO, 1);
udelay(10);
gpio_set_value(HC_SR04_TRIG_GPIO, 0);
}
3.2.3 字符设备read函数
c复制static ssize_t hc_sr04_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
int ret;
unsigned int dist;
// 启动一次测距
mod_timer(&trig_timer, jiffies + msecs_to_jiffies(10));
// 等待测距完成(最多300ms)
msleep(300);
dist = distance;
ret = copy_to_user(buf, &dist, sizeof(dist));
if (ret) return -EFAULT;
return sizeof(dist);
}
3.3 驱动初始化流程
- 申请并配置GPIO
- 注册Echo引脚中断
- 初始化字符设备
- 创建sysfs接口
- 设置定时器
关键点:中断标志需同时包含上升沿和下降沿触发(IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
4. 交叉编译与部署
4.1 驱动编译配置
驱动Makefile关键配置:
makefile复制SDK=/home/book/work/rk3506/sdk
KERNELDIR ?= $(SDK)/kernel-6.1
CROSS_COMPILE = $(SDK)/prebuilts/gcc/linux-x86/arm/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf/bin/arm-none-linux-gnueabihf-
obj-m := hc_sr04.o
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) modules
4.2 测试程序编译
测试程序Makefile配置:
makefile复制$(CROSS_COMPILE)gcc *.c -o test_hc_sr04
4.3 部署步骤
- 将编译好的hc_sr04.ko和test_hc_sr04拷贝到开发板
- 加载驱动:
bash复制
insmod hc_sr04.ko - 运行测试程序:
bash复制
./test_hc_sr04
5. 性能优化与问题排查
5.1 常见问题及解决方案
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 读取距离为0 | Trig信号太短 | 确保Trig高电平持续10us |
| 距离值不稳定 | 电源干扰 | 增加电源滤波电容 |
| 驱动加载失败 | GPIO冲突 | 检查GPIO是否被其他驱动占用 |
| 中断不触发 | 电平不匹配 | 确认Echo信号为3.3V电平 |
5.2 性能优化建议
- 降低CPU占用:将定时器触发间隔调整为100ms(默认10ms)
- 提高精度:使用高精度定时器(hrtimer)替代jiffies
- 滤波处理:对连续5次测量结果取中值
- 电源管理:不测量时关闭模块电源
6. 扩展应用场景
6.1 多传感器集成
通过修改驱动支持多个HC-SR04模块:
- 为每个传感器分配独立的GPIO和设备节点
- 使用设备树配置传感器参数
- 实现同步触发机制
6.2 与用户空间交互
除了字符设备接口,还可以实现:
- IIO子系统接口
- 通过sysfs配置参数
- 实现ioctl控制测量间隔
在实际项目中,我将这个驱动应用于智能小车避障系统,通过三个超声波模块实现360°障碍物检测。关键优化点是降低了中断延迟,确保在高速移动时仍能准确测距。一个实用技巧是在Echo引脚上添加100nF电容,有效滤除了信号抖动。