STC89C52单片机学习——第25节: [11-1]蜂鸣器
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做!
本文写于:2025.03.18
51单片机学习——第25节: [11-1]蜂鸣器
- 前言
- 开发板说明
- 引用
- 解答和科普
- 一、蜂鸣器原理和驱动
- 二、乐理部分
- 三、按键提示音设置
- 问题
- 总结
- 鸡汤时刻
前言
本次笔记是用来记录我的学习过程,同时把我需要的困难和思考记下来,有助于我的学习,同时也作为一种习惯,可以督促我学习,是一个激励自己的过程,让我们开始51单片机的学习之路。
欢迎大家给我提意见,能给我的嵌入式之旅提供方向和路线,现在作为小白,我就先学习51单片机了,就跟着B站上的江协科技开始学习了.
在这里会记录下江协科技51单片机开发板的配套视频教程所作的实验和学习笔记内容,因为我之前有一个开发板,我大概率会用我的板子模仿着来做.让我们一起加油!
另外为了增强我的学习效果:每次笔记把我不知道或者问题在后面提出来,再下一篇开头作为解答!
开发板说明
本人采用的是慧净的开发板,因为这个板子是我N年前就买的板子,索性就拿来用了。不再另外购买视频中的普中开发板了。
原理图如下

视频中的都用这个开发板来实现,如果有资源就利用起来。
仔细看了看:开发板的晶振为:11.0592Mhz;12Mhz晶振是用来给CH340G芯片外置晶振;
下图是实物图

引用
51单片机入门教程-2020版 程序全程纯手打 从零开始入门
还参考了下图中的书籍:
手把手教你学51单片机(C语言版)

STC89C52手册

解答和科普
一、蜂鸣器原理和驱动

可以看到我们使用的是无源蜂鸣器,我们控制震荡脉冲,通过调整提供振荡脉冲的频率,可以发出不同频率的声音。

我们要编这个音乐,首先需要去找到它的谱子,我们有了这个谱子呢,至少得知道这个谱子它在我们的钢铁键盘上,它是怎么样去按的,然后知道这个谱子对应钢琴键,它怎么按之后按多长时间,然后呢我们利用单片机去把每个键它背后的音给模拟出来。根据这个频率对照表,把每个按键它的音模拟出来,然后我们编写这个曲目,由谱曲到我们的蜂鸣器播放。这整个过程才能实现。那么我们单片机的任务呢就是模拟这个钢琴键盘,我们按下它按多长时间。
然后把它的频率发出来就好了,这就是我们代码的任务。那么还有一个任务呢就是,我们需要根据这个谱子,看到这个谱子之后,知道它是怎么对应的这个钢琴键盘上的。然后我们怎么去按。

我们首先来看一下这个蜂鸣器的介绍,第一句话是蜂鸣器是一种将电信号转化为声音信号的器件,那我知道这个分频器它通电会响,那么怎么响呢?
我们来看一下他想的用途呢是用来产生我们设备的按键音,报警音等提示信号。它可以分为有源蜂鸣器和无源蜂鸣器,有源蜂鸣器频率是固定的,不能随之改变。内部自带震荡源,那么它使用起来就是很简单,将正负极接上直流电压即可持续发生,频率固定。我们给他的是直流电,但直流电本身不能发声,它内部有电路产生的震荡,所以它发声,那因此呢它的频率也是固定的。因为它内部的震荡源它已经固定好了,它的频率就只有只有这么大。
三极管驱动:


低电平导通,高电平断开。之前已经分析过三极管(PNP)的驱动原理。
在这里如果P1^3输入低电平那么基极和发射极直接有电压差,就会控制发射极和集电极导通,因此就是蜂鸣器接上了电源,此时发声。
芯片驱动

控制P15的1或0,就能控制蜂鸣器是是否有电流
无源蜂鸣器不能一直通电,很容易烧毁,IO口上电默认为高电平,BZ默认为0;始终通电流。


给1取反为0,有驱动,给0取反为1,好像不行;

我们蜂鸣器原理和驱动部分就已经讲完了,接下来我们就呃给大家讲一下这个这个乐理部分。
二、乐理部分

