Linux驱动开发学习笔记6《蜂鸣器实验》

news2025/1/11 4:29:08

目录

一、蜂鸣器驱动原理

二、硬件原理分析

三、实验程序编写

1、 修改设备树文件

(1)添加pinctrl节点

(2)添加BEEP设备节点

(3)检查PIN 是否被其他外设使用

2、蜂鸣器驱动程序编写

3、编写测试APP

 四、运行测试


一、蜂鸣器驱动原理

        蜂鸣器常用于计算机、打印机、报警器、电子玩具等电子产品中,常用的蜂鸣器有两种:有源蜂鸣器和无源蜂鸣器,这里的有“源”不是电源,而是震荡源有源蜂鸣器内部带有震荡源,所以有源蜂鸣器只要通电就会叫。无源蜂鸣器内部不带震荡源,直接用直流电是驱动不起来的,需要2K-5K 的方波去驱动。I.MX6U-ALPHA 开发板使用的是有源蜂鸣器,因此只要给其供电就会工作,I.MX6U-ALPHA 开发板所使用的有源蜂鸣器如下图所示:

        有源蜂鸣器只要通电就会叫,所以我们可以做一个供电电路,这个供电电路可以由一个IO来控制其通断,一般使用三极管来搭建这个电路。为什么我们不能像控制LED 灯一样,直接将GPIO 接到蜂鸣器的负极,通过IO 输出高低来控制蜂鸣器的通断。因为蜂鸣器工作的电流比LED 灯要大,直接将蜂鸣器接到I.MX6U 的GPIO 上有可能会烧毁IO,所以我们需要通过一个三极管来间接的控制蜂鸣器的通断,相当于加了一层隔离。

二、硬件原理分析

        上图中通过一个PNP 型的三极管8550 来驱动蜂鸣器,通过SNVS_TAMPER1 这个IO来控制三极管Q1 的导通,当SNVS_TAMPER1 输出低电平的时候Q1 导通,相当于蜂鸣器的正极连接到DCDC_3V3,蜂鸣器形成一个通路,因此蜂鸣器会鸣叫。同理,当SNVS_TAMPER1输出高电平的时候Q1 不导通,那么蜂鸣器就没有形成一个通路,因此蜂鸣器也就不会鸣叫。

三、实验程序编写

1、 修改设备树文件

(1)添加pinctrl节点

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

pinctrl_beep: beepgrp{
			fsl,pins = <
				MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10B0
			>;
		};

(2)添加BEEP设备节点

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

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

(3)检查PIN 是否被其他外设使用

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

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

2、蜂鸣器驱动程序编写

 编写beep.c文件:

#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 //开蜂鸣器

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; //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_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt)
{
    int retvalue;
    unsigned char databuf[1];
    unsigned char beepstat;
    struct beep_dev *dev = filp->private_data;

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

    beepstat = databuf[0]; //获取状态值

    if(beepstat == BEEPON)
    {
        gpio_set_value(dev->beep_gpio, 0); //8550三极管是PNP型,高电压截至,低电压导通
    }
    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,
    .write = beep_write,
    .release = beep_release,
};

//驱动入口函数
static int __init beep_init(void)
{
    int ret = 0;

    //设置BEEP所使用的GPIO
    //1、获取设备节点: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");
    }

    //2、获取设备树中的gpio属性,得到BEEP所使用的GPIO编号
    beep.beep_gpio = of_get_named_gpio(beep.nd, "beep-gpio", 0);
    if (beep.beep_gpio < 0)
    {
        printk("can't get beep-gpio");
        return -EINVAL;
    }
    printk("led-gpio num = %d\r\n", beep.beep_gpio);  
    
    //3、设置GPIO5_IO01为输出,并且输出高点平,默认关闭BEEP
    ret = gpio_direction_output(beep.beep_gpio, 1);
    if(ret < 0)
    {
        printk("can't set gpio!\r\n");
    }
    //注册字符设备驱动
    //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("beep 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);
    }
    return 0;
}
//驱动出口函数
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("ssz");

3、编写测试APP

编写测试文件beepApp.c:

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

