首页 > 系统相关 >Linux驱动入门实验班——SR501红外模块驱动(附百问网视频链接)

Linux驱动入门实验班——SR501红外模块驱动(附百问网视频链接)

时间:2024-08-14 20:53:35浏览次数:9  
标签:sr501 val int 实验班 SR501 static gpio 驱动 include

目录

 一、工作方式

二、接口图

三、编写思路

1.构造file_operations结构体

2.实现read函数

3.编写入口函数

4.编写中断处理函数

5.编写出口函数

6.声明出入口函数以及协议

四、源码

五、课程链接


一、工作方式

SR501人体红外感应模块有两种工作模式:
        通过跳线来设置是否可以重复触发,默认为L。其中L表示不可重复,H表示可重复。含义如下:

①不可重复触发方式:

感应到人体并输出高电平后,延时时间一结束,输出将自动从高电平变为低电平。

②重复触发方式:

        感应到人体后输出高电平后,在延时时间段内,如果有人体在其感应范围内活动,其输出将一直保持高电平,直到人离开后才延时将高电平变为低电平(感应模块检测到人体的每一次活动后会自动顺延一个延时时间段,并且以最后一次活动的时间为延时时间的起始点)。

在本次实验中,我们使用的是不可重复触发方式。

二、接口图

根据下面接口图,我们可以算出SR501模块所在的引脚编号为115。

三、编写思路

1.构造file_operations结构体

        对于SR501模块我们只需要读取他即可。

static struct file_operations sr501_drv = {
	.owner = THIS_MODULE,
	.read = sr501_drv_read,
};

2.实现read函数

先是构造了,一个环形buf用来存放数据,读取也是直接从这个环形buf中读取数据。此外,还引入了对应用层是使用阻塞还是非阻塞方式执行的判断。

使用到的函数:

  • wait_event_interruptible()
  •  copy_to_user()
  • DECLARE_WAIT_QUEUE_HEAD()

3.编写入口函数

先将gpio编号转换为中断号,然后再申请中断,然后就是注册file_operations结构体

使用到的函数:

  • gpio_to_irq()
  • request_irq()
  • register_chrdev()
  • class_create()
  • device_create()

4.编写中断处理函数

每当产生上升沿或者下降沿时,就会触发中断,这时候就读取引脚电平,将数据放入环形buf。

使用到的函数:

  •  gpio_get_value()

5.编写出口函数

 释放掉入口函数中注册的资源。

使用到的函数:

  • device_destroy()
  • class_destroy()
  • unregister_chrdev()
  • free_irq()

6.声明出入口函数以及协议

  • module_init()
  • module_exit()
  • MODULE_LICENSE("GPL")

四、源码

驱动

#include "asm-generic/errno-base.h"
#include "asm-generic/gpio.h"
#include "asm/uaccess.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 BUF_LEN 128

struct gpio_desc{
	int gpio;
	int irq;
	char *name;
	int key;
	struct timer_list key_time;
};

static struct gpio_desc gpios[2] = {
	{115, 0, "sr501"},
};

static int major;
static struct class *sr501_class;
static struct fasync_struct *sr501_fasync;

static int r, w;
static int g_buf[BUF_LEN];

static int is_empty(void)
{
	return (r == w);
}

static int is_full(void)
{
	return (r = ((w + 1) % BUF_LEN));
}

static void put_val(int val)
{
	if (!is_full())
	{
		g_buf[w] = val;
		w = (w + 1) % BUF_LEN;
	}
}

static int get_val(void)
{
	int val = 0;
	if (!is_empty())
	{
		val = g_buf[r];
		r = (r + 1) % BUF_LEN;
	}
	return val;
}

static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);

static ssize_t sr501_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	int val;
	int ret;
	if (!is_empty() && (file->f_flags & O_NONBLOCK))
	{
		return -EINVAL;
	}

	wait_event_interruptible(gpio_wait, !is_empty());
	val = get_val();
	ret = copy_to_user(buf, &val, 4);

	return 4;
}


static struct file_operations sr501_drv = {
	.owner = THIS_MODULE,
	.read = sr501_drv_read,
};

static irqreturn_t sr501_isr(int irq, void *dev_id)
{
	int val;
	int key;
	struct gpio_desc *gpio_desc = dev_id;

	val = gpio_get_value(gpio_desc->gpio);
	key = (gpio_desc->key) | (val << 8);
	put_val(key);
	wake_up_interruptible(&gpio_wait);

	return IRQ_HANDLED;
}

static int __init sr501_drv_init(void)
{
	int ret;
	int count = sizeof(gpios) / sizeof(gpios[0]);
	int i;
	for (i = 0; i < count; i++)
	{
		gpios[i].irq = gpio_to_irq(gpios[i].gpio);

		ret = request_irq(gpios[i].irq, sr501_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[i].name, &gpios[i]);
	}
	major = register_chrdev(0, "sr501_drv",&sr501_drv);

	sr501_class = class_create(THIS_MODULE, "sr501_class");
	device_create(sr501_class, NULL, MKDEV(major, 0), NULL, "sr501_drv");

	return ret;
}

static void __exit sr501_drv_exit(void)
{
	int i;
	int count = sizeof(gpios) / sizeof(gpios[0]);
	
	device_destroy(sr501_class, MKDEV(major, 0));
	class_destroy(sr501_class);
	unregister_chrdev(major, "sr501_drv");

	for (i = 0; i < count; i++)
	{
		free_irq(gpios[i].irq, &gpios[i]);
	}
}

