SR04 超声波测距模块

简介: SR04 超声波测距模块

前言

超声波测距模块 是利用超声波来测距。模块先发送超声波,然后接收反射回来的超声波,由反射经历的时间和声音的传播速度 340m/s,计算得出距离。本实验采用 中断 的方法,来进行测距。


一、SR04 模块介绍

引脚 :VCCTrigEchoGND

Trig脉冲触发 引脚.

Echo回响接收 引脚

测距原理 :

  1. 触发:
    向Trig(脉冲触发引脚)发出一个大约10us的高电平。
  2. 发出超声波,接收反射信号:
    模块就自动发出8个40Khz的超声波,超声波遇到障碍物后反射回来,模块收到返回来的超声波。
  3. 回响:
    模块接收到反射回来的超声波后,Echo引脚输出一个与检测距离成比例的高电平。

我们只要在该引脚为高时,开启定时器计数,在该引脚变为低时,结束定时器计数。根据定时器的计数和定时器频率就可以算出经历

  1. 时间,根据时间即可推导出距离。

二、设备树设置

设备树 中 compatible 与 驱动程序 进行匹配。

通过原理图可知 TrigEcho 引脚是低电平有效,将其分别接到 开发板的 gpio4-19gpio4-20 引脚。每一组 GPIO 有 32 个引脚。

配置设备树需要对 GPIO 引脚 以及相关的 pincontrol 配置。由于本实验是使用 SR04 模块,所以不需要配置 pincontrol 。

三、驱动程序

  1. 首先 定义、注册一个file_operations 结构体。read 函数便于读取引脚电平。major 是返回的主设备号。

在入口函数里进class_create 创建类 , device_create 创建设备节点,register_chrdev 注册 file_operations 结构体。

出口函数里 device_destroyclass_destroy 将其逐个销毁 ,platform_driver_unregister 卸载 file_operations 结构体 。

函数的详细使用可参考 上一篇文章:SR501人体红外模块

  static struct file_operations sr04_fops = {
    .owner   = THIS_MODULE,
    .read    = sr04_drv_read,
  };
  /* 注册结构体 */
  major = register_chrdev(0, "sr04", &sr04_fops);  
  1. 定义、注册一个platform_driver
    ask100_sr04 用于 设备树和驱动设备匹配。
static const struct of_device_id ask100_sr04[] = {
    { .compatible = "my,sr04"},
    { },
};
static struct platform_driver sr04s_driver = {
    .probe      = sr04_probe,
    .remove     = sr04_remove,
    .driver     = {
        .name   = "100ask_sr04",
        .of_match_table = ask100_sr04,
    },
};
/* 注册 platform_driver */
err = platform_driver_register(&sr04s_driver);
  1. probe 函数里进行 获取引脚,并对其引脚 初始化。
    使用 gpiod_get 获取对应引脚。参数二 是对应引脚的名字(设备树中自定义节点中的引脚名)。
  /* 设置 trig 初始化时为低电平状态 */
  trig_gpio = gpiod_get(&pdev->dev, "trig",GPIOD_OUT_LOW);
  /* 设置 echo初始化时为输入引脚 */
  echo_gpio = gpiod_get(&pdev->dev, "echo",GPIOD_IN);

  1. 获取中断号 irq ,request_irq 请求中断。

前面了解到 echo 为输入引脚,trig 为 输出引脚。 (获取中断号 和 请求中断 可以在 probe 函数里实现。)

  /* 获取中断号 */
  irq = gpiod_to_irq(echo_gpio);
  /* 申请中断 */
  request_irq(irq, sr04_isr, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, "sr04", NULL);

那什么时候发生中断呢?

request_irq 函数里 可以看到 参数三 IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING。当 电平处于上升沿 或者 下降沿时发生中断(电平发生变化)。

  • 当 电平由 低变高 时,触发中断,记录时间为 t1。此时并不唤醒处于休眠的函数。
  • 当 电平由 高变低 时,触发中断,记录时间为 t2。t = t2 - t1 。 t 是 超声波 从发出到接受的时间,就是声波在待测距离上的往返时间。 这时 就可以唤醒休眠的 read 函数了。

