华清远见上海中心22071班--11.19作业

news2025/7/15 16:29:23

题目:实现开发板点灯操作

程序要求:

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

        2)自动创建设备节点

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

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

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

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

操作方法:

在串口工具进行输入:

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

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

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

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

程序:

#ifndef __LED_H__
#define __LED_H__

typedef struct{
    volatile unsigned int MODER;
    volatile unsigned int OPTYPER;
    volatile unsigned int OSPEEDR;
    volatile unsigned int PUPDR;
    volatile unsigned int IDR;
    volatile unsigned int ODR;
}gpio_t;
typedef enum{
    LED1,
    LED2,
    LED3
}led_t;
#define GPIOE 0x50006000
#define GPIOF 0x50007000
#define PHY_RCC 0x50000A28


#endif

​​​​​​​

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include "led.h"
#include <linux/uaccess.h>
#include <linux/io.h>
#define CNAME "myled"
struct class *cls;
struct device *dev;
struct cdev *mycdev;
#if 1
unsigned int major = 0;
#else
unsigned int major = 500;
#endif
int minor =0;
const int count = 3;
volatile unsigned int* virt_rcc;
gpio_t *virt_gpioe;
gpio_t *virt_gpiof;
int mycdev_open(struct inode *inode,struct file *file)
{
    int pos = MINOR(inode->i_rdev);
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    file->private_data = (void*)pos;
    return 0;
}
ssize_t mycdev_read(struct file* file,char __user *ubuf,size_t size,loff_t *loffs)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
ssize_t mycdev_write(struct file* file,const char __user *ubuf,size_t size,loff_t *loffs)
{
    int pos;
    int ret = 0;
    char kbuf[5]={0};
    if(size > 5) size=5;
    ret = copy_from_user(kbuf,ubuf,size);
    if(ret)
    {
        printk("copy from user error\n");
        return -EIO;
    }
    //判断是点灯还是熄灭
    pos =(int)file->private_data;
    if('1' == kbuf[0])
    {
        //通过次设备号判断是哪个灯需要亮
        switch (pos)
        {
            case 0:
                virt_gpioe->ODR |= (0x1 << 10); //led1输出高电平
                break;
            case 1:
                virt_gpiof->ODR |= (0x1 << 10); //led2输出高电平
                break;
            case 2:
                virt_gpioe->ODR |= (0x1 << 8); //led3输出高电平
                break;
        } 
    }
    if('0' == kbuf[0])
    {
        //通过次设备号判断是哪个灯需要灭
        switch (pos)
        {
            case 0:
                virt_gpioe->ODR &= ~(0x1 << 10); //led1输出低电平
                break;
            case 1:
                virt_gpiof->ODR &= ~(0x1 << 10); //led2输出低电平
                break;
            case 2:
                virt_gpioe->ODR &= ~(0x1 << 8); //led3输出低电平
                break;
        } 
    }
    printk("kbuf=%s\n",kbuf);
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return size;
}
int mycdev_close(struct inode *inode,struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
const struct file_operations fops ={
    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,
};
static int __init demo_init(void)
{
    int ret = 0;
    dev_t devno;
    int i;
    //分配cdev结构体空间
    mycdev = cdev_alloc();
    if(NULL == mycdev)
    {
        printk("cdev alloc error\n");
        ret = -EIO;
        goto ERR1;
    }
    //初始化结构体
    cdev_init(mycdev,&fops);
    //申请设备号
    if(major >0)
    {
        //静态申请设备号
        ret = register_chrdev_region(MKDEV(major,minor),count,CNAME);
        if(ret)
        {
            printk("register chrdev regin error\n");
            ret = -ENOMEM;
            goto ERR2;
        }
    }
    else 
    {
        //动态申请设备号
        ret = alloc_chrdev_region(&devno,0,count,CNAME);
        if(ret)
        {
            printk("alloc_chrdev error\n");
            ret = -ENOMEM; 
            goto ERR2;
        }
        major = MAJOR(devno);
        minor = MINOR(devno);
    }
    //驱动注册
    ret = cdev_add(mycdev,MKDEV(major,minor),count);
    if(ret)
    {
        printk("cdev add error\n");
        ret = -EIO;
        goto ERR3;
    }
    //自动创建设备节点
        //提交目录信息
    cls = class_create(THIS_MODULE,CNAME);
    if(IS_ERR(cls))
    {
        printk("class create error\n");
        ret = PTR_ERR(cls);
        goto ERR4;
    }
        //提交设备节点信息
    for(i=0;i<count;i++)
    {
        dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
        if(IS_ERR(dev))
        {
            printk("device create error\n");
            ret = PTR_ERR(dev);
            goto ERR5;
        }
    }
    //对灯的物理地址进行映射
    virt_rcc = ioremap(PHY_RCC,4);
    if(NULL == virt_rcc)
    {
        printk("rcc ioremap is error\n");
        return -ENOMEM;
    }
    virt_gpioe = ioremap(GPIOE,sizeof(GPIOE));
    if(NULL == virt_gpioe)
    {
        printk("gpio moder ioremap is error\n");
        return -ENOMEM;
    }
    virt_gpiof = ioremap(GPIOF,sizeof(GPIOF));
    if(NULL == virt_gpiof)
    {
        printk("gpio odr ioremap is error\n");
        return -ENOMEM;
    }
    //将rcc、gpio初始化   PE10\PF10\PE8
    *virt_rcc |= (0x3<<4);
    //PE10初始化
    virt_gpioe->MODER &= (~(0x3<<20));
    virt_gpioe->MODER |= 0x1<<20;
    virt_gpioe->ODR &= (~(0x1<<10));
    //PE8初始化
    virt_gpioe->MODER &= (~(0x3<<16));
    virt_gpioe->MODER |= 0x1<<16;
    virt_gpioe->ODR &= (~(0x1<<8));
    //PF10初始化
    virt_gpiof->MODER &= (~(0x3<<20));
    virt_gpiof->MODER |= 0x1<<20;
    virt_gpiof->ODR &= (~(0x1<<10));
    return 0;
ERR5:
    for(--i;i>=0;i--)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    class_destroy(cls);

ERR4:
    cdev_del(mycdev);
ERR3:
    unregister_chrdev_region(MKDEV(major,minor),count);
ERR2:
    kfree(mycdev);
ERR1:
    return -EIO;
}
static void __exit demo_exit(void)
{
    int i = 0;
    //销毁设备节点信息
    for(i=0;i<count;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //销毁目录信息
    class_destroy(cls);
    //驱动注销
    cdev_del(mycdev);
    //注销设备号
    unregister_chrdev_region(MKDEV(major,minor),count);
    //释放结构体指针
    kfree(mycdev);
}

module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");

测试命令

        在串口工具依次输入命令,点亮LED1\LED2\LED3,然后依次熄灭LED1\LED2\LED3,如下图

测试结果:

LED1亮:

LED1\LED2亮:

LED1\LED2\LED3亮:

 LED1熄灭:

LED1\LED2熄灭:

LED1\LED2\LED3熄灭:

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

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

相关文章

Js逆向教程-10常见代码混淆

作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; Js逆向教程-10常见代码混淆 一、常见代码混淆 eval混淆AA和OO混淆JSFuck 混淆就是将正常的代码进行语法上的改变或者变量名称上的改变…

基于javaweb,ssm学生宿舍系统(带论文)

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat8.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 系统分前后台&#xff0c;非前后端分离 前端技术&#xff1a;vue.jselementUI等框架实现 服务端技术&#xff1a;springspringmvcmybat…

基于stm32单片机的输入捕获测量脉宽Proteus仿真

资料编号&#xff1a;109 下面是相关功能视频演示&#xff1a; 109-基于stm32的输入捕获测量脉宽Proteus仿真(源码仿真全套资料)功能介绍&#xff1a; 采用stm32单片机作为主控&#xff0c;采用单片机的GPIO进行输入捕获&#xff0c;可以测量按键按下的低电平脉宽时间&#x…

云原生系列七【轻松入门容器基础操作】

✅作者简介&#xff1a; CSDN内容合伙人&#xff0c;全栈领域新星创作者&#xff0c;阿里云专家博主&#xff0c;华为云享专家博主&#xff0c;掘金后端评审团成员 &#x1f495;前言&#xff1a; 最近云原生领域热火朝天&#xff0c;那么云原生是什么&#xff1f;何为云原生&a…

驱动——串口工具点灯实验

通过串口工具输入命令&#xff0c;操作LED灯的点亮与熄灭 要求&#xff1a; 1&#xff09;分部实现注册字符设备驱动 2&#xff09;自动创建设备节点 3&#xff09;通过结构体对led灯地址进行映射 4&#xff09;次设备号完成私有数据传参 代码实现&#xff1a; 1、头文件…

如何使用闲置的云服务器搭建一个属于自己的私人云网盘(可道云kodbox)

你是否有过网盘下载速度只有十几KB&#xff0c;时不时出现网盘的文件被删除的问题&#xff0c;不如自己搭建一个云网盘吧&#xff0c;只需要一云服务器&#xff0c;即可搭建一个跟某度云一样的云盘。可以自由下载&#xff0c;不限制网速&#xff0c;随时都可上传下载。这篇文章…

[附源码]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…

Redis应用问题解决(缓存穿透、击穿、雪崩、分布式锁)

Redis应用问题解决(缓存穿透、击穿、雪崩、分布式锁) 缓存穿透 问题描述 当系统中引入redis缓存后&#xff0c;一个请求进来后&#xff0c;会先从redis缓存中查询&#xff0c;缓存有就直接返回&#xff0c;缓存中没有就去db中查询&#xff0c;db中如果有就会将其丢到缓存中&…

Dockerfile构建SpringBoot项目

【1】将SpringBoot项目打包 jar包-->用JDK运行(我们这里打成jar包)war包-->用Tomcat运行 MySQL的url配置 1.useSSLfalse MySQL 8.0 以上版本不需要建立 SSL 连接的&#xff0c;需要显示关闭 2.allowPublicKeyRetrievaltrue 允许客户端从服务器获取公钥。 3.serverTime…

git3:github的使用

1.github创建远程库 创建远程库 名字一般与本地库的名字相同推送远程库push poll https://github.com/likejin123/gitdemo.git 可以创建别名&#xff0c;因为连接太长git remote -v 查看别名 当前没有别名 git remote add gitdemo https://github.com/likejin123/gitdemo.gitg…

初阶数据结构学习记录——여덟 二叉树

树 顾名思义&#xff0c;结构即为树&#xff0c;由一个根节点分出多个节点&#xff0c;这几个节点再继续往下连接其他节点形成一个个子树。不过这棵树是根朝上&#xff0c;叶朝下的。一个根不限制连接多少个节点&#xff0c;把第二层的几个节点也看成根节点&#xff0c;最终形…

2011年408大题总结

2011年408大题第41题第42题第43题第44题第45题第46题第47题第41题 关键信息&#xff1a;有向带权、上三角、行为主序 就可以解决第一二小问 关键路径&#xff1a;最长 0 1 2 3 5&#xff0c;长度为16 第42题 一如既往的暴力 最简单的思路&#xff0c;合并取中位数 所以用数组就…

[附源码]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…

Android App开发动画特效中帧动画和电影淡入淡出动画的讲解及实战(附源码和演示视频 简单易懂)

需要图片集和源码请点赞关注收藏后评论区留言~~~ 一、帧动画 Android的动画分为三类&#xff0c;帧动画&#xff0c;补间动画和属性动画。其中帧动画是实现原理最简单的一种&#xff0c;跟现实生活中的电影胶卷类似&#xff0c;都是在短时间内连续播放多张图片&#xff0c;从而…

Request和Response

目录 1、Request和Response的概述 2、Request对象 2.1、Request继承体系 2.2、Request获取请求数据 2.2.1 获取请求行数据 2.2.2 获取请求头数据 2.2.3 获取请求体数据 2.2.4、获取请求参数的通用方式 2.3 IDEA快速创建Servlet 2.4、请求参数中文乱码问题 2.4.1、POS…

认识Spring

1.1 Spring的历程 早期的 Java EE 使用 EJB 为核心的开发方式,但是这种开发方式在实际开发环境中存在诸多问题: 使用复杂, 代码臃肿, 移植性差等.于是"Spring 之父" Rod Johnson 在其畅销书《Expert One-on-One J2EE Design and Development》中使用一个3万行代码的…

MySQL8.0优化 - 锁 - 按加锁的方式划分:显示锁、隐式锁

文章目录学习资料锁的不同角度分类锁的分类图如下按加锁的方式划分&#xff1a;显示锁、隐式锁隐式锁显式锁学习资料 【MySQL数据库教程天花板&#xff0c;mysql安装到mysql高级&#xff0c;强&#xff01;硬&#xff01;-哔哩哔哩】 【阿里巴巴Java开发手册】https://www.w3…

[附源码]计算机毕业设计JAVA基于Java的快递驿站管理系统

[附源码]计算机毕业设计JAVA基于Java的快递驿站管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; S…

车联网解决方案-最新全套文件

车联网解决方案-最新全套文件一、建设背景面临的挑战1、平台难以支撑高并发接入2、海量数据难以挖掘价值3、缺乏使能套件&#xff0c;开发效率低4、车联网的安全难以保证二、建设架构三、建设方案四、获取 - 车联网全套最新解决方案合集一、建设背景 面临的挑战 1、平台难以支…

Teams Tab App 代码深入浅出 - 配置页面

上一篇文章我们使用Teams Toolkit 来创建、运行 tab app。这篇文章我们深入来分析看一下tab app 的代码。 先打开代码目录&#xff0c;可以看到在 src 目录下有入口文件 index.tsx&#xff0c;然后在 components 目录下有更多的一些 tsx 文件&#xff0c;tsx 是 typescript的一…