驱动开发(中断)

news2024/9/9 5:24:55

头文件:

#ifndef __LED_H__
#define __LED_H__

#define PHY_LED1_MODER 0X50006000
#define PHY_LED1_ODR  0X50006014
#define PHY_LED1_RCC 0X50000A28

#define PHY_LED2_MODER 0X50007000
#define PHY_LED2_ODR  0X50007014
#define PHY_LED2_RCC  0X50000A28

#define PHY_LED3_MODER 0X50006000
#define PHY_LED3_ODR  0X50006014
#define PHY_LED3_RCC  0X50000A28
//风扇
#define PHY_FAN_MODER 0X50006000
#define PHY_FAN_ODR  0X50006014
#define PHY_FAN_RCC 0X50000A28
//蜂鸣器
#define PHY_BUZZER_MODER 0X50003000
#define PHY_BUZZER_ODR  0X50003014
#define PHY_BUZZER_RCC 0X50000A28
//马达
#define PHY_MOTOR_MODER 0X50007000
#define PHY_MOTOR_ODR  0X50007014
#define PHY_MOTOR_RCC 0X50000A28
//功能码
#define LED_ON _IO('l',1)
#define LED_OFF _IO('l',0)
#define FAN_ON _IO('f',1)
#define FAN_OFF _IO('f',0)
#define BUZZER_ON _IO('b',1)
#define BUZZER_OFF _IO('b',0)
#define MOTOR_ON _IO('m',1)
#define MOTOR_OFF _IO('m',0)
#endif

 

应用层程序:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"
int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    int led1_fd, led2_fd, led3_fd;
    // 打开led设备文件
    led1_fd = open("/dev/mycdev0", O_RDWR);
    if (led1_fd < 0)
    {
        printf("打开led1设备文件失败\n");
        exit(-1);
    }
    led2_fd = open("/dev/mycdev1", O_RDWR);
    if (led2_fd < 0)
    {
        printf("打开led2设备文件失败\n");
        exit(-1);
    }
    led3_fd = open("/dev/mycdev2", O_RDWR);
    if (led3_fd < 0)
    {
        printf("打开led3设备文件失败\n");
        exit(-1);
    }
    int a, b;
    while (1)
    {
        printf("请选择要控制的器件: 1(led灯1) 2 (led灯2) 3 (led灯3) ");
        scanf("%d", &a);
        printf("请输入指令:0(关闭) 1 (打开)");
        scanf("%d", &b);

        switch (b)
        {
        case 1:
            switch (a)
            {
            case 1:
                ioctl(led1_fd, LED_ON, a);
                break;
            case 2:
                ioctl(led2_fd, LED_ON, a);
                break;
            case 3:
                ioctl(led3_fd, LED_ON, a);
                break;
            }
            break;
        case 0:
            switch (a)
            {
            case 1:
                ioctl(led1_fd, LED_OFF, a);
                break;
            case 2:
                ioctl(led2_fd, LED_OFF, a);
                break;
            case 3:
                ioctl(led3_fd, LED_OFF, a);
                break;
            }

            break;
        }
    }

    close(led1_fd);
    close(led2_fd);
    close(led3_fd);

    return 0;
}

驱动程序:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
#include "head.h"
struct cdev* mycdev;
struct class* cls;
struct device* dev_d;
unsigned int major = 500;
unsigned int minor = 0;
dev_t devno;
char kbuf[128] = {0};
wait_queue_head_t wq_head;
int condition = 0;
struct device_node *dev,*led_dev;
unsigned int irqno1,irqno2,irqno3;
struct gpio_desc* gpiono1,*gpiono2,*gpiono3;
// 封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
	int a = inode->i_rdev;
	file->private_data = (void *)MINOR(a);
	printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
	return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{

	printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
	return 0;
}
long mychrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{	unsigned int a;
	printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
	a = (unsigned int)file->private_data;
	switch(a)
	{
		
		case 0:
			if(cmd == LED_ON){
				 gpiod_set_value(gpiono1,1);
			}
			else{
				 gpiod_set_value(gpiono1,0);
			}
			
			break;
		case 1:
			if(cmd == LED_ON){
				 gpiod_set_value(gpiono2,1);
			}
			else{
				 gpiod_set_value(gpiono2,0);
			}
			
			break;
		case 2:
			if(cmd == LED_ON){
				 gpiod_set_value(gpiono3,1);
			}
			else{
				 gpiod_set_value(gpiono3,0);
			}
			
			break;
		
	}
	return 0;
}
irqreturn_t myirq_handler(int irq,void *dev)
{
    gpiod_set_value(gpiono1,!gpiod_get_value(gpiono1));
    return IRQ_HANDLED;
}
irqreturn_t myirq2_handler(int irq,void *dev)
{
    gpiod_set_value(gpiono2,!gpiod_get_value(gpiono2));
    return IRQ_HANDLED;
}
irqreturn_t myirq3_handler(int irq,void *dev)
{
    gpiod_set_value(gpiono3,!gpiod_get_value(gpiono3));
    return IRQ_HANDLED;
}
//对设备文件进行操作的结构体
struct file_operations fops = {

