华清远见:驱动点灯第N回目

news2025/7/10 10:44:56

1.在串口工具进行输入:

echo 1 > /dev/myled0 ---->led1灯点亮

echo 0 > /dev/myled0 ---->led1灯熄灭

echo 1 > /dev/myled1 ---->led1灯点亮

echo 0 > /dev/myled1 ---->led1灯熄灭

echo 1 > /dev/myled2 ---->led1灯点亮

echo 0 > /dev/myled2 ---->led1灯熄灭

linux@ubuntu:/sys/class/myled$ ls /dev/myled* -ll

crw------- 1 root root 236, 0 Nov 18 14:55 /dev/myled0 ----->控制PE10(LED1)

crw------- 1 root root 236, 1 Nov 18 14:55 /dev/myled1----->控制PF10(LED2)

crw------- 1 root root 236, 2 Nov 18 14:55 /dev/myled2----->控制PE8(LED3)

2.驱动:

open:在open函数中获取到次设备号,用私有数据传参,传递给write函数

write:在write函数,判断次设备号,就知道操作的是哪盏灯

3.要求:

1)分部实现注册字符设备驱动

2)自动创建设备节点

3)通过结构体对led灯地址进行映射

4)次设备号完成私有数据传参

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include<linux/slab.h>
#include "demo2.h"

#define CNAME "myled" //宏定义设备名


//定义设备号
#if 1
unsigned int major = 0; //动态设备号
#else
unsigned int major = 500; //动态设备号
#endif

//int all_led_init();
const int count = 3;

int mnior = 0;      //次设备号
struct cdev *cdev;  //
struct class *cls;  //目录句柄
struct device *dev; //

gpio_t *led1;
unsigned int *RCC;
gpio_t *led2;
gpio_t *led3;



//打开
int mydemo_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);

    file->private_data = (void*)(MINOR(inode->i_rdev));
    
    return 0;
}

//读
ssize_t mydemo_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
//写
ssize_t mydemo_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
    char kbuf[10]={0};
    int ret;
    int a;
     if(size>sizeof(kbuf))
    size=sizeof(kbuf);
    a=(int)file->private_data;
    printk("myled%d open\n",a);

    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);

    ret = copy_from_user(kbuf, ubuf, size);
    if (ret)
    {
        printk("copy from user is error\n");
        return -EIO;
    }

    //接收第一个灯信息
    if (kbuf[0] == '1') //开灯
    {
        if (a == 0)
            led1->ODR |= (1 << 10);
        else if (a == 1)
            led2->ODR |= (1 << 10);
        else if (a == 2)
            led3->ODR |= (1 << 8);
    }
    else if (kbuf[0] == '0') //关灯
    {
        if (a == 0)
            led1->ODR &= ~(1 << 10);
        else if (a == 1)
            led2->ODR &= ~(1 << 10);
        else if (a == 2)
            led3->ODR &= ~(1 << 8);
    }
    return size;
}
//关闭

int mydemo_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

//操作方法结构体初始化
const struct file_operations fops =
{
        .open = mydemo_open,
        .read = mydemo_read,
        .write = mydemo_write,
        .release = mydemo_close,
};

int all_led_init(void)
{

    //映射地址
    //映射物理地址为虚拟地址
    RCC = ioremap(0x50000A28, 4);  // GPLOE使能
    led1 = ioremap(0x50006000, 4); // PE引脚设置为输出模式
    led2 = ioremap(0x50007000, 4);
    led3 = ioremap(0x50006000, 4);

    (*RCC) |= (0x3 << 4);
    // led1
    led1->MODER &= ~(0x3 << 20);
    led1->MODER |= (0x1 << 20);
    led1->ODR &= ~(0x1 << 10);

    // led2
    led2->MODER &= ~(0x3 << 20);
    led2->MODER |= (0x1 << 20);
    led2->ODR &= ~(0x1 << 10);

    // led3
    led3->MODER &= ~(0x3 << 16);
    led3->MODER |= (0x1 << 16);
    led3->ODR &= ~(0x1 << 8);

    return 0;
}