首先我们来认识一下这个钢琴键盘,这钢琴键盘呢上面就是钢琴键盘。这个呢是五线谱,然后下面是简谱。然后呢钢键盘嗯它可以分组,小写字母也是一组,它命名方式一组有七个白键,五个黑键组成的。然后这个呢就叫做小字组。然后左边这个叫做大字组,如果左边还有人就大字一组,右边这个叫做小字二组,小字二组右边还有就是小字三组,在这里这里首先分为几组,这几组呢每一个都是单独的,就是常见的do re mi fa so la xi。然后呢每一个组的相同的音,比如说这个C1和C2相差8度.相邻的按键是半音。
然后呢我们来讲一下如何根据这个简谱去对应的这个键盘啊,就是再升高8度的话,那么这个一上面要加个点,然后呢如果降低8度呢,就是在下面在这个音的,在这个数字下面加点,降低两个8度,下面加两个点。那么升高两个8度呢,就上面加两个点。我们就可以把所有音高给表示出来。所有的白键音标就可以表示出来,然后如果我们想表示黑键的音高,我们就需要用到升音符号和降音符号这两个符号进行。

-表示时长延长, #表示升半个音,就是黑键,b为降音。
有了这个数字上面加点,下面加点,然后再配合升降符号的话,就可以表示所有钢琴上的按键了。我们就可以把钢琴键盘所有的音高的表示出来了,然后呢有了音高之后,我们按钢琴这个键盘的时候,主要有音高和按的时长,主要有这两个因素。我们这写程序也按照这两个因素来。一个是音高,一个是时间。有了这两个部分,我们就能够演奏出这个音乐了。


4分音符 500us ,2分1s,8分音符250ms 16音符为125ms,5表示4分音符,5-表示2分音符;下面加一个横线是8分音符,加两条线是16分音符。他们时间都是二倍的关系,利用它们组合起来,我们就可以组合各种时长。在我们下面呢一般来说都是以四分音符为基准。
4/4是拍号,四分音符为一拍,每小节4拍;
1的上面加点表示音高,右边有点表示附点,延长原来的1/2,500+250,250,500,500;
——为连音,时长加起来;
我们直接写个数字,它就是我们的四分音符,如果想表示二分音符的话,那么这个数字后面再加一个横线,它就可以表示二分音符。如果是全音符的话,在后面加两条横线,我加三条横线,一共四倍的关系,这就是全音符。
然后如果想表示分开,比如说四分音符分成八分音符,那么就在下面加线,比这个六我下面加一个线,它就是四分音符时值的一半。如果下面加两条线呢,就是八分音符。在右边加线就增长,下面加线就缩短,就可以表示时长然后表示完时长之后,右边这个4/4就是我们的拍号从下往上读,它叫做以四分音符为一拍,每小节有四拍。
我们需要以一个音符时长为基准,就以四分音符为基准,就是写一个数字,画一条竖线就代表小节,一小节有4拍,这就是以四分音符为一拍,每小节四拍的意思。
==右边加点就是附点这个音符加上原来的一半,比如说这个四分音符是500ms,然后加个点它加原来500ms的一半,就是加上250ms,就是750ms。

弧度是延音线,按下去不放的, 为了识谱方便.

我们就是根据这个频率值,根据频率值去控制我们的定时器,产生一个相应频率的计时,有了频率就有了计时频率,计时的周期我们有了,然后去控制我们的中断,再去控制IO口的翻转,就可以控制我们的频率.

频率关系是:首先需要一个基准的频率,就是低音6,小子组的a为基准频率440,下一个a是880,左边的a是220,中间是以等比数列,也叫十二平分律。440*2^(1/12)是下一个频率。
利用定时器中断产生频率,依靠我们TH0、TL0,产生周期,周期等于1/f,然后是IO口,一个周期IO翻转两次,所以反正一次用的时间是半个周期,

12MHZ对应的重装载值

11.05926HZ对应的重装载值