read 函数读取时间 t 后,即可在测试程序中 算出距离 D = 340 * t / 2

  1. 在 入口函数里 初始化等待队列头。
static wait_queue_head_t sr04_wq;        // 定义等待队列头对象
init_waitqueue_head(&sr04_wq);          // 初始化等待队列头
  1. 中断处理函数,wake_up 唤醒 休眠函数。
    触发中断后调用中断处理函数。

gpiod_get_value 获取相应引脚电平。

ktime_get_ns(); 获取内核启动到现在的时间,在挂起时会暂停。单位是 ns (纳秒)

wake_up 唤醒 在 read 函数里休眠的队列。

static irqreturn_t sr04_isr(int irq, void *dev_id)
{
  int val = gpiod_get_value(echo_gpio);
  if(val)
  {
    sr04_data_ns = ktime_get_ns();      //获取上升沿时的时间
  }
  else
  {
    sr04_data_ns = ktime_get_ns() - sr04_data_ns;   //获取下降沿时的时间,并相减得到高电平时间
    wake_up(&sr04_wq);              //唤醒队列
  }
  return IRQ_HANDLED; // IRQ_WAKE_THREAD;
}

实现 read 函数。

wait_event_interruptible_timeout 负责 等待队列和超时控制。它的作用是使当前执行的线程(或进程)进入睡眠状

  1. 态,直到满足指定的条件,或者经过指定的时间。
    gpiod_set_value 设置 trig 输出 不少于 10 us 的高电平。
static ssize_t sr04_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
  int timeout=0;
  /* 发送10us高电平    , 测量距离 2cm-450cm */
  gpiod_set_value(trig_gpio, 1);
  udelay(15);
  gpiod_set_value(trig_gpio, 0);
  timeout = wait_event_interruptible_timeout(sr04_wq, sr04_data_ns, HZ);
  if(timeout)
  {
    copy_to_user(buf, &sr04_data_ns, 4);
    sr04_data_ns = 0;
    return 4;
  }
  else
  {
    return -EAGAIN;
  }
}

四、测试程序

判断参数,打开文件,读取电平。若引脚为高电平 则读取距离,否则读取错误。

  if (argc != 2) 
  {
    printf("Usage: %s <dev>\n", argv[0]);
    return -1;
  }
  fd = open(argv[1], O_RDWR);
  if (fd == -1)
  {
    printf("can not open file %s\n", argv[1]);
    return -1;
  }
  while (1)
  {
    if (read(fd, &ns, 4) == 4)
    {
      printf("get distance: %d ns\n", ns);
      printf("get distance: %d mm\n", ns*340/2/1000000);  /* mm */
    }
    else
      printf("get distance: -1\n");
    sleep(1);
  }
  close(fd);

五、上级测试及效果

执行 insmod 命令可以将 .ko 文件加载到内核中,再 执行测试程序。(rmmod命令可以卸载已加载的模块,lsmod 命令 可以观察已加载到内核的文件。)

将 遮挡物 置于 超声波模块 前,前后移动即可。 /dev/sr04 是 驱动程序中创建的设备节点( device_create )。


总结

相关文章
|
传感器
SR501人体红外模块
SR501人体红外模块
129 0
|
传感器 芯片
STM32外设系列—HC-SR04(超声波)
本文主要介绍了超声波测距的原理,常用的超声波传感器。并且针对HC-SR04给出了使用思路和程序设计。最后,简单进行了思路拓展。
373 1
STM32外设系列—HC-SR04(超声波)
|
传感器 机器人 Linux
Linux驱动基础(HC-SR04超声波模块)
Linux驱动基础(HC-SR04超声波模块)
153 0
|
传感器 Linux
Linux驱动基础(SR501人体感应模块)
Linux驱动基础(SR501人体感应模块)
130 0
|
7月前
|
安全 BI
GE Multilin SR469-P5-HI-A20-E 电机管理继电器
GE Multilin SR469-P5-HI-A20-E 电机管理继电器
|
7月前
|
传感器 机器人
|
传感器 数据采集 SDN
STM32(HAL库)驱动AD8232心率传感器
STM32(HAL库)驱动AD8232心率传感器
|
传感器
STM32驱动HC-SR04超声波模块
STM32驱动HC-SR04超声波模块
486 0