华清远见嵌入式学习——驱动开发——DAY8

作业要求:

1.使用GPIO子系统编写LED灯驱动,应用程序测试

2.注册三个按键的中断,只需要写内核代码

需要发布到CSDN

作业答案:

GPIO子系统:

代码效果:

应用程序:

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

//创建功能码
#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;
}

驱动程序:

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

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("/myled");
    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 <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_led; // 保存解析到的led设备树节点地址
struct device_node *dnode_int; // 保存解析到的中断设备树节点地址
unsigned int irqno1;       // 按键1软中断号
unsigned int irqno2;       // 按键2软中断号
unsigned int irqno3;       // 按键3软中断号
struct gpio_desc *gpiono1; // led1设备号
struct gpio_desc *gpiono2; // led2设备号
struct gpio_desc *gpiono3; // led3设备号

// 中断处理函数1
irqreturn_t myirq_handler1(int irq, void *dev)
{
    printk("key1_intc\n");
    //关灯三 开灯一
    gpiod_set_value(gpiono3, 0);
    gpiod_set_value(gpiono1, 1);
    return IRQ_HANDLED;
}
// 中断处理函数2
irqreturn_t myirq_handler2(int irq, void *dev)
{
    printk("key2_intc\n");
    //关灯一 开灯二
    gpiod_set_value(gpiono1, 0);
    gpiod_set_value(gpiono2, 1);
    return IRQ_HANDLED;
}
// 中断处理函数3
irqreturn_t myirq_handler3(int irq, void *dev)
{
    printk("key3_intc\n");
    //关灯二 开灯三
    gpiod_set_value(gpiono2, 0);
    gpiod_set_value(gpiono3, 1);
    return IRQ_HANDLED;
}

