驱动 控制开发版3盏灯、蜂鸣器、风扇、马达

news2024/11/24 18:52:24

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;
//查看开发扩展板原理图可知
//蜂鸣器 PB6
//风扇 PE9
//马达 PF6
//LED1 PE10
//LED2 PF10
//LED3 PE8
#define PHY_BEE_ADDR 0X50003000
#define PHY_LED1_ADDR 0X50006000
#define PHY_LED2_ADDR 0X50007000
#define PHY_LED3_ADDR 0X50006000
#define PHY_RCC_ADDR  0X50000A28
#define LED_ON _IOW('l',1,int)  //开灯
#define LED_OFF _IOW('l',0,int)//关灯
#define BEE_ON _IOW('l',3,int)  //打开蜂鸣器
#define BEE_OFF _IOW('l',2,int)//关闭蜂鸣器
#define FAN_ON _IOW('l',5,int) //开风扇 
#define FAN_OFF _IOW('l',4,int)//关风扇
#define MOTOR_ON _IOW('l',7,int)//开马达 
#define MOTOR_OFF _IOW('l',6,int)//关马达
#endif 

test.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"

int main(int argc, char const *argv[])
{
	int a,b;
    char buf[128] = {0};
    int fd = open("/dev/mychrdev0", O_RDWR);
    if (fd < 0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    while (1)
    {   
		//从终端读取
		printf("请选择要实现的功能\n");
        printf("1(打开) 0(关闭)\n");
		scanf("%d",&a);
		printf("请输入要控制的部件\n");
		printf("1(LED1)2(LED2)3(LED3)4(BEE)5(FAN)6(MOTOR)\n");
		getchar();
		scanf("%d",&b);
		getchar();
		if(a==1)//打开
        {
			switch(b)
			{
			case 1://LED1
            ioctl(fd,LED_ON,&b);break;
			case 2://LED2
            ioctl(fd,LED_ON,&b);break;
			case 3://LED3
            ioctl(fd,LED_ON,&b);break;
			case 4://BEE
            ioctl(fd,BEE_ON,&b);break;
			case 5://FAN
            ioctl(fd,FAN_ON,&b);break;
			case 6://MOTOR
            ioctl(fd,MOTOR_ON,&b);break;
			}
        }
        else if(a==0)//关闭
        {
       		switch(b)
			{
			case 1://LED1
            ioctl(fd,LED_OFF,&b);break;
			case 2://LED2
            ioctl(fd,LED_OFF,&b);break;
			case 3://LED3
            ioctl(fd,LED_OFF,&b);break;
			case 4://BEE
            ioctl(fd,BEE_OFF,&b);break;
			case 5://FAN
            ioctl(fd,FAN_OFF,&b);break;
			case 6://MOTOR
            ioctl(fd,MOTOR_OFF,&b);break;
			}		
		}
    }
    close(fd);
    return 0;
}

mychrdev.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include "head.h"
int all_led_init(void);

struct class *cls;//用于保存目录信息
struct device *dev;//用于保存设备节点信息
int major; // 用于保存主设备号
char kbuf[128]={0};
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
gpio_t *vir_bee;
gpio_t *vir_fan;
gpio_t *vir_motor;
unsigned int *vir_rcc;

// 封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
int mycdev_close(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;
	//通过拷贝函数获取ioctl第三个参数对应空间的数值
	int ret=copy_from_user(&which,(void *)arg,4);
	if(ret)
	{
		printk("拷贝用户空间数据失败\n");
		return -EIO;
	}
	//进行功能控制
	switch (cmd)
	{
		case LED_ON: // 开灯
			switch (which)
			{
			case 1: // LED1
				vir_led1->ODR |= (0x1 << 10);
				break;
			case 2: // LED2
				vir_led2->ODR |= (0x1 << 10);
				break;
			case 3: // LED3
				vir_led3->ODR |= (0x1 << 8);
				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;
			}
		break;
		case BEE_ON:
			vir_bee->ODR |= (1<<6);break;
		case FAN_ON:
			vir_fan->ODR |= (1<<9);break;
		case MOTOR_ON:
			vir_motor->ODR |= (1<<6);break;
		case BEE_OFF:
			vir_bee->ODR &=(~(1<<6));break;
		case FAN_OFF:
			vir_fan->ODR &=(~(1<<9));break;
		case MOTOR_OFF:
			vir_motor->ODR &=(~(1<<6));break;
	}
	
    return 0;
}
//定义操作方法结构体变量并赋值
struct file_operations fops =
{
	.open = mycdev_open,
    .unlocked_ioctl = mycdev_ioctl,
	.release = mycdev_close,
};

static int __init mycdev_init(void)
{
	int i;
    //字符设备驱动注册
	major = register_chrdev(0, "mychrdev", &fops);
	if(major < 0)
	{
		printk("字符设备驱动注册失败\n");
		return major;
	}
	printk("字符设备驱动注册成功major=%d\n", major);
	//向上提交目录
	cls=class_create(THIS_MODULE,"mychrdev");
	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,"mychrdev%d",i);
		if(IS_ERR(dev))
		{
			printk("向上提交设备节点信息失败\n");
			return -PTR_ERR(dev);
		}
	}		
	//为蜂鸣器创建设备文件
	dev=device_create(cls,NULL,MKDEV(major,3),NULL,"mychrdev_BEE");
	if(IS_ERR(dev))
	{
		printk("向上提交设备节点信息失败\n");
		return -PTR_ERR(dev);
	}
	//为风扇创建设备文件
	dev=device_create(cls,NULL,MKDEV(major,4),NULL,"mychrdev_FAN");
	if(IS_ERR(dev))
	{
		printk("向上提交设备节点信息失败\n");
		return -PTR_ERR(dev);
	}	
	//为马达创建设备信息
	dev=device_create(cls,NULL,MKDEV(major,5),NULL,"mychrdev_MOTOR");
	if(IS_ERR(dev))
	{
		printk("向上提交设备节点信息失败\n");
		return -PTR_ERR(dev);
	}
	printk("向上提交设备节点信息成功\n");
	//映射物理寄存器
	//寄存器映射以及初始化
	all_led_init();
	return 0;
}
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_rcc=ioremap(PHY_RCC_ADDR,4);
	if(vir_rcc==NULL){
		printk("ioremap filed:%d\n",__LINE__);
		return -ENOMEM;
	}
	vir_bee=ioremap(PHY_BEE_ADDR,sizeof(gpio_t));
	if(vir_bee==NULL)
	{
		printk("ioremap filed:%d\n",__LINE__);
		return -ENOMEM;
	}
	vir_fan=vir_led1;
	vir_motor=vir_led2;
	printk("物理地址映射成功\n");
	//寄存器的初始化
	//rcc
	(*vir_rcc) |= (1<<1);
	(*vir_rcc) |= (3<<4);
	//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));
	//BEE
	vir_bee->MODER &=(~(3<<12));
	vir_bee->MODER |= (1<<12);
	vir_bee->ODR &= (~(1<<6));
	//FAN
	vir_fan->MODER &=(~(3<<18));
	vir_fan->MODER |=(1<<18);
	vir_fan->ODR &=(~(1<<9));
	//MOTOR
	vir_motor->MODER &= (~(3<<12));
	vir_motor->MODER |= (1<<12);
	vir_motor->ODR &=(~(1<<6));
	printk("寄存器初始化成功\n");
	return 0;
}
static void __exit mycdev_exit(void)
{
	int i;
    //取消地址映射
    iounmap(vir_led1);
	iounmap(vir_led2);
	iounmap(vir_rcc); 
	iounmap(vir_bee);
	//销毁设备节点信息
	for(i=0;i<6;i++)
	{
		device_destroy(cls,MKDEV(major,i));
	}
	//销毁目录信息
	class_destroy(cls);
	//字符设备驱动的注销
	unregister_chrdev(major,"mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

Makefile

arch?=arm
modname?=demo
#指定内核顶层目录的路径
ifeq ($(arch),arm)
	KERNELDIR:=/home/ubuntu/FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61  #编译为ARM架构的内核路径
else
	KERNELDIR:=/lib/modules/$(shell uname -r)/build   #编译生成x86架构文件的内核路径
endif
#指定当前源码所在的路径
PWD:=$(shell pwd)  #将shell命令pwd的执行结果赋值给变量PWD
#指定使用的符号表文件的路径
KBUILD_EXTRA_SYMBOLS +=/home/ubuntu/23031_driver/day2/1/Module.symvers
all:
	#make modules表示进行模块化编译
	#make -C $(KERNELDIR)先切换路径到KERNELDIR下,按照这个路径下Makefile的规则进行make
	#M=$(PWD)指定模块化编译的路径
	make -C $(KERNELDIR) M=$(PWD) modules
clean:
	#编译清除
	make -C $(KERNELDIR) M=$(PWD) clean
	#将指定的.o文件独立链接为模块文件
obj-m:=$(modname).o

在这里插入图片描述
在这后面分别输入01 02 03 04 05 06分别关闭了6个设备
输入11 12 13后的现象
在这里插入图片描述
输入11后的现象
在这里插入图片描述
分别输入01 02 03 04 05 06后的现象
在这里插入图片描述
输入11 12后的现象
在这里插入图片描述
输入14 15 16后的现象
在这里插入图片描述

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

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

相关文章

商用车线控底盘需求文档

一、 概述 商用车线控底盘主要用于接收智能驾驶域控制器&#xff08;控制器ADU&#xff09;的请求指令&#xff0c;完成ADU 对驱动、制动、档位转向、驻车声光等部分的指令控制&#xff0c;从而实现智能驾驶功。 即 ADU 可通过 CAN 通讯的方式以特定周期和指令控制 一台车的线控…

驱动开发作业2 —— ioctl

通过ioctl函数选择不同硬件的控制&#xff0c;如实现对LED、蜂鸣器、马达、风扇的控制 1.将GPIO的相关寄存器封装成结构体 --------> gpio.h 2.LED相关驱动文件 --------> led.c 3.蜂鸣器相关驱动文件 --------> beep.c 4.风扇相关驱动文件 --------> fan.c 5.马…

Ubuntu/Debian等Linux系统安装微信客户端

【写在前面】 由于本人的工作环境基本是在ubuntu下&#xff0c;而ubuntu使用网页版微信常常会出现无法登陆的现象&#xff0c;为了能够在linux系统用上微信&#xff0c;于是在网上找了找办法&#xff0c;没想到还真有大神做了&#xff0c;特此分享出来。 【安装步骤】 其实只…

UNIX网络编程卷一 学习笔记 第二十二章 高级UDP套接字编程

TCP是一个字节流协议&#xff0c;又使用滑动窗口&#xff0c;因此没有记录边界或发送者数据发送能力超过接收者接受能力之类的事情&#xff0c;但对于UDP&#xff0c;每个输入操作对应一个UDP数据报&#xff08;一个记录&#xff09;&#xff0c;因此当收取的数据报大于引用的输…

软件测试--Fiddler的使用(持续更新)

1.工具界面介绍 2.抓取请求 打开Fiddler,随便访问一些网址,左边便会抓取到很多请求 3.删除请求(Remove all或者输入命令) 4.过滤请求 ps: 5.打开抓HTTPS设置 6.界面熟悉 7.抓包图标说明

MPC vs Multi-sig——误解及重点关注

1. 引言 资金托管的2大主流方案为&#xff1a; MPC&#xff1a;MPC钱包——对应EOA账号。用于高信任企业场景。Multi-sig&#xff1a;多签钱包——对应智能合约钱包。用于个人场景&#xff0c;可强化安全性并易于恢复。 不过V神认为&#xff0c;基于MPC的EOA账号存在根本性缺…

不变的誓言 字符串常量

## 不变的誓言 字符串常量字符串常量&#xff0c;这节课的主题、 水帘洞一直都没有变1.什么是字符串呢&#xff1f; 就是一个一个字符连起来就是字符串&#xff0c;qq聊天 都是字符串。 字符串常量&#xff0c;“”1.什么是字符串呢&#xff1f; 就是一个一个字符连起来就是字…

sqlserver收缩数据库

1.收缩数据库 首先收缩的前提是需要有可用空间如下图&#xff0c;没有可用空间无法收缩数据库 2.减小数据库大小 通过链接: 查询数据库中各表的大小 如果查询的比较大而且无用的数据可以直接把表结构给拿出来&#xff0c;然后删除该表空间就直接释放出来了 3.收缩文件 我…

SpringBoot项目打包部署后页面无法访问问题定位处理记录

问题描述 项目在idea中可以正常访问&#xff0c;但是达成jar包后访问时候访问异常&#xff0c;并报错&#xff0c;部分异常栈如下: org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/views/login], template might not exist or might not be a…

插入排序(直接插入排序 折半插入排序)

直接插入排序 void InsertSort(ElemType A[],int n) {int i,j;for(i2;i<n;i)if(A[i]<A[i-1]){A[0]A[i];for(ji-1;A[0]<A[j];--j)A[j1]A[j];A[j1]A[0];} }折半插入排序 void BinInsertSort(int A[],int n) {int i,j,low,high,mid;for(i2;i<n;i){A[0]A[i];low1;high…

【MySQL】基本查询之表的增删改查

【MySQL】表的增删改查 一、插入操作----insert1.1 简单插入1.2 插入时是否更新----ON DUPLICATE KEY UPDATE1.3 插入时替换----REPLACE 二、查询----select2.1 简单查询与去重2.2 基本查询----where条件2.2.3 案列演示 2.4 排序----order by 三、修改操作----update四、删除--…

产品经理有效管理项目进度的5个关键方法

作为产品经理&#xff0c;管理项目进度是确保产品开发成功的关键组成部分。产品经理负责推动产品开发过程&#xff0c;并确保团队在最后期限前完成并保持在正轨上。以下是产品经理有效管理项目进度的一些关键方法。 1、创建详细的项目进度表 这个时间表应该包括开发过程的所有任…

java业务开发经典常见错误例子

java业务开发经典常见错误例子 文章目录 java业务开发经典常见错误例子1.ThreadLocal线程重用导致用户信息错乱的 Bug2.使用了线程安全的并发工具&#xff0c;并不代表解决了所有线程安全问题3.没有认清并发工具的使用场景&#xff0c;导致性能问题4.加锁前要清楚锁和被保护的对…

DM8:达梦数据库数据文件与日志文件介绍

DM8:达梦数据库数据文件与日志文件介绍 环境介绍1 表空间中的数据文件1.1 表空间1.2 数据文件1.3 系统自带的表空间1.3.1 SYSTEM 表空间1.3.2 ROLL 表空间1.3.3 TEMP 表空间1.3.4 MAIN 表空间1.3.5 用户自定义表空间1.3.6 DM数据库的表空间和数据文件分布 2 日志文件2.1 重做日…

Redis 数据库的概念、常用命令

Redis数据库 一、关系数据库与非关系型数据库概述1、关系型数据库2、非关系型数据库3、关系数据库与非关系型数据库区别&#xff08;1&#xff09;数据存储方式不同&#xff08;2&#xff09;扩展方式不同&#xff08;3&#xff09;对事务性的支持不同 4、非关系型数据库产生背…

【数据结构课程设计系列】完全二叉树操作演示

完全二叉数操作演示 1.完全二叉树操作演示要求&#xff1a; &#xff08;1&#xff09;创建完全二叉树(用顺序方式存储) &#xff08;2&#xff09;求二叉树的深度和叶子结点数 &#xff08;3&#xff09;实现二叉树的前序、中序、后序和层次遍历。 &#xff08;4&#xff09;…

基于ubuntu的驱动开发

一般的linux驱动开发都是基于交叉编译来进行的&#xff0c;本文尝试着从另一个角度&#xff1a;基于ubuntu的本地驱动开发来学习一下驱动的开发 一、驱动的开发与编译 1.1、编写驱动文件 #include <linux/init.h> #include <linux/module.h> static int hello_i…

FL Studio中文版21最新免费音乐编曲软件制作工具

FL Studio较为适合专业的音乐制作者&#xff0c;操作难度较大&#xff0c;学习门槛也较高&#xff1b;Studio One则主打一站式的音乐制作&#xff0c;从编曲到录音到后期的专辑制作都可以在其中实现&#xff0c;同时操作难度不大&#xff0c;对初学者和业余爱好者都较为友好。 …

【NX】NX二次开发中自动选择当前实体和方向

在NX的二次开发中&#xff0c;我们经常需要选择实体和方向&#xff0c;如果每次手动选择&#xff0c;势必会影响调试的效率&#xff0c;那么有没有办法&#xff0c;让程序一启动就自动选择当前实体和方向呢&#xff0c;自然是有的。 经过我一番研究&#xff0c;因为可能有多个实…

Apikit 自学日记:团队管理

团队管理 一、工作空间管理 工作空间类似于部门或公司的概念&#xff0c;能帮助您更好地管理团队。 1.1 创建空间 点击页面左上角功能菜单&#xff0c;在下拉菜单中选择要切换的工作空间。 点击创建/加入&#xff0c;在引导页面中选择创建工作空间&#xff0c;填写工作空间…