Linux 蜂鸣器驱动实验

news2024/12/23 19:31:03

蜂鸣器驱动原理

①、在设备树中添加 SNVS_TAMPER1 引脚的 pinctrl 信息。

②、在设备树中创建蜂鸣器节点,在蜂鸣器节点中加入 GPIO 信息。

1、修改设备树文件


  • 添加 pinctrl 节点

I.MX6U-ALPHA开发板上的BEEP使用了SNVS_TAMPER1这个PIN,打开imx6ull-alientekemmc.dts,在 iomuxc 节点的 imx6ul-evk 子节点下创建一个名为“pinctrl_beep”的子节点,节点 内容如下所示:

 

  • 添加 BEEP 设备节点

在根节点“/”下创建 BEEP 节点,节点名为“beep”,节点内容如下:

beep {
     #address-cells = <1>;
     #size-cells = <1>;
     compatible = "atkalpha-beep";
     pinctrl-names = "default";
     pinctrl-0 = <&pinctrl_beep>;
     beep-gpio = <&gpio5 1 GPIO_ACTIVE_HIGH>;
     status = "okay";
 };

第 6 行,pinctrl-0 属性设置蜂鸣器所使用的 PIN 对应的 pinctrl 节点。

第 7 行,beep-gpio 属性指定了蜂鸣器所使用的 GPIO。

  • 检查 PIN 是否被其他外设使用

中蜂鸣器使用的 PIN 为 SNVS_TAMPER1,因此先检查 PIN 为 SNVS_TAMPER1 这个 PIN 有没有被其他的 pinctrl 节点使用,如果有使用的话就要屏蔽掉,然后再检查 GPIO5_IO01 这个 GPIO 有没有被其他外设使用,如果有的话也要屏蔽掉。

设备树编写完成以后使用“make dtbs”命令重新编译设备树,然后使用新编译出来的 imx6ull-alientek-emmc.dtb 文件启动 Linux 系统。启动成功以后进入“/proc/device-tree”目录中 查看“beep”节点是否存在,如果存在的话就说明设备树基本修改成功

蜂鸣器驱动程序编写

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>


#define BEEP_CNT		1		  	/* 设备号个数 */
#define BEEP_NAME	 "beep"	/* 名字 */

#define BEEPOFF   0  //关闭
#define BEEPON    1 //打开

/* gpiobeep设备结构体 */
struct beep_dev{
	dev_t devid;			/* 设备号 	 */
	struct cdev cdev;		/* cdev 	*/
	struct class *class;	/* 类 		*/
	struct device *device;	/* 设备 	 */
	int major;				/* 主设备号	  */
	int minor;				/* 次设备号   */
	struct device_node	*nd; /* 设备节点 */
	int beep_gpio;
	
};

struct beep_dev beep;	/* beep设备 */


static int beep_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &beep; /* 设置私有数据 */
	return 0;
}


static ssize_t beep_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{	

	return 0;
}


static ssize_t beep_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	int retval = 0;
	unsigned char databuf[1];
	unsigned char beepstat;
	struct beep_dev *dev = filp->private_data;

	retval = copy_from_user(databuf,buf,cnt);
	if(retval < 0)
	{
		printk("kernel write failed!\r\n");
		return -EFAULT;
	}

	beepstat = databuf[0];
	if(beepstat == BEEPON)
	{
		gpio_set_value(dev->beep_gpio,0);   //打开蜂鸣器	
	}else if (beepstat == BEEPOFF)
	{
		gpio_set_value(dev->beep_gpio,1);  //关闭蜂鸣器
	}

	return 0;
}


static int beep_release(struct inode *inode, struct file *filp)
{
	return 0;
}

