22071班(11月18日)

news2025/8/2 20:31:49

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灯熄灭
要求:
    1)分部实现注册字符设备驱动
    2)自动创建设备节点
    3)通过结构体对led灯地址进行映射
    4)次设备号完成私有数据传参

driver.c:

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

#define CNAME "myled"

struct cdev* cdev;
dev_t devnum;
struct device* dev;
struct class* cls;

#if 0
unsigned int major = 0;
#else
unsigned int major = 500;
#endif

int minor=1;
const int count=3;


int k_open(struct inode *inode, struct file *file)
{
    //终端在传参时会打开对应的驱动文件,相当于调用了open和write函数,
    //inode结构体中存放着该驱动的设备号,次设备号不同,通过私有数据传参到write函数中进行判断
    file->private_data=(void*)MINOR(inode->i_rdev);
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
ssize_t k_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 K_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
    char ch;
    int ret;
    int kminjor;
    //接收终端传入的字符(控制led的亮灭)
    ret=copy_from_user(&ch,ubuf,sizeof(char));
    if(ret)
    {
        printk("copy from user is error\n");
        return -EIO;
    }
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    //接收k_open函数传递的私有数据(次设备号)
    kminjor=(int)file->private_data;
    if(ch=='1')
    {
        if(kminjor==1)
        {
            gpioe->ODR |= (0x1 << 10);
        }
        if(kminjor==2)
        {
            gpiof->ODR |= (0x1 << 10);
        }
        if(kminjor==3)
        {
            gpioe->ODR |= (0x1 << 8);
        }
    }
    else
    {
        if(kminjor==1)
        {
            gpioe->ODR &= (~(0x1 << 10));
        }
        if(kminjor==2)
        {
            gpiof->ODR &= (~(0x1 << 10));
        }
        if(kminjor==3)
        {
            gpioe->ODR &= (~(0x1 << 8));
        }
    }
    return size;
}
int  k_close (struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
//初始化操作方法结构体
const struct file_operations fops=
{
    .open=k_open,
    .read=k_read,
    .write=K_write,
    .release=k_close,
};
//入口,安装驱动时执行
static int __init k_init(void)
{
    int ret,i;
    //分配字符设备驱动
    cdev=cdev_alloc();
    if(cdev==NULL)
    {
        printk("cdev_alloc is error\n");
        ret=-EIO;
        goto ERR1;
    }
    //初始化设备驱动
    cdev_init(cdev,&fops);
    //申请设备号
    if(major>0)
    {
        ret=register_chrdev_region(MKDEV(major,minor),count,CNAME);
        if(ret)
        {
            printk("register_chrdev_region is error\n");
            ret=-ENOMEM;
            goto ERR2;
        }  
    }
    else
    {
        ret=alloc_chrdev_region(&devnum,1,count,CNAME);
        if(ret)
        {
            printk("alloc_chrdev_region is error\n");
            ret=-ENOMEM;
            goto ERR2;
        }
        major=MAJOR(devnum);
        minor=MINOR(devnum);
    }
    //驱动的注册
    ret=cdev_add(cdev,MKDEV(major,minor),count);
    if(ret)
    {
        printk("cdev add is error\n");
        ret = -EIO;
        goto ERR3;
    }

    //自动创建设备节点
    cls = class_create(THIS_MODULE,CNAME);
    if(IS_ERR(cls)) 
    {
        printk("class create is error\n");
        ret = PTR_ERR(cls); 
        goto ERR4;
    }
    for(i=1;i<=count;i++)
    {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
        if(IS_ERR(dev))
        {
           printk("device create is error\n");
           ret = PTR_ERR(dev);
           goto ERR5;
        }
    }
    //RCC寄存器地址映射
    rcc=ioremap(RCC,4);
    if(NULL == rcc)
    {
        printk("rcc ioremap is error\n");
        return -ENOMEM;
    }
    //GPIOE寄存器地址映射
    gpioe=ioremap(GPIOE,sizeof(gpio_t));
    if(NULL == gpioe)
    {
        printk("gpioe ioremap is error\n");
        return -ENOMEM;
    }
    //GPIOF寄存器地址映射
    gpiof=ioremap(GPIOF,sizeof(gpio_t));
    if(NULL == gpiof)
    {
        printk("gpiof ioremap is error\n");
        return -ENOMEM;
    }
   
    //LED1--->PE10引脚初始化
    *rcc|= (0x1 << 4);
    gpioe->MODER &= (~(0x3 << 20));
    gpioe->MODER |= (0x1 << 20);
    gpioe->ODR &= (~(0x1 << 10));
    // LED2--->PF10初始化
    *rcc|= (0x1 << 5);
    gpiof->MODER &= (~(0x3 << 20));
    gpiof->MODER |= (0x1 << 20);
    gpiof->ODR &= (~(0x1 << 10));
    //LED3--->PE8初始化
    *rcc|= (0x1 << 4);
    gpioe->MODER &= (~(0x3 << 16));
    gpioe->MODER |= (0x1 << 16);
    gpioe->ODR &= (~(0x1 << 8));

    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,minor),count);