#define BEEPOFF 0
#define BEEPON 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];

    //打开beep驱动
    fd = open(filename ,O_RDWR);
    if(fd < 0)
    {
        printf("file %s open failed!\r\n",argv[1]);
        return -1;
    }
    databuf[0] = atoi(argv[2]);
    //向/dev/beep文件写入数据
    retvalue = write(fd, databuf, sizeof(databuf));
    if(retvalue < 0)
    {
        printf("BEEP Control Failed!\r\n");
        close(fd);
        return -1;
    }
    retvalue = close(fd); //关闭文件
    if(retvalue < 0)
    {
        printf("file %s close failed!\r\n",argv[1]);
        return -1;
    }
    return 0;
}

 四、运行测试

同前面章节步骤。

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

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

相关文章

LVM与磁盘配额

文章目录 LVM与磁盘配额一、LVM概述1、LVM概述2、LVM机制的基本概念2.1 PV&#xff08;Physical Volume&#xff0c;物理卷&#xff09;2.2 VG&#xff08;Logical Volume&#xff0c;逻辑卷&#xff09;2.3 LV&#xff08;Logical Volume&#xff0c;逻辑卷&#xff09; 二、L…

PayPal账户被封是因为什么?如何解决?

Paypal作为跨境出海玩家最常用的付款工具之一&#xff0c;同时也是最容易出现冻结封号现象。保障PP账号安全非常重要&#xff0c;只有支付渠道安全&#xff0c;才不会“白费力气”&#xff0c;那么最重要的就是要了解它的封号原因以做好规避。 一、Paypal账号被封原因 1、账号…

Anolis安装Jdk保姆级教学

前言 欢迎来到本博客&#xff0c;我们将带领你完成在Anolis操作系统上安装Java Development Kit&#xff08;JDK&#xff09;的详细过程。Anolis操作系统是一款基于Linux的轻量级操作系统&#xff0c;专为容器和云原生应用而设计。在Anolis上安装JDK将为你提供一个稳定、高效的…

释放资源的方式

为什么要学这个释放资源的方式&#xff1f; //5 关流outputStream.close();inputStream.close();原来这种方式&#xff0c;一般项目都会有很多代码&#xff0c;万一前面的代码有异常&#xff0c;就无法执行到这一步&#xff0c;绑定的系统资源就得不到释放&#xff0c;影响系统…

【Web】Ctfshow Thinkphp5 非强制路由RCE漏洞

目录 非强制路由RCE漏洞 web579 web604 web605 web606 web607-610 前面审了一些tp3的sql注入,终于到tp5了&#xff0c;要说tp5那最经典的还得是rce 下面介绍非强制路由RCE漏洞 非强制路由RCE漏洞原理 非强制路由相当于开了一个大口子&#xff0c;可以任意调用当前框…

CleanMyMac X 4.14.6中文版2024年最新必备的Mac系统清理工具

CleanMyMac X 4.14.6中文版是一款专业的Mac系统清理软件&#xff0c;可一键智能扫描清理mac系统日志缓存磁盘垃圾和多余语言安装包&#xff0c;快速释放电脑内存&#xff0c;轻松管理和升级Mac上的应用。同时CleanMyMac X 破解版可以强力卸载恶意软件&#xff0c;修复系统漏洞&…

Flink 输出至 Elasticsearch

【1】引入pom.xml依赖 <dependency><groupId>org.apache.flink</groupId><artifactId>flink-connector-elasticsearch6_2.12</artifactId><version>1.10.0</version> </dependency>【2】ES6 Scala代码&#xff0c;自动导入的…

数组形式的整数加法C语言❤

一、题目&#xff1a; 整数的 数组形式 是按照从左到右的顺序表示其数字的数组。num 例如&#xff0c;对于 &#xff0c;数组形式是 。num 1321[1,3,2,1] 给定 &#xff0c;整数的 数组形式 &#xff0c;和整数 &#xff0c;返回 整数 num k 的 数组形式 。numk 示例 1&…

猫咪吃哪种冻干最好?推荐新手养猫五款口碑最好主食冻干猫粮牌子

现在越来越多的铲屎官关注猫咪的食品选择&#xff0c;而冻干猫粮一直是热门话题。其中主食冻干的肉含量很高&#xff0c;富含猫咪成长所需的蛋白质、维生素等营养物质。而且冻干工艺还保留了食材的原始风味&#xff0c;复水后可以恢复鲜肉的口感&#xff0c;猫咪很喜欢吃&#…

