Linux 驱动开发基础知识——编写LED驱动程序(三)
个人名片:
🦁作者简介:一名喜欢分享和记录学习的在校大学生
🐯个人主页:妄北y🐧个人QQ:2061314755
🐻个人邮箱:2061314755@qq.com
🦉个人WeChat:Vir2021GKBS
🐼本文由妄北y原创,首发CSDN🎊🎊🎊
🐨座右铭:大多数人想要改造这个世界,但却罕有人想改造自己。
专栏导航:
妄北y系列专栏导航:
C/C++的基础算法:C/C++是一种常用的编程语言,可以用于实现各种算法,这里我们对一些基础算法进行了详细的介绍与分享。🎇🎇🎇
C/C++刷题库:分享一些关于编程的练习基础题,也会后续加入一系列的算法题,分享自己的解题思路和方法。🥰🥰🥰
计算机网络:对计算机网络的基础知识框架有一个简单的学习与认识,对计算机网络中常见的题型进行一个总结与归纳。🍾🍾🍾
QT基础入门学习:对QT的基础图形化页面设计进行了一个简单的学习与认识,利用QT的基础知识进行了翻金币小游戏的制作🤹🤹🤹
Linux基础编程:初步认识什么是Linux,为什么学Linux,安装环境,进行基础命令的学习,入门级的shell编程。🍻🍻🍻
Linux的系统编程+网络编程:IO编程、进程、线程、进程间通讯(包括管道、信号、信号量、共享内存等)网络编程主要就是socket,poll,epoll,以及对TCP/IP的理解,同时要学会高并发式服务器的编写。🙌🙌🙌
Linux应用开发基础开发:分享Linux的基本概念、命令行操作、文件系统、用户和权限管理等,网络编程相关知识,TCP/IP 协议、套接字(Socket)编程等,可以实现网络通信功能。💐💐💐
Linux项目开发:Linux基础知识的实践,做项目是最锻炼能力的一个学习方法,这里我们会学习到一些简单基础的项目开发与应用,而且都是毕业设计级别的哦。🤸🤸🤸
非常期待和您一起在这个小小的互联网世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨
目录:
一、LED 驱动程序编程_基于 IMX6ULL
1.字符设备驱动程序框架
2.驱动怎么操作硬件?
3.驱动怎么和 APP 传输数据?
4.实现什么功能
(1)先编写驱动程序:
(2)再编写测试程序。
二、编写代码:
1.驱动程序led_drv.c
2.应用程序 ledtest.c
3.Makefile
三、上机实验
1.编译
2.挂载到开发板
3.实验效果
文章介绍:
🎉本篇文章对Linux 驱动开发基础知识学习的相关知识进行分享!🥳🥳🥳
如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作动力的源泉,让我们一起加油,一起奔跑,让我们顶峰相见!!!💪💪💪
🎁感谢大家点赞👍收藏⭐评论✍️
一、LED 驱动程序编程_基于 IMX6ULL
1.字符设备驱动程序框架