ERR2:
    kfree(cdev);
ERR1:
    return -EIO;
}
//出口,卸载驱动时执行
static void __exit k_exit(void)
{
     int i;
    //销毁设备节点信息
    for(i=1;i<=count;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //销毁目录信息
    class_destroy(cls);
    //驱动的注销
    cdev_del(cdev);
    //销毁设备号
    unregister_chrdev_region(MKDEV(major,minor),count);
    //释放cdev结构体
    kfree(cdev);
    //取消地址映射
    iounmap(rcc);
    iounmap(gpioe);
    iounmap(gpiof);
}

module_init(k_init);
module_exit(k_exit);
MODULE_LICENSE("GPL");

myled.h:

#ifndef __MYLED__H__
#define __MYLED__H__

typedef struct{
    volatile unsigned int MODER;
    volatile unsigned int OTYPER;
    volatile unsigned int OSPEEDR;
    volatile unsigned int PUPDR;
    volatile unsigned int IDR;
    volatile unsigned int ODR;
}gpio_t;
#define GPIOE 0x50006000
#define GPIOF 0x50007000
#define RCC 0x50000A28
volatile unsigned int* rcc;
gpio_t* gpioe;
gpio_t* gpiof;

#endif

实验现象:

 串口工具如图:

 

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

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

相关文章

【附源码】计算机毕业设计JAVA校园跑腿平台

【附源码】计算机毕业设计JAVA校园跑腿平台 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA mybati…

什么是PaaS平台

PaaS平台概述 PaaS平台通常是基于IaaS平台构建的&#xff0c;PaaS平台和IaaS平台最大的差别是需求即服务。所有的管理都是以服务为粒度的&#xff0c;在IaaS以资源管理为中心的平台上提供了更高层次的抽象。 PaaS的本质 &#xff08;1&#xff09;运维自动化&#xff0c;故障…

统计聚类法的基本步骤:

统计聚类法的基本步骤&#xff1a; 1>形成数据框 2>计算距离阵 计算n个样品两两间的距离D。 3>进行系统聚类 (I&#xff09;构造n个类,每个类只包含一个样品; (2&#xff09;合并距离最近的两类为一新类; (3&#xff09;计算新类与当前各类的距离,若类个数为1,…

观测云产品更新|Pipeline 使用体验优化;支持写入用户的自定义事件;自定义查看器支持选择更多类型的数据等

观测云更新 Pipeline 使用体验优化 Pipeline 支持过滤条件配置多选 支持将任意一个 Pipeline 脚本设置为“默认 Pipeline 脚本“&#xff0c;若当前数据类型在匹配 Pipeline 处理的时候&#xff0c;未匹配到其他的 Pipeline 脚本&#xff0c;则数据会按照默认 Pipeline 脚本的…

vs2017编译的64位libssh2库

需求&#xff1a;使用sftp上传下载文件 环境&#xff1a;windows vs2017 参考 链接: link 链接: link 编译 环境准备 libssh2依赖于openssl和zlib&#xff0c;所以需要有所以需要先编译&#xff1a;openssl和zlib才行。openssl和zlib。openssl和zlib我是下载人家编译好的…

【MySQL基础】数据库系统之关系型数据库与非关系型数据库

目录 一、数据库系统 1. 数据库 2. 数据库应用 3. 数据库管理系统&#xff08;数据库软件&#xff09; 3.1关系型数据库【RDBMS】 3.2非关系型数据库【NoSQL】 4. SQL和数据库管理系统的关系 5. 关系型数据库管理系统的组成 &#x1f49f; 创作不易&#xff0c;不妨点…

DIY CY7C68013A模块为逻辑分析仪

DIY CY7C68013A模块为逻辑分析仪摘要工具软件步骤参考资料&#xff1a;摘要 将淘宝购买的CY7C68013A模块修改为8通道逻辑分析仪。 购买的CY7C68013A模块如下&#xff1a; 工具软件 Zadig&#xff1a;用于安装逻辑分析仪驱动。 PulseView&#xff1a;Sigrok逻辑分析仪应用软…

Python面向对象2-继承-

文章目录目标一. 继承的概念二. 单继承三. 多继承 [python又支持多继承了]四. 子类重写父类同名方法和属性 #TODO目标 继承的概念单继承多继承子类重写父类的同名属性和方法子类调用父类的同名属性和方法多层继承super()私有属性和私有方法 一. 继承的概念 生活中的继承&…

实验(三):单片机I/O口实验-模拟开关灯

一、实验目的与任务 实验目的&#xff1a; 1&#xff0e;掌握单片机I/O口输入输出使用&#xff1b; 2&#xff0e;掌握单片机I/O口位操作的编程。 任务&#xff1a; 1.根据要求编写程序&#xff0c;并写出原理性注释&#xff1b; 2. 检查程序运行的结果&#xff0c;分析一下是…

VLAN和VLAN间路由

VLAN和VLAN间路由一 交换机二 vlan2.1 华为交换机的特性2.2 access接口2.2.1 在华为交换机上配置access接口2.2.2 access接口接收到报文的处理流程&#xff08;打vlan tag&#xff09;2.2.3 access接口发送报文的处理流程&#xff08;剥离\弹出vlan tag&#xff09;![在这里插入…

【仿牛客网笔记】项目进阶,构建安全高效的企业服务——权限控制

引入依赖 将登录检查拦截器删除掉 授权 首先显示路径 除了这些请求&#xff0c;其他的请求统统允许。 当权限不够处理的时候 返回XML是异步请求 添加denied的路径 获取用户权限的方法 将结果存入到集合中&#xff0c;实例化一个集合 获得用户权限&#xff0c;并把…

java框架学习笔记——SpringMVC

SpringMVC1. SpringMVC简介1.1 什么是MVC1.2 Spring MVC1.3 Spring MVC 的常用组件2. Hello SPring MVC2.1 基础配置2.2 总结3. RequestMapping注解3.1 功能3.2 位置3.3 value属性3.4 method属性3.5 params属性3.6 headers属性3.7 SpringMVC支持ant风格的路径3.8 SpringMVC支持…

数据中心网络方案设计

大家好&#xff0c;我是技福的小咖老师。 云计算、大数据、人工智能等技术的快速发展&#xff0c;对承载数据流量的数据中心网络提出了更高的要求&#xff0c;高吞吐量、高可靠性、低时延、适应服务器虚拟化等都是业务对数据中心网络提出的要求。为了满足业务对网络的要求&…

若依 弹出复选框表格

需求&#xff1a; 工资表用户应该可以弹框选择&#xff08;弹窗选择用户表的id&#xff09; 最后效果差不多这样&#xff1a; 步骤&#xff1a; 1.首先&#xff0c;先看我们需求啊&#xff0c; 工资表用户应该可以弹框选择 通过需求确认&#xff1a; 与这个需求关联的表有…

APS自动排产-AP工厂高级计划

安达发AP主要解决的问题&#xff1a; 客户交货需求&#xff1a;将销售订单、销售预测&#xff0c;同一转换为客户交货需求。生产净需求&#xff1a;考虑客户交货需求、当前库存、采购在途、生产在制、生产提前期、生产周期等&#xff0c;扣库存、展 BOM&#xff0c;最终产生产…

你知道数字化表单在防疫中的运用有哪些吗?

说到信息登记&#xff0c;很多人第一印象就是纸质化表格。但是随着科技发展&#xff0c;纸质化登记模式早已被out了。相比传统的纸质表格登记信息&#xff0c;现在普及的数字化表单登记模式有着更多的优势&#xff0c;例如&#xff1a;成本低、不宜丢失、打破了时间与地点限制&…

EasyCode的Mybatis终极版模板

EasyCode的Mybatis终极版距离我第一次上手EasyCode已经有一年的时间提醒一下&#xff0c;看这篇文章&#xff0c;如果你已经有EasyCode使用基础&#xff0c;只是来拿一下模板&#xff0c;可以直接看&#xff0c;如果你同时想知道知道到底怎么用easy code&#xff0c;请先看[Eas…

RabbitMQ初步到精通-第四章-RabbitMQ工作模式-Routing

第四章-RabbitMQ工作模式-Routing 1.模式介绍 1.1 模式 路由模式-继续还是和Exchange打交道&#xff0c;上节提到的Exchange类型为Fanout&#xff0c;此次声明的类型为direct 与默认Exchange一致。但还有最核心的一点&#xff0c;上节未使用Routing key&#xff0c;此次模式中…

SpringBoot实用开发篇复习3

我们之前学习了数据访问层的解决方案&#xff0c;包括关系数据库和非关系数据库&#xff0c;这一篇我们重点学校SpringBoot整合第三方技术&#xff0c;下面一起努力学习吧。 目录 一、整合第三方技术 1.1、缓存 1.1.1、缓存的作用 1.1.2、SpringBoot缓存使用方式 1.1.3、手…

C/C++自动 21 级(含卓越 211)《软件技术基础》期末大作业

C/C自动 21 级(含卓越 211)《软件技术基础》期末大作业 一、作业内容 题目一&#xff1a;请你设计一个算法&#xff0c;从顺序表中删除自第 i 个结点开始的 k 个结点。要求先输出整个顺序表&#xff0c;再输出删除自第 i 个结点开始的 k 个结点后的结果。 【编程提示】 假设…