驱动 实现三个灯的亮灭

news2024/11/18 17:30:20

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

head.h

#ifndef __HEAD_H__
#define __HEAD_H__

#define PHY_LED1_MODER 0x50006000
#define PHY_LED1_ODR 0x50006014
#define PHY_LED1_RCC 0x50000A28

#define PHY_LED2_MODER 0x50007000
#define PHY_LED2_ODR 0x50007014
#define PHY_LED2_RCC 0x50000A28

#define PHY_LED3_MODER 0x50006000
#define PHY_LED3_ODR 0x50006014
#define PHY_LED3_RCC 0x50000A28

#endif

mycdev.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 "head.h"
int major;
char kbuf[128] = {0};
// 定义指针接收映射成功的虚拟内存首地址
unsigned int *vir_led1_moder;
unsigned int *vir_led1_odr;
unsigned int *vir_led1_rcc;
unsigned int *vir_led2_moder;
unsigned int *vir_led2_odr;
unsigned int *vir_led2_rcc;
unsigned int *vir_led3_moder;
unsigned int *vir_led3_odr;
unsigned int *vir_led3_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)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    int ret;
    ret = copy_to_user(ubuf, kbuf, size);
    if (ret)
    {
        printk("copy_to_user filad\n");
        return ret;
    }
    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
    int ret;
    ret = copy_from_user(kbuf, ubuf, size);
    if (ret)
    {
        printk("copy_from_user filed\n");
        return ret;
    }
    if (kbuf[0] == '1' && kbuf[1]== '1') // 开灯
    {
        // 开灯逻辑
        printk("开灯\n");
        (*vir_led1_odr) |= (0X1 << 10);
    }
    if (kbuf[0] == '1' && kbuf[1]== '0') // 关灯
    {
        // 关灯逻辑
        printk("关灯\n");
        (*vir_led1_odr) &= (~(0X1 << 10));
    }
    if (kbuf[0] == '2' && kbuf[1]== '1') // 开灯
    {
        // 开灯逻辑
        printk("开灯\n");
        (*vir_led2_odr) |= (0X1 << 10);
    }
    if (kbuf[0] == '2' && kbuf[1]== '0') // 关灯
    {
        // 关灯逻辑
        printk("关灯\n");
        (*vir_led2_odr) &= (~(0X1 << 10));
    }
    if (kbuf[0] == '3' && kbuf[1]== '1') // 开灯
    {
        // 开灯逻辑
        printk("开灯\n");
        (*vir_led3_odr) |= (0X1 << 8);
    }
    if (kbuf[0] == '3' && kbuf[1]== '0') // 关灯
    {
        // 关灯逻辑
        printk("关灯\n");
        (*vir_led3_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)
{
    int i;
    // 注册字符设备驱动
    major = register_chrdev(0, "mycdev", &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");
    // 向上提交设备信息
    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_led1_moder = ioremap(PHY_LED1_MODER, 4);
    if (vir_led1_moder == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    vir_led1_odr = ioremap(PHY_LED1_ODR, 4);
    if (vir_led1_odr == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    vir_led1_rcc = ioremap(PHY_LED1_RCC, 4);
    if (vir_led1_rcc == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }

    vir_led2_moder = ioremap(PHY_LED2_MODER, 4);
    if (vir_led2_moder == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    vir_led2_odr = ioremap(PHY_LED2_ODR, 4);
    if (vir_led2_odr == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    vir_led2_rcc = ioremap(PHY_LED2_RCC, 4);
    if (vir_led2_rcc == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
	
    vir_led3_moder = ioremap(PHY_LED3_MODER, 4);
    if (vir_led3_moder == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    vir_led3_odr = ioremap(PHY_LED3_ODR, 4);
    if (vir_led3_odr == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    vir_led3_rcc = ioremap(PHY_LED3_RCC, 4);
    if (vir_led3_rcc == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    printk("物理内存映射成功\n");
    // 硬件寄存器的初始化
    (*vir_led1_moder) &= (~(0X3 << 20)); // 设置为输出
    (*vir_led1_moder) |= (0X1 << 20);
    (*vir_led2_moder) &= (~(0X3 << 20)); // 设置为输出
    (*vir_led2_moder) |= (0X1 << 20);
    (*vir_led3_moder) &= (~(0X3 << 16)); // 设置为输出
    (*vir_led3_moder) |= (0X1 << 16);
    // rcc使能
    (*vir_led1_rcc) |= (0X1 << 4);
    (*vir_led2_rcc) |= (0X1 << 5);
    (*vir_led3_rcc) |= (0X1 << 4);
    // 默认关灯
    (*vir_led1_odr) &= (~(0X1 << 10));
    (*vir_led2_odr) &= (~(0X1 << 10));
    (*vir_led3_odr) &= (~(0X1 << 8)); 
    return 0;
}
static void __exit mycdev_exit(void)
{
    // 取消物理内存的映射
    iounmap(vir_led1_moder);
    iounmap(vir_led1_odr);
    iounmap(vir_led1_rcc);
    iounmap(vir_led2_moder);
    iounmap(vir_led2_odr);
    iounmap(vir_led2_rcc);
    iounmap(vir_led3_moder);
    iounmap(vir_led3_odr);
    iounmap(vir_led3_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 <string.h>
int main(int argc, const char *argv[])
{
	char buf[128] = {};
	int fd = open("/dev/mycdev0",O_RDWR);
	if(fd < 0)
	{
		printf("打开设备文件失败\n");
		exit(-1);
	}
	printf("成功打开设备文件\n");
	while(1)
	{
		printf("输入要实现的逻辑:>\n");
		fgets(buf,sizeof(buf),stdin);//从终端读取一个字符存放到buf
		buf[strlen(buf)-1]='\0';
		write(fd,buf,sizeof(buf));
	}
	close(fd);
	return 0;
}

实验现象

 

 

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

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

相关文章

解决git reset --soft HEAD^撤销commit时报错

今天在使用git回退功能的时候&#xff0c;遇到以下错误&#xff1a; 解决git reset --soft HEAD^撤销commit时报错 问题&#xff1a; 在进行完commit后&#xff0c;想要撤销该commit&#xff0c;于是使用了git reset --soft HEAD^命令&#xff0c;但是出现如下报错&#xff1…

Java 的文档注释其实并没有那么简单

Java 的文档注释其实并没有那么简单 我们在写java 程序的只有三种注释方式&#xff1a; “//” 后面跟上想要写入的注释 “/* */” 里面跟上想要写入的注释 “/** */” 说明注释&#xff0c;可以多行之间注释 说明注释允许我们在程序中嵌入关于程序的信息。 我们可以使用…

节点不连续伽辽金方法在求解线性和非线性平流方程中的一维实现(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

嵌入式:ARM Day4

一、自己编写代码实现三盏灯点亮 源码&#xff1a; .text .global _start _start: 进行一次初始化bl RCC_INITbl LED1_INITbl LED2_INITbl LED3_INITb looploop: 循环开关灯bl LED1_ONbl delay_1sbl LED1_OFFbl delay_1sbl LED2_ONbl delay_1sbl LED2_OFFbl delay_1sbl…

13 Web全栈 pnpm

什么是pnpm&#xff1f; 可以理解成performant npm缩写 速度快、节省磁盘空间的软件包管理器 特点 快速- pnpm比其他包管理器快2倍高效- node_modules中的文件链接自特定的内容寻址存储库支持monorepos- 内置支持单仓多包严格- pnpm默认创建了一个非平铺的node_modules 因此代…

Spring中循环依赖解决方案

循环依赖 循环依赖是Spring框架中常见的问题之一&#xff0c;当两个或多个类相互引用对方时&#xff0c;就会出现循环依赖的情况。这种情况下&#xff0c;Spring框架无法确定哪个类应该先实例化和初始化&#xff0c;从而导致异常。常见的解决方法有&#xff1a;构造函数注入、s…

STM32单片机通过串口烧录hex程序

我之前买过一个STM32最小程序单片机&#xff0c;原来下载51单片机都是使用串口方式&#xff0c;这里也通过串口方式烧录STM32单片机&#xff0c;还需要借助一个USB TO TTL工具。 USB TO TTL工具类似一个U盘工具&#xff0c;只不过它另一端是接线&#xff0c;一般电脑会自动安装…

C++入门篇9---list

list是带头双向循环链表 一、list的相关接口及其功能 1. 构造函数 函数声明功能说明list(size_type n,const value_type& valvalue_type())构造的list中包含n个值为val的元素list()构造空的listlist(const list& x)拷贝构造list(InputIterator first, InputIterator…

推荐系统系列之推荐系统概览(上)

在当今信息化高速发展的时代&#xff0c;推荐系统是一个热门的话题和技术领域&#xff0c;一些云厂商也提供了推荐系统的SaaS服务比如亚马逊云科技的 Amazon Personalize 来解决客户从无到有迅速构建推荐系统的痛点和难点。在我们的日常生活中&#xff0c;推荐系统随处可见&…

论文阅读 - Understanding Diffusion Models: A Unified Perspective

文章目录 1 概述2 背景知识2.1 直观的例子2.2 Evidence Lower Bound(ELBO)2.3 Variational Autoencoders(VAE)2.4 Hierachical Variational Autoencoders(HVAE) 3 Variational Diffusion Models(VDM)4 三个等价的解释4.1 预测图片4.2 预测噪声4.3 预测分数 5 Guidance5.1 Class…

【项目设计】从零实现一个高并发内存池

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《项目设计》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录 &#x1f449;项目介绍&…

005-Spring 扩展点 :PostProcess

目录 Spring 扩展点 &#xff1a;PostProcess介绍PostProcess大纲文字明细使用方法示例Autowired 功能实现Resource 功能实现 后记 Spring 扩展点 &#xff1a;PostProcess 介绍 Spring 核心做的事情其实很简单就是&#xff1a;控制反转和依赖注入 也就是把 Class 解析为 Bea…

npm install ffi各种失败,换命令npm i ffi-napi成功

网上各种帖子安装ffi&#xff0c;基本上到了windows build tools这里会卡住。 使用命令npm install --global --production windows-build-tools 安装报错信息如下&#xff1a; PS E:\codes\nodejsPath\tcpTest> npm install --global --production windows-build-tools …

06-加密算法

加密算法 一、前言知识1、加密解密2、MD5&#xff08;最常见&#xff09;3、SHA4、进制5、时间戳6、URL编码7、base64编码8、unescape编码9、AES加密10、DES&#xff08;类似于base64&#xff09; 二、常见加密形式算法解析三、演示案例1、某 CTF 比赛题目解析2、某 CMS 密码加…

【不带权重的TOPSIS模型详解】——数学建模

目录索引 定义&#xff1a;问题引入&#xff1a;不合理之处&#xff1a;进行修改&#xff1a; 指标分类&#xff1a;指标正向化&#xff1a;极小型指标正向化公式&#xff1a;中间型指标正向化公式&#xff1a;区间型指标正向化公式&#xff1a; 标准化处理(消去单位)&#xff…

pytorch报错torch.cuda.is_available()结果false处理方法

文章目录 问题及起因问题起因 解决方法 问题及起因 问题 前几天跑项目&#xff0c;笔记本上的GPU可以正常跑起来。要跑VAE模型&#xff0c;重新安装了torch,GPU就无法使用了&#xff0c;我重新安装了 cuda,torch.cuda.is_available()的结果依然是False。 起因 配置项目环境…

测试人员的BUG防不胜防

“灵异事件&#xff01;程序里发现了新Bug但是它正常运行啦&#xff01;”、“谁敢信&#xff0c;我电脑死机竟然是因为放青藏高原的时候硬盘共振振幅太大了——”…… 人生处处有Bug&#xff0c;哪一个最令你目瞪口呆&#xff0c;久久不能忘怀&#xff1f;今天就来浅浅分享一…

Spring系列篇--关于IOC【控制反转】的详解

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Spring的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.什么是Spring 二.Spring的特点 三.什…

TCP服务器—实现数据通信

目录 前言 1.接口介绍 2.编写服务器 3.编写客户端 4.编译链接 5.测试 6.总结 前言 今天我们要介绍的是使用TCP协议实现数据通信&#xff0c;相比于之前写的UDP服务器实现数据信&#xff0c;在主体逻辑上并没有差别。客户端向服务器发送信息&#xff0c;服务器接受信息并回…

如何进行无线网络渗透测试?

今天我们将继续深入探讨Kali Linux的应用&#xff0c;这次我们将重点介绍如何使用Kali Linux进行无线网络渗透测试。无线网络渗透测试是评估无线网络安全性的重要步骤&#xff0c;而Kali Linux作为一款专业的渗透测试发行版&#xff0c;提供了丰富的工具来帮助你进行这项任务。…