	.open = mycdev_open,//打开
	.unlocked_ioctl = mychrdev_ioctl,//硬件功能的选择
	.release = mycdev_close,//关闭
};
static int __init mycdev_init(void)
{
    int i;
	major = register_chrdev(0,"mycdev",&fops);
	if(major<0){
		printk("注册设备驱动失败\n");
		return major;
	}
	printk("注册设备驱动成功major=%d\n",major);
	//************自动申请设备节点*********************
	//1、向上提交目录
	cls = class_create(THIS_MODULE, "mycdev");
	if(IS_ERR(cls)){
		printk("向上提交目录失败\n");
		return -PTR_ERR(cls);
	}
	printk("向上提交目录成功\n");
	// 2、向上提交设备节点信息
	
		for (i = 0; i < 3; i++)
	{
		dev_d = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);
		if (IS_ERR(dev_d))
		{
			printk("提交led设备信息失败\n");
			return -PTR_ERR(dev_d);
		}
	}
	printk("提交设备信息成功\n");
    /***********************************/
    //解析设备树的节点
    int ret;
    dev = of_find_node_by_name(NULL,"myirq");
    if(dev == NULL){
        printk("解析设备树节点失败\n");
        return -EIO;
    }
    printk("解析myirq设备树节点成功\n");
    led_dev = of_find_node_by_name(NULL,"leds");
    if(led_dev == NULL){
        printk("解析led设备树节点失败\n");
        return -EIO;
    }
    printk("解析led设备树节点成功\n");
    gpiono1 = gpiod_get_from_of_node(led_dev,"led1-gpios",0,GPIOD_OUT_LOW,NULL);
    if(IS_ERR(gpiono1)){
        printk("申请gpio对象失败\n");
        return -PTR_ERR(gpiono1);
    }
    gpiono2 = gpiod_get_from_of_node(led_dev,"led2-gpios",0,GPIOD_OUT_LOW,NULL);
    if(IS_ERR(gpiono2)){
        printk("申请gpio2对象失败\n");
        return -PTR_ERR(gpiono2);
    }
    gpiono3 = gpiod_get_from_of_node(led_dev,"led3-gpios",0,GPIOD_OUT_LOW,NULL);
    if(IS_ERR(gpiono3)){
        printk("申请gpio3对象失败\n");
        return -PTR_ERR(gpiono3);
    }
    //根据设备树节点解析出软中断号
    irqno1 = irq_of_parse_and_map(dev,0);
    if(!irqno1){
        printk("解析led1软中断号失败\n");
        return -ENXIO;
    }
    printk("解析软led1中断号成功irqno=%d\n",irqno1);
    irqno2 = irq_of_parse_and_map(dev,1);
    if(!irqno2){
        printk("解析led2软中断号失败\n");
        return -ENXIO;
    }
    printk("解析led2软中断号成功irqno=%d\n",irqno2);
    irqno3 = irq_of_parse_and_map(dev,2);
    if(!irqno3){
        printk("解析led3软中断号失败\n");
        return -ENXIO;
    }
    printk("解析led3软中断号成功irqno=%d\n",irqno3);
    //注册中断
    ret = request_irq(irqno1,myirq_handler,IRQF_TRIGGER_FALLING,"key1",NULL);
    if(ret){
        printk("key1软中断号注册失败\n");
        return ret;
    }
    printk("key1软中断号注册成功\n");
     ret = request_irq(irqno2,myirq2_handler,IRQF_TRIGGER_FALLING,"key2",NULL);
    if(ret){
        printk("key2软中断号注册失败\n");
        return ret;
    }
    printk("key2软中断号注册成功\n");
     ret = request_irq(irqno3,myirq3_handler,IRQF_TRIGGER_FALLING,"key3",NULL);
    if(ret){
        printk("key3软中断号注册失败\n");
        return ret;
    }
    printk("key3软中断号注册成功\n");

    return 0;
}
static void __exit mycdev_exit(void)
{
   int i;
    //灭灯
    gpiod_set_value(gpiono1,0);
    //释放gpio编号
    gpiod_put(gpiono1);
    //灭灯
    gpiod_set_value(gpiono2,0);
    //释放gpio编号
    gpiod_put(gpiono2);
    //灭灯
    gpiod_set_value(gpiono3,0);
    //释放gpio编号
    gpiod_put(gpiono3);
    //注销中断号
    free_irq(irqno1,NULL);
    free_irq(irqno2,NULL);
    free_irq(irqno3,NULL);
    //销毁节点信息
	for (i = 0; i < 3; i++)
	{
		device_destroy(cls, MKDEV(major, i));
	}
	//销毁目录信息
	class_destroy(cls);
	//注销字符设备驱动
	unregister_chrdev(major,"mycdev");


}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

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

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