用于IT管理的COBIT

随着世界的不断发展和变化&#xff0c;企业必须像冲浪者一样乘风破浪&#xff0c;适应社会不断更新的浪潮&#xff0c;拥抱新技术。信息技术&#xff08;IT&#xff09;已成为大多数企业运营的支柱&#xff0c;对战略决策、客户互动和整体效率都起了一定的影响作用。然而&#…

《Spring Cloud学习笔记:分布式事务Seata》

1.分布式事务理论基础 1.1.本地事务 本地事务&#xff0c;也就是传统的单机事务&#xff0c;在传统的数据库事务中&#xff0c;必须要满足ACID四个原则&#xff1a; 1.2.分布式事务 分布式事务&#xff0c;就是指不是在单个服务或单个数据库架构下产生的事务。 分布式事务是…

polar CTF上传

WEB-上传 一、查看题目信息 二、漏洞分析 经过上传测试发现&#xff0c;这题过滤掉了<?&#xff0c;这样正常的一句话木马就没法上传&#xff0c;这里可以用utf-16编码绕过。因为utf-16占utf-8的两倍长度&#xff0c;上传时默认检测为utf-8,从而就能绕过检测成功上传。 同…

BOM和DOM有什么区别和联系

BOM (Browser Object Model) 和 DOM (Document Object Model) 都是与 Web 开发相关的术语&#xff0c;它们分别代表了浏览器对象模型和文档对象模型。 BOM 是浏览器对象模型的缩写&#xff0c;它提供了一组用于操作浏览器窗口、浏览器历史记录、浏览器的位置等浏览器相关对象的…

C语言中关于while语句的理解以及getchar和putchar

while是一个循环语句&#xff0c;关于while的一些理解可以看下面这串代码 #include <stdio.h> int main() {int i 0;scanf("%d", &i);printf("输入十以内的数字&#xff0c;从输入的数字开始一直数到十&#xff1a;");while (i<10){printf(…

05-C++ 类和对象-继承

类与对象-03 继承与派生 1. 继承的概念 c最重要的特征是代码重用&#xff0c;通过继承机制可以利用已有的数据类型&#xff0c;来定义新的数据类型&#xff0c;新的类不仅拥有旧类的成员&#xff0c;还拥有新定义的成员。 一个 B 类继承于 A 类&#xff0c;或称从类 A 派生…

【操作系统】不同操作系统内核架构分析

一、内核架构与操作系统性能之间的关系的分析 1. 适用性和专业化&#xff1a; 不同的内核架构往往会有不同的设计目标和优化点。例如&#xff0c;实时操作系统&#xff08;RTOS&#xff09;和通用操作系统&#xff08;像Linux或Windows&#xff09;在设计时就有不同的重点&am…

数据结构--二叉搜索树的实现

目录 1.二叉搜索树的概念 2.二叉搜索树的操作 二叉搜索树的插入 中序遍历(常用于排序) 二叉搜索树的查找 二叉搜索树的删除 完整二叉树代码&#xff1a; 二叉搜索树的应用 key/value搜索模型整体代码 1.二叉搜索树的概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一…

【第十三课】Trie字符串统计(acwing-835 / 二维数组的含义 / c++代码)

思想 Trie树在我们之前学习树的时候简单提过一嘴。 Trie树也称为前缀树或字典树&#xff0c;是一种用于高效存储和查找字符串的数据结构。Trie树的主要思想是利用字符串之间的公共前缀来节省存储空间&#xff0c;提高查询效率。 节点表示&#xff1a;Trie树中的每个节点代表一…

[Angular] 笔记 16:模板驱动表单 - 选择框与选项

油管视频&#xff1a; Select & Option (Template Driven Forms) Select & Option 在 pokemon.ts 中新增 interface: export interface Pokemon {id: number;name: string;type: string;isCool: boolean;isStylish: boolean;acceptTerms: boolean; }// new interface…

JavaScript(简写js)常用事件举例演示

目录 1.窗口事件onblur :失去焦点onfocus:获得焦点onload:窗口加载事件onresize:窗口大小缩放事件 二、表单事件oninput &#xff1a;当文本框内容改变时 &#xff0c;立即将改变内容 输出在控制台onchange&#xff1a; 内容改变事件onclick&#xff1a;鼠标单击时触发此事件 三…