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  100

struct 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;
	else
		return -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 timer
			mod_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 timer
		del_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 pin
	err = 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 pin
	gpio_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  100

static 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);
			else
				printf("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博客

 

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Loadrunner的使用

Loadrunner的使用 选项公网测试地址&#xff1a;http://cfgjt.cn:8981/devt-web 用户名admin&#xff0c;密码11111111 1.Loadrunner介绍 ​ LoadRunner&#xff0c;是一种预测系统行为和性能的负载测试工具。通过模拟上千万用户实施并发负载及实时性能监测的方式来确认和查…

Ubuntu部署BOA服务器

BOA服务器概述 BOA是一款非常小巧的Web服务器&#xff0c;源代码开放、性能优秀、支持CGI通用网关接口技术&#xff0c;特别适合用在嵌入式系统中。 BOA服务器主要功能是在互联嵌入式设备之间进行信息交互&#xff0c;达到通用网络对嵌入式设备进行监控&#xff0c;并将反馈信…

【c/c++】深入探秘:C++内存管理的机制

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章我们详细讲解c中的动态内存管理 目录 1.C/C内存分布2.C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free3.c内存管理方式3.1new/delete对内…

LeetCode-199. 二叉树的右视图【树 深度优先搜索 广度优先搜索 二叉树】

LeetCode-199. 二叉树的右视图【树 深度优先搜索 广度优先搜索 二叉树】 题目描述&#xff1a;解题思路一&#xff1a;广度优先搜索解题思路二&#xff1a;深度优先搜索解题思路三&#xff1a;0 题目描述&#xff1a; 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它…

股权激励和期权激励对比辨析

文章目录 概念定义 收益方式 风险评估 应用和分析 股权激励和期权激励&#xff0c;两者的区别是什么&#xff0c;本文就来梳理对比一下。 概念定义 股权激励&#xff0c;是指上市公司以本公司股票为标的&#xff0c;对其董事、高级管理人员及其他员工进行的长期性激励。取得…

微服务(基础篇-008-es、kibana安装)

目录 05-初识ES-安装es_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1LQ4y127n4?p81&vd_source60a35a11f813c6dff0b76089e5e138cc 1.部署单点es 1.1.创建网络 1.2.加载镜像 1.3.运行 2.部署kibana 2.1.部署 2.2.DevTools 3.安装IK分词器 3.1.在线安装ik…

程序员们应注意的行业特有的法律问题

大家好&#xff0c;我是不会魔法的兔子&#xff0c;是一枚执业律师&#xff0c;持续分享技术类行业项目风险及预防的问题。 一直以来兔子都在以大家做项目时候会遇到的风险问题做分享&#xff0c;最近有个念头一直挥之不去&#xff0c;就是要不要给我们广大的程序员们也分享一…

一文彻底搞懂ZooKeeper选举机制

文章目录 1. ZooKeeper 集群2. ZooKeeper 启动3. ZooKeeper 选举机制4. Follower&#xff08;跟随者&#xff09;和Candidate&#xff08;候选者&#xff09;节点区别5. Leader节点挂掉期间写操作是否会丢失 1. ZooKeeper 集群 ZooKeeper 是一个分布式的开源协调服务&#xff…

Node.js------模块化

◆ 能够说出模块化的好处◆ 能够知道 CommonJS 规定了哪些内容◆ 能够说出 Node.js 中模块的三大分类各自是什么◆ 能够使用 npm 管理包◆ 能够了解什么是规范的包结构◆ 能够了解模块的加载机制 一.模块化的基本概念 1.模块化 模块化是指解决一个复杂问题时&#xff0c…

基于SpringBoot+Thymeleaf的学生会管理系统

在这里插入图片描述 在这里插入图片描述

MYSQL——索引概念索引结构

索引 索引是帮助数据库高效获取数据的排好序的数据结构。 有无索引时&#xff0c;查询的区别 主要区别在于查询速度和系统资源的消耗。 查询速度&#xff1a; 在没有索引的情况下&#xff0c;数据库需要对表中的所有记录进行扫描&#xff0c;以找到符合查询条件的记录&#…

现在优秀企业都用SaaS知识库工具,原因就在这里

在这个信息化、知识化时代&#xff0c;企业的竞争力往往取决于能否有效管理和利用内部的知识资源。而如何实现这一任务呢&#xff1f;答案就在SaaS知识库工具。现在&#xff0c;很多优秀的企业已经使用了SaaS知识库工具进行知识管理&#xff0c;那么&#xff0c;他们为什么要这…

【洛谷 P8695】[蓝桥杯 2019 国 AC] 轨道炮 题解(映射+模拟+暴力枚举+桶排序)

[蓝桥杯 2019 国 AC] 轨道炮 题目描述 小明在玩一款战争游戏。地图上一共有 N N N 个敌方单位&#xff0c;可以看作 2D 平面上的点。其中第 i i i 个单位在 0 0 0 时刻的位置是 ( X i , Y i ) (X_i, Y_i) (Xi​,Yi​)&#xff0c;方向是 D i D_i Di​ (上下左右之一, 用…

kubadm部署kubernetes

什么是kubernetes Kubernetes是一款应用于集群的&#xff0c;容器自动部署、扩展和管理的开源平台&#xff0c;提供了一种以容器为中心的基础架构。利用kubernetes&#xff0c;你可以快速高效地响应客户如下请求&#xff1a; 应用程序的动态、精准部署应用程序的动态扩展无缝推…

【机器学习】K-近邻算法(KNN)介绍、应用及文本分类实现

一、引言 1.1 K-近邻算法&#xff08;KNN&#xff09;的基本概念 K-近邻算法&#xff08;K-Nearest Neighbors&#xff0c;简称KNN&#xff09;是一种基于实例的学习算法&#xff0c;它利用训练数据集中与待分类样本最相似的K个样本的类别来判断待分类样本所属的类别。KNN算法…

2024福建三支一扶报名流程,超全超详细!

2024年福建三支一扶报名已经开始&#xff0c;请注意时间&#xff01; ⚠2024年福建省省级“三支一扶”计划招募岗位1070个 报名时间&#xff1a;4月1日8:00至4月17日17:00 审查考核&#xff1a;4月18日至5月10日 确定派遣人员&#xff1a;5月11日至5月31日 报名入口&#xff1…

数据质量决定大模型能力,景联文科技提供高质量大模型数据

随着大模型的深入发展&#xff0c;各类资源要素的配置状态已悄然变化。其中&#xff0c;数据的价值已被提升到一个新高度。 大模型往往拥有庞大的参数和复杂的网络结构&#xff0c;需要大量的数据来学习和优化。数据的质量和数量直接决定了模型的训练效果。若数据不足或质量不佳…

【JavaScript 漫游】【051】Set 和 Map 数据结构

文章简介 本篇文章为【JavaScript 漫游】专栏的第 051 篇文章&#xff0c;记录了 ES6 规范新增的 Set 和 Map 数据结构的相关知识点。 SetWeakSetMapWeakMap Set 基本用法 类似于数组&#xff0c;但是成员的值都是唯一的&#xff0c;没有重复的值。 Set 本身是一个构造函…

IT外包行业未来发展趋势

随着企业对高可用性系统和分布式系统需求的增加&#xff0c;IT人才外包行业迎来了前所未有的发展机遇。未来几年&#xff0c; IT外包行业将呈现出一系列发展趋势 首先&#xff0c;IT外包人才队伍将不断壮大。随着企业对人效的需求日益增长&#xff0c;以及为规避用工风险和降低…

StarRocks实战——携程火车票指标平台建设

目录 前言 一、早期OLAP架构与痛点 二、指标平台重构整体设计 2.1 指标查询过程 2.1.1 明细类子查询 2.1.2 汇总类子查询 2.1.3 “缓存” 2.2 数据同步 三、Starrocks使用经验分享 3.1 建表经验 3.2 数据查询 3.3 函数问题 四、查询性能大幅提升 五、 后续优化方…