//入口函数
static int __init demo_init(void)
{
    int ret, i;
    dev_t devno;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    // 1.分配结构体对象
    cdev = cdev_alloc();
    if (NULL == cdev)
    {
        printk("cdev alloc is error\n");
        ret = -ENOMEM;
        goto ERR1;
    }
    printk("cdev 分配成功\n");
    // 2.设备对象初始化
    cdev_init(cdev, &fops);

    // 3.设备号申请
    if (major == 0)
    {
        ret = alloc_chrdev_region(&devno, mnior, count, CNAME); //动态申请设备号
        if (ret)
        {
            printk("alloc_chrdev_register is error \n");
            goto ERR2;
        }

        major = MAJOR(devno);
        mnior = MINOR(devno);
        printk("动态申请设备号成功\n");
    }
    else
    {
        ret = register_chrdev_region(MKDEV(major, mnior), count, CNAME); //静态申请设备号
        if (ret)
        {
            printk("静安申请设备号失败\n");
            goto ERR2;
        }
        printk("静态申请设备号成功\n");
    }

    // 4.注册字符设备驱动
    ret = cdev_add(cdev,MKDEV(major, mnior), count);
    if (ret)
    {
        printk("字符设备驱动注册失败\n");
        goto ERR3;
    }
    printk("字符设备注册成功\n");

    // 5.自动创建设备结点
    cls = class_create(THIS_MODULE, "led");
    if (IS_ERR(cls))
    {
        printk("创建设备目录失败\n");
        ret = PTR_ERR(cls);
        goto ERR4;
    }

    //向上提交设备结点信息
    for (i = 0; i < 3; i++)
    {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
        if (IS_ERR(dev))
        {
            printk("创建逻辑结点失败\n");
            ret = PTR_ERR(dev);
            goto ERR5;
        }
    }
    printk("创建逻辑节点成功\n");
    //寄存器的初始化

    all_led_init();
    return 0;

ERR5:
    for (--i; i >= 0; i--)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);
ERR4:
    cdev_del(cdev);
ERR3:
    unregister_chrdev_region(MKDEV(major, mnior), count);
ERR2:
    kfree(cdev);
ERR1:
    return ret;
}

//出口函数
static void __exit demo_exit(void)
{

    // 1.销毁设备节点
    int i;
    for (i = 0; i < count; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);
    // 2.注销字符设备驱动
    cdev_del(cdev);
    // 3.释放设备号
    unregister_chrdev_region(MKDEV(major, mnior), count);
    // 4.释放动态申请的空间
    kfree(cdev);
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
}

//内核寻找入口出口宏封装
module_init(demo_init);
module_exit(demo_exit);

//许可证
MODULE_LICENSE("GPL");

 

 

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

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

相关文章

力扣刷题day52|84. 柱状图中最大的矩形

文章目录84. 柱状图中最大的矩形思路动态规划单调栈84. 柱状图中最大的矩形 力扣题目链接 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1: …

空间域图像增强处理-含Labview程序

⭕⭕ 目 录 ⭕⭕✳️ 一、引言✳️ 二、领域图像增强实例分析✳️ 2.1 线性滤波实例分析✳️ 2.2 非线性滤波实例分析✳️ 2.3 Canny边缘检测✳️ 三、Labview程序获取✳️ 一、引言 图像在其采集或传递过程中常会受到各种噪声的影响&#xff0c;这会导致其中包含的重要信息很…

忘机工尺谱 - 快速打谱软件

引言 为了实现高效快速打谱&#xff0c;我实现了一种词谱分离的输入方案&#xff0c;解决了当前工尺谱平台打谱过程频繁切换输入法和频繁点击鼠标等问题&#xff0c;大大提高了打谱效率。同时借鉴了Markdown编辑器”所见即所得“的思想&#xff0c;输入的同时可以见到排版后的…

java线程控制