编写驱动程序的套路:
(1)确定主设备号,也可以让内核分配
(2)定义自己的 file_operations 结构体
(3)实现对应的 drv_open/drv_read/drv_write 等函数,填入 file_operations 结构体
(4)把 file_operations 结构体告诉内核:register_chrdev
(5) 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这 个入口函数。
(6)有入口函数就应该有出口函数:卸载驱动程序时,出口函数调用 unregister_chrdev 其他完善:提供设备信息,自动创建设备节点:class_create,device_create。
2.驱动怎么操作硬件?
通过 ioremap 映射寄存器的物理地址得到虚拟地址,读写虚拟地址。
3.驱动怎么和 APP 传输数据?
通过 copy_to_user、copy_from_user 这 2 个函数。
4.实现什么功能
(1)先编写驱动程序:
实现 led_open 函数,在里面初始化 LED 引脚。
实现 led_write 函数,在里面根据 APP 传来的值控制 LED。
(2)再编写测试程序。
二、编写代码:
1.驱动程序led_drv.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <asm/io.h>static int major;
static struct class *led_class;/* registers */
// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址:0x02290000 + 0x14
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;// GPIO5_GDIR 地址:0x020AC004
static volatile unsigned int *GPIO5_GDIR;//GPIO5_DR 地址:0x020AC000
static volatile unsigned int *GPIO5_DR;static ssize_t led_write(struct file *filp, const char __user *buf,size_t count, loff_t *ppos)
{char val;int ret;/* copy_from_user : get data from app */ret = copy_from_user(&val, buf, 1);/* to set gpio register: out 1/0 */if (val){/* set gpio to let led on */*GPIO5_DR &= ~(1<<3);}else{/* set gpio to let led off */*GPIO5_DR |= (1<<3);}return 1;
}static int led_open(struct inode *inode, struct file *filp)
{/* enable gpio5* configure gpio5_io3 as gpio* configure gpio5_io3 as output */*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;*GPIO5_GDIR |= (1<<3);return 0;
}static struct file_operations led_fops = {.owner = THIS_MODULE,.write = led_write,.open = led_open,
};/* 入口函数 */
static int __init led_init(void)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);major = register_chrdev(0, "100ask_led", &led_fops);/* ioremap */// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址:0x02290000 + 0x14IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290000 + 0x14, 4);// GPIO5_GDIR 地址:0x020AC004GPIO5_GDIR = ioremap(0x020AC004, 4);//GPIO5_DR 地址:0x020AC000GPIO5_DR = ioremap(0x020AC000, 4);led_class = class_create(THIS_MODULE, "myled");device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled"); /* /dev/myled */return 0;
}static void __exit led_exit(void)
{iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);iounmap(GPIO5_GDIR);iounmap(GPIO5_DR);device_destroy(led_class, MKDEV(major, 0));class_destroy(led_class);unregister_chrdev(major, "100ask_led");
}module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
第15行:系统主设备号
第28~49行:为应用程序write提供驱动程序
第35行:从应用程序APP得到数据,读取用户空间传进来的值
把用户空间的数据buf拷贝到&val内核空间,拷贝1个字节
第36~42行:根据数据去设置GPIO的寄存器去输出1/0
第38~48行:根据val判断是将GPIO配置高还是低
第51~63行:为应用程序open提供驱动程序
启动GPIO
配置gpio5 io3为gpio
配置gpio5 io3为输出
第65~69行:定义一个file_operations结构体,里面每个成员是驱动程序的具体功能
第72~92行:入口函数
第74行:监测入口函数是否被执行
__FILE__:文件
__FUNCTION:__函数
__LINE__:第几行
第76行:调用register_chrdev()来注册某个file_operations结构体,获得系统提供的主设备号
第79行:映射虚拟地址
第88~89行:系统为我们创建/dev/myled的设备节点
第88行:根据系统函数提供设备节点
第89行:在这个led_class下创建设备
第94~104行:出口函数
第103行:卸载驱动程序
第100行:销毁掉创建的设备节点/dev/myled
第101行:销毁掉创建的类
第106行:修饰入口函数
第107行:修饰出口函数
第108行:获取指定GPL协议
以上为驱动程序的模板部分,下面我们对IMX6ull的硬件操作进行梳理
使能GPIO5:本身默认使能,所以我们可以忽视这部分的操作
第18~26行:设置GPIO5_3为GPIO:
IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址:0x02290000 + 0x14
第19~26行:定义变量操作寄存器:使用指针操作读写寄存器地址,物理地址,后面需要把物理地址映射成虚拟地址
第19行:第一个寄存器地址,GPIO5_3的地址
第22行:设置GPIO5_GDIR地址用于设置输入输出的方向
第26行:设置GPIO5_DR地址用于设置输入或输出电平
第79~86行:在入口函数里将物理地址映射为虚拟地址
第80行:用ioremap将0x02290000 + 0x14物理地址映射为4个字节虚拟地址
第83行:用ioremap将0x020AC004物理地址映射为4个字节虚拟地址
第86行:用ioremap将0x020AC000物理地址映射为4个字节虚拟地址
第96~98行:在出口函数里清除ioremap的虚拟地址
第53~60行:使用虚拟地址操作寄存器
第57行:清除掉最低的4位,防止其他驱动程序调用
第58行:设置为101,将引脚配置为GPIO
第60行:设置GPI05_3为1,设置为输出的方向
实现点灯操作:将GPI05_3输出低电平
第31行:设置GPI05_3为输出0, 实现点亮led
第46行:设置GPI05_3为输出1,实现关闭led
2.应用程序 ledtest.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>// ledtest /dev/myled on
// ledtest /dev/myled offint main(int argc, char **argv)
{int fd;char status = 0;if (argc != 3){printf("Usage: %s <dev> <on|off>\n", argv[0]);printf(" eg: %s /dev/myled on\n", argv[0]);printf(" eg: %s /dev/myled off\n", argv[0]);return -1;}// openfd = open(argv[1], O_RDWR);if (fd < 0){printf("can not open %s\n", argv[0]);return -1;}// writeif (strcmp(argv[2], "on") == 0){status = 1;}write(fd, &status, 1);return 0;
}
第15行:监测当前状态值,根据 on和off进行判断
第17~23行:当输入不正确时打印用法
第19行:具体用法
第20行:打开led的用法
第21行:关闭led的用法
第23行:打印文件
第26~30行:打开文件失败
第32~36行:打开成功,写入数据
3.Makefile
# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH, 比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
# 请参考各开发板的高级用户使用手册KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88all:make -C $(KERN_DIR) M=`pwd` modules $(CROSS_COMPILE)gcc -o ledtest ledtest.c clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.orderrm -f ledtestobj-m += led_drv.o
第10行:编译时用到的Linux内核路径
第12~19行:编译测试程序
第21行:编译内核程序
三、上机实验
1.编译
编译程序,把代码上传代服务器后执行 make 命令。