其中的转化过程,因为时钟频率不同,机器周期不同,重装载值也不同。
三、按键提示音设置
3.1 main.c
#include <REGX52.H>
#include <INTRINS.H>
#include "Delay.h"
#include "Key.h"
#include "Timer0.h"
#include "LCD1602.h"
#include "Init.h"
#include "Nixie.h"sbit Buzzer = P2^3;
unsigned char KeyNum;
unsigned int i;
void main()
{DianZhengGuan(); //关闭点阵while(1){KeyNum=Key();if(KeyNum){for(i=0;i<500;i++) //2ms一个周期,500HZ 的频率响500ms{ //f=1/T=1/0.002=500hzBuzzer=!Buzzer;Delay(1);}Nixie(1,KeyNum);}}
}
3.2 Key.c
#include <REGX52.H>
#include "Delay.h"/*** @brief 独立按键获取键码值* @param 无* @retval 按下的键码值,范围1-8,没有独立按键按下是为0*/
unsigned char Key()
{unsigned char KeyNumber=0;if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=1;}if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=2;}if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}if(P3_4==0){Delay(20);while(P3_4==0);Delay(20);KeyNumber=5;}if(P3_5==0){Delay(20);while(P3_5==0);Delay(20);KeyNumber=6;}if(P3_6==0){Delay(20);while(P3_6==0);Delay(20);KeyNumber=7;}if(P3_7==0){Delay(20);while(P3_7==0);Delay(20);KeyNumber=8;}return KeyNumber;}
#ifndef __KEY_H
#define __KEY_Hunsigned char Key();#endif
3、Nixie.c
#include <REGX52.H>
#include "Delay.h"sbit wei= P2^1;
sbit duan=P2^0;
unsigned char NixieDuanTable[]= {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x00};
unsigned char NixieWeiTable[]={0xFF,0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};void Nixie(unsigned char WeiNum, DuanNum) //动态显示
{duan=1;P0=NixieDuanTable[DuanNum];duan=0;wei=1;P0=NixieWeiTable[WeiNum];wei=0;Delay(1);
}
#ifndef __NIXIE_H
#define __NIXIE_Hvoid Nixie(unsigned char WeiNum, DuanNum);#endif
实验现象:
按键提示音(蜂鸣器)
对蜂鸣器设置私有化延迟函数
1、main.c
#include <REGX52.H>
#include <INTRINS.H>
#include "Delay.h"
#include "Key.h"
#include "Timer0.h"
#include "LCD1602.h"
#include "Init.h"
#include "Nixie.h"
#include "Buzzer.h"unsigned char KeyNum;void main()
{DianZhengGuan(); //关闭点阵while(1){KeyNum=Key();if(KeyNum){Buzzer_Time(100); //1Khz响100msNixie(1,KeyNum);}}
}
2.Buzzer.c
#include <REGX52.H>
#include <INTRINS.H>
#include "Delay.h"sbit Buzzer = P2^3; //蜂鸣器端口/*** @brief 蜂鸣器私有延迟函数 //@11.0592MHz 500us* @param 无* @retval 无*/
void Buzzer_Delay500us() //@11.0592MHz
{unsigned char i;_nop_();i = 227;while (--i);
}/*** @brief 蜂鸣器鸣响 * @param xms :发声的时间* @retval 无*/
void Buzzer_Time(unsigned int xms)
{unsigned int i;for(i=0;i<xms*2;i++) //1ms一个周期,1000HZ 的频率响xms{Buzzer=!Buzzer;Buzzer_Delay500us();}
}
#ifndef __BUZZER_H
#define __BUZZER_Hvoid Buzzer_Time(unsigned int ms);#endif
问题
1、就是还是对乐理部分有点乱。
总结
本节课主要学了蜂鸣器的原理和驱动,学习了音乐相关的乐理知识。让我们看着简谱去弹钢琴,主要是音高和音长,这两点,其中有#升音、头上加点,b降音底部加点;下面加——,一半音,右边——延长,还有附点延长一半,还有弧度延音键为了看拍子数,这样基本解决了音高和音长两个关键。
接下来为了让单片机发出对应的音高,单片机不能控制频率,通过频率得到计数频率,所以通过控制周期,得到计数频率也就得到了技术周期,半个周期触发中断,进行一次IO变换,一个周期IO变换两次==(高电平半个周期,低电平半个周期)==,那么我们通过频率最后到达计算重装值。其中还进行了11.0592Mhz的转换。就剩下如何实现了。
鸡汤时刻

