当前位置: 首页 > news >正文

驱动开发 day3 (模块化驱动启动led,蜂鸣器,风扇,震动马达)

模块化驱动启动led,蜂鸣器,风扇,震动马达并加上Makefile

封装模块化驱动,可自由安装卸载驱动,便于驱动更新(附图)

1.安装模块驱动同时初始化各个设备并使能

2.该驱动会自动创建驱动节点.

3.通过c函数程序输入控制各个设备

4.卸载模块驱动

//编译驱动(注意Makefile的编译到移植到开发板的内核)

        make arch=arm

//安装驱动

        insmod mycdev.ko

//卸载驱动

        rmmod mycdev

//编译fun.c 函数(用到交叉工具编译)

        arm-linux-gnueabihf-gcc fun.c

        

head.h //头文件

#ifndef __HEAD_H__
#define __HEAD_H__typedef struct{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR;
}gpio_t;
#define PHY_LED1_ADDR   0X50006000   //GPIOE 10
#define PHY_LED2_ADDR   0X50007000   //GPIOF 10
#define PHY_LED3_ADDR   0X50006000   //GPIOE 8
#define PHY_RCC_ADDR    0X50000A28   //RCC#define PHY_FAN_ADDR    0X50006000      //GPIOE 9  TIM1  风扇
#define PHY_ATO_ADDR    0X50007000      //GPIOF 6  TIM16 震动马达
#define PHY_WMM_ADDR    0X50003000      //GPIOB 6  TIM4  蜂鸣器//功能码
#define LED_ON _IOW('1',1,int)
#define LED_OFF _IOW('1',0,int)#endif // MACRO

mycmod.c //驱动函数 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include "head.h"unsigned int major;
char kbuf[128] = {0};gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;gpio_t *vir_wmm;
gpio_t *vir_fan;
gpio_t *vir_ato;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;
}long mycdev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{int which;copy_from_user(&which,(void *)arg,4);switch (cmd){case LED_ON:switch (which){case 1:                           // LED1vir_led1->ODR |= (0x1 << 10); // LED1开灯break;case 2:                           // LED2vir_led2->ODR |= (0x1 << 10); // LED2开灯break;case 3:                          // LED3vir_led3->ODR |= (0x1 << 8); // LED3开灯break;case 4:                           // FANvir_fan->ODR |= (0x1 << 9); // FAN开灯break;case 5:                           // ATOvir_ato->ODR |= (0x1 << 6); // ATO开灯break;case 6:                          // WMMvir_wmm->ODR |= (0x1 << 6); // WMM开灯break;}break;case LED_OFF:switch (which){case 1:vir_led1->ODR &= (~(0X1 << 10));break;case 2:vir_led2->ODR &= (~(0X1 << 10));break;case 3:vir_led3->ODR &= (~(0X1 << 8));break;case 4:vir_fan->ODR &= (~(0X1 << 9));break;case 5:vir_ato->ODR &= (~(0X1 << 6));break;case 6:vir_wmm->ODR &= (~(0X1 << 6));break;default:return -1;}default:return -1;}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,.release = mycdev_close,.unlocked_ioctl = mycdev_ioctl,
};int all_led_init(void)
{// 寄存器地址的映射vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));if (vir_led1 == NULL){printk("ioremap filed:%d\n", __LINE__);return -ENOMEM;}vir_led2 = ioremap(PHY_LED2_ADDR, sizeof(gpio_t));if (vir_led2 == NULL){printk("ioremap filed:%d\n", __LINE__);return -ENOMEM;}vir_led3 = vir_led1;vir_fan = vir_led1;vir_ato = vir_led2;vir_wmm = ioremap(PHY_WMM_ADDR, sizeof(gpio_t));if (vir_wmm == NULL){printk("ioremap filed:%d\n", __LINE__);return -ENOMEM;}vir_rcc = ioremap(PHY_RCC_ADDR, 4);if (vir_rcc == NULL){printk("ioremap filed:%d\n", __LINE__);return -ENOMEM;}printk("物理地址映射成功\n");// 寄存器的初始化// rcc(*vir_rcc) |= (3 << 4);(*vir_rcc) |= (1 << 1);// led1vir_led1->MODER &= (~(3 << 20));vir_led1->MODER |= (1 << 20);vir_led1->ODR &= (~(1 << 10));// led2vir_led2->MODER &= (~(3 << 20));vir_led2->MODER |= (1 << 20);vir_led2->ODR &= (~(1 << 10));// led3vir_led3->MODER &= (~(3 << 16));vir_led1->MODER |= (1 << 16);vir_led1->ODR &= (~(1 << 8));// WMM  B 6vir_wmm->MODER &= (~(3 << 12));vir_wmm->MODER |= (1 << 12);vir_wmm->ODR &= (~(1 << 6));// FAM  E 9vir_fan->MODER &= (~(3 << 18));vir_fan->MODER |= (1 << 18);vir_fan->ODR &= (~(1 << 9));// ATO  F 6vir_ato->MODER &= (~(3 << 12));vir_ato->MODER |= (1 << 12);vir_ato->ODR &= (~(1 << 6));printk("寄存器初始化成功\n");return 0;
}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,"myled%d",i);if(IS_ERR(dev)){printk("向上提交设备节点信息失败\n");return -PTR_ERR(dev);}}printk("向上提交设备节点信息成功\n");//寄存器映射以及初始化all_led_init();return 0;}
static void __exit mycdev_exit(void)
{int i;//设备初始化all_led_init();//取消虚拟映射iounmap(vir_led1);iounmap(vir_led2);iounmap(vir_led3);iounmap(vir_rcc);//销毁节点信息for(i = 0; i < 3; i++){device_destroy(cls,MKDEV(major,i));}//销毁目录信息class_destroy(cls);//注销字符设备驱动unregister_chrdev(major,"mycdev");printk("出口函数\n");
}module_init(mycdev_init);module_exit(mycdev_exit);MODULE_LICENSE("GPL");

