驱动 - 20230816

news2024/11/19 19:25:13

练习

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;
}

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

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

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

相关文章

toB营销如何从品牌营销转向获客营销?

“解构纷享新营销&#xff0c;赋能用户新增长”&#xff0c;这是2023年下半年&#xff0c;纷享销客践行“以客户成功定义成功”价值观&#xff0c;针对企业用户市场营销领域的全国巡回研讨会&#xff0c;希望把纷享销客在成长路上经历的、收获的经验、踩过的“坑”与用户共享&a…

Postman如何做接口测试:什么?postman 还可以做压力测试?

我们都知道&#xff0c; postman 是一款很好用的接口测试工具。不过 postman 还可以做简单的压力测试&#xff0c;而且步骤只需要 2 步。 首先&#xff0c;打开 postman, 编写接口的请求参数。 然后&#xff0c;点击右下方的 runner 运行器&#xff0c;把需要测试的接口拖动到…

序列模型和循环网络

Sequence Modeling and Recurrent Networks Sequence modeling tasks 在以往的模型中&#xff0c;各个输入之间是独立分布的 x ( i ) x^{(i)} x(i) 之间是相互独立的&#xff0c;同样输出 y ( i ) y^{(i)} y(i)之间也是相互独立的。 但是在序列模型中&#xff0c;输入输出是…

应用开源框架平台,实现流程化办公!

如今&#xff0c;实现流程化办公&#xff0c;管理好数据资源是很多企业的共同想法。如果采用传统的办公方式显然无法实现这一愿望。利用开源框架平台&#xff0c;可以管理好数据资源&#xff0c;为企业提高办公协作效率&#xff0c;进入流程化办公。流辰信息是专业的低代码技术…

如何使用Python编写小游戏?

大家好&#xff0c;我是沐尘而生&#xff0c;如果你是一个热爱编程的小伙伴&#xff0c;又想尝试游戏开发&#xff0c;那么这篇文章一定能满足你的好奇心。不废话&#xff0c;让我们马上进入Python游戏开发的精彩世界吧&#xff01; Python游戏开发的魅力 编写小游戏不仅仅是锻…

Linux系统管理:虚拟机ESXi安装

目录 一、理论 1.VMware Workstation 2.VMware vSphere Client 3.ESXi 二、实验 1.ESXi 7安装 一、理论 1.VMware Workstation 它是一款专业的虚拟机软件&#xff0c;可以在一台物理机上运行多个操作系统&#xff0c;支持Windows、Linux等操作系统&#xff0c;可以模拟…

opencv-进阶05 手写数字识别原理及示例

前面我们仅仅取了两个特征维度进行说明。在实际应用中&#xff0c;可能存在着更多特征维度需要计算。 下面以手写数字识别为例进行简单的介绍。 假设我们要让程序识别图 20-2 中上方的数字&#xff08;当然&#xff0c;你一眼就知道是“8”&#xff0c;但是现在要让计算机识别…

lvs负载均衡集群(NAT模式)

lvs负载均衡集群&#xff1a; 1.什么是集群&#xff08;含义&#xff09;&#xff1a;就是将多台主机作为一个整体&#xff0c;对外提供相同的服务 2.集群使用在哪一个场景&#xff1a;高并发 并发量过大时候加服务器的方式就是向外扩展(横向扩展)&#xff0c;就是集群。 3…

HoudiniVex笔记_P24_ForceBasics力基础

原视频&#xff1a;https://www.youtube.com/playlist?listPLzRzqTjuGIDhiXsP0hN3qBxAZ6lkVfGDI Bili&#xff1a;Houdini最强VEX算法教程 - VEX for Algorithmic Design_哔哩哔哩_bilibili Houdini版本&#xff1a;19.5 1、什么是Force 本章主要讲重力、弹力、速度与质量、…

强训第33天

选择 C A ping是TCP/IP协议族的一部分&#xff0c;使用ICMP协议&#xff0c;ICMP底层使用IP协议。如果要ping其他网段&#xff0c;则需要设置网关。 如果是二层交换机故障&#xff0c;则ping同网段的也会不通。 C Dos攻击被称之为“拒绝服务攻击”&#xff0c;其目的是使计算机…

