通过字符设备驱动并编写应用程序控制三盏灯亮灭
现象 键盘按1三灯全亮 按0三灯全灭
头文件.h
#ifndef __HEAD_H__
#define __HEAD_H__
#define PHY_LED1_MODER 0X50006000
#define PHY_LED1_ODR 0X50006014
#define PHY_RCC 0X50000A28#define PHY_LED2_MODER 0X50007000
#define PHY_LED2_ODR 0X50007014#define PHY_LED3_MODER 0X50006000
#define PHY_LED3_ODR 0X50006014#endif
驱动程序demo.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "head.h"
unsigned int major;
char kbuf[128] = {};
// 定义三个指针指向映射后的虚拟内存
unsigned int *vir_led1_moder;
unsigned int *vir_led1_odr;
unsigned int *vir_led2_moder;
unsigned int *vir_led2_odr;
unsigned int *vir_led3_moder;
unsigned int *vir_led3_odr;
unsigned int *vir_rcc;
// 封装操作方法
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 filed\n");return -EIO;}return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);int ret;ret = copy_from_user(kbuf, ubuf, size);if (ret){printk("copy_from_user filed\n");return -EIO;}if (kbuf[0] == '0') // 关灯{// 关灯逻辑(*vir_led1_odr) &= (~(0X1<<10));//默认关灯(*vir_led2_odr) &= (~(0X1<<10));//默认关灯(*vir_led3_odr) &= (~(0X1<<8));//默认关灯}else if (kbuf[0] == '1'){// 开灯逻辑(*vir_led1_odr) |= (0X1<<10);(*vir_led2_odr) |= (0X1<<10);(*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)
{// 注册字符设备驱动major = register_chrdev(0, "mychrdev", &fops);if (major < 0){printk("字符设备驱动注册失败\n");return major;}printk("注册字符设备驱动成功major=%d\n", major);// 进行寄存器的地址映射// LED1寄存器地址映射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;}//LED2寄存器地址映射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;}//LED3寄存器地址映射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;}//RCC寄存器地址映射vir_rcc = ioremap(PHY_RCC, 4);if (vir_rcc == NULL){printk("物理内存地址映射失败%d\n", __LINE__);return -EFAULT;}printk("寄存器内存映射成功\n");//LED1寄存器初始化(*vir_rcc) |= (0X3<<4);//GPIOEF控制器时钟使能(*vir_led1_moder) &= (~(0X3<<20));//MODER[21:20]->00(*vir_led1_moder) |= (0X1<<20);//MODER[21:20]->01(*vir_led1_odr) &= (~(0X1<<10));//默认关灯//LED2寄存器初始化(*vir_led2_moder) &= (~(0X3<<20));//MODER[21:20]->00(*vir_led2_moder) |= (0X1<<20);//MODER[21:20]->01(*vir_led2_odr) &= (~(0X1<<10));//默认关灯//LED3寄存器初始化(*vir_led3_moder) &= (~(0X3<<16));//MODER[17:16]->00(*vir_led3_moder) |= (0X1<<16);//MODER[17:16]->01(*vir_led3_odr) &= (~(0X1<<8));//默认关灯return 0;
}
static void __exit mycdev_exit(void)
{//取消内存映射iounmap(vir_led1_moder);iounmap(vir_led1_odr);iounmap(vir_rcc);iounmap(vir_led2_moder);iounmap(vir_led2_odr);iounmap(vir_led3_moder);iounmap(vir_led3_odr);// 注销字符设备驱动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 <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{char buf[128] = {0};int fd = open("/dev/mychrdev", O_RDWR);if (fd < 0){printf("打开设备文件失败\n");return -1;}printf("打开设备文件成功\n");while (1){printf("请输入要进行的操作:0(关灯)1(开灯)>");fgets(buf, sizeof(buf), stdin); // 在终端读一个字符串buf[strlen(buf) - 1] = '\0';write(fd, buf, sizeof(buf)); // 将数据传递给内核}close(fd);return 0;
}
现象为:

相关文章:
通过字符设备驱动并编写应用程序控制三盏灯亮灭
现象 键盘按1三灯全亮 按0三灯全灭 头文件.h #ifndef __HEAD_H__ #define __HEAD_H__ #define PHY_LED1_MODER 0X50006000 #define PHY_LED1_ODR 0X50006014 #define PHY_RCC 0X50000A28#define PHY_LED2_MODER 0X50007000 #define PHY_LED2_ODR 0X50007014#defin…...
SpringCloud链路追踪——Spring Cloud Sleuth 和 Zipkin 介绍 Windows 下使用初步
前言 在微服务中,随着服务越来越多,对调用链的分析越来越复杂。如何能够分析调用链,定位微服务中的调用瓶颈,并对其进行解决。 本篇博客介绍springCloud中用到的链路追踪的组件,Spring Cloud Sleuth和Zipkin…...
深入探究音视频开源库 WebRTC 中 NetEQ 音频抗网络延时与抗丢包的实现机制
目录 1、引言 2、什么是NetEQ? 3、NetEQ技术详解 3.1、NetEQ概述 3.2、抖动消除技术 3.3、丢包补偿技术 3.4、NetEQ概要设计 3.5、NetEQ的命令机制 3.6、NetEQ的播放机制 3.7、MCU的控制机制 3.8、DSP的算法处理 3.9、DSP算法的模拟测试 4、NetEQ源文件…...
一篇文章教会你C++11入门知识点
C11入门 列表初始化1. {}初始化2. initializer_list 声明1. auto2. decltype3. nullptr 范围for循环STL新增容器1. array2. forward_list3. unordered_map和unordered_set 右值引用和移动语义1. 左值引用和右值引用2. 左值引用和右值引用比较3. 右值引用使用场景和意义4. 右值引…...
idea leetcode配置
idea leetcode配置 配置页面如下图所示,根据需要,填入登录用户名、密码、文件存放路径,注意如果要使用自定义的代码结构配置,要勾选图中框出来的选项。 Code FileName: $!velocityTool.camelCaseName(${question.tit…...
Golang通道(Channel)原理解析
引言 并发编程是现代软件开发中的一个重要主题。Golang作为一门并发友好的编程语言,提供了一种简单而强大的机制,即通道(Channel),用于在不同的Goroutine之间进行通信和同步。通道的设计和原理是Golang并发模型的核心…...
使用树莓派搭建文件共享服务器-samba服务器
局域网内部通过文件共享来传输文件是一种非常方便的方式,小米摄像头也支持用文件共享smb模式将视频备份到局域网中的文件服务器上。之前我一直使用荣耀pro路由器游戏版,是自带USB接口支持文件共享服务的,接上USB移动硬盘,小米摄像…...
GitLab使用webhook触发Jenkins自动构建
1、jenkins安装gitlab插件 在插件管理中,搜索gitlab安装这个插件。 2、job中配置webhook地址和密钥 进入job设置,构建触发器中就可以看到gitlab的webhook配置,复制URL地址和随机令牌至gitlab中 勾选后,就可以展开设置ÿ…...
柔性数组的使用及注意事项
1.柔性数组在结构体当中,并且在结构体的最后面. 2.结构体中除了柔型数组外至少还要有一个其他成员. 3.sizeof()返回结构体的大小不包含柔性数组的大小. 4.malloc 例:struct sdshdr16 *p malloc(sizeof (struct sdshdr16) 32); // 32 为柔性数组的大小 5.free 例: fre…...
数学建模——最优连接(基于最小支撑树)
一、概念 1、图的生成树 由图G(V,E)的生成子图G1(V,E1)(E1是E的子集)是一棵树,则称该树为图G的生成树(支撑树),简称G的树。图G有支撑树的充分必要条件为图G连通。 2、最小生成树问题 连通图G(V,E),每条边…...
【LeetCode】43. 字符串相乘
1 问题 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。 注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: num1 “2”, num2 “3” 输出: “…...
车联网之电子围栏模型使用翻滚窗口【二十一】
1. 电子围栏模型使用翻滚窗口 l 创建90秒翻滚窗口,计算中电子围栏信息(ElectricFenceModel中的值根据车辆是否在围栏内进行设置) 设置电子围栏水印 根据vin进行分组 创建翻滚窗口,90秒为一个窗口周期 自定义窗口函数,计算电子围栏中和围栏外车辆信息 1.1 创建90秒翻滚窗口 …...
图形库篇 | EasyX | 基本介绍
图形库篇 | EasyX | 基本介绍 简介 EasyX 是一个针对 C/C 的图形库,可以帮助 C/C 初学者快速上手图形和游戏编程。 比如,可以基于 EasyX 图形库很快的用几何图形画一个房子,或者一辆移动的小车,可以编写俄罗斯方块、贪吃蛇、黑白…...
凉鞋的 Unity 笔记 202. 变量概述与简介
202. 变量概述与简介 想要用好变量不是一件简单的事情,因为变量需要命名。 我们可以从两个角度看待一个变量,第一个角度是变量的功能,第二个是变量的可读性。 变量的功能其实非常简单,变量可以存储一个值,这个值是特…...
基于主动移频法与AFD孤岛检测的单相并网逆变器仿真(Simulink仿真实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
jvm的jshell,学生的工具
jshell 在我眼里,只能作为学校教学的一个玩具,事实上官方也做了解释,以下是官方的解释: 在学习编程语言时,即时反馈很重要,并且 它的 API。学校引用远离Java的首要原因 教学语言是其他语言有一个“REPL”…...
深度解析 Bing 搜索引擎的排名因素与算法
自从和ChatGPT搞上了,Bing在搜索引擎界就像是新晋的网红,风头一时无两。 搜索引擎的排名算法是确定搜索结果排名的核心,每个搜索引擎都有其独特的排名规则和算法。Bing作为全球第二大搜索引擎,其排名因素和算法同样至关重要。在本…...
使用自定义 PyTorch 运算符优化深度学习数据输入管道
在这篇文章[1]中,我们讨论 PyTorch 对创建自定义运算符的支持,并演示它如何帮助我们解决数据输入管道的性能瓶颈、加速深度学习工作负载并降低训练成本。 构建 PyTorch 扩展 PyTorch 提供了多种创建自定义操作的方法,包括使用自定义模块和/或…...
瑞芯微RKNN开发·yolov5
官方预训练模型转换 下载yolov5-v6.0分支源码解压到本地,并配置基础运行环境。下载官方预训练模型 yolov5n.ptyolov5s.ptyolov5m.pt… 进入yolov5-6.0目录下,新建文件夹weights,并将步骤2中下载的权重文件放进去。修改models/yolo.py文件 …...
Flutter之Widget生命周期
目录 初始化构造函数initStatedidChangeDependencies 运行时builddidUpdateWidget 组件移除deactivatedisposereassemble 函数生命周期说明:实际场景App生命周期 前言:生命周期是一个组件加载到卸载的整个周期,熟悉生命周期可以让我们在合适的…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
