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

news2025/1/9 10:28:29

模块化驱动启动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:                           // LED1
            vir_led1->ODR |= (0x1 << 10); // LED1开灯
            break;
        case 2:                           // LED2
            vir_led2->ODR |= (0x1 << 10); // LED2开灯
            break;
        case 3:                          // LED3
            vir_led3->ODR |= (0x1 << 8); // LED3开灯
            break;
        case 4:                           // FAN
            vir_fan->ODR |= (0x1 << 9); // FAN开灯
            break;
        case 5:                           // ATO
            vir_ato->ODR |= (0x1 << 6); // ATO开灯
            break;
        case 6:                          // WMM
            vir_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);
    // led1
    vir_led1->MODER &= (~(3 << 20));
    vir_led1->MODER |= (1 << 20);
    vir_led1->ODR &= (~(1 << 10));
    // led2
    vir_led2->MODER &= (~(3 << 20));
    vir_led2->MODER |= (1 << 20);
    vir_led2->ODR &= (~(1 << 10));
    // led3
    vir_led3->MODER &= (~(3 << 16));
    vir_led1->MODER |= (1 << 16);
    vir_led1->ODR &= (~(1 << 8));

    // WMM  B 6
    vir_wmm->MODER &= (~(3 << 12));
    vir_wmm->MODER |= (1 << 12);
    vir_wmm->ODR &= (~(1 << 6));
    // FAM  E 9
    vir_fan->MODER &= (~(3 << 18));
    vir_fan->MODER |= (1 << 18);
    vir_fan->ODR &= (~(1 << 9));
    // ATO  F 6
    vir_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 ?= mycdev

arch ?= arm