module_init(sr501_drv_init);
module_exit(sr501_drv_exit);

MODULE_LICENSE
("GPL");

应用


#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>

int main(int argc, char **argv)
{
	int fd;
	int val;
	
	if (argc != 2)
	{
		printf("Usage : %s <dev>\n", argv[0]);
		return -1;
	}

	fd = open(argv[1], O_RDWR);
	if (fd == -1)
	{
		printf("open %s error\n", argv[1]);
		return -1;
	}

	while (1)
	{
		if (read(fd, &val, 4) == 4)
		{
			printf("get sr501 : %d\n", val);
		}
		else
		{
			printf("get sr501 : error\n");
		}
	}

	close(fd);
	return 0;
}

五、课程链接

40_模板1实战_SR501红外模块驱动编程 (100ask.net)icon-default.png?t=N7T8https://video.100ask.net/p/t_pc/course_pc_detail/video/v_636c762ce4b0276efeaea816?product_id=p_634cbce4e4b00a4f37500252&content_app_id=&type=6

标签:sr501,val,int,实验班,SR501,static,gpio,驱动,include
From: https://blog.csdn.net/m0_75183905/article/details/141185034

相关文章

  • linux内核模块 字符设备驱动模板
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、linux内核模块是什么?二、代码示例总结前言提示:这里可以添加本文要记录的大概内容:内核版本5.10.92linux内核模块字符设备驱动模板cdev注册字符设备,创建一个/dev/下设备节点和/sy......
  • Linux驱动开发基础(LED驱动)
    所学来自百问网目录1.LED原理2.普适的GPIO引脚操作方法2.1GPIO模块的一般结构2.2GPIO框图2.3寄存器的操作2.3.1一般的操作方式2.3.2高效的操作方式3.基于IMX6UL_6ULL的GPIO操作方法3.1GPIO框图3.2CCM3.3IOMUXC3.4GPIO模块内部3.5读写GPIO4.LED驱......
  • 事件驱动系统设计之将事件检索与事件处理解耦
    0前言part1讨论了集成过程中遇到的挑战以及幂等事件处理的作用。解决集成问题之后,我们需要反思事件检索的问题。我们的经验教训表明,将事件检索与事件处理解耦至关重要。1事件处理与请求/响应API紧耦合part1讨论了将请求/响应API集成到事件驱动微服务中时,由于基于请求/响......
  • 驱动开发环境搭建
    1.安装VS2019首先,我们需要安装VS2019,资源链接如下:VS2019+WDK:https://pan.baidu.com/s/1LYIn1MXLjY_zgEgLr8SgYA?pwd=xyji在安装的时候我们需要注意务必要注意,图上已勾选的选项必须要全部勾选,漏勾可能会导致各种奇怪的问题!可选部分我们需要勾选的安装项如下:需要注意的......
  • JDBC加载MySQL驱动【底层实现】
    JDBC4.0如何加载引入依赖<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.32</version></dependency>上代码importjava.sql.Connection;impor......
  • ubuntu网卡驱动修复
    问题引起更换显卡驱动时频繁重启,突然发现右上角没有网络图标了。尝试法1网络上查到的大多与NetworkManager相关。sudoserviceNetworkManagerstopsudorm/var/lib/NetworkManager/NetworkManager.statesudogedit/etc/NetworkManager/NetworkManager.conf这一步将打......
  • 事件驱动架构在云时代为什么会再次流行呢?
    事件驱动架构在云时代为什么会再次流行呢?什么是事件驱动架构(EDA)事件驱动架构与消息再度流行的事件驱动架构作为一个经典架构模式,在全行业数字化转型的时代,事件驱动架构(EDA)应用范围扩大,成为Gartner年度十大技术趋势。在新型的数字化商业解决方案里,会有60%采纳EDA......
  • Realtek 网卡驱动程序是用于操作系统与 Realtek 网络适配器之间的通信软件。这些驱动
    Realtek网卡,特别是用于个人电脑和服务器的网卡,曾经发现过一些安全漏洞。以下是一些常见的Realtek网卡漏洞及其相关信息:CVE-2020-28015:这个漏洞存在于RealtekRTL8188EU驱动程序中,影响了在特定情况下的无线网络连接。攻击者可以利用这个漏洞执行任意代码或引发系统崩溃。......
  • 医用微网孔雾化片驱动芯片—和迅康科技
    HK9002系列是微孔雾化片驱动专用集成电路,主要用于医疗产品上,适应频率范围为100KHz~120KHz(中心频率108KHz)的微孔雾化片,自适应频率范围为140KHz~160KHz(中心频率150KHz)的微孔雾化片,正常工作电压4.5-5.0V,其内部集成微孔雾化片频率适应电路,可以检测微孔雾化片需要频率进行......
  • LLM分类模式驱动一
      今天给大家带来的文章是LLM分类模式驱动,希望能对学习LLM的同学们有所帮助。文章目录1.前言2.模式驱动生成1.前言  随着这两年大语言模型的应用,各种语言模型已经在很多领域带来了许多颠覆性的成果,但是在融入各种程序环境时,大语言模型也遇到了一些阻碍。为了......