驱动——LED灯循环闪烁

news2024/11/19 1:29:33

 使用结构体形式对寄存器地址进行映射,实现3盏LED灯的循环点亮

1、创建LED灯点亮所需要的GPIO寄存器的结构体,并对寄存器地址进行宏定义

 2、①通过ioremap函数将物理地址映射为虚拟地址

void* ioremap(phys_addr_t offset, size_t size)

函数功能:将物理地址映射为虚拟地址

参数:

@offset:物理地址

@size:映射大小,单位字节

返回值: 成功返回虚拟地址,失败返回NULL

②通过映射的虚拟地址对寄存器进行初始化

3、通过copy_from_user函数从用户空间读取信息,对要进行操作的灯进行判断,并对相应寄存器进行操作

int copy_from_user(void *to, const void __user volatile *from, unsigned long n)

函数功能:将数据从用户空间拷贝到内核空间

参数:

@to:内核空间首地址

@from:用户空间首地址

@ n:拷贝数据大小(以字节为单位)

返回值: 成功返回0 失败返回未拷贝的字节数

 4、通过iounmap取消对寄存器的映射

void iounmap(void __iomem *addr)

函数功能:取消映射

参数:

 

@offset:映射之后的虚拟地址

返回值: 无

附实现代码

测试代码:

#include <stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
char buf[128] = {0};

int main(int argc, const char *argv[])
{
    int fd = -1;
    int i=0;
    fd = open("/dev/led",O_RDWR);
    if(-1 == fd)
    {
        perror("open is error");
        exit(1);
    }
    while(1)
    {
        buf[0]='1';
        buf[1]='1';
        write(fd,buf,sizeof(buf));
        sleep(1);
        buf[1]='0';
        write(fd,buf,sizeof(buf));
        sleep(1);

        buf[0]='2';
        buf[1]='1';
        write(fd,buf,sizeof(buf));
        sleep(1);
        buf[1]='0';
        write(fd,buf,sizeof(buf));
        sleep(1);

        buf[0]='3';
        buf[1]='1';
        write(fd,buf,sizeof(buf));
        sleep(1);
        buf[1]='0';
        write(fd,buf,sizeof(buf));
    }
    close(fd);
	
	return 0;
}
#ifndef __LED_H__
#define __LED_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_ADDR 0x50006000
#define GPIOF_ADDR 0x50007000
#define RCC_ADDR 0x50000A28



#endif

 功能代码

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

#define GNAME "mydev"
volatile gpio_t* VIRT_GPIOE;
volatile gpio_t* VIRT_GPIOF;
volatile unsigned int* VIRT_RCC;
int major;
char kbuf[128]={0};
int mydev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
ssize_t mydev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{ 
    int set;
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    if(size > sizeof(kbuf)) size = sizeof(kbuf);
    set = copy_to_user(ubuf,kbuf,size);
    if(set)
    {
        printk("copy to user is error\n");
        return -EIO;
    }
    return size;
}
ssize_t mydev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
    int ret;
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    if(size > sizeof(kbuf)) size = sizeof(kbuf);
    ret = copy_from_user(kbuf,ubuf,size);
    if(ret)
    {
        printk("copy from user is error\n");
        return -EIO;
    }
    printk("copy from user kbuf = %s\n",kbuf);
    switch(kbuf[0])
    {
        case '1':
                if(kbuf[1]=='1')
                {
                    VIRT_GPIOE->ODR |= (0x1<<10);
                }
                else if(kbuf[1]=='0')
                {
                    VIRT_GPIOE->ODR &= (~(0x1<<10));
                }
                break;
        case '3':
                if(kbuf[1]=='1')
                {
                    VIRT_GPIOE->ODR |= (0x1<<8);
                }
                else if(kbuf[1]=='0')
                {
                    VIRT_GPIOE->ODR &= (~(0x1<<8));
                }
                break;
        case '2':
                if(kbuf[1]=='1')
                {
                    VIRT_GPIOF->ODR |= (0x1<<10);
                }
                else if(kbuf[1]=='0')
                {
                    VIRT_GPIOF->ODR &= (~(0x1<<10));
                }
                break;
    }

    return size;
}
int mydev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
struct file_operations fops={
    .open=mydev_open,
    .read=mydev_read,
    .write=mydev_write,
    .release=mydev_close,
};

