驱动 - 20230816

练习

1.编写LED灯的驱动,可以控制三个灯,应用程序中编写控制灯的逻辑,要使用自动创建设备节点机制

驱动头文件 ledHead.h

#ifndef __HEAD_H__
#define __HEAD_H__

#define PHY_GPIOE_MODER 0X50006000
#define PHY_GPIOE_ODR 0X50006014
#define PHY_RCC 0X50000A28

#define PHY_GPIOF_MODER 0X50007000
#define PHY_GPIOF_ODR 0X50007014

#endif

驱动demo.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include "ledHead.h"

int major;
char buf[128];

unsigned int *vir_gpioe_moder;
unsigned int *vir_gpioe_odr;
unsigned int *vir_gpiof_moder;
unsigned int *vir_gpiof_odr;
unsigned int *vir_rcc;

struct class *cls;
struct device *dev;

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) {
    
    int ret = copy_to_user(ubuf, buf, size);
    if (ret) {
        printk("内核read失败: %d \n", ret);
    }
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}

ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof) {
    int ret = copy_from_user(buf, ubuf, size);
    if (ret) {
        printk("内核write失败: %d \n", ret);
		return ret;
    }
	
    
	if (buf[0] == '1' && buf[1] == '1') {
		//LED1开灯
        (*vir_gpioe_odr) |= (0x1 << 10);
	} else if (buf[0] == '1' && buf[1] == '0') {
		//LED1关灯
		(*vir_gpioe_odr) &= (~(0x1 << 10));
	} else if (buf[0] == '2' && buf[1] == '1') {
        //LED2开灯
		(*vir_gpiof_odr) |= (0x1 << 10);
	} else if (buf[0] == '2' && buf[1] == '0') {
		//LED2关灯
		(*vir_gpiof_odr) &= (~(0x1 << 10));
	} else if (buf[0] == '3' && buf[1] == '1') {
		//LED1开灯
		(*vir_gpioe_odr) |= (0x1 << 8);
	} else if (buf[0] == '3' && buf[1] == '0') {
		//LED1关灯
		(*vir_gpioe_odr) &= (~(0x1 << 8));
	}

    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,
    .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, "mycdev");
    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, "mycdev%d", i);
        if (IS_ERR(dev)) {
            printk("向上提交设备节点失败\n");
            return -PTR_ERR(cls);
        }
    }
    printk("向上提交设备节点信息成功\n");

    /*
    *完成硬件寄存器物理映射
    */
	vir_gpioe_moder = ioremap(PHY_GPIOE_MODER, 4);
	if (vir_gpioe_moder == NULL) {
		printk("物理内存映射失败%d\n", __LINE__);
		return -EFAULT;
	}
	vir_gpioe_odr = ioremap(PHY_GPIOE_ODR, 4);
	if (vir_gpioe_odr == NULL) {
		printk("物理内存映射失败%d\n", __LINE__);
		return -EFAULT;
	}
    vir_gpiof_moder = ioremap(PHY_GPIOF_MODER, 4);
	if (vir_gpiof_moder == NULL) {
		printk("物理内存映射失败%d\n", __LINE__);
		return -EFAULT;
	}
    vir_gpiof_odr = ioremap(PHY_GPIOF_ODR, 4);
	if (vir_gpiof_odr == NULL) {
		printk("物理内存映射失败%d\n", __LINE__);
		return -EFAULT;
	}
	vir_rcc = ioremap(PHY_RCC, 4);
	if (vir_rcc == NULL) {
		printk("物理内存映射失败%d\n", __LINE__);
		return -EFAULT;
	}
	printk("物理内存映射成功\n");
	//硬件寄存器初始化
    //设置LED1
	(*vir_gpioe_moder) &= (~(0x3 << 20));
	(*vir_gpioe_moder) |= (0x1 << 20);
    //设置LED2
    (*vir_gpiof_moder) &= (~(0x3 << 20));
	(*vir_gpiof_moder) |= (0x1 << 20);
     //设置LED3
    (*vir_gpioe_moder) &= (~(0x3 << 16));
	(*vir_gpioe_moder) |= (0x1 << 16);
	//rcc使能
    (*vir_rcc) |= (0x1 << 4);
    (*vir_rcc) |= (0x1 << 5);
	//默认关灯
    //LED1
	(*vir_gpioe_odr) &= (~(0x1 << 10));
    //LED2
    (*vir_gpiof_odr) &= (~(0x1 << 10));
    //LED3
    (*vir_gpioe_odr) &= (~(0x1 << 8));
    return 0;
}

