1. 超声波测试模块简介
超声波测距模块是利用超声波来测距。模块先发送超声波,然后接收反射回来的超声波,由反射经历的时间和声音的传播速度 340m/s,计算得出距离。
SR04 是一款常见的超声波传感器,模块自动发送 8 个 40KHz 的方波,自动检测是否有信号返回,用户只需提供一个触发信号,随后检测回响信号的时间长短即可。
SR04 采用 5V 电压,静态电流小于 2mA,感应角度最大约 15 度,探测距离约 2cm-450cm。
硬件设计
SR04 模块上面有四个引脚,分别为:VCC、Trig、Echo、GND
- Trig 是脉冲触发引脚,即控制该脚让 SR04 模块开始发送超声波。
- Echo 是回响接收引脚,即 SR04 模块一旦接收到超声波的返回信号则输出回响信号,回响信号的脉冲宽度与所测距离成正比。
时序图:

- 触发信号:向
Trig(脉冲触发引脚)发出一个大约10us的高电平。注意:两次触发信号的时间间隔应该大于 50us - 发出超声波,接收反射信号:模块就自动发出
8个40Khz的超声波,超声波遇到障碍物后反射回来,模块收到返回来的超声波。 - 回响信号:模块接收到反射回来的超声波后,
Echo引脚输出一个与检测距离成比例的高电平。
总而言之,我们只要在Echo 引脚电平为高时,开启定时器计数,在该引脚变为低时,结束定时器计数。根据定时器的计数和定时器频率就可以算出经历时间,根据时间即可推导出距离
假设 Echo引脚高电平持续时间为 T(单位:ns),则Distance(单位:cm) 的计算公式为:Distance = 340*T/1000000(cm)
2. 应用程序的操作

应用程序的逻辑:
- 打开设备节点
- 在循环中,使用使用
ioctl函数调用驱动中的ioctl函数发出Trig信号 - 然后读取时间范围
T,然后根据公式计算出距离;
3. 在通用框架基础上修改驱动程序
从入口函数开始,入口函数包含 GPIO 操作、注册 file_operations 结构体、以及其他辅助信息。
首先是GPIO的操作:
- 对于
Trig引脚,它不需要申请中断,只需要发出Trig信号即可。因此只需要申请占用引脚(request_gpio),并设置初始的方向(Trig引脚平时为低电平,故默认初始化为低电平) - 对于
Echo引脚,需要申请中断。当上升沿时,记录开始时间;当下降沿时,记录结束时间,由此计算时间差。
然后,分析和修改驱动的核心 file_operations 结构体:
- 根据硬件原理可知,超声波测距模块不需要写数据,因此删除
write操作函数; - 增加ioctl操作函数,该函数一般用于设置或者获取硬件的属性,这里用来触发
Trig信号(可以查看内核源码中其他驱动程序如何使用) -
- 在 ioctl 函数中,发送触发信号:维持 `10us1 的高电平,然后恢复为低电平
发送触发信号后,我们需要在中断处理函数中处理中断。值得注意的是,上升沿和下降沿触发需要做不同的处理:
- 核心函数:
ktime_get_ns();用于获取当前的高精度时间(monotonic time),返回单位为纳秒的系统时间; - 上升沿触发中断时,记录开始时间;
- 下降沿触发中断时,记录结束时间,并计算时间间隔;
- 注意:容错处理——当下降沿触发时,如果时间间隔为0,表示丢失了中断;

其他信息: - 根据需求修改类名、设备名等等
出口函数:
- 完成入口函数的反操作
#include "asm-generic/gpio.h"
#include "linux/irqreturn.h"
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>
#define CMD_TRIG 100
struct gpio_desc{
int gpio;
int irq;
char *name;
int key;
struct timer_list key_timer;
} ;
static

最低0.47元/天 解锁文章
1686

被折叠的 条评论
为什么被折叠?