/* 设备操作函数 */
static struct file_operations beep_fops = {
	.owner = THIS_MODULE,
	.open = beep_open,
	.read = beep_read,
	.write = beep_write,
	.release = 	beep_release,
};

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static int __init beep_init(void)
{
	int ret = 0;
	/* 注册字符设备驱动 */
	/* 1、创建设备号 */
	if (beep.major) {		/*  定义了设备号 */
		beep.devid = MKDEV(beep.major, 0);
		register_chrdev_region(beep.devid, BEEP_CNT, BEEP_NAME);
	} else {						/* 没有定义设备号 */
		alloc_chrdev_region(&beep.devid, 0, BEEP_CNT, BEEP_NAME);	/* 申请设备号 */
		beep.major = MAJOR(beep.devid);	/* 获取分配号的主设备号 */
		beep.minor = MINOR(beep.devid);	/* 获取分配号的次设备号 */
	}
	printk("gpiobeep major=%d,minor=%d\r\n",beep.major, beep.minor);	
	
	/* 2、初始化cdev */
	beep.cdev.owner = THIS_MODULE;
	cdev_init(&beep.cdev, &beep_fops);
	
	/* 3、添加一个cdev */
	cdev_add(&beep.cdev, beep.devid, BEEP_CNT);

	/* 4、创建类 */
	beep.class = class_create(THIS_MODULE, BEEP_NAME);
	if (IS_ERR(beep.class)) {
		return PTR_ERR(beep.class);
	}

	/* 5、创建设备 */
	beep.device = device_create(beep.class, NULL, beep.devid, NULL, BEEP_NAME);
	if (IS_ERR(beep.device)) {
		return PTR_ERR(beep.device);
	}

	/*初始化beep*/
	/*获取设备节点:beep*/
	beep.nd = of_find_node_by_path("/beep");
	if(beep.nd == NULL)
	{
		printk("beep node not find!\r\n");
		return -EINVAL;
	}else
	{
		printk("beep node find!\r\n");
	}

	/*获取设备树中的gpio属性,得到BEEP所使用的beep编号*/
	beep.beep_gpio  = of_get_named_gpio(beep.nd,"beep-gpio",0);
	if(beep.beep_gpio < 0)
	{
		printk("can not get beep-gpio\n");
		return -EINVAL;
	}
	
	printk("led-gpio num = %d\r\n",beep.beep_gpio);

	/*设置GPIO5_IO01为输出,并且输出高电平,默认关闭BEEP*/
	ret = gpio_direction_output(beep.beep_gpio,1);
	if (ret < 0)
	{
		printk("cant set gpio!\r\n");
	}
	

	return 0;
}

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static void __exit beep_exit(void)
{
	/* 注销字符设备驱动 */
	cdev_del(&beep.cdev);/*  删除cdev */
	unregister_chrdev_region(beep.devid, BEEP_CNT); /* 注销设备号 */

	device_destroy(beep.class, beep.devid);
	class_destroy(beep.class);
}