fun.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <string.h>
#include "head.h"int main(int argc, char const *argv[])
{/* code */int a,b;char buf[128] = {0};printf("调用open\n");int fd = open ("/dev/myled0",O_RDWR);if(fd < 0){printf("打开设备文件失败\n");exit(-1);}while(1){//从终端读取printf("请输入指令\n");printf("0(关) 1(开)\n");printf("请输入>");scanf("%d",&a);if(a){printf("打开以下设备\n");}else{printf("关闭以下设备\n");}printf(" 1(LED1) 2(LED2) 3(LED3)\n");printf(" 4(FAN)  5(ATO)  6(WMM)\n");printf("请输入要控制的设备:");scanf("%d",&b);switch(a){case 1:ioctl(fd,LED_ON,&b);//开灯break;case 0:ioctl(fd,LED_OFF,&b);break;}}printf("调用close\n");close (fd);   return 0;
}

Makefile

modname ?= mycdevarch ?= armifeq ($(arch),arm)
KERNELDIR:= /home/ubuntu/13_UBOOT/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build/
endifPWD:=$(shell pwd)all:make -C $(KERNELDIR) M=$(PWD) modulesclean:make -C $(KERNELDIR) M=$(PWD) cleanobj-m:=$(modname).o

 

 

相关文章:

驱动开发 day3 (模块化驱动启动led,蜂鸣器,风扇,震动马达)

模块化驱动启动led,蜂鸣器,风扇,震动马达并加上Makefile 封装模块化驱动&#xff0c;可自由安装卸载驱动&#xff0c;便于驱动更新(附图) 1.安装模块驱动同时初始化各个设备并使能 2.该驱动会自动创建驱动节点. 3.通过c函数程序输入控制各个设备 4.卸载模块驱动 //编译驱动…...

数据结构与算法基础-学习-27-图之最短路径之Dijkstra(迪杰斯特拉)算法

一、最短路径应用案例 例如从北京到上海旅游&#xff0c;有多条路可以到目的地&#xff0c;哪条路线最短&#xff0c;哪条路线最省钱&#xff0c;就是典型的最短路径问题。 二、最短路径问题分类 最短路径问题可以分为两类&#xff0c;第一类为&#xff1a;两点间最短路径。第…...

Windows Server 2012 能使用的playwright版本

由于在harkua_bot里面使用到了playwright&#xff0c;我的服务器又是Windows Server 2012 R2&#xff0c;最新版playwright不支持Windows Server 2012 R2&#xff0c;支持Windows Server 2016以上&#xff0c;所以有了这个需求 https://cdn.npmmirror.com/binaries/playwright…...

css实现溢出变为省略号

单行文本溢出省略 text-overflow&#xff1a;规定当文本溢出时&#xff0c;显示省略符号来代表被修剪的文本 white-space&#xff1a;设置文字在一行显示&#xff0c;不能换行 overflow&#xff1a;文字长度超出限定宽度&#xff0c;则隐藏超出的内容overflow设为hidden&#…...

nginx如何配置两个服务器的连接

nginx 中通过server_name listen的方式配置多个服务器 nginx配置两个站点的windows操作方法&#xff0c;双域名双站点...

Linux环境Arduino IDE中配置ATOM S3

linux选择ubuntu发行版。 硬件设备有多小呢&#xff1a; 功能超级强大。 之前的ROS1和ROS2案例已经全部移植完成并测试结束&#xff08;三轮纯人力校验&#x1f60e;&#xff09;。 官网文档信息非常非常好&#xff1a; https://docs.m5stack.com/zh_CN/quick_start/atoms3…...

【C#】.Net Framework框架下的Authorize权限类

2023年&#xff0c;第31周&#xff0c;第3篇文章。给自己一个目标&#xff0c;然后坚持总会有收货&#xff0c;不信你试试&#xff01; 在C#的.NET Framework中&#xff0c;你可以使用Authorize类来处理权限认证。Authorize类位于System.Web.Mvc命名空间中&#xff0c;它提供了…...

C++ list底层实现原理

文章目录 一、list底层实现二、类构成三、构造函数四、迭代器五、获取第一个元素六、获取最后一个元素七、插入元素 一句话&#xff1a;list底层实现一个双向循环链表 一、list底层实现 一个双向循环链表 二、类构成 class list : protected_List_base_list_base.lsit_impl…...

C#实现数字验证码

开发环境&#xff1a;VS2019&#xff0c;.NET Core 3.1&#xff0c;ASP.NET Core API 1、建立一个验证码控制器 新建两个方法Create和Check&#xff0c;Create用于创建验证码&#xff0c;Check用于验证它是否有效。 声明一个静态类变量存放列表&#xff0c;列表中存放包含令…...

Git的常用命令以及使用场景

文章目录 1.前言2.工作区,暂存区,版本库简介3.Git的常用命令4.版本回退5.撤销修改6.删除文件7.总结 1.前言 在学习Git命令之前,需要先了解工作区,暂存区和版本库这三个概念 2.工作区,暂存区,版本库简介 在使用Git进行版本控制时&#xff0c;有三个重要的概念&#xff1a;工作…...

tcp keepalive

tcp keepalive用于检查两者之间的链路是否正常&#xff0c;或防止链路断开。 一旦建立了TCP连接&#xff0c;该连接被定义为有效&#xff0c;直到一方关闭它。一旦连接进入连接状态&#xff0c;它将无限期地保持连接状态。但实际上&#xff0c;这种联系不会无限期地持续下去。如…...

PP-Matting: AI高精度图像前景Matting,让抠图轻而易举

分割和Matting的一个重要区别是:分割返回的是像素分类标签,其结果是整型数据;而Matting返回的是属于前景或背景的概率P,从而在前景与背景交互区域产生渐变的效果,使得抠图更加自然。Matting分割模型训练完成后,对于原始图像每个位置上的像素,都将生成一个表示其前景透明…...

VUE3-01

1.选项式和组合式 选项式API&#xff1a;按照作用组织代码 组合式API&#xff1a;按照功能组织代码 2.<script setup> <template><div class"about"><h1>{{name}}</h1><button click"sayHello">测试</button>…...

分库分表之基于Shardingjdbc+docker+mysql主从架构实现读写分离(二)

说明&#xff1a;如果实现了docker部署mysql并完成主从复制的话再继续&#xff0c;本篇文章主要说明springboot配置实现Shardingjdbc进行读写分离操作。 如果没实现docker部署mysql实现主从架构的话点击我 Shardingjdbc配置介绍&#xff08;版本&#xff1a;5.3.2&#xff09;…...

Python 进阶(四):日期和时间(time、datetime、calendar 模块)

❤️ 博客主页&#xff1a;水滴技术 &#x1f338; 订阅专栏&#xff1a;Python 入门核心技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; 文章目录 1. time模块1.1 获取当前时间1.2 时间休眠1.3 格式化时间 2. datetime模块2.1 获取当前…...

Transformer背景介绍

目录 Transformer的诞生Transformer的优势Transformer的市场 Transformer的诞生 论文地址 Transformer的优势 Transformer的市场...

深入理解BeanDefinition和Spring Beans

深入理解BeanDefinition和Spring Beans 引言 在Spring框架中&#xff0c;BeanDefinition和Spring Beans是非常重要的概念。BeanDefinition定义了Spring Bean的元数据&#xff0c;而Spring Beans是应用程序中的对象实例。理解BeanDefinition和Spring Beans的概念和使用方法对于…...

实验六 调度器-实验部分

目录 一、知识点 1.进程调度器设计的目标 1.1.进程的生命周期 1.2.用户进程创建与内核进程创建 1.3.进程调度器的设计目标 2.ucore 调度器框架 2.1.调度初始化 2.2.调度过程 2.2.1.调度整体流程 2.2.2.设计考虑要点 2.2.3.数据结构 2.2.4.调度框架应与调度算法无关…...

基于飞桨paddle波士顿房价预测练习模型测试代码

基于飞桨paddle波士顿房价预测练习模型测试代码 导入基础库 #paddle&#xff1a;飞桨的主库&#xff0c;paddle 根目录下保留了常用API的别名&#xff0c;当前包括&#xff1a;paddle.tensor、paddle.framework、paddle.device目录下的所有API&#xff1b; import paddle #Lin…...

只会“点点点”,凭什么让开发看的起你?

众所周知&#xff0c;如今无论是大厂还是中小厂&#xff0c;自动化测试基本是标配了&#xff0c;毕竟像双 11、618 这种活动中庞大繁杂的系统&#xff0c;以及多端发布、多版本、机型发布等需求&#xff0c;但只会“写一些自动化脚本”很难胜任。这一点在招聘要求中就能看出来。…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代&#xff0c;海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构&#xff0c;在处理大规模数据抓取任务时展现出强大的能力。然而&#xff0c;随着业务规模的不断扩大和数据抓取需求的日益复杂&#xff0c;传统…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...