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

目录

一、蜂鸣器驱动原理

二、硬件原理分析

三、实验程序编写

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; //cdevstruct 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、获取设备节点:beepbeep.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为输出,并且输出高点平,默认关闭BEEPret = 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、初始化cdevbeep.cdev.owner = THIS_MODULE;cdev_init(&beep.cdev, &beep_fops);//3、添加一个cdevcdev_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); //删除cdevunregister_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 1int 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.mzph.cn/news/585382.shtml

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

相关文章

基于js和html的骰子游戏

介绍&#xff1a; 1.游戏者选择“大”时&#xff0c;三个骰子点数之和为11-18时&#xff0c;游戏者获胜。2.游戏者选择“小”时&#xff0c;三个骰子点数之和为3-10时&#xff0c;游戏者获胜。3.如果游戏者选择具体点数&#xff0c;则根据三个骰子的点数计算&#xff0c;如果与…

Linux 安装Jupyter notebook 并开启远程访问

文章目录 安装Python安装pip安装Jupyter启动Jupyter Notebook1. 生成配置文件2. 创建密码3. 修改jupyter notebook的配置文件4. 启动jupyter notebook5. 远程访问jupyter notebook 安装Python 确保你的系统上已经安装了Python。大多数Linux发行版都预装了Python。你可以在终端…

【深度学习-图像分类】02 - AlexNet 论文学习与总结

论文地址&#xff1a;ImageNet Classification with Deep Convolutional Neural Networks 论文学习 1. 摘要 本研究训练了一个大型深度卷积神经网络&#xff08;CNN&#xff09;&#xff0c;用于对ImageNet LSVRC-2010比赛中的1.2百万高分辨率图像进行分类&#xff0c;这些图…

SQL面试题挑战14:每年的在校人数

目录 问题&#xff1a;SQL解答&#xff1a; 问题&#xff1a; year表示学生入学年度&#xff0c;num表示对应年度录取学生人数&#xff0c;stu_len表示录取学生的学制&#xff1b;说明&#xff1a;例如录取年度2018学制是3年&#xff0c;表示该批学生在校年份为20182019、2019…

【WPF.NET开发】属性更改事件

本文内容 先决条件标识属性更改事件属性触发器 Windows Presentation Foundation (WPF) 定义几个为响应属性值的更改而引发的事件。 该属性通常是依赖项属性。 事件本身可以是路由事件&#xff0c;也可以是标准公共语言运行时 (CLR) 事件&#xff0c;具体取决于事件是应通过元…

阿里高级Java面试真题

请解释Java中的反射机制及其潜在的性能影响。 Java中的反射机制是指在运行时检查或操作类、接口、字段、方法等程序结构的能力。通过反射&#xff0c;你可以在运行时获取类的信息、调用类的方法、访问或修改类的字段等&#xff0c;而不需要在编译时就确定这些操作。反射机制为…

MYSQL 深入探索系列六 SQL执行计划

概述 好久不见了&#xff0c;近期一直在忙项目的事&#xff0c;才有时间写博客&#xff0c;近期频繁出现sql问题&#xff0c;今天正好不忙咱们看看千万级别的表到底该如何优化sql。 案例 近期有个小伙伴生产环境收到了告警&#xff0c;有个6千万的日志表&#xff0c;查询耗时大…

“undefined reference to XXX“问题总结

"undefined reference to XXX"问题总结 引言 我们在Linux下用C/C工作的时候&#xff0c;经常会遇到"undefined reference to XXX"的问题&#xff0c;直白地说就是在链接(从.cpp源代码到可执行的ELF文件&#xff0c;要经过预处理->编译->链接三个阶…

1panel使用指南(一)面板安装

一、1panel简介 1Panel是杭州飞致云信息科技有限公司推出的产品 [1]&#xff0c;帮助用户实现快速建站。 [2]是一款现代化、开源的Linux服务器运维管理面板&#xff0c;于2023年3月推出&#xff0c;深度集成WordPress和Halo&#xff0c;一键完成域名绑定、SSL证书配置等操作&a…