相关文章

java学习路程之篇六、进阶知识、常用API、Arrays工具类、冒泡排序、选择排序、二分查找、正则表达式

文章目录 1、Arrays工具类2、冒泡排序3、选择排序4、二分查找5、正则表达式 1、Arrays工具类 2、冒泡排序 3、选择排序 4、二分查找 5、正则表达式

抖音引流推广的几个方法,抖音全自动引流脚本软件详细使用教学

大家好我是你们的小编一辞脚本&#xff0c;今天给大家分享新的知识&#xff0c;很开心可以在CSDN平台分享知识给大家,很多伙伴看不到代码我先录制一下视频 在给大家做代码&#xff0c;给大家分享一下抖音引流脚本的知识和视频演示 不懂的小伙伴可以认真看一下&#xff0c;我们…

快速搭建Vue项目

1.安装node环境 下载地址为&#xff1a;https://nodejs.org/en/ 注意node版本问题&#xff0c;有很多情况下是node版本问题导致的错误。 2.安装淘宝镜像cnpm 为了提高我们的效率&#xff0c;可以使用淘宝的镜像&#xff1a;http://npm.taobao.org/ npm install cnpm -g --r…

【Redis】内存数据库Redis进阶(搭建各种集群)

目录 单机安装Redis搭建Redis主从集群搭建Redis哨兵集群 基于 CentOS 7 的 Redis 集群 单机安装Redis 安装 Redis 所需要的依赖&#xff1a; yum install -y gcc tcl将 Redis 安装包&#xff08;redis-6.2.4.tar.gz&#xff09;上传到任意目录 解压缩&#xff1a; tar -xzf …

如何过一个高质量的周末?

如何过一个高质量的周末&#xff1f; &#x1f607;博主简介&#xff1a;我是一名正在攻读研究生学位的人工智能专业学生&#xff0c;我可以为计算机、人工智能相关本科生和研究生提供排忧解惑的服务。如果您有任何问题或困惑&#xff0c;欢迎随时来交流哦&#xff01;&#x1…

分布式系统常见理论讲解

分布式系统是指由多个节点通过网络进行通信和协作的系统&#xff0c;它具有高可用性、高扩展性、高性能等优点&#xff0c;但也面临着一些挑战&#xff0c;如数据一致性、容错性、负载均衡等。为了解决这些问题&#xff0c;分布式系统设计出现了一些经典的理论和方法&#xff0…

阻塞队列BlockingQueue详解

一、阻塞队列介绍 1、队列 队列入队从队首开始添加&#xff0c;直至队尾&#xff1b;出队从队首出队&#xff0c;直至队尾&#xff0c;所以入队和出队的顺序是一样的 Queue接口 add(E) &#xff1a;在指定队列容量条件下添加元素&#xff0c;若成功返回true&#xff0c;若当前…

【C++奇遇记】初探名称空间

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集 数据库专栏 初阶数据结构 &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如…

Ubuntu篇——Ubuntu20.04备份成ISO镜像文件并安装到其他电脑上(完整步骤)

注意&#xff0c;此方法制作的镜像&#xff0c;仅限于相同硬件配置的电脑安装&#xff0c;否则可能会发生某些驱动不兼容导致无法安装的情况。&#xff08;例如英伟达显卡的笔记本电脑&#xff0c;很大概率无法安装你在其他显卡电脑上制作的镜像。&#xff09; 一、安装systemb…

