014——超声波模块驱动开发Plus(基于I.MX6uLL、SR04和poll机制)

目录

一、基础知识

二、分析为什么打印会影响中断 

三、驱动程序

四、应用程序

五、验证及其它


一、基础知识

013——超声波模块驱动开发(基于I.MX6uLL与SR04)-CSDN博客

二、分析为什么打印会影响中断 

 

asmlinkage __visible int printk(const char *fmt, ...)  
{  va_list args;  int r;  // 初始化可变参数列表  va_start(args, fmt);  // 调用 vprintk_func 函数来格式化字符串并输出到内核日志  r = vprintk_func(fmt, args);  // 清理可变参数列表  va_end(args);  // 返回 vprintk_func 的结果  return r;  
}  EXPORT_SYMBOL(printk);

我们一层一层往下找找到了这个

        这是一个保护中断的自旋锁,这里上锁后其它需要用中断的进程就无法使用了。

        所以当超声波模块中断触发后我们没有接收到。这就是为什么打印会影响中断的原因,这里相当于32库函数里面关闭全局中断的那个操作,实现虽然不一样但是作用是一样的。

三、驱动程序

#include "asm-generic/errno.h"
#include "asm-generic/gpio.h"
#include "asm/delay.h"
#include "linux/jiffies.h"
#include <linux/module.h>
#include <linux/poll.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  100struct gpio_desc{int gpio;int irq;char *name;int key;struct timer_list key_timer;
} ;static struct gpio_desc gpios[2] = {{115, 0, "trig", },{116, 0, "echo", },
};/* 主设备号                                                                 */
static int major = 0;
static struct class *gpio_class;/* 环形缓冲区 */
#define BUF_LEN 128
static int g_keys[BUF_LEN];
static int r, w;struct fasync_struct *button_fasync;#define NEXT_POS(x) ((x+1) % BUF_LEN)static int is_key_buf_empty(void)
{return (r == w);
}static int is_key_buf_full(void)
{return (r == NEXT_POS(w));
}static void put_key(int key)
{if (!is_key_buf_full()){g_keys[w] = key;w = NEXT_POS(w);}
}static int get_key(void)
{int key = 0;if (!is_key_buf_empty()){key = g_keys[r];r = NEXT_POS(r);}return key;
}static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);/* 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t sr04_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);int err;int key;if (is_key_buf_empty() && (file->f_flags & O_NONBLOCK))return -EAGAIN;// printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);wait_event_interruptible(gpio_wait, !is_key_buf_empty());key = get_key();if (key == -1)return -ENODATA;err = copy_to_user(buf, &key, 4);return 4;
}static unsigned int sr04_poll(struct file *fp, poll_table * wait)
{//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);poll_wait(fp, &gpio_wait, wait);return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
}static int sr04_fasync(int fd, struct file *file, int on)
{if (fasync_helper(fd, file, on, &button_fasync) >= 0)return 0;elsereturn -EIO;
}// ioctl(fd, CMD, ARG)
static long sr04_ioctl(struct file *filp, unsigned int command, unsigned long arg)
{// send trig switch (command){case CMD_TRIG:{//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);gpio_set_value(gpios[0].gpio, 1);udelay(20);gpio_set_value(gpios[0].gpio, 0);// start timermod_timer(&gpios[1].key_timer, jiffies + msecs_to_jiffies(50));  }}return 0;
}/* 定义自己的file_operations结构体                                              */
static struct file_operations sr04_drv = {.owner	 = THIS_MODULE,.read    = sr04_read,.poll    = sr04_poll,.fasync  = sr04_fasync,.unlocked_ioctl = sr04_ioctl,
};static irqreturn_t sr04_isr(int irq, void *dev_id)
{struct gpio_desc *gpio_desc = dev_id;int val;static u64 rising_time = 0;u64 time;val = gpio_get_value(gpio_desc->gpio);//printk("sr04_isr echo pin %d is %d\n", gpio_desc->gpio, val);if (val){/* 上升沿记录起始时间 */rising_time = ktime_get_ns();}else{if (rising_time == 0){//printk("missing rising interrupt\n");return IRQ_HANDLED;}/* 下降沿记录结束时间, 并计算时间差, 计算距离 */// stop timerdel_timer(&gpios[1].key_timer);time = ktime_get_ns() - rising_time;rising_time = 0;put_key(time);wake_up_interruptible(&gpio_wait);kill_fasync(&button_fasync, SIGIO, POLL_IN);}return IRQ_HANDLED;
}static void sr04_timer_func(unsigned long data)
{put_key(-1);wake_up_interruptible(&gpio_wait);kill_fasync(&button_fasync, SIGIO, POLL_IN);
}/* 在入口函数 */
static int __init sr04_init(void)
{int err;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);// trig pinerr = gpio_request(gpios[0].gpio, gpios[0].name);gpio_direction_output(gpios[0].gpio, 0);// echo pin{		gpios[1].irq  = gpio_to_irq(gpios[1].gpio);err = request_irq(gpios[1].irq, sr04_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[1].name, &gpios[1]);setup_timer(&gpios[1].key_timer, sr04_timer_func, (unsigned long)&gpios[1]);}/* 注册file_operations 	*/major = register_chrdev(0, "100ask_sr04", &sr04_drv);  /* /dev/gpio_desc */gpio_class = class_create(THIS_MODULE, "100ask_sr04_class");if (IS_ERR(gpio_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "100ask_sr04");return PTR_ERR(gpio_class);}device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "sr04"); /* /dev/sr04 */return err;
}/* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数*/
static void __exit sr04_exit(void)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);device_destroy(gpio_class, MKDEV(major, 0));class_destroy(gpio_class);unregister_chrdev(major, "100ask_sr04");// trig pingpio_free(gpios[0].gpio);// echo pin{free_irq(gpios[1].irq, &gpios[1]);del_timer(&gpios[1].key_timer);}
}/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */module_init(sr04_init);
module_exit(sr04_exit);MODULE_LICENSE("GPL");