static void __exit mycdev_exit(void) {
    /**
     * 取消物理内存的映射
    */
	iounmap(vir_gpioe_moder);
	iounmap(vir_gpioe_odr);
    iounmap(vir_gpiof_moder);
	iounmap(vir_gpiof_odr);
	iounmap(vir_rcc);

    /**
     * 销毁设备信息
    */
    int i;
    for (i=0; i<3; i++) {
        device_destroy(cls, MKDEV(major, i));
    }
    /**
     * 销毁目录信息
    */
    class_destroy(cls);

    unregister_chrdev(major, "mychrdev");
}

module_init(mycdev_init);
module_exit(mycdev_exit);

MODULE_LICENSE("GPL");

应用层测试代码 test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>

int main(int argc, const char *argv[]) {
	char buf[128] = {};
	int fd = open("/dev/mycdev0", O_RDWR);
	if (fd < 0) {
		printf("打开设备文件失败\n");
		return -1;
	}
	int fds[3] = {-1};
	int i;
	for (i=0; i<3; i++) {
		char str[20];
		sprintf(str, "/dev/mycdev%d", i);
		fds[i] = open(str, O_RDWR);
		if (fds[i] < 0) {
			printf("打开设备文件%d失败", i);
			return -1;
		}
	}
	while(1) {
		printf("选择LED1控制方式: 1(开灯), 0(关灯) > \n");

		printf("请输入要实现的逻辑 > \n");
		printf("11: LED1亮");
		printf("10: LED1灭");
		printf("21: LED2亮");
		printf("20: LED2灭");
		printf("31: LED3亮");
		printf("30: LED3灭");
		fgets(buf, sizeof(buf), stdin);
		buf[strlen(buf)-1] = 0;
		if (buf[0] == '1') {
			write(fds[0], buf, sizeof(buf));
		} else if (buf[0] == '2') {
			write(fds[1], buf, sizeof(buf));
		} else if (buf[0] == '3') {
			write(fds[2], buf, sizeof(buf));
		}
	}
	close(fd);
	return 0;
}

结果展示:
请添加图片描述
请添加图片描述

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

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

相关文章

leetcode228. 汇总区间

题目 给定一个 无重复元素 的 有序 整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说&#xff0c;nums 的每个元素都恰好被某个区间范围所覆盖&#xff0c;并且不存在属于某个范围但不属于 nums 的数字 x 。 列表中的每个区间范围 [a,b]…

MySQL入门学习教程(三)

上一章给大家说的是数据库的视图&#xff0c;存储过程等等操作&#xff0c;这章主要讲索引&#xff0c;以及索引注意事项&#xff0c;如果想看前面的文章&#xff0c;url如下&#xff1a; MYSQL入门全套(第一部)MYSQL入门全套(第二部) 索引简介 索引是对数据库表中一个或多个…

自动化安装系统(一)

系统安装过程 加载boot loader加载启动安装菜单加载内核和initrd文件加载根系统运行anaconda的安装向导 安装光盘中与安装相关的文件 安装autofs启动后会自动出现/misc目录。 在虚拟机设置中添加CD/DVD&#xff0c;使用系统ISO文件&#xff0c;登录系统后mount /dev/cdrom …

【Linux】进程的基本属性|父子进程关系

个人主页&#xff1a;&#x1f35d;在肯德基吃麻辣烫 我的gitee&#xff1a;Linux仓库 个人专栏&#xff1a;Linux专栏 分享一句喜欢的话&#xff1a;热烈的火焰&#xff0c;冰封在最沉默的火山深处 文章目录 前言进程属性1.进程PID和PPID2.fork函数创建子进程1&#xff09;为什…

【深入了解PyTorch】PyTorch模型解释性和可解释性:探索决策过程与预测结果的奥秘

【深入了解PyTorch】PyTorch模型解释性和可解释性:探索决策过程与预测结果的奥秘 PyTorch模型解释性和可解释性:探索决策过程与预测结果的奥秘1. 引言2. 梯度可视化3. 特征重要性分析4. 结论PyTorch模型解释性和可解释性:探索决策过程与预测结果的奥秘 在机器学习和深度学习…

【Docker】Docker使用之容器技术发展史

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集 &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0…

嵌入式学习之字符串

通过今天的学习&#xff0c;我主要提高了对sizeof 和 strlen、puts()、gets()、strcmp 、strncmp、strstr、strtok的理解。重点对sizeof的使用有了更加深刻的理解

山东布谷科技直播软件开发WebRTC技术:建立实时通信优质平台

在数字化的时代&#xff0c;实时通信成为了人们远程交流的主要方式&#xff0c;目前市场上也出现了很多带有实时通信交流的软件&#xff0c;实时通信符合人们现在的需求&#xff0c;所以在直播软件开发过程中&#xff0c;开发者也运用了实时通信技术为直播软件加入了实时通信的…