draw.io学习笔记

1、链接 1.1、自动连接图形 鼠标放在图形上&#xff0c;点击出现的箭头&#xff0c;会自动出常用图形 1.2、固定连接 如果拖动其中一个图形的话&#xff0c;固定链接的形状会是曲线连过去。 方法&#xff1a;不要点击左边图形鼠标放在边框上面左边出现绿圆点鼠标左键点击图形的…

小秋SLAM入门实战ROS文章汇总

小秋SLAM入门实战教程汇总 【launch文件中如何启动gdb调试单个节点多个节点】 一个ros可执行程序可以定义几个节点&#xff1f; ros启动节点的launch文件你真的会写吗&#xff1f; 【Point Cloud ROS】用一张彩色图像和深度图像生成点云图像 【Point Cloud ROS】两张点云图像之…

Oracle研学-对象

学自B站黑马程序员 1.视图 (物化视图序列同义词oracle特有&#xff09; 1.对一个SQL语句的封装&#xff0c;一个虚拟的表。-简化开发 视图是一种数据库对象&#xff0c;是从一个或者多个数据表或视图中导出的虚表&#xff0c;视图所对应的数据并不真正地存储在视图中&#xff…

【Linux】深度解剖环境变量

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟悉并掌握Linux的环境变量。 > 毒鸡汤&#x…

LeetCode刷题--- 单词搜索

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​​http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述…

LLM之RAG实战(十一)| 使用Mistral-7B和Langchain搭建基于PDF文件的聊天机器人

在本文中&#xff0c;使用LangChain、HuggingFaceEmbeddings和HuggingFace的Mistral-7B LLM创建一个简单的Python程序&#xff0c;可以从任何pdf文件中回答问题。 一、LangChain简介 LangChain是一个在语言模型之上开发上下文感知应用程序的框架。LangChain使用带prompt和few-…

CENTOS docker拉取私服镜像

概述 docker的应用越来越多&#xff0c;安装部署越来越方便&#xff0c;批量自动化的镜像生成和发布都需要docker镜像的拉取。 centos6版本太老&#xff0c;docker的使用过程中问题较多&#xff0c;centos7相对简单容易。 本文档主要介绍centos系统安装docker和拉取docker私…

一文了解无线通信 - NB-IOT、LoRa

NB-IOT、LoRa 目录概述需求&#xff1a; 设计思路实现思路分析 NB-IOT1.LoRa2.区别 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,chall…

奇偶公式推导

推导前提: 基函数: f ( x ) − f ( − x ) f(x)-f(-x) f(x)−f(−x)偶函数: f ( x ) f ( − x ) f(x)f(-x) f(x)f(−x) 1. 奇函数 ∗ 奇函数 偶函数 奇函数*奇函数偶函数 奇函数∗奇函数偶函数 f 1 ( x ) ∗ f 2 ( x ) f_1(x)*f_2(x) f1​(x)∗f2​(x) − f 1 ( x ) ∗ …

[sparkSQL] Shuffle

在Spark SQL中&#xff0c;Shuffle 是指将数据重新分布到不同的节点上以进行处理的操作。在 Spark SQL 中&#xff0c;以下是一些可能触发 Shuffle 的操作或代码&#xff1a; group by 和 aggregations&#xff1a; 当使用 GROUP BY 或聚合函数&#xff08;如 SUM、AVG&#xf…

istio 虚拟服务 yaml 解释

虚拟服务 virtualservice 可以类比 k8s service 管理 pod&#xff0c; vs 是管理 svc 的 vs 对 svc 定义了流量规则&#xff0c;将满足条件的流量转发到对应的服务后端 配置定义 hosts&#xff1a;流量发送的目标 在 k8s 中&#xff0c;hosts 一般是 servic 的短域名&#x…