网页设计详解(一)-HTML简介

本文作为博主学习笔记&#xff1a;2023-05-04星期四 一、网页介绍 网页是构成网站的基本元素&#xff0c;它是一个包含HTML标签的纯文本文件&#xff0c;是超文本标记语言格式(文件扩展名为.html或.htm)。网页通常用图像档来提供图画&#xff0c;通过浏览器来阅读。 超文本介…

C#__Action和Func委托的基本用法

// 类 class DelegateC{// Action&#xff0c;内置的委托类型&#xff0c;引用了一个void返回值类型的方法&#xff0c;T表示方法参数public static void AText1(){Console.WriteLine("Atext1");}public static void AText2(int x){Console.WriteLine("Atext2&…

【LINUX相关】生成随机数(srand、/dev/random 和 /dev/urandom )

目录 一、问题背景二、修改方法2.1 修改种子2.2 使用linux中的 /dev/urandom 生成随机数 三、/dev/random 和 /dev/urandom 的原理3.1 参考连接3.2 重难点总结3.2.1 生成随机数的原理3.2.2 随机数生成器的结构3.2.3 二者的区别和选择 四、在代码的使用方法 一、问题背景 在一个…

2023一建各科考点归纳

一级建造师《建设工程项目管理》高频考点 1Z201000建设工程项目的组织与管理 1Z201010建设工程管理的内涵和任务 系统的目标决定了系统的组织&#xff0c;而组织是目标能否实现的决定性因素。 建设工程管理涉及工程项目全过程&#xff0c;包括: 决策阶段-开发管理: 实施阶…

《零基础7天入门Arduino物联网-01》学前必看

配套视频课程&#xff1a;《零基础学Arduino物联网&#xff0c;入门到进阶》 配套课件资料获取&#xff1a;微联实验室 配套学习套件购买&#xff1a;淘宝搜索店铺【微联实验室】 学前须知 注意事项 本系列课程主要针对零基础的物联网爱好者群体开发&#xff0c;非系统性讲解…

Java 中操作 Redis

文章目录 一、Redis 常用数据类型二、Redis 常用操作命令1. 字符串命令2. 哈希命令3. 列表命令4. 集合命令5. 有序集合命令6. 通用命令 三、在 Java 中操作 Redis1. 导入 maven 坐标2. 配置 Redis 数据源3. 编写配置类 四、在代码中的具体使用 一、Redis 常用数据类型 Redis 存…

6.4 恶意代码

数据参考&#xff1a;CISP官方 目录 恶意代码概念及发展历程恶意代码的传播方式恶意代码防护 一、恶意代码概念及发展历程 1、什么是恶意代码 什么是恶意代码 《中华人民共和国计算机信息系统安全保护条例》第二十八条&#xff1a;“计算机病毒&#xff0c;是指编制或者…

VMware虚拟机下载与安装

VMware虚拟机下载与安装 目录 VMware虚拟机下载与安装[TOC](目录) 概述 1. 下载虚拟机1.1 访问官网1.2 点击产品菜单&#xff0c;然后选择产品 VMware Workstation Pro1.3 选择试用版下载 2.安装虚拟机2.1 右键点击安装包&#xff0c;选择以管理员身份运行2.2 按照说明进行安装…

玩转VS code 之 C/C++ 环境配置篇

PS&#xff1a;俺是菜鸟&#xff0c;整理和踩坑试错花了不少时间&#xff0c;如果这篇文章对您有用的话&#xff0c;请麻烦您留下免费的赞赞&#xff0c;赠人玫瑰&#xff0c;手留余香&#xff0c;码字踩坑不易&#xff0c;望三连支持 上一篇&#xff1a;玩转 VS code 之下载篇…

数字人如何赋能汽车品牌营销线下实时交互?

为了进一步巩固和拓展消费群体&#xff0c;扩大品牌影响力&#xff0c;别克汽车在线下开展了新品体验日活动&#xff0c;在品鉴会现场数字人影萱作为神秘嘉宾惊喜亮相&#xff0c;与现场嘉宾和众多媒体同屏实时互动&#xff0c;这虚拟与现实的碰撞互动形式&#xff0c;让现场嘉…