ifeq ($(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/
endif


PWD:=$(shell pwd)

all:
	make -C $(KERNELDIR) M=$(PWD) modules

clean:
	make -C $(KERNELDIR) M=$(PWD) clean

obj-m:=$(modname).o



 

 

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

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

相关文章

裂缝二维检测:裂缝类型判断

裂缝类型选择 裂缝类型有很多种&#xff0c;这里我们判断类型的目的是要搞明白是否有必要检测裂缝的长度。在本文中&#xff0c;需要判断的裂缝类型共有四种&#xff1a;横向裂缝、纵向裂缝、斜裂缝、网状裂缝。 环境搭建 上一节骨架图提取部分&#xff0c;我们已经安装了sk…

Linux centos安装openoffice在线预览

前言&#xff1a;由于项目里需要用到word、excel等文件的在线预览&#xff0c;所有选择了openoffice 1、下载openoffice Apache OpenOffice - Official Download 大家自行选择需要安装的版本&#xff0c;楼主由于之前在其他服务器安装过&#xff0c;选择了之前用过的版本&am…

4.Docker数据管理和容器互联

文章目录 Docker数据管理数据卷&#xff08;容器与宿主机之间数据共享&#xff09;数据卷容器&#xff08;容器与容器之间数据共享&#xff09;容器互联 Docker数据管理 数据卷&#xff08;容器与宿主机之间数据共享&#xff09; 数据卷是一个供容器使用的特殊目录&#xff0…

【UE5 多人联机教程】03-创建游戏

效果 步骤 打开“UMG_MainMenu”&#xff0c;增加创建房间按钮的点击事件 添加如下节点 其中&#xff0c;“FUNL Fast Create Widget”是插件自带的函数节点&#xff0c;内容如下&#xff1a; “创建会话”节点指游戏成功创建一个会话后&#xff0c;游戏的其他实例即可发现&am…

mysql -速成

目录 1.概述 1.3SQL的优点 1.4 SQL 语言的分类 2. 软件的安装与启动 2.1 安装 2.2 MySQL服务的启动和停止 2.3 MySQL服务的登录和退出 ​编辑 2.4 mysql常用命令 2.5 图形化用户结构Sqlyong 3.DQL 语言 3.1 基础查询 3.1.1、语法 3.1.2 特点 3.2 条件查询 3.2.1 …

数据库的聚合函数和窗口函数

1. 聚合函数 数据库的聚合函数是用于对数据集执行聚合计算的函数。它们将一组值作为输入&#xff0c;并生成单个聚合值作为输出。聚合函数通常与GROUP BY子句结合使用&#xff0c;以便在数据分组的基础上执行聚合操作。 1.1. 常用的聚合函数 COUNT()&#xff1a;计算指定列或…

(五)springboot实战——springboot自定义事件的发布和订阅

前言 本节内容我们主要介绍一下springboot自定义事件的发布与订阅功能&#xff0c;一些特定应用场景下使用自定义事件发布功能&#xff0c;能大大降低我们代码的耦合性&#xff0c;使得我们应用程序的扩展更加方便。就本身而言&#xff0c;springboot的事件机制是通过观察者设…

Python(三十九)for-in循环

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

JAVA设计模式——模板设计模式(heima)

JAVA设计模式——模板设计模式&#xff08;heima&#xff09; 文章目录 JAVA设计模式——模板设计模式&#xff08;heima&#xff09;一、模板类二、子类2.1 Tom类2.2 Tony类 三、测试类 一、模板类 package _01模板设计模式;public abstract class TextTemplate{public final…

利用FME实现批量提取图斑特征点、关键界址点提取、图斑拐点抽稀,解决出界址点成果表时点数过多问题的方法

目录 一、实现效果 二、实现过程 1.提取图斑界址点 2.计算各界址点的角度 3.筛选提取关键界址点 三、总结 对于范围较大的图斑&#xff0c;界址点数目较大&#xff0c;在出界址点成果表前&#xff0c;往往需要对界址点进行处理&#xff0c;提取出关键特征点作为出界址点成…

数据库集群方案详解

本期直播我们邀请 KaiwuDB 资深解决方案专家周幸骏&#xff0c;为大家分享数据库集群方案详解。周老师毕业于复旦大学数学系&#xff0c;从业 20 余年&#xff0c;曾在 IBM 公司任资深技术专家&#xff0c;并为多家国有大型商业银行提供技术咨询和数据库业务连续方案设计等服务…

IBM:2023 年数据泄露的平均成本将达到 445 万美元

IBM 发布年度《数据泄露成本报告》&#xff0c;显示 2023 年全球数据泄露平均成本达到 445 万美元&#xff0c;比过去 3 年增加了 15%。创下该报告的历史新高。 报告显示&#xff0c;企业在计划如何应对日益增长的数据泄露频率和成本方面存在分歧。研究发现&#xff0c;虽然 95…

Linux学成之路(基础篇)(二十三)MySQL服务(上)

目录 一、概述 一、什么是MySQL 二、数据库能干什么 三、为什么要用数据库&#xff0c;优势、特性&#xff1f; 二、数据库类型 一、关系型数据库 RDBMS 一、概述 二、特点 三、代表产品 二、非关系型数据库 一、概述 二、特点 三、代表产品 三、数据库模型 一、…

【GEE笔记】主成分分析(PCA)算法的实现和应用

前言 主成分分析&#xff08;PCA&#xff09;是一种常用的降维方法&#xff0c;它可以将多个相关的变量转换为少数几个不相关的变量&#xff0c;称为主成分&#xff08;PC&#xff09;。这些主成分可以反映原始变量的大部分信息&#xff0c;同时减少数据的复杂度和冗余性。在遥…

结构型设计模式之组合模式【设计模式系列】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 设计模式系列 期待你的关注哦&#xff01;&#xff01;&#xff01; 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everythi…

【nginx】nginx中root与alias的区别:

文章目录 root与alias主要区别在于nginx如何解释location后面的uri&#xff0c;这会使两者分别以不同的方式将请求映射到服务器文件上。 root的处理结果是&#xff1a;root路径&#xff0b;location路径 alias的处理结果是&#xff1a;使用alias路径替换location路径 alias是一…

前端配置nginx反向代理

1.下载nginx 2.进入nginx.conf 3.配置 4.将nginx放入前端项目根目录 5.启动后端项目和nginx服务 启动命令 start nginx ; 重新启动命令 nginx -s reload 6.访问localhost就能看到项目了&#xff08;默认80端口&#xff09; 注意&#xff1a;如果nginx配置了域名&#xff0…

Android ConstraintLayout使用攻略

原文链接 Android ConstraintLayout使用攻略 ConstraintLayout是新一代的布局&#xff0c;它汲取了众家之长&#xff0c;把布局的概念进行了大统一&#xff0c;灵活且强大&#xff0c;基本上可以干掉以前所有的常用布局&#xff08;LinearLayout, RelativeLayout和FrameLayout…

94.qt qml-分页Table表格组件

在我们之前学习了87.qt qml-分页组件控件(支持设置任意折叠页数等)_qt分页控件_诺谦的博客-CSDN博客 然后我们又学习了Table实现,所以本章实现一个分页Table表格组件,配合分页控件, 模拟请求服务器数据来实现数据分解效果,因为一般使用分页的时候,一般都是分页请求,避免数…

Flutter的开发环境搭建-图解

前言&#xff1a;Flutter作为一个移动应用开发框架&#xff0c;具有许多优点和一些局限性。最大的优点就是-跨平台开发&#xff1a;Flutter可以在iOS和Android等多个平台上进行跨平台开发&#xff0c;使用一套代码编写应用程序&#xff0c;节省开发时间和成本。 Flutter可以编…