static int __init mydev_init(void)
{
    major=register_chrdev(0,GNAME,&fops);
    if(major<0)
    {
        printk("register file\n");
        return major;
    }
    printk("major=%d\n",major);
    VIRT_RCC = ioremap(RCC_ADDR,4);
    if(NULL == VIRT_RCC)
    {
        printk("VIRT_RCC error\n");
        return -ENXIO;
    }
    VIRT_GPIOE = ioremap(GPIOE_ADDR,4);
    if(NULL == VIRT_GPIOE)
    {
        printk("VIRT_GPIOE error\n");
        return -ENXIO;
    }
    VIRT_GPIOF = ioremap(GPIOF_ADDR,4);
    if(NULL == VIRT_GPIOF)
    {
        printk("VIRT_GPIOF error\n");
        return -ENXIO;
    }
    *VIRT_RCC |= (0x3<<4);

    VIRT_GPIOE->MODER &= (~(0x3<<20));
    VIRT_GPIOE->MODER |= (0x1<<20);
    VIRT_GPIOE->ODR &= (~(0x1<<10));

    VIRT_GPIOE->MODER &= (~(0x3<<16));
    VIRT_GPIOE->MODER |= (0x1<<16);
    VIRT_GPIOE->ODR &= (~(0x1<<8));

    VIRT_GPIOF->MODER &= (~(0x3<<20));
    VIRT_GPIOF->MODER |= (0x1<<20);
    VIRT_GPIOF->ODR &= (~(0x1<<10));
    return 0;
}

static void __exit mydev_exit(void)
{
    unregister_chrdev(major,GNAME);
    iounmap(VIRT_GPIOE);
    iounmap(VIRT_GPIOF);
    iounmap(VIRT_RCC);
}

module_init(mydev_init);
module_exit(mydev_exit);

MODULE_LICENSE("GPL");

led

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

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

相关文章

Mysql主从复制出现connecting

主从同步时出现Slave_IO_Running&#xff1a;Connecting首先解决Slave_IO_Running和Slave_SQL_Running是no的问题&#xff0c;原因是一台虚拟机是由另一台虚拟机复制过来的&#xff0c;就会导致uuid是一样的&#xff0c;需要先修改server的uuid&#xff0c;具体请查阅相关资料。…

【FME实战教程】001:FME2020中文安装图文教程(附安装包下载)

文章目录1. 安装license2. 安装FME Desktop3. 安装中文语言4. FME软件下载地址1. 安装license 打开软件安装包中的fme-flexnet-win-x64.msi&#xff0c;如下图所示&#xff1a; 点击Next。 点击Next。 单击install。 点击finish&#xff0c;完成。 &#xff08;1&#xff09;修…