java线程控制的语法很多 这里我们主要说以下三个方法 我们先新建一个包 包下建立两个类 customException 线程类 参考代码如下 public class customException extends Thread {public String name;public customException(){}public void run(){for(int i 0;i < 100;i)…

逆变器电力计量仪表可安装在分布式光伏运维云平台、光伏变电站

安科瑞 李可欣 1、概述 AcrelCloud-1200分布式光伏运维云平台通过监测光伏站点的逆变器设备&#xff0c;气象设备以及摄像头设备、帮助用户管理分散在各地的光伏站点。主要功能包括&#xff1a;站点监测&#xff0c;逆变器监测&#xff0c;发电统计&#xff0c;逆变器一次图&…

解决找不到依赖项的问题(根源直接解决)

&#xff08;文章最后&#xff0c;我会介绍一个万能解决方法&#xff09; 问题&#xff1a; 原因&#xff1a; &#xff08;1&#xff09;可能是你的本地仓库里没有该依赖项。 &#xff08;2&#xff09;如果有的话&#xff0c;可能是没有更新同步到idea 解决方法&#xff1…

基于Springboot+mybatis+mysql+html教育培训中心教学系统

基于Springbootmybatismysqlhtml教育培训中心教学系统一、系统介绍二、功能展示1.用户登陆2.用户注册3.个人中心4.人员信息管理5.课程管理6.缴费管理7.学生考勤管理8.器材管理9.问题管理&#xff08;学生、老师&#xff09;一、系统介绍 系统主要功能&#xff1a; 管理员&…

第五届“传智杯”全国大学生计算机大赛(练习赛)[传智杯 #5 练习赛] 时钟

[传智杯 #5 练习赛] 时钟 题目描述 你有一个电子钟&#xff0c;可以显示 0:00 到 23:59 之间的所有时间&#xff0c;以数字的形式显示。其中小时是 0 到 23&#xff08;0 时会显示一个 0&#xff0c;而 1 到 9 时不会显示前导 0&#xff09;&#xff0c;分钟是 00 到 59&…

矩阵分析与计算学习记录-矩阵函数

本章重点内容&#xff1a; 矩阵函数的定义和计算 矩阵函数的导数和积分&#xff1a;导数定义和性质、对矩阵变量的导数、矩阵函数的积分及其性质 利用矩阵函数求解线性常系数微分方程&#xff1a;一阶线性常系数微分方程、n阶线性常系数微分方程 1. 矩阵函数的定义和计算 1…

前端面试总结

自我检查&#xff1a; 1、 vue有哪些常用的指令 2、 v-if和v-show的区别? v-show 控制的哪个css元素?v-if和v-show初始条件都为false的时候哪个会加载? 3、 3.Vue常用的修饰符? .sync 怎么在子组件触发修改父组件属性的值?具体是$emit哪个事件触发修改? .sync 的原理有了…

栈的应用----括号匹配问题

1.题目 括号匹配 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合…

Linux常见指令与shell理解

Linux常用指令与shell理解 文章目录Linux常用指令与shell理解1. ls指令2. cd指令3. pwd命令4. touch指令5. mkdir指令6. rmdir和rm指令7. man指令8. cp指令9. mv指令10. cat与tac指令11. more指令12. less指令13. head指令14. tail指令15. 时间指令16. Cal指令17. find指令18. …

[附源码]SSM计算机毕业设计置地房屋租赁信息系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

2E服务-WriteDataByIdentifier

诊断协议那些事儿 诊断协议那些事儿专栏系列文章&#xff0c;本文介绍数据传输服务下的2E服务WriteDataByIdentifier&#xff0c;允许客户端在通过提供的dataidentifier数据标识符指定的内部位置将信息写入服务器。 参考文章&#xff1a; 数据传输功能单元——DID参数定义 2…

汇编语言与微机原理 期末复习题整理(大题)

写出实现下列计算的指令序列。&#xff08;假定X、Y、Z、W、R都为有符号字变量&#xff09; Z 2*&#xff08;W-X&#xff09;/&#xff08;5*Y&#xff09; ;因为(5*Y)会出现32位变量&#xff0c;32位变量不能作为除数&#xff0c;所以需要改变运算顺序 MOV AX,W ;AX←W S…

【算法05】合并两个有序链表

目录 问题 思路 版本一 版本二 答案 版本一 版本二 问题 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 示例二&a…

[附源码]java毕业设计球队管理系统论文

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

四十三、Fluent增强收敛性-伪瞬态计算

0. 伪瞬态作用 为什么要使用伪瞬态的算法&#xff1f;伪瞬态的作用实际上是增加收敛性的&#xff0c;当你的稳态计算收敛性不好时&#xff0c;可以将稳态计算更改为伪瞬态计算&#xff0c;收敛性会增强。 当然还可以通过前面所说的降低松弛因子的方式来增强收敛性。 但是&#…

Contextual Transformer Networks for Visual Recognition

Contextual Transformer Networks for Visual Recognition一、引言&#xff08;一&#xff09;、Our Approach&#xff08;二&#xff09;、Multi-head Self-attention in Vision Backbones二、Contextual Transformer Block&#xff08;一&#xff09;、Contextual Transforme…

分享125个ASP源码,总有一款适合你

源码下载链接&#xff1a;https://pan.baidu.com/s/1qgovtTI3srp2A8oJKGxWlA?pwdpkhu 提取码&#xff1a;pkhu 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;大家下载后可以看到。 康城汽车租赁类网站系统 淘特 旅…