四、应用程序

加入poll机制查询是不是有数据


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <signal.h>
#include <sys/ioctl.h>#define CMD_TRIG  100static int fd;/** ./button_test /dev/sr04**/
int main(int argc, char **argv)
{int val;struct pollfd fds[1];int timeout_ms = 5000;int ret;int	flags;int i;/* 1. 判断参数 */if (argc != 2) {printf("Usage: %s <dev>\n", argv[0]);return -1;}/* 2. 打开文件 */fd = open(argv[1], O_RDWR);if (fd == -1){printf("can not open file %s\n", argv[1]);return -1;}while (1){ioctl(fd, CMD_TRIG);printf("I am goning to read distance: \n");fds[0].fd = fd;fds[0].events = POLLIN;if (1 == poll(fds, 1, 5000)){if (read(fd, &val, 4) == 4)printf("get distance: %d cm\n", val*17/1000000);elseprintf("get distance err\n");}else{printf("get distance poll timeout/err\n");}sleep(1);}close(fd);return 0;
}

五、验证及其它

我们现在用的4.9.88版本用setup_timer

新的5.几的内核使用timer_setup

key_timer_expire函数的参数也不一样,4点几是long,5点几是把结构体传入。

现象和上次一样

013——超声波模块驱动开发(基于I.MX6uLL与SR04)-CSDN博客

 

这个数据后面需要处理一下不然太不稳定了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/790247.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue的双向绑定v-model详细介绍

使用&#xff1a; 比如用户在登录注册时需要提交账号密码&#xff1b; 比如用户创建&#xff0c;更新时&#xff0c;需要提交一些数据&#xff1b; v-model指令可以在表单 input、textarea以及select元素上创建双向绑定&#xff1b; 它会根据控件类型自动选取正确的方法来更…

一条SQL查询语句是如何执行的

这是专栏的第一篇文章&#xff0c;我想来跟你聊聊 MySQL 的基础架构。我们经常说&#xff0c;看一个事儿千万不要直接陷入细节里&#xff0c;你应该先鸟瞰其全貌&#xff0c;这样能够帮助你从高维度理解问题。同样&#xff0c;对于 MySQL 的学习也是这样。平时我们使用数据库&a…

Windows11安装MySql-8.0.36安装详细教程(保姆级教程)

之前一直用的mysql5.7&#xff0c;最近导入一个项目一直报错&#xff0c;经查阅发现数据库mysql版本太老&#xff0c;今天特地重头下载安装配置一下&#xff0c;做个记录供大家参考。 下载安装包&#xff1a; 下载地址&#xff1a;https://dev.mysql.com/downloads/ 进入后选…

【linux】公共服务器如何清理过多的.cache缓存

【linux】公共服务器如何清理过多的.cache缓存. 【先赞后看养成习惯】求关注+点赞+收藏😀 问题叙述:用的公共服务器,管理员反映.cache缓存过大,让我清理一下 .cache介绍:在Linux系统中,.cache目录通常用于存储应用程序运行时生成的缓存文件。这些文件包括临时文件、预览…

C++STL--排序算法

sort 使用快速排序,平均性能好O(nlogn),但最差情况可能很差O(n^2)。不稳定。 sort(v.begin(),v.end());//对v容器进行排序,默认升序 sort(v.begin(),v.end(),greater<int>());//降序排序对于支持随机访问的迭代器的容器&#xff0c; 都可以利用sort算法直接对其进行排序…

滑动窗口算法 - LC76 最小覆盖子串

接上文滑窗基础题&#xff1a;滑动窗口算法 - LC3 无重复字符的最长子串-CSDN博客&#xff0c;介绍了滑窗的基础题目和滑窗解法模板&#xff0c;这次带来滑窗进阶题解。 76. 最小覆盖子串 困难 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果…

基于SSM的师生交流平台

