Linux驱动学习笔记之蜂鸣器(b站讯为电子)

1、项目描述

使用杂项设备来完成一个蜂鸣器的应用,上层应用发送1来打开蜂鸣器,发送0来关闭蜂鸣器。开发板使用imx6ull。要控制蜂鸣器的逻辑操作,就涉及到了对寄存器的操作,Linux开发不同于单片机或者裸机开发不能直接对硬件寄存器进行操作,需要将物理地址映射为虚拟地址进行操作。

2、涉及到的知识点

(1)杂项设备的概念

(2)杂项设备驱动的写法

(3)对imx6ull开发板蜂鸣器所在物理寄存器的了解,查看开发板手册得到蜂鸣器的数据寄存器地址是GPIO5_DR=0x020AC000

(4)使用MMU,将物理地址映射为虚拟地址

3、驱动代码

(1)蜂鸣器的驱动代码beep.c

#include<linux/init.h>
#include<linux/module.h>
/*注册杂项设备头文件*/ 
#include <linux/miscdevice.h> 
/*注册设备节点的文件结构体*/ 
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#define GPIO5_DR 0x020AC000
unsigned int * vir_gpio5_dr;
int beep_open(struct inode* inode,struct file* file){
     printk("beep_open\n");
     return 0;
}
int beep_release(struct inode* inode,struct file* file){
     printk("beep_release\n");
     return 0;
}
ssize_t beep_read(struct file *file, char __user * ubuf, size_t size, loff_t * loff_t){
     printk("beep_read\n ");
     return 0;
}
ssize_t beep_write(struct file *file, const char __user * ubuf, size_t size, loff_t * loff_t){
	 //上层应用传入参数1为打开蜂鸣器,传入参数0为关闭蜂鸣器
	 char kbuf[64]={0};
     if(copy_from_user(kbuf,ubuf,size)!=0)
     {
        printk("copy_from_user error\n ");
        return -1;
     }
	 if(kbuf[0]==1){
		//打开蜂鸣器,第二位数据置为1(1左移1位为10,与虚拟地址或第二位置为1)
		*vir_gpio5_dr|=(1<<1);

	 }else if(kbuf[0]==0){
		//关闭蜂鸣器,第二位数据置为0
		*vir_gpio5_dr&=~(1<<1);
	 }
     printk("beep_write\n ");
     return 0;
}

struct file_operations misc_fops={
    .owner = THIS_MODULE, //宏,指向当前模块
    .open = beep_open,
    .release = beep_release,
    .read = beep_read,
    .write = beep_write,
   
};
struct miscdevice beep_dev = { 
    .minor = MISC_DYNAMIC_MINOR, //宏,自动分配空闲的次设备号
    .name = "beep", 
    .fops = &misc_fops, 
};
static int beep_init(void){ 
    int ret; 
    ret = misc_register(&beep_dev); 
    //注册杂项设备 
    if(ret<0) 
    { 
    	printk("misc registe is error\n"); 
    } 
    printk("misc registe is succeed\n"); 

	vir_gpio5_dr = ioremap(GPIO5_DR,4);
	if(vir_gpio5_dr == NULL){
		printk("GPIO5_DR Ioremap error\n");
		return -EBUSY;
	}
	printk("GPIO5_DR Ioremap succeed\n");
    return 0; 
} 
static void beep_exit(void){ 
    misc_deregister(&beep_dev); 
	iounmap(vir_gpio5_dr);    
    printk("misc gooodbye! \n"); 
}
module_init(beep_init); 
module_exit(beep_exit); 
MODULE_LICENSE("GPL");

(2)上层应用测试代码app.c

#include <stdio.h>
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
int main(int argc,char const* argv[]){
	int fd;//定义一个句柄 
	char buf[64] = {0}; 
	fd = open("/dev/beep",O_RDWR);//打开设备节点 
	if(fd < 0) 
	{ 
		perror("open error \n"); 
		return fd; 
	} 
	buf[0]=atoi(argv[1]);
	write(fd,buf,sizeof(buf)); 
	close(fd); 
	return 0;
}

(3)Makefile文件

obj-m += beep.o  # 编译驱动模块

KDIR := /home/zyd/topeet/driver/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga
PWD ?= $(shell pwd)   # 获取当前路径
ARCH = arm
CROSS_COMPILE = /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-

# 默认目标,编译内核模块
all: beep.ko app

# 编译内核模块
beep.ko:
	make -C $(KDIR) M=$(PWD) modules ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE)

# 编译应用程序
app: app.c
	$(CROSS_COMPILE)gcc -o app app.c

# 清理目标
clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers *.order app

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值