2.挂载到开发板
在开发板上挂载 NFS

![]()
最后在开发板上加载驱动程序,执行测试程序,如下:
[root@100ask:~]# echo "7 4 1 7" > /proc/sys/kernel/printk // 打开内核的打印信息,有些
板子默认打开了
[ 1426.505931] /home/book/05_嵌入式Linux驱动开发基础知识/source/02_led_drv/00_led_drv_simple/imx6ull/led_drv.c led_init 75 //安装后打印的信息
[root@100ask:~]# insmod /mnt/led_drv.ko //安装驱动
[root@100ask:~]# lsmod //查询驱动
[root@100ask:~]# rmmod /mnt/led_drv.ko //卸载驱动
/mnt/ledtest /dev/myled on // 点灯
/mnt/ledtest /dev/myled off // 关灯


3.实验效果
点亮的是红灯旁边的黄色灯,照片可能看的效果不是很明显
执行/mnt/ledtest /dev/myled on 这里有一个黄色小灯会亮起来

执行/mnt/ledtest /dev/myled off 这里有一个黄色小灯会熄灭

大佬觉得有用的话点个赞 👍🏻 呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥任务在无形中完成,价值在无形中升华,让我们一起加油吧!🌙🌙🌙
相关文章:
Linux 驱动开发基础知识——编写LED驱动程序(三)
个人名片: 🦁作者简介:一名喜欢分享和记录学习的在校大学生 🐯个人主页:妄北y 🐧个人QQ:2061314755 🐻个人邮箱:2061314755qq.com 🦉个人WeChat:V…...
YOLOv8 视频识别
YOLOv8 是一种目标检测算法,用于识别视频中的物体。要控制视频识别中的帧,可以通过以下方式来实现: 设置帧率:可以通过设置视频的帧率来控制视频的播放速度,从而影响视频识别的速度。 跳帧处理:可以通过跳…...
elementplus Dialog 对话框设置距离页面顶部的距离
默认为 15vh,当弹窗过于高的时候,这个距离其实是不合适的 <el-dialogv-model"dialogVisible"title"Tips"width"30%":before-close"handleClose"top"6vh"><span>This is a message</s…...
便捷接口调测:API 开发工具大比拼 | 开源专题 No.62
hoppscotch/hoppscotch Stars: 56.1k License: MIT Hoppscotch 是一个开源的 API 开发生态系统,主要功能包括发送请求和获取实时响应。该项目具有以下核心优势: 轻量级:采用简约的 UI 设计。快速:实时发送请求并获得响应。支持多…...
openssl3.2/test/certs - 008 - root-nonca trust variants: +serverAuth +anyEKU
文章目录 openssl3.2/test/certs - 008 - root-nonca trust variants: serverAuth anyEKU概述笔记END openssl3.2/test/certs - 008 - root-nonca trust variants: serverAuth anyEKU 概述 openssl3.2 - 官方demo学习 - test - certs 笔记 // \file my_openssl_win_log_doc…...
cg插画设计行业怎么样,如何学习插画设计
插画设计行业是一个充满创意和艺术性的行业,随着数字化时代的不断发展,cg插画的应用范围越来越广泛,市场需求也在逐年增长。以下是一些关于acg插画设计行业的现状和发展趋势: 市场需求不断增长:随着广告、媒体、影视、…...
1.25学习总结
今天学习了二叉树,了解了二叉树的创建和遍历的过程 今天所了解的遍历过程主要分为三种,前序中序和后序,都是DFS的想法 前序遍历:先输出在遍历左节点和右节点(输出->左->右) 中序遍历:先…...
C语言每日一题(48)回文链表
力扣 234 回文链表 题目描述 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。 示例 1: 输入:head [1,2,2,1] 输出:true示例 2࿱…...
提高代码效率的5个Python内存优化技巧
大家好,当项目变得越来越大时,有效地管理计算资源是一个不可避免的需求。Python与C或c等低级语言相比,似乎不够节省内存。 但是其实有许多方法可以显著优化Python程序的内存使用,这些方法可能在实际应用中并没有人注意࿰…...
基于一款热门大屏可视化设计器使用教程
乐吾乐大屏可视化设计器是一个用于创建和定制大屏幕数据可视化展示的工具,支持零代码实现物联网、工业智能制造等领域的可视化大屏、触摸屏端UI以及工控可视化的解决方案。同时也是一个Web组态工具,支持2D、3D等多种形式,用于构建具有实时数据…...
梯度下降法、模拟训练、拟合二次曲线、最小二乘法、MSELoss、拟合:f(x)=ax^2+bx+c
本文目标: 以这个公式为例,设计一个算法,用梯度下降法来模拟训练过程,最终得出参数a,b,c 原理介绍 目标函数: 损失函数:,就是mse 损失函数展开: 损失函数对a,b,c求导数: 导数就是梯度…...
Web3.0投票如何做到公平公正且不泄露个人隐私
在当前的数字时代,社交平台举办投票活动已成为了一种普遍现象。然而,随之而来的是一些隐私和安全方面的顾虑,特别是关于个人信息泄露和电话骚扰的问题。期望建立一个既公平公正又能保护个人隐私的投票系统。Web3.0的出现为实现这一目标提供了…...
灰度图像的自动阈值分割
第一种:Otsu (大津法) 一、基于cv2的API调用 1、代码实现 直接给出相关代码: import cv2 import matplotlib.pylab as pltpath r"D:\Desktop\00aa\1.png" img cv2.imread(path, 0)def main2():ret, thresh1 cv2.…...
利用Maven获取jar包
我有一个习惯,就是程序不在线依赖网络的任何包。以前用C#时候虽然用Nuget找包,但是添加引用后又马上把Nuget引用删了,再把Nuget下载的dll拷贝到工程再引用dll。 这样做的好处是: 1.别人得到程序代码可以直接编译,不用…...
将vue组件发布成npm包
文章目录 前言一、环境准备1.首先最基本的需要安装nodejs,版本推荐 v10 以上,因为需要安装vue-cli2.安装vue-cli 二、初始化项目1.构建项目2.开发组件/加入组件3. 修改配置文件 三、调试1、执行打包命令2、发布本地连接包3、测试项目 四、发布使用1、注册…...
江科大STM32 中
目录 6、TIM(Timer)定时器基本定时器通用定时器高级定时器示例程序(定时器定时中断&定时器外部时钟)TIM输出比较示例程序(PWM驱动LED呼吸灯&PWM驱动舵机&PWM驱动直流电机)TIM输入捕获示例程序&…...
vue+draggable+el-upload上传图片拖拽重排方法
vuedraggableel-upload上传图片拖拽重排方法 1.html <el-row><el-col><el-form-item label"添加视频/图片" prop"device_id"><div class"image-upload"><draggable v-model"fileList" update"dataDr…...
微信的新版canvas绘制的图案发生变形和偏移的问题
一,现象 this.context.beginPath(); this.context.moveTo(10, 10); this.context.lineTo(10, 100); this.context.lineTo(100, 100); this.context.lineTo(100, 10); this.context.lineTo(10, 10); this.context.stroke();本来绘制的是正方形,结果绘制出来是个矩形,边的宽度也…...
[ACM学习] 进制转换
进制的本质 本质是每一位的数位上的数字乘上这一位的权重 将任意进制转换为十进制 原来还很疑惑为什么从高位开始,原来从高位开始的,可以被滚动地乘很多遍。 将十进制转换为任意进制...
redis + 拦截器 :防止数据重复提交
1.项目用到,不是核心 我们干系统开发,不免要考虑一个点,数据的重复提交。 我想我们之前如果要校验数据重复提交要求,会怎么干?会在业务层,对数据库操作,查询数据是否存在,存在就禁止插入数据; 但是吧,我们每次crud操作都会连接…...
SEO_10个简单有效的SEO技巧,快速提升网站排名
SEO:10个简单有效的SEO技巧,快速提升网站排名 在当今互联网时代,网站的排名直接关系到它的流量和盈利能力。SEO(搜索引擎优化)技巧就是为了帮助网站在搜索引擎中获得更高的排名。本文将分享十个简单有效的SEO技巧,帮助…...
Rasa Pro企业级对话AI实战:从安全扫描到密钥管理的完整配置指南
Rasa Pro企业级对话AI实战:从安全扫描到密钥管理的完整配置指南 在金融行业数字化转型浪潮中,智能对话系统已成为客户服务的核心组件。作为Rasa的商业化企业版本,Rasa Pro凭借其专业级的安全防护和可观测性功能,正在成为银行、保险…...
Stable Diffusion XL 1.0艺术表现力:灵感画廊1024x1024超清水墨质感实测
Stable Diffusion XL 1.0艺术表现力:灵感画廊1024x1024超清水墨质感实测 1. 开篇:当AI遇见东方美学 想象一下,你坐在一间安静的书房里,窗外是细雨绵绵,桌面上铺着宣纸,手边是笔墨砚台。你想画一幅水墨山水…...
java毕业设计基于SpringBoot酒店预定系统
前言 Spring Boot酒店预定系统是一种功能丰富、易于维护和扩展的在线预订平台。它通过整合前后端技术,实现了酒店信息的在线展示、预订、支付以及管理等一系列功能,为用户和酒店提供了便捷、高效的预订服务。随着旅游业和酒店业的不断发展,该…...
跨平台实战:Windows与macOS下OpenClaw对接nanobot的差异详解
跨平台实战:Windows与macOS下OpenClaw对接nanobot的差异详解 1. 为什么需要关注跨平台差异 上周我在团队内部推广OpenClaw时,遇到了一个典型问题:同样的nanobot对接流程,在Windows和macOS上执行时出现了完全不同的行为。这让我意…...
创意工作者利器:OpenClaw驱动Qwen3-32B批量生成营销文案
创意工作者利器:OpenClaw驱动Qwen3-32B批量生成营销文案 1. 为什么需要自动化文案生成 作为长期从事数字营销的自由职业者,我每天需要为不同客户产出大量营销文案。传统工作流程中,我需要反复查阅产品文档、手动调整关键词密度、为不同平台…...
收藏!8年传统后端转AI应用开发,2026年实战干货全拆解(小白/程序员必看)
本人做了8年传统后端开发,去年顶着30的年龄焦虑,果断跳出舒适圈,咬牙转型AI应用开发。这一年里,面试被面试官追问到哑口无言、项目落地踩遍各种坑、熬夜调试到凌晨都是常态,但所有付出都有回报:薪资直接上涨…...
LED点阵驱动库LEDMatrix:嵌入式硬件时序控制实战指南
1. LEDMatrix 库概述:面向硬件驱动的二维点阵控制框架LEDMatrix 是一个专为嵌入式系统设计的轻量级 C 语言库,核心目标是将抽象的二维布尔数组(bool matrix[rows][cols])高效、可靠地映射至物理 LED 点阵屏。其设计哲学并非通用图…...
开源项目依赖管理:从冲突解决到高效协作的实践指南
开源项目依赖管理:从冲突解决到高效协作的实践指南 【免费下载链接】IPED IPED Digital Forensic Tool. It is an open source software that can be used to process and analyze digital evidence, often seized at crime scenes by law enforcement or in a corp…...
长尾关键词优化策略对SEO效果的深度解析与实践指导
本文将深入探讨长尾关键词优化策略在搜索引擎优化(SEO)中的重要性与应用。通过分析长尾关键词的独特优势,如低竞争、高转化率,读者将了解到如何发现和利用这些关键词以提升网站流量。同时,文章结合多个实际案例&#x…...


第31行:设置GPI05_3为输出0, 实现点亮led