设计模式行为型——命令模式

目录 什么是命令模式 命令模式的实现 命令模式角色 命令模式类图 命令模式举例 命令模式代码实现 命令模式的特点 优点 缺点 使用场景 注意事项 什么是命令模式 命令模式&#xff08;Command Pattern&#xff09;是一种数据驱动的设计模式&#xff0c;它属…

一篇关于CPU的硬核知识

不管你玩硬件还是做软件&#xff0c;你的世界都少不了计算机最核心的 —— CPU。 01CPU是什么&#xff1f; CPU与计算机的关系就相当于大脑和人的关系&#xff0c;它是一种小型的计算机芯片&#xff0c;通常嵌入在电脑的主板上。CPU的构建是通过在单个计算机芯片上放置数十亿…

iOS开发-UIScrollView嵌套tableView实现顶部tab横向切换

iOS开发-UIScrollView嵌套tableView实现顶部tab横向切换 通过ScollView嵌套两个TableView左右切换功能 一、UIScollView UIScrollView可滚动控件&#xff0c;这里初始化需要设置_backScollView.pagingEnabled YES; 代码如下 _backScollView [[UIScrollView alloc] initWi…

ARP协议请求

文章目录 作用请求与应答流程数据包ARP协议以太网帧协议具体应用 作用 通过 IP地址 查找 MAC地址。 请求与应答流程 A&#xff1a;数据发送主机 B&#xff1a;目标主机 目前只知道目标主机IP地址&#xff0c;想把数据发送过去&#xff0c;需要查询到目标主机的MAC地址&#x…

构建基于大模型的Autonomous Agents案例(一)

构建基于大模型的Autonomous Agents案例 1.1 Autonomous Agents原理机制 在本节中&#xff0c;我们将聚焦于LangChain上的自治代理&#xff08;Autonomous Agents on LangChain&#xff09;。自治代理是当前业界最热门的话题之一&#xff0c;特别是在企业级应用中。当然&#x…

关于综合能源智慧管理系统的架构及模式规划的研究

安科瑞 华楠 摘 要&#xff1a;探讨了国内外能源互联网的研究发展&#xff0c;分析了有关综合智慧能源管理系统的定位&#xff0c;以及系统的主要特点&#xff0c;研究了综合智慧能源管理系统的构架以及模式规划。 关键词&#xff1a;综合能源&#xff1b;智慧管理系统&#…

MySql操作进阶

目录 1.多表联查 1.1内连接 1.2左连接和右连接 1.3自连接 2.子查询 3.合并查询 1.多表联查 多表联查实际上就是对多张表中的数据合并在一起进行查询&#xff0c;具体合并多张表中的数据方式为&#xff1a;取笛卡尔积的方式进行合并。 但仅是以笛卡尔积的方式合并表较为…

网络安全进阶学习第九课——SQL注入介绍

文章目录 一、什么是注入二、什么是SQL注入三、SQL注入产生的原因四、SQL注入的危害五、SQL注入在渗透中的利用1、绕过登录验证&#xff1a;使用万能密码登录网站后台等。2、获取敏感数据3、文件系统操作4、注册表操作5、执行系统命令 六、如何挖掘SQL注入1、SQL注入漏洞分类按…

无涯教程-Lua - Arrays(数组)

数组是对象的有序排列&#xff0c;可以是包含行集合的一维数组&#xff0c;也可以是包含多行和多列的多维数组。 在Lua中&#xff0c;数组是使用带有整数的索引表实现的。数组的大小不是固定的&#xff0c;并且可以根据无涯教程的要求(取决于内存限制)来增长。 一维数组 一维…

WEB应用程序数据库防守篇之预防SQL漏洞注入

前言: 国内目前几乎市面上所有的web应用程序都使用关系型数据库来存储用户的数据信息&#xff0c;可以这么说&#xff0c;数据库是一个项目&#xff0c;一个互联网公司乃至国家最重要的数据中心。如果数据库被入侵成功&#xff0c;所引发的后果将是灾难性&#xff0c;无法想象…

JavaSE 【类和对象】(3)(重点:代码块、对象的打印)

目录 一、代码块 1.静态代码块 2.构造代码块/实例代码块 3.总结 代码块执行的顺序&#xff1a; 1.静态代码块 2.构造代码块&#xff08;实例代码块&#xff09; 3.执行对应的构造方法 其中&#xff1a;静态的只执行一次 二、 对象的打印 有一个快速打印的方法&#x…