static int __init mycdev_init(void)
{
    // 解析按键的设备树节点
    dnode_int = of_find_compatible_node(NULL, NULL, "hqyj,myirq");
    if (dnode_int == NULL)
    {
        printk("解析设备树节点失败\n");
        return -ENXIO;
    }
    printk("解析设备树节点成功\n");

    // 解析LED灯设备树节点
    dnode_led = of_find_node_by_path("/myled");
    if (dnode_led == NULL)
    {
        printk("解析设备树节点失败\n");
        return -ENXIO;
    }
    printk("解析设备树节点成功\n");

    // 解析按键1的软中断号
    irqno1 = irq_of_parse_and_map(dnode_int, 0);
    if (!irqno1)
    {
        printk("解析按键1软中断号失败\n");
        return -ENXIO;
    }
    printk("解析按键1软中断号成功%d\n", irqno1);
    // 解析按键2的软中断号
    irqno2 = irq_of_parse_and_map(dnode_int, 1);
    if (!irqno2)
    {
        printk("解析按键2软中断号失败\n");
        return -ENXIO;
    }
    printk("解析按键2软中断号成功%d\n", irqno2);
    // 解析按键3的软中断号
    irqno3 = irq_of_parse_and_map(dnode_int, 2);
    if (!irqno3)
    {
        printk("解析按键3软中断号失败\n");
        return -ENXIO;
    }
    printk("解析按键3软中断号成功%d\n", irqno3);
    // 注册按键1中断
    int ret1 = request_irq(irqno1, myirq_handler1, IRQF_TRIGGER_FALLING, "key1", (void *)1);
    if (ret1)
    {
        printk("中断注册失败\n");
        return ret1;
    }
    printk("中断注册成功\n");
    // 注册按键2中断
    int ret2 = request_irq(irqno2, myirq_handler2, IRQF_TRIGGER_FALLING, "key2", (void *)2);
    if (ret2)
    {
        printk("中断注册失败\n");
        return ret2;
    }
    printk("中断注册成功\n");
    // 注册按键3中断
    int ret3 = request_irq(irqno3, myirq_handler3, IRQF_TRIGGER_FALLING, "key3", (void *)3);
    if (ret3)
    {
        printk("中断注册失败\n");
        return ret3;
    }
    printk("中断注册成功\n");

    // 解析LED1的gpio编号
    gpiono1 = gpiod_get_from_of_node(dnode_led, "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_led, "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_led, "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)
{
    // 释放软中断号
    free_irq(irqno1, (void *)1);
    free_irq(irqno2, (void *)2);
    free_irq(irqno3, (void *)3);

    // 释放gpio编号
    gpiod_put(gpiono1);
    gpiod_put(gpiono2);
    gpiod_put(gpiono3);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

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

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

相关文章

网页403错误(Spring Security报异常 Encoded password does not look like BCrypt)

这个错误通常表现为"403 Forbidden"或"HTTP Status 403"&#xff0c;它指的是访问资源被服务器理解但拒绝授权。换句话说&#xff0c;服务器可以理解你请求看到的页面&#xff0c;但它拒绝给你权限。 也就是说很可能测试给定的参数有问题&#xff0c;后端…

fastApi笔记05-路径参数和数值校验

使用Path可以对路径参数声明与Query相同类型的校验和元数据 from typing import Annotatedfrom fastapi import FastAPI, Path, Queryapp FastAPI()app.get("/items/{item_id}") async def read_items(item_id: Annotated[int, Path(title"The ID of the item …

软件开发工程师,几款常用的APP,你用过几款?最后一个测试网络必备

作为一名程序员&#xff0c;手机里一定有几个常用的app&#xff0c;下面给大家推荐几款。 1. CSDN 国内最大编程论坛&#xff1b;虽然有多少人吐槽现在使用csdn就像屎里淘金&#xff0c; 但是不得不承认他仍然是大家搜索技术资料、问题的首选。 遇到问题打开app搜索&#x…

【LeetCode】升级打怪之路 Day 01:二分法

今日题目&#xff1a; 704. 二分查找35. 搜索插入位置34. 在排序数组中查找元素的第一个和最后一个位置 目录 今日总结Problem 1: 二分法LeetCode 704. 二分查找 【easy】LeetCode 35. 搜索插入位置 ⭐⭐⭐⭐⭐LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置 【medi…

MySQL加锁策略详解

我们主要从三个方面来讨论这个问题&#xff1a; 啥时候加&#xff1f;如何加&#xff1f;什么时候该加什么时候不该加&#xff1f; 1、啥时候加 1.1 显式锁 MySQL 的加锁可以分为显式加锁和隐式加锁&#xff0c;显式加锁我们比较好识别的&#xff0c;因为他往往直接体现在 S…

SketchUp好用的插件介绍!最后一个渲染必备

在3D设计的世界里&#xff0c;SketchUp因其用户友好的界面和高效能特性而广受欢迎。如果你期望扩展SketchUp的功能范围&#xff0c;市场上提供了众多插件&#xff0c;它们能够帮助你更进一步地取得专业级的设计效果。让我们一探究竟&#xff01; 1、Multiple Offsets 由Sam D …

Leo赠书活动-18期 《高效使用Redis》

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 赠书活动专栏 ✨特色专栏&#xff1a;…

mac真的安装不了vmware吗 mac如何安装crossover crossover序列号从哪里买 购买正版渠道

有些用户可能想在mac上运行一些只能在windows上运行的软件&#xff0c;比如游戏、专业软件等。这时候&#xff0c;就需要用到虚拟机技术&#xff0c;也就是在mac上安装一个可以模拟其他操作系统的软件&#xff0c;比如vmware或者crossover。那么&#xff0c;mac真的安装不了vmw…

js谐音梗创意小游戏《望子成龙》

&#x1f33b; 前言 龙年到来&#xff0c;祥瑞满天。愿您如龙般矫健&#xff0c;事业腾飞&#xff1b;如龙鳞闪耀&#xff0c;生活美满。祝您龙年大吉&#xff0c;万事如意&#xff01; 龙年伊始&#xff0c;我给各位设计了一款原创的小游戏&#xff0c;话不多说&#xff0c;直…

WP----Look 我看的见你,你却看不见我 tips:sql injection tips2: mysql 字符集

0x00 题目连接打开后&#xff0c;是空白的&#xff0c;源代码也是空白的 这种情况就抓包&#xff0c;看请求包和相应包里面是否有提示 相应包中存在很特别的响应头X-HT: verify 可能是参数&#xff0c;传递任意参数过去 0x01 传递5个长度的参数时&#xff0c;返回 说明参数的…

Java SourceDataLine 播放音频 显示频谱

Java SourceDataLine 播放MP3音频 显示频谱 1 添加依赖2 快速傅里叶变换2.1 FFT.java2.2 Complex.java 3 音频播放3.1 Player.java3.1 XPlayer.java 4 显示频谱5 结果 项目Value音频格式 添加依赖*.wav(JDK 原生支持)*.pcm(JDK 原生支持)*.au(JDK 原生支持)*.aiff(JDK 原生支持…

SQL 练习题目(入门级)

今天发现了一个练习SQL的网站--牛客网。里面题目挺多的&#xff0c;按照入门、简单、中等、困难进行了分类&#xff0c;可以直接在线输入SQL语句验证是否正确&#xff0c;并且提供了测试表的创建语句&#xff0c;也可以方便自己拓展练习&#xff0c;感觉还是很不错的一个网站&a…

10MARL深度强化学习 Value Decomposition in Common-Reward Games

文章目录 前言1、价值分解的研究现状2、Individual-Global-Max Property3、Linear and Monotonic Value Decomposition3.1线性值分解3.2 单调值分解 前言 中心化价值函数能够缓解一些多智能体强化学习当中的问题&#xff0c;如非平稳性、局部可观测、信用分配与均衡选择等问题…

2024年.NET框架发展趋势预测

.NET框架仍然是全球开发人员的编程基石&#xff0c;为构建广泛的应用程序提供了一个通用的、强大的环境。微软对创新的坚定承诺见证了.NET的发展&#xff0c;以满足技术领域不断变化的需求。今年&#xff0c;在更广泛的行业运动、技术进步和开发者社区反馈的推动下&#xff0c;…

软件测试需要学习什么?好就业吗?

目前来说的话&#xff0c;整个it 都不太好&#xff01;但是既然你问了&#xff0c;我也就告诉你吧&#xff01; 1功能测试 &#xff1a;前端和后端&#xff0c;前端就是简单的页面&#xff0c;你需要考虑的是&#xff1a;必填项&#xff0c;边界值&#xff0c;组合&#xff0c…

智能搬运机器人|海格里斯将如何持续推进工业和物流的智能化升级与发展?

存取、搬运、分拣是物流行业中的通用功能&#xff0c;但具体到每个行业又十分不同&#xff0c;例如&#xff1a;新能源电池领域&#xff0c;它所搬运的东西是电池&#xff0c;50KG~200KG&#xff1b;快递行业领域&#xff0c;所要处理的物料是那种扁平件和信封等等&#xff0c;…

51单片机学习(3)-----独立按键控制LED的亮灭状态

前言&#xff1a;感谢您的关注哦&#xff0c;我会持续更新编程相关知识&#xff0c;愿您在这里有所收获。如果有任何问题&#xff0c;欢迎沟通交流&#xff01;期待与您在学习编程的道路上共同进步了。 目录 一. 器件介绍及实验原理 1.独立按键 &#xff08;1&#xff09;独…

Unity3d C#转换微信小游戏按小游戏包内模式包体20M限制问题记录

前言 在利用这个官方插件&#xff08;minigame-unity-webgl-transform&#xff09;将Unity3d的 项目转换为微信小游戏的过程中&#xff0c;转出的包体&#xff08;首包资源加载方式&#xff1a;小游戏包内&#xff09;不能超过20m的限制&#xff0c;如果大于这个值就需要采用首…

libigl 网格曲率计算

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 Mesh曲率特征通常指的是在三维几何网格(Mesh)上计算的曲率相关的一系列特征,包括主曲率、高斯曲率、平均曲率等。这些曲率特征提供了对Mesh表面形状的详细描述,对于表面形状分析、形状比较和几何建模等领域非常…

BUGKU-WEB 文件包含

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 解题思路 你说啥我就干啥&#xff1a;点击一下试试你会想到PHP伪协议这方面去嘛&#xff0c;你有这方面的知识储备吗&#xff1f; 相关工具 解题步骤 查看源码 看到了一点提示信息&#xff1a; ./index.…