目录 背景 技术简介 系统简介 界面预览 背景 传统的师生互动平台主要依赖于面对面的线下交流&#xff0c;用户必须亲自到场以获取和交流相关信息。然而&#xff0c;随着信息技术的广泛传播&#xff0c;众多教育机构开始转向线上发展&#xff0c;寻求更多样化的发展途径。线…

day17-二叉树part04

110.平衡二叉树 &#xff08;优先掌握递归&#xff09;后序遍历 左右中 class Solution {public boolean isBalanced(TreeNode root) {return getHeight(root) ! -1;}//递归三部曲 确定方法的参数与返回值private int getHeight(TreeNode root){//明确终止条件if(root null){r…

数据库管理-第168期 惯性(20240402)

数据库管理168期 2024-04-02 数据库管理-第168期 惯性&#xff08;20240402&#xff09;1 加法的惯性2 创新的惯性3 长期的责任总结 数据库管理-第168期 惯性&#xff08;20240402&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#xff08;尹海文&#xff09; Oracle ACE Associa…

JS-优先级相关出现的一个小问题

console.log("嵌套函数中调用fn this值被赋给self" self o);这个输出会是 false。 在 JavaScript 中&#xff0c;比较两个对象是否相等时&#xff0c;实际上比较的是它们在内存中的引用地址&#xff0c;而不是它们的属性值。即使两个对象有相同的属性值&#xff…

C++11:声明 初始化

C11&#xff1a;声明 & 初始化 初始化{ }初始化initializer_list 声明autodecltypenullptr 初始化 { }初始化 在C98中&#xff0c;允许使用花括号{ }对数组或者结构体元素进行统一的列表初始化。 用{ }初始化数组&#xff1a; int arr[] { 1, 2, 3, 4, 5 };用{ }初始化…

详解2024年阿里云服务器租用价格表,最新报价

阿里云服务器租用价格表2024年最新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核…

C++中的List容器用法详解

文章目录 C中的List容器用法详解List 的特点List 的重要接口用法介绍1.创建和初始化Listlist 2.插入元素push_backpush_forntinsert 删除元素pop_backpop_fontclearerase 遍历List迭代器遍历范围for遍历 排序Listsort 反转Listreverse 转移Listsplice 去重unique 合并merge 总结…

网站可扩展架构设计——中台

从公众号转载&#xff0c;关注微信公众号掌握更多技术动态 --------------------------------------------------------------- 一、中台简介 1.传统项目架构的痛点 (1)重复造轮子 各项目相对独立&#xff0c;许多项目在重复造轮子&#xff0c;让项目本身越来越臃肿&#xf…

ts之基本类型,联合类型,函数,类的概念

1.ts中基础类型 数字 字符串 布尔 数组 元组 any never void null undefined 枚举 1.最基础的就是数字 字符串 布尔 number 和 大Number的区别 js特性 装箱的概念 xxx.xxx&#xff0c;string,boolean同理 let num1: number 1; let num2: Number 1; // 用来描述实例的 类也可…

精通并发【基础四】:创建线程的几种方式

在 Java 中&#xff0c;多线程编程是一种常见且强大的编程范式&#xff0c;它允许程序同时执行多个任务。创建线程是多线程编程的基础&#xff0c;Java 提供了几种不同的方法来创建和启动线程。本文将介绍三种常用的创建线程的方法&#xff1a;继承 Thread 类、实现 Runnable 接…

[Leetcode笔记] 动态规划相关

前言 写题目写到了一些和动态规划相关的内容&#xff0c;所以在这里记录一下 LCR 089 题解思路 总的来说&#xff0c;就是用一个数组去存储当前的最优解&#xff0c;然后从0开始一路向上顺推过去&#xff0c;求得最后一位的最优解。 class Solution { public:int rob(vect…

MT3016 竹鼠通讯

在真空中&#xff0c;一块无限平坦光滑绝缘不导热草地上有很多光滑且相同球形竹鼠&#xff0c;它们的坐标为&#xff08;xi​&#xff0c;yi​&#xff09;。竹鼠之间会通过脑电波联系彼此。现在请问相距最近两只竹鼠的直线距离分别是多少&#xff08;所有竹鼠都在草地的第一象…

检测头篇 | 利用RT-DETR模型的检测头去替换YOLOv8中的检测头

前言:Hello大家好,我是小哥谈。RT-DETR号称是打败YOLO的检测模型,其作为一种基于Transformer的检测方法,相较于传统的基于卷积的检测方法,提供了更为全面和深入的特征理解,将RT-DETR检测头融入YOLOv8,我们可以结合YOLO的实时检测能力和RT-DETR的深度特征理解能力,打造出…

VLAN基础讲解+不同VLAN间通信(实验)

第一章 VLAN基础 1.1 什么是VLAN 随着网络中计算机的数量越来越多&#xff0c;传统的以太网络开始面临广播泛滥以及安全性无法保证等各种问题。 VLAN即虚拟局域网&#xff0c;是将一个物理的局域网在逻辑上划分成多个广播域的技术。通过在交换机上配置VLAN&a…