2.22使用GPIO子系统编写LED灯驱动,应用程序测试//注册三个按键的中断

使用GPIO子系统编写LED灯驱动

驱动程序

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include "my3led.h"int major;
char kbuf[128] = {0};
struct class *cls;
struct device *dev;struct gpio_desc *gpiono1; // led1设备号
struct gpio_desc *gpiono2; // led2设备号
struct gpio_desc *gpiono3; // led3设备号
struct device_node *dnode; // 保存解析到的设备树节点地址// 创建功能码
#define LED_ON _IOW('l', 1, int)
#define LED_OFF _IOW('l', 0, int)int mycdev_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);unsigned long ret;// 向用户空间读取拷贝if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小size = sizeof(kbuf);ret = copy_to_user(ubuf, kbuf, size);if (ret) // 拷贝失败{printk("copy_to_user filed\n");return ret;}return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{unsigned long ret;// 从用户空间读取数据if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小size = sizeof(kbuf);ret = copy_from_user(kbuf, ubuf, size);if (ret) // 拷贝失败{printk("copy_to_user filed\n");return ret;}return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{switch (cmd){case LED_ON:switch (arg){case 1:gpiod_set_value(gpiono1, 1);break;case 2:gpiod_set_value(gpiono2, 1);break;case 3:gpiod_set_value(gpiono3, 1);break;}break;case LED_OFF:switch (arg){case 1:gpiod_set_value(gpiono1, 0);break;case 2:gpiod_set_value(gpiono2, 0);break;case 3:gpiod_set_value(gpiono3, 0);break;}break;}return 0;
}int mycdev_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}// 定义操作方法结构体变量并赋值
struct file_operations fops = {.open = mycdev_open,.read = mycdev_read,.write = mycdev_write,.unlocked_ioctl = mycdev_ioctl,.release = mycdev_close,
};static int __init mycdev_init(void)
{// 字符设备驱动注册major = register_chrdev(0, "mychrdev", &fops);if (major < 0){printk("字符设备驱动注册失败\n");return major;}printk("字符设备驱动注册成功:major=%d\n", major);// 向上提交目录cls = class_create(THIS_MODULE, "mychrdev");if (IS_ERR(cls)){printk("向上提交目录失败\n");return -PTR_ERR(cls);}printk("向上提交目录成功\n");// 向上提交设备节点信息int i; // 向上提交三次设备节点信息for (i = 0; i < 3; i++){dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);if (IS_ERR(dev)){printk("向上提交设备节点失败\n");return -PTR_ERR(dev);}}printk("向上提交设备节点成功\n");// 解析LED灯设备树节点dnode = of_find_node_by_path("/leds");if (dnode == NULL){printk("解析设备树节点失败\n");return -ENXIO;}printk("解析设备树节点成功\n");// 解析LED1的gpio编号gpiono1 = gpiod_get_from_of_node(dnode, "led1-gpio", 0, GPIOD_OUT_LOW, NULL);if (gpiono1 == NULL){printk("解析gpio编号失败\n");return -ENXIO;}printk("解析gpio编号成功\n");// 解析LED2的gpio编号gpiono2 = gpiod_get_from_of_node(dnode, "led2-gpio", 0, GPIOD_OUT_LOW, NULL);if (gpiono2 == NULL){printk("解析gpio编号失败\n");return -ENXIO;}printk("解析gpio编号成功\n");// 解析LED3的gpio编号gpiono3 = gpiod_get_from_of_node(dnode, "led3-gpio", 0, GPIOD_OUT_LOW, NULL);if (gpiono3 == NULL){printk("解析gpio编号失败\n");return -ENXIO;}printk("解析gpio编号成功\n");return 0;
}
static void __exit mycdev_exit(void)
{// 销毁设备节点信息device_destroy(cls, MKDEV(major, 0));// 销毁设备节点信息int i;for (i = 0; i < 3; i++){device_destroy(cls, MKDEV(major, i));}// 释放gpio编号gpiod_put(gpiono1);gpiod_put(gpiono2);gpiod_put(gpiono3);// 销毁目录class_destroy(cls);// 注销字符设备驱动unregister_chrdev(major, "mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

应用程序:

#include<stdlib.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#include<string.h>
#include<sys/ioctl.h>
#include "my3led.h"//创建功能码
#define LED_ON _IOW('l',1,int)  
#define LED_OFF _IOW('l',0,int)int main(int argc, char const *argv[])
{int a,b;int fd=open("/dev/myled0",O_RDWR);if(fd<0){printf("打开设备文件失败\n");exit(-1);}while(1){//从终端读取printf("请输入要实现的功能\n");printf("0(关灯) 1(开灯)\n");printf("请输入>");scanf("%d",&a);printf("请输入要控制的灯\n");printf("1(LED1) 2(LED2) 3(LED3)\n");printf("请输入>");scanf("%d",&b);switch(a){case 1:ioctl(fd,LED_ON,b);break;case 0:ioctl(fd,LED_OFF,b);break;}}close(fd);return 0;
}

头文件 

#ifndef __HEAD_H__
#define __HEAD_H__ 
typedef struct{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR;
}gpio_t;
#define PHY_LED1_ADDR 0X50006000
#define PHY_LED2_ADDR    0X50007000
#define PHY_LED3_ADDR 0X50006000
#define PHY_RCC_ADDR    0X50000A28//构建功能码
#define LED_ON _IO('l',1)  
#define LED_OFF _IO('l',0)
#endif 

运行效果图:

注册三个按键的中断---代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
/*myirq{compatible = "hqyj,myirq";interrupt-parent = <&gpiof>;interrupts=<9 0>,<7 0>,<8 0>;
};
*/struct device_node *dnode; // 保存解析到的设备树节点地址
unsigned int irqno1;
unsigned int irqno2;
unsigned int irqno3;
// 中断处理函数按键1
irqreturn_t myirq_handler1(int irq, void *dev)
{printk("key1_intc\n");return IRQ_HANDLED;
}
//按键2
irqreturn_t myirq_handler2(int irq, void *dev)
{printk("key2_intc\n");return IRQ_HANDLED;
}
//按键3
irqreturn_t myirq_handler3(int irq, void *dev)
{printk("key3_intc\n");return IRQ_HANDLED;
}static int __init mycdev_init(void)
{// 解析按键的设备树节点dnode = of_find_compatible_node(NULL, NULL, "hqyj,myirq");if (dnode == NULL){printk("解析设备树节点失败\n");return -ENXIO;}printk("解析设备树节点成功\n");// 解析按键1的软中断号irqno1 = irq_of_parse_and_map(dnode, 0);if (!irqno1){printk("解析软中断号失败\n");return -ENXIO;}printk("解析软中断号成功%d\n", irqno1);// 解析按键2的软中断号irqno2 = irq_of_parse_and_map(dnode, 1);if (!irqno2){printk("解析软中断号失败\n");return -ENXIO;}printk("解析软中断号成功%d\n", irqno2);// 解析按键3的软中断号irqno3 = irq_of_parse_and_map(dnode, 2);if (!irqno3){printk("解析软中断号失败\n");return -ENXIO;}printk("解析软中断号成功%d\n", irqno3);// 注册按键1中断int ret1 = request_irq(irqno1, myirq_handler1, IRQF_TRIGGER_FALLING, "key1", (void *)1);if (ret1){printk("1中断注册失败\n");return ret1;}printk("中断注册成功\n");// 注册按键2中断int ret2 = request_irq(irqno2, myirq_handler2, IRQF_TRIGGER_FALLING, "key2", (void *)2);if (ret2){printk("2中断注册失败\n");return ret2;}printk("中断注册成功\n");// 注册按键3中断int ret3 = request_irq(irqno3, myirq_handler3, IRQF_TRIGGER_FALLING, "key3", (void *)3);if (ret3){printk("3中断注册失败\n");return ret3;}printk("中断注册成功\n");return 0;
}
static void __exit mycdev_exit(void)
{free_irq(irqno1, (void *)1);free_irq(irqno2, (void *)2);free_irq(irqno3, (void *)3);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

三个按键按下后效果图:

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

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

相关文章

高防服务器主要运用在哪些场景?

高防服务器主要是用来防御DDOS攻击的服务器&#xff0c;能够为客户提供安全维护&#xff0c;高防服务器能够帮助网站拒绝服务攻击&#xff0c;定时扫描网络主节点&#xff0c;进行查找可能会出现的安全漏洞的服务类型&#xff0c;高防服务器也会根据不同的IDC机房环境来提供硬防…

Java的编程之旅22——将类作为对象的返回值

在Java中&#xff0c;可以将类作为对象的返回值。这可以通过在方法的声明中指定返回值类型为该类来实现。以下是一个示例&#xff1a; 首先定义一个“人”类 &#xff0c;Person类有三个成员变量&#xff1a;name、age和一个方法eat。 public class Person{public String nam…

ubuntu22.04@Jetson Orin Nano之CSI IMX219安装

ubuntu22.04Jetson Orin Nano之CSI IMX219安装 1. 源由2. 安装2.1 硬件安装2.2 软件配置2.3 新增摄像头 3. 效果4. 参考资料 1. 源由 折腾半天时间&#xff0c;捣鼓这个套装摄像头(IMX219)的安装&#xff0c;死活就是没有这个设备。世界总是这么小&#xff0c;看看遇到问题的大…

排序算法之——快速排序

快速排序 1.基本思想2.图示详解——以升序排列为例3.对基本思想和图示的补充说明4.代码实现5.空间、时间复杂度5.1最好情况5.2最坏情况 6.区间按照基准值划分的方法6.1 Hoare法6.2 挖坑法 7.优化措施7.1三数取中法7.1.1三数取中法——核心代码7.1.2优化效果7.1.3补充说明 7.2 递…

docker 容器内服务随容器自动启动

docker 容器内服务随容器自动启动 背景准备工作方案一&#xff0c;直接修改.bashrc文件&#xff08;简单粗暴&#xff09;方案二&#xff0c;编写启动脚本加入.bashrc文件&#xff08;文明一点&#xff09;制作nginx服务自启动镜像测试新镜像&#xff0c;nginx服务随容器自动启…

Pygame:让Python游戏开发无处不在

Pygame 是一个用于编写视频游戏的 Python 模块集。由于它提供了大量的工具和功能&#xff0c;使得 Python 开发者能够轻松地创建 2D 游戏&#xff0c;因此它已经成为 Python 游戏开发社区中非常受欢迎的选择。Pygame 支持跨平台开发&#xff0c;这意味着使用 Pygame 编写的游戏…

回显服务器的制作方法

文章目录 客户端和服务器TCP和UDP的特点UDP socket api的使用DatagramSocketDatagramPacketInetSocketAddress API 做一个简单的回显服务器UDP版本的回显服务器TCP版本的回显服务器 客户端和服务器 在网络中&#xff0c;主动发起通信的一方是客户端&#xff0c;被动接受的这一方…

Rman全备和增量备份说明

RMAN备份分为全备和增量备份&#xff0c;全备不能成为增量备份策略的一部分&#xff0c;它也不能作为后续增量备份的基础。 RMAN增量备份分为0、1、2三级&#xff0c;其中0级备份是增量备份的基础&#xff0c;备份内容也跟全备份一样&#xff0c;要使用增量备份&#xff0c;必…

华为交换机如何配置Web网管登录?直接用网页管理交换机

Web网管是一种对交换机的管理方式&#xff0c;它利用交换机内置的Web服务器&#xff0c;为用户提供图形化的操作界面。用户可以从终端通过HTTPS登录到Web网管&#xff0c;对交换机进行管理和维护&#xff0c;同时也非常方便。 一、配置思路&#xff1a; 1、配置管理IP地址&am…

mysql 自定义函数create function

方便后续查询&#xff0c;做以下记录&#xff1b; 自定义函数是一种与存储过程十分相似的过程式数据库对象&#xff0c; 它与存储过程一样&#xff0c;都是由 SQL 语句和过程式语句组成的代码片段&#xff0c;并且可以被应用程序和其他 SQL 语句调用。 自定义函数与存储过程之间…

使用 Nginx 将 HTTP 重定向到 HTTPS

配置重定向 HTTP 流量在 80 号端口被监听。这里我们将全部 HTTP 的流量都永久重定向到 HTTPS&#xff08;301&#xff09;。重定向时&#xff0c;保留原有的主机&#xff08;host&#xff09;和请求 URI。 server {listen 80;server_name _;return 301 https://…

提供英语励志名言的软件有哪些?这些软件不可错过

提供英语励志名言的软件有哪些&#xff1f;在追求个人成长和激励的道路上&#xff0c;英语励志名言常常为我们提供前进的动力。这些言简意赅、充满智慧的话语&#xff0c;不仅能在我们迷茫时指引方向&#xff0c;还能在挫折中给予我们勇气和力量。如今&#xff0c;随着科技的发…

题目 1124: C语言训练-大、小写问题

问题描述&#xff1a; 输入一串字符,将其中的大写变成小写&#xff0c;若不为大写则原样输出 样例输入&#xff1a; A123b 样例输出&#xff1a; a123b 问题分析&#xff1a; 潜在的缓冲区溢出风险&#xff1a; 代码声明了一个大小为 100 的字符数组 str 来存储输入的字…

工具变量-全国各省368个地级市河流密度数据集

1、数据来源&#xff1a;国家基础地理信息中心 2、时间跨度&#xff1a;-- 3、区域范围&#xff1a;全国各省市 4、指标说明&#xff1a; 根据河流矢量和中国城市行政边界矢量地理信息&#xff0c;计算每个城市河流的总长度&#xff1b;根据各城市的行政区划面积&#xff0…

C# 语言教程

一、引言 C#&#xff08;读作“C Sharp”&#xff09;是由微软开发的一种面向对象的编程语言&#xff0c;它结合了 C 的强大功能和 Java 的易用性。C# 语言是 .NET 框架的一部分&#xff0c;特别适用于 Windows 桌面应用程序、Web 应用程序以及分布式系统的开发。本教程将介绍…

stm32和嵌入式linux可以同步学习吗?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「stm3的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;如果需要使用STM32&#xff0c;建…

http://127.0.0.1:9222/json打不开Chrome环境变量问题

解决方案&#xff1a; 系统环境变量Path设置错误&#xff0c; 1、先看下端口是否占用&#xff1a;netstat -ano|findstr “9222” &#xff0c; 如下127.0.0.1:9222端口显示LISTENING是正常的 如果是SYN_SENT可能不太正常&#xff0c;这个时候&#xff0c; taskkill /PID 端…

【OpcUA开发笔记 2】open62541在Linux下编译及Qt开发

前言 在上一篇中&#xff0c;我们记录了在windows下通过CMake编译mingw版本的open62541&#xff0c;事实上是为了这一篇做铺垫&#xff0c;我们本次就在ubuntu下编译open62541&#xff0c;并通过Qt来调用它。 一、编译 1. 建立工程文件夹 我在主目录中建立文件夹project&#x…

【前端素材】推荐优质后台管理系统APP Zina平台模板(附源码)

一、需求分析 当我们从多个层次来详细分析后台管理系统时&#xff0c;可以将其功能和定义进一步细分&#xff0c;以便更好地理解其在不同方面的作用和实际运作。 1. 功能层次 a. 用户管理功能&#xff1a; 用户注册和登录&#xff1a;管理用户账户的注册和登录过程。权限管…

用js-插入HTML元素

这段代码是一个有序列表&#xff08;ordered list&#xff09;&#xff0c;使用<ol>标签包裹起来。有序列表中的每一项由<li>标签表示。 在这个例子中&#xff0c;有三个列表项&#xff1a; 目录 1目录 2目录 3 这段代码会渲染成一个有序列表&#xff0c;显示为&am…