相关文章:
STC89C52单片机学习——第25节: [11-1]蜂鸣器
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.03.18 51单片机学习——第25节: [11-1]蜂鸣器 前言开发板说明引用解答和科普一、蜂鸣器…...
音视频入门基础:RTP专题(19)——FFmpeg源码中,获取RTP的音频信息的实现(下)
本文接着《音视频入门基础:RTP专题(18)——FFmpeg源码中,获取RTP的音频信息的实现(上)》,继续讲解FFmpeg获取SDP描述的RTP流的音频信息到底是从哪个地方获取的。本文的一级标题从“四”开始。 四…...
搭建Python量化开发环境:从零开始的完整指南
搭建Python量化开发环境:从零开始的完整指南 在量化投资领域,一个稳定且高效的开发环境是成功的关键。本文将引导你一步步搭建起自己的Python量化开发环境,确保你能够顺利开始编写和运行量化策略。 🚀量化软件开通 Ὠ…...
卷积神经网络 - 卷积的变种、数学性质
本文我们来学习卷积的变种和相关的数学性质,为后面学习卷积神经网络做准备,有些概念可能不好理解,可以先了解其概念,然后慢慢理解、逐步深入。 在卷积的标准定义基础上,还可以引入卷积核的滑动步长和零填充来增加卷积…...
BLIP论文阅读
目录 现存的视觉语言预训练存在两个不足: 任务领域 数据集领域 相关研究 知识蒸馏 Method 单模态编码器: 基于图像的文本编码器: 基于图像的文本解码器: 三重目标优化 图像文本对比损失:让匹配的图像文本更加…...
Opencv之计算机视觉一
一、环境准备 使用opencv库来实现简单的计算机视觉。 需要安装两个库:opencv-python和opencv-contrib-python,版本可以自行选择,注意不同版本的opencv中的某些函数名和用法可能不同 pip install opencv-python3.4.18.65 -i https://pypi.t…...
批量测试IP和域名联通性2
在前面批量测试IP和域名联通性-CSDN博客的基础上,由于IP和域名多样性,比如带端口号的192.168.1.17:17,实际上应该ping 192.168.1.17。如果封禁http://www.abc.com/a.exe,实际可ping www.abc.com。所以又完善了代码。 echo off se…...
[动手学习深度学习]26. 网络中的网络 NiN
前面的LeNet、AlexNet、VGG在设计上的共同之处在于:先以卷积层构成的模块充分抽取空间特征,再以全连接层构成的模块来输出分类结果 其中AlexNet和VGG对LeNet的改进主要在于如何对这两个模块价款(增加通道数)和加深 这一节的NiN提出…...
C语言论递归函数及其本质
一个函数在函数体内又调用了本身,我们称为递归调用,这样的函数就是递归函数。 递归函数成功执行需满足以下两个条件: 必须有一个明显的结束条件。必须有一个趋近于结束条件的趋势。 举个生活例子:数钱 假设你有一叠钞票…...
碰一碰发视频saas系统技术源头一站式开发文档
碰一碰发视频系统技术源头一站式开发文档 一、引言 在数字化信息传播高速发展的当下,如何让视频分享更便捷、高效,成为商家和开发者们关注的焦点。“碰一碰发视频”系统以其独特的交互方式和强大的功能优势,为视频分享领域带来了革命性变革。…...
Linux目录理解
前言 最近在复习linux,发现有些目录总是忘记内容,发现有些还是得从原义和实际例子去理解会记忆深刻些。以下是个人的一些理解 Linux目录 常见的Linux下的目录如下: 1. 根目录 / (Root Directory) 英文含义:/ 是文件系统的根…...
可视化图解算法:链表中倒数(最后)k个结点
1. 题目 描述 输入一个长度为 n 的链表,设链表中的元素的值为ai ,返回该链表中倒数第k个节点。 如果该链表长度小于k,请返回一个长度为 0 的链表。 数据范围:0≤n≤105,0 ≤ai≤109,0 ≤k≤109 要求&am…...
Swift 并发中的任务让步(Yielding)和防抖(Debouncing)
网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…...
@SpringBootApplication
SpringBootApplication拓展 一. SpringBootConfiguration注解 是SpringBoot的注解, 标识一个类为配置类, 与Configration功能一致 run方法初始化了SpringBootConfiguration注解 注解源码 Target(ElementType.TYPE)//类型 Retention(RetentionPolicy.RUNTIME)//生命周期 Docu…...
什么是状态管理?有何种方式可以实现?它们之间有什么区别?
目录 一、状态管理的核心概念 二、常见状态管理方案及对比 1. 基础方案:setState 2. 官方推荐:Provider 3. 事件驱动:Bloc (Business Logic Component) 4. 响应式增强:Riverpod 5. 轻量级全能库:GetX 三、方案对比与选型指南 四、实战建议 在 Flutter 中,状态管…...
HW基本的sql流量分析和wireshark 的基本使用
前言 HW初级的主要任务就是看监控(流量) 这个时候就需要我们 了解各种漏洞流量数据包的信息 还有就是我们守护的是内网环境 所以很多的攻击都是 sql注入 和 webshell上传 (我们不管对面是怎么拿到网站的最高权限的 我们是需要指出它是…...
docker-compose install nginx(解决fastgpt跨区域)
CORS前言 CORS(Cross-Origin Resource Sharing,跨源资源共享)是一种安全措施,它允许或拒绝来自不同源(协议、域名、端口任一不同即为不同源)的网页访问另一源中的资源。它的主要作用如下: 同源策略限制:Web 浏览器的同源策略限制了从一个源加载的文档或脚本如何与另一…...
设计模式(创建型)-单例模式
摘要 在软件开发的世界里,设计模式是开发者们智慧的结晶,它们为解决常见问题提供了经过验证的通用方案。单例模式作为一种基础且常用的设计模式,在许多场景中发挥着关键作用。本文将深入探讨单例模式的定义、实现方式、应用场景以及可…...
Leetcode 刷题笔记1 图论part01
图论的基础知识: 图的种类: 有向图(边有方向) 、 无向图(边无方向)、加权有向图(边有方向和权值) 度: 无向图中几条边连接该节点,该节点就有几度࿱…...
鸿蒙NEXT开发问题大全(不断更新中.....)
目录 问题1:鸿蒙NEXT获取华为手机的udid 问题2:[Fail]ExecuteCommand need connect-key? 问题3:测试时如何安装app包 问题1:鸿蒙NEXT开发获取华为手机的udid hdc -t "设备的序列号" shell bm get --udid 问题2&…...
分享一个项目中遇到的一个算法题
需求背景: 需求是用户要创建一个任务计划在未来执行,要求在创建任务计划的时候判断选择的时间是否符合要求,否则不允许创建,创建的任务类型有两种,一种是单次,任务只执行一次;另一种是周期&…...
TI的Doppler-Azimuth架构(TI文档)
TI在AWR2944平台上推出新的算法架构,原先的处理方式是做完二维FFT后在RD图上做CFAR检测,然后提取各个通道数据做测角。 Doppler-Azimuth架构则是做完二维FFT后,再做角度维FFT,生成Doppler-Azimuth频谱图,然后在该频谱图…...
电子邮件常用协议技术详解与C++实践(SMTP POP3 IMAP)
一、核心协议概览 协议端口(明文/加密)核心功能数据同步方式典型场景SMTP25 / 587邮件发送单向传输客户端提交邮件POP3110 / 995邮件下载单向同步单设备离线阅读IMAP143 / 993邮件管理双向同步多设备实时同步 二、协议深度解析 1. SMTP(简单…...
机器学习算法:一文掌握 K近邻算法 的详细用法(2个案例可直接运行)
文章目录 一、KNN 算法概述1.1 算法原理1.2 KNN 的优缺点1.3 K 值的选择 二、Python 实现 KNN 案例2.1 使用 KNN 算法进行手写数字识别2.2 使用 Python 实现 KNN 分类 三、总结 KNN(K-Nearest Neighbors,K近邻算法) 是一种简单且常用的分类和…...
设计C语言的单片机接口
一、主要内容 (一)控制引脚 1、定义管脚 // 定义管脚的结构体 struct pin{ int id; // 管脚编号 int mode; // 模式,输入为1,输出为0 int pull; // 输入电阻 int driver; // 功率 } 2、输出电平 语法: void pin_output(s…...
[从零开始学习JAVA] Stream流
前言: 本文我们将学习Stream流,他就像流水线一样,可以对我们要处理的对象进行逐步处理,最终达到我们想要的效果,是JAVA中的一大好帮手,值得我们了解和掌握。(通常和lambda 匿名内部类 方法引用相…...
「自动驾驶的数学交响曲:线性代数、微积分与优化理论的深度共舞」—— 解析人工智能背后的高阶数学工具链
引言 自动驾驶系统是数学工具链的集大成者。从传感器数据的多维空间映射到控制指令的生成,每一步都隐藏着线性代数、微积分、概率论和优化理论的精妙配合。本文将构建一个数学模型完整的自动驾驶案例,结合Python代码实现,揭示以下核心数学工具: 线性代数:张量运算与特征空…...
调试 Rust + WebAssembly 版康威生命游戏
1. 启用 Panic 日志 1.1 让 Panic 信息显示在浏览器控制台 如果 Rust 代码发生 panic!(),默认情况下不会在浏览器开发者工具中显示详细的错误信息。这使得排查问题变得困难。 我们可以使用 console_error_panic_hook 这个 Rust crate,将 Panic 信息打…...
VSCode通过SSH远程登录Windows服务器
系列 1.1 VSCode通过SSH远程登录Windows服务器 1.2 VSCode通过SSH免密远程登录Windows服务器 文章目录 系列1 准备工作2 远程服务器配置2.1 安装SSH服务器2.2 端口 3 本地电脑配置3.1 安装【Remote - SSH】。3.2 登录 1 准备工作 本地电脑Windows 11,已安装VS Cod…...
qt下载和安装教程国内源下载地址
qt不断在更新中,目前qt6日渐成熟,先前我们到官方下载或者国内镜像直接可以下载到exe文件安装,但是最近几年qt官方似乎在逐渐关闭旧版本下载通道,列为不推荐下载。但是qt5以其广泛使用和稳定性,以及积累大量代码使得qt5…...