整理分享Springboot项目中java实现将数据库表中指定表中的的数据按条件导出生成Excel表格的功能实现(学习笔记)

在Spring Boot中&#xff0c;我们可以使用Apache POI库来实现将数据库表中的数据导出为Excel表格。可以根据条件从数据库中查询数据并将其导出为Excel&#xff1a;如下 准备工作&#xff1a;首先&#xff0c;确保在你的项目中引入Apache POI依赖。在pom.xml文件中添加以下依赖项…

系统架构设计专业技能 · 网络规划与设计(三)【系统架构设计师】

系列文章目录 系统架构设计专业技能 网络规划与设计&#xff08;三&#xff09;【系统架构设计师】 系统架构设计专业技能 系统安全分析与设计&#xff08;四&#xff09;【系统架构设计师】 系统架构设计高级技能 软件架构设计&#xff08;一&#xff09;【系统架构设计师…

MAVEN利器:一文带你了解MAVEN以及如何配置

前言&#xff1a; 强大的构建工具——Maven。作为Java生态系统中的重要组成部分&#xff0c;Maven为开发人员提供了一种简单而高效的方式来构建、管理和发布Java项目。无论是小型项目还是大型企业级应用&#xff0c;Maven都能帮助开发人员轻松处理依赖管理、编译、测试和部署等…

Centos8安装docker并配置Kali Linux图形化界面

鉴于目前网上没有完整的好用的docker安装kali桌面连接的教程&#xff0c;所以我想做一个。 准备工作 麻了&#xff0c;这服务器供应商提供的镜像是真的纯净&#xff0c;纯净到啥都没有。 问题一&#xff1a;Centos8源有问题 Error: Failed to download metadata for repo ap…

【实战】十一、看板页面及任务组页面开发(一) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十三)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…

shell编程

1.特殊变量 $n &#xff1a;n为数字&#xff0c;$0代表该脚本名称&#xff0c;$1-$9代表第一到第九个参数&#xff0c;十以上的参数&#xff0c;十以上的参数需要用大括号包含&#xff0c;如${10} $# &#xff1a;获取所有输入参数个数 $#&#xff1a;命令行中所有的参数&…

卡巴斯基为基于Linux的嵌入式设备推出专用解决方案

导读卡巴斯基在其卡巴斯基嵌入式系统安全产品中引入了对 Linux 的支持。这种适应性强的多层解决方案现在为基于Linux的嵌入式系统、设备和场景提供优化的安全&#xff0c;合通常适用于这些系统的严格监管标准。 卡巴斯基在其卡巴斯基嵌入式系统安全产品中引入了对 Linux 的支持…

非谓语动词1(背)

非谓语动词的概述 for:对某人来说做某事是怎么怎么样的 of&#xff1a;人的内在品质,你真的太怎么怎么样了 非谓语动词作主语 非谓语动词作宾语 非谓语动词作表语 现在分词作表语时时常时形容事物的 过去分词作表语一般是形容人的 非谓语动词作补语 注&#xff1a;无论是使役…

星星之火:国产讯飞星火大模型的实际使用体验(与GPT对比)

#AIGC技术内容创作征文&#xff5c;全网寻找AI创作者&#xff0c;快来释放你的创作潜能吧&#xff01;# 文章目录 1 前言2 测试详情2.1 文案写作2.2 知识写作2.3 阅读理解2.4 语意测试&#xff08;重点关注&#xff09;2.5 常识性测试&#xff08;重点关注&#xff09;2.6 代码…

使用wxPython和PyMuPDF在Python中显示PDF目录的实现

展示如何使用wxPython和PyMuPDF库在Python中选择PDF文件并将目录显示在列表框中。 简介&#xff1a; 在本篇教程中&#xff0c;我们将学习如何使用wxPython和PyMuPDF库在Python中选择PDF文件&#xff0c;并将其目录显示在一个列表框中。这将使用户能够方便地浏览PDF文档的目录…

Flask Web开发实战(狼书)| 笔记第1、2章

前言 2023-8-11 以前对网站开发萌生了想法&#xff0c;又有些急于求成&#xff0c;在B站照着视频敲了一个基于flask的博客系统。但对于程序的代码难免有些囫囵吞枣&#xff0c;存在许多模糊或不太理解的地方&#xff0c;只会照葫芦画瓢。 而当自己想开发一个什么网站的时&…

使用Java服务器实现UDP消息的发送和接收(多线程)

目录 简介&#xff1a;1. 导入必要的库2. 创建服务器端代码3. 创建客户端代码4. 实现多线程处理5. 测试运行示例代码&#xff1a;函数说明服务器端代码说明&#xff1a;客户端代码说明&#xff1a; 总结&#xff1a; 简介&#xff1a; 在本篇博客中&#xff0c;我们将介绍如何…