module_init(beep_init);
module_exit(beep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hsj");

 

编写测试 APP

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#define LEDOFF 0 
#define LEDON  1

int main(int argc,char *argv[])
{
   int fd,retvalue;
   char *filename;
   unsigned char databuf[1];

   if(argc != 3)
   {
       printf("error usage!\r\n");
       return -1;
   }

   filename = argv[1];
   fd = open(filename,O_RDWR);
   if(fd < 0)
   {
      printf("open failed\r\n");
      return -1;
   }
   
   databuf[0] = atoi(argv[2]);   //将字符转换为数字
   retvalue = write(fd,databuf,1);
   if (retvalue < 0)
    {
      printf("LED Control failed!\r\n");
      close(fd);
      return -1;   
    }


    close(fd);
    return 0;
}

运行测试

depmod       //第一次加载驱动的时候需要运行此命令

modprobe beep.ko   //加载驱动

./beepApp /dev/beep 1   //打开蜂鸣器

/beepApp /dev/beep 0   //关闭蜂鸣器

 

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

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

相关文章

【01】C++的第一个程序Hello World

C的第一个应用程序&#xff08;Hello World程序&#xff09; 引言一、代码二、代码解释三、注意事项总结 引言 &#x1f4a1; 作者简介&#xff1a;专注于C/C高性能程序设计和开发&#xff0c;理论与代码实践结合&#xff0c;让世界没有难学的技术。 &#x1f449; &#x1f39…

报表生成工具Stimulsoft Reports.JS如何减少产品脚本的加载时间

Stimulsoft Reports 是一款报告编写器&#xff0c;主要用于在桌面和Web上从头开始创建任何复杂的报告。可以在大多数平台上轻松实现部署&#xff0c;如ASP.NET, WinForms, .NET Core, JavaScript, WPF, Angular, Blazor, PHP, Java等&#xff0c;在你的应用程序中嵌入报告设计器…

Django框架之视图HttpResponse 对象

本篇文章主要内容为&#xff1a;视图中HttpResponse对象的属性、方法及json、redirect子类包含使用cookie使用、跳转、json返回的示例。 概述 HttpResponse对象是对用户访问的响应&#xff0c;与HttpRequest对象由django创建&#xff0c;HttpResponse对象是由开发人员创建。Ht…

001+limou+MySQL的基础命令

0.前言 您好&#xff0c;这里是limou3434的一篇个人博文&#xff0c;感兴趣的话您也可以看看我的其他文章。本博文是借鉴于李小威前辈所著的书籍《SQL 基础教程》所成的博文笔记&#xff0c;这本书真的很适合新手学习数据库相关的内容。本次我想给您带来的是关于MySQL的一些基…

网站神奇工具Viewport Resizer,支持手机、pad和电脑等不同尺寸大小

标题&#xff1a;Viewport Resizer&#xff1a;让网站适应不同设备的神奇工具&#xff01; 导语&#xff1a; 在互联网世界中&#xff0c;我们常常需要在不同设备上浏览网站。为了让用户在手机、平板或电脑上都能看到美观易用的页面&#xff0c;网站开发者们努力优化网站的适应…

qemu-虚拟机

qemu 官网下载地址 https://www.qemu.org/ 跨平台虚拟机&#xff0c;类型vmware&#xff0c;执行效率比vmware高 官方参考文档&#xff1a;https://www.qemu.org/docs/master/system/introduction.html kvm&#xff0c;轻量级虚拟机&#xff0c;可以加速qemu的执行 qemu-e…

微信云开发技术架构

&#xff08;仅有把抱怨环境的情绪&#xff0c;化为上进的力量&#xff0c;才是成功的保证。——罗曼罗兰&#xff09; 微信云开发 官方文档 文本只用来概述微信云开发的技术架构&#xff0c;并结合实战场景进行说明。更详细的请直接查看微信官方文档。 背景 微信云开发是微…

Oracle11g全新讲解之游标

游标 游标的作用&#xff1a;处理多行数据&#xff0c;类似与java中的集合 1.隐式游标 一般是配合显示游标去使用的&#xff0c;不需要显示声明&#xff0c;打开&#xff0c;关闭&#xff0c;系统自定维护,名称为&#xff1a;sql 常用属性&#xff1a; sql%found:语句影响了…

快速分隔文件(split),合并文件(paste)的命令;eval(先扫描输出在执行)命令

split快速分割文件&#xff0c;paste快速合并文件&#xff1b;eval命令 split命令快速分隔文件paste命令快速合并文件eval命令 split命令快速分隔文件 语法格式&#xff1a; split 【选项】 参数 原始文件 拆分后文件名前缀 常用选项 -l&#xff1a;以行数拆分 -b&#xf…

7.对象模型

对象模型 信号和槽 信号和槽是一种用于对象之间通信的机制。信号是对象发出的通知&#xff0c;槽是用于接收这些通知的函数。 当对象的状态发生变化时[按钮被点击]&#xff0c;它会发出一个信号[clicked()]&#xff0c;然后与该对象连接的槽函数将被自动调用。 若某个信号与多…

图像分割之SAM(Segment Anything Model)

论文&#xff1a;Segment Anything Github&#xff1a;https://github.com/facebookresearch/segment-anything 论文从zero-shot主干网络的基础出发&#xff0c;提出了SAM&#xff08;Segment Anything Model&#xff09;模型。该模型有别于传统的分割模型。传统分割模型只能输…

正则表达式的一些元符号

正则表达式 正则表达式—通常用于判断语句中&#xff0c;用来检查某一字符串是否满足某一格式 正则表达式是由普通字符与元字符组成 普通字符包括大小写字母、数字、标点符号及一些其他符号元字符是指在正则表达式中具有特殊意义的专用字符&#xff0c;可以用来规定其前导字…

(数字图像处理MATLAB+Python)第四节:频域高通滤波与综合案例

文章目录 一&#xff1a;频域高通滤波&#xff08;1&#xff09;理想的高通滤波器&#xff08;2&#xff09;巴特沃斯高通滤波器&#xff08;3&#xff09;指数高通滤波器&#xff08;4&#xff09;梯形高通滤波器 二&#xff1a;综合案例——人像美化&#xff08;1&#xff09…

vue2实现高德地图 JSAPI 2.0海量点标记(标注和标注图层)->自定义点位->定时刷新点位

前提: 需要注册高德开放平台,之后创建应用并且开通Web端(JS API)平台,然后拿到securityJsCode和key 1. 基础抽取(还原示例) 1.1 组件代码 代码说明: 需要修改securityJsCode和key为自己的allowCollision为标注是否避让marker,默认为false不避让markers为地图上的标记数组layer…

【Axure教程】中继器表格寻找和标记数据

在系统表格中&#xff0c;我们想在表格中快速找到对应的数据&#xff0c;通常我们会用条件筛选来完成&#xff0c;但是用筛选的方式&#xff0c;其他数据就看不到了&#xff0c;少了两种条件之间的对比。所以如果需要数据对比的情况下&#xff0c;我们更多的是用标记数据的方式…

Unity学习笔记 关于Unity相机的FOV以及水平FOV和垂直FOV之间的转换

前言 关于FOV FOV 是在任何给定时间通过人眼、相机取景器或在显示屏上可见的可观察世界的范围。它指的是整个区域的覆盖范围&#xff0c;而不是单个固定焦点。FOV 还描述了一个人可以看到可见世界的角度。 FOV 越宽&#xff0c;可以看到的可观察世界就越多。它是水平、垂直和对…

vue3中使用外部字体

首先要找一个免费网站&#xff0c;去下载你想用的字体&#xff0c;推荐 DaFont - Download fonts 或者问UI要&#xff0c;ui在设计图的时候也会下载对应的特殊字体的包&#xff0c;所以问她要方便快捷 ~~ 如果是进入网站下载的话&#xff0c;操作步骤如下&#xff1a; 在官网…

MTN模型LOSS均衡相关论文解读

一、综述 MTN模型主要用于两个方面&#xff0c;1.将多个模型合为一个显著降低车载芯片负载。2.将多个任务模型合为一个&#xff0c;有助于不同模型在共享层的特征可以进行互补&#xff0c;提高模型泛化性能的同时&#xff0c;也有可能提高指标。传统的方法是直接不同任务loss相…

谷歌打响全面反击战!官宣AI重构搜索、新模型比肩GPT-4,朝着ChatGPT微软开炮

明敏 丰色 发自 凹非寺 量子位 | 公众号 QbitAI 万众瞩目&#xff0c;谷歌的反击来了。 现在&#xff0c;谷歌搜索终于要加入AI对话功能了&#xff0c;排队通道已经开放。 当然这还只是第一步。 大的还在后面&#xff1a; 全新大语言模型PaLM 2正式亮相&#xff0c;谷歌声称…

vue解决跨域的几种办法

当我们遇到请求后台接口遇到 Access-Control-Allow-Origin 时&#xff0c;那说明跨域了。 跨域是因为浏览器的同源策略所导致&#xff0c;同源策略&#xff08;Same origin policy&#xff09;是一种约定&#xff0c;它是浏览器最核心也最基本的安全功能&#xff0c;同源是指&…