pytorch入门教程(小土堆

pytorch入门教程、一些基础函数的概念&#xff08;参考代码&#xff09;&#xff0c;主要是带着读了一遍pytorch官方文档、另外推荐一个网站 www.paperswithcode.com&#xff0c;感觉很厉害的样子。 P5. PyTorch加载数据初认识_哔哩哔哩_bilibili import torch torch.cuda.is_a…

年产10000吨即食型大头菜工厂设计

目 录 摘 要 I ABSTRACT II 第1章 绪论 1 1.1即食大头菜发展现状及市场前景 1 1.1.1世界即食大头菜发展的特点与趋势 1 1.1.2我国即食大头菜发展现状 1 1.1.3即食大头菜的生产现状及前景展望 2 1.2专家点评 3 第2章 厂址选择 5 2.1厂址选择依据及范围 5 2.1.1选址依据 5 2.1.2选…

3.46 OrCAD软件怎么输出物料清单BOM表格?

笔者电子信息专业硕士毕业&#xff0c;获得过多次电子设计大赛、大学生智能车、数学建模国奖&#xff0c;现就职于南京某半导体芯片公司&#xff0c;从事硬件研发&#xff0c;电路设计研究。对于学电子的小伙伴&#xff0c;深知入门的不易&#xff0c;特开次博客交流分享经验&a…

asp.net+sqlserver笔记本电脑售后服务管理系统C#

研究内容与章节安排 全文的结构如下&#xff1a; 第一章&#xff1a;引言。论述课题提出的背景、对目前笔记本电脑售后服务系统的国内外发展水平进行了分析研究&#xff0c;通过比对&#xff0c;提出笔记本电脑售后服务系统的涵义及其优越性。 第二章&#xff1a;笔记本电脑售后…

LabVIEW性能和内存管理 4

LabVIEW性能和内存管理 4 本文介绍LabVIEW性能和内存管理的几个建议4。 传输缓冲区 传输缓冲区保护操作缓冲区和执行缓冲区之间的数据传输 只有当前面板在内存中时才更新 为了保护操作和执行缓冲区之间的数据传输&#xff0c;LabVIEW使用传输缓冲区。当您处理大型数据集&am…

17-Explain执行计划-01

Explain 执行计划 什么是执行计划 有了慢查询语句后&#xff0c;就要对语句进行分析。一条查询语句在经过 MySQL 查询优化器的各种基于成本和规则的优化会后生成一个所谓的执行计划&#xff0c;这个执行计划展示了接下来具体执行查询的方式&#xff0c;比如多表连接的顺序是什…

Java基于springboot +vue的箱包销售购物网站 多商家

随着人们生活的节奏越来越快&#xff0c;很多时候人们在外出的时候会有大包小包。所以这个时候如何选择适合自己的物美价廉的箱包是一个很重要的环节。选对了箱包不仅能够增加大街上的回头率同时也能够方便自己的出行。当前箱包市场鱼目混杂且价格昂贵。随着互联网的发展&#…

intellij plugin(插件)的项目解析及研读

文章目录资料action_basics (基本的响应操作)plugin.xmlCustomDefaultActionGroupPopupDialogActionDynamicActionGroupcomparing_references_inspection (关注代码提示)conditional_operator_intention [未成功复现]editor_basics (选择文字替换等)Caret PositionEditor Add C…

java项目-第137期jsp+servlet的周公算命预测系统-java毕业设计

java项目-第137期jspservlet的周公算命预测系统-计算机毕业设计 【源码请到资源专栏下载】 今天分享的项目是《周公算命预测系统》 该项目分为管理员和普通用员2个角色。 管理员主要负责后台的信息维护&#xff1a;算命分类管理(比如八字、星座、相命)、管理员信息管理、用户信…

实用数据结构【并查集】 - 原理

实用数据结构【并查集】 - 原理 [一个问题] 若某个部落过于庞大&#xff0c;则部落成员见面也有可能不认识。 已知某个部落的成员关系图&#xff0c;任意给出其中两个人&#xff0c;判断是否有亲戚关系。规定&#xff1a;①若x、y 是亲戚&#xff0c;y 和z 是亲戚&#xff0…

【C++】string的模拟实现

目录 一、std::swap和std::string::swap的区别 二、string的默认构造函数 1、构造函数 2、拷贝构造 3、赋值运算符重载 4、析构函数 三、string中的小接口 四、遍历接口的实现 1、对operator[]进行重载 2、迭代器 五、reserve和resize 六、插入删除查找相关接口 1…

DirtyCow脏牛漏洞复现(CVE-2016-5195)

DirtyCow脏牛漏洞复现 本文以vulnhub靶场中的lampiao为例复现脏牛提权漏洞 扫描c段 nmap -sS -Pn 192.168.1.0/24找到疑似ip 对该ip端口进行扫描&#xff0c;多扫出个1898端口 nmap -A -sV -p- 192.168.1.13访问80端口&#xff0c;没有有用的信息 1898也是个apche的http服务…

立足小餐饮,“新名酒”江小白能走多远?

&#xff08;图片来源于网络&#xff0c;侵删&#xff09; 来源 | 螳螂观察 文 | 叶小安 白酒市场从不缺新故事&#xff0c;但一直缺年轻人喜欢的白酒。 上月底&#xff0c;江小白旗下江记酒庄获重庆市江津区华信集团10亿元战略投资。与此同时&#xff0c;江小白产品理念升…

技术贴 | Rocksdb 中 Memtable 源码解析

一、什么是 Memtable&#xff1f; Memtable 是 Rocksdb 在内存中保存数据的一种数据结构&#xff0c;一个 Memtable 的容量是固定的&#xff0c;在 Memtable 写满后&#xff0c;会转换为 Immutable Memtable&#xff0c;Immutable Memtable 中的数据会 Flush 到 SST File 中。…

编程中老生常谈的【编码规范】你还记得多少?进来回顾一下吧【文末送书】

&#x1f3ac; 博客主页&#xff1a;https://xiaoy.blog.csdn.net &#x1f3a5; 本文由 呆呆敲代码的小Y 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;Unity精品学习专栏 &#x1f332; 游戏制作专栏推荐&#xff1a;游戏制作分享 &…

【genius_platform软件平台开发】第八十一讲:ARM Neon指令集一(ARM NEON Intrinsics, SIMD运算, 优化心得)

1. ARM Neon Intrinsics 编程 1.入门&#xff1a;基本能上手写Intrinsics 1.1 Neon介绍、简明案例与编程惯例 1.2 如何检索Intrinsics 1.3 优化效果案例 1.4 如何在Android应用Neon 2. 进阶&#xff1a;注意细节处理&#xff0c;学习常用算子的实现 2.1 与Neon相关的ARM体系结…

寻 友 软 件

寻友软件项目技术技术功能部署Redis部署RocketMQJWT&#xff08;Json Web Token&#xff09;虹软人脸识别部署MongoDB&#xff08;尽量不用docker部署mongo&#xff09;部署Nginx过滤器及拦截器加缓存编码流程DOC接口文档bug技术 技术 前端&#xff1a; flutterandroid环信S…

分销微信小程序介绍_分销小程序有什么作用呢

不同的微商城系统对于分销功能的支持会有不要的叫法&#xff0c;一般来说主要有两种&#xff0c;一种是基于商品分享的分销方式&#xff0c;通过分享链接识别客户从属关系&#xff0c;订单完成&#xff0c;结算佣金&#xff1b;另一种分销商可以建立并独立运营一个分销店铺&…