(学习日记)2023.4.22

news2024/12/25 8:53:01

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


点击此处进入学习日记的总目录

2023.4.22

  • 一、51:蜂鸣器
  • 二、51:按键控制蜂鸣器发声时间
  • 三、51:蜂鸣器唱歌——天空之城

一、51:蜂鸣器

  1. 蜂鸣器介绍
    在这里插入图片描述

  2. 驱动电路
    在这里插入图片描述

  3. ULN2003
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  4. 音符对照频率
    在这里插入图片描述
    在这里插入图片描述

  5. 常见乐谱
    在这里插入图片描述
    在这里插入图片描述

二、51:按键控制蜂鸣器发声时间

  1. 寻找引脚,很显然是P25
    在这里插入图片描述
    在这里插入图片描述
  2. 编写延时函数
    为了实现震荡,首先编写一个延时函数,保证定时震荡
/**
  * @brief  蜂鸣器私有延时函数,延时500us
  * @param  无
  * @retval 无
  */
void Buzzer_Delay500us()		//@12.000MHz
{
	unsigned char i;

	_nop_();
	i = 247;
	while (--i);
}
  1. 编写发声函数
    让蜂鸣器在规定时间内发声
//蜂鸣器端口:
sbit Buzzer=P2^5;

/**
  * @brief  蜂鸣器发声
  * @param  ms 发声的时长,范围:0~32767
  * @retval 无
  */
void Buzzer_Time(unsigned int ms)
{
	unsigned int i;
	for(i=0;i<ms*2;i++)
	{
		Buzzer=!Buzzer;
		Buzzer_Delay500us();
	}
}

Buzzer_Time 函数中,有一个循环语句 for(i=0;i<ms*2;i++)。这个循环的目的是让蜂鸣器在指定的时长内产生一系列的脉冲
当调用 Buzzer_Time(1000) 时,参数 ms 的值为 1000,表示要让蜂鸣器响 1000 毫秒(1秒)的时间。
在循环中,i 的初始值为 0,每次循环结束后 i 增加 1。由于循环条件是 i<ms*2,也就是 i<2000,所以这个循环将会执行 2000次。
在循环体内部,首先会对蜂鸣器状态进行取反,然后调用Buzzer_Delay500us()函数延时约为 500 微秒。因此,每次循环会产生一次蜂鸣器的状态变化和延时,持续约为 500 微秒。
总共有 2000 次循环,所以总的延时时间为 2000 * 500 微秒 = 1000 毫秒(1秒)

三、51:蜂鸣器唱歌——天空之城

  1. 自动重装载值(TH0TL0)计算
    在8051系列微控制器中,定时器0的自动重装载值(Auto-Reload Value)用于设置定时器的计时初值。定时器0是一个8位定时器,其计时范围为0到255。当定时器0计数器达到255时,会自动将计数器重置为自动重装载值,并触发定时器0溢出中断。
计算自动重装载值(TH0,TL0)的方法取决于所需的定时周期和时钟频率。下面是一个示例计算步骤:

- 确定所需的定时周期。假设我们希望定时器01毫秒触发一次中断。
- 确定系统的时钟频率。假设系统的时钟频率为12.000MHz。
- 计算定时器的计数周期。由于定时器0是一个8位定时器,它可以计数的最大值为255。因此,定时器的计数周期为256- 计算所需的计数值。要实现1毫秒的定时周期,需要确定每个计数周期的时间。根据时钟频率和计数周期,可以计算出每个计数周期的时间(以秒为单位)。
- 计数周期时间 = 1 / (时钟频率 / 计数周期) = 1 / (12.000MHz / 256)21.33纳秒
注意:以上计算假设时钟频率和计数周期的单位相同,如均为Hz或均为MHz。
- 计算自动重装载值。根据所需的定时周期,可以计算出需要多少个计数周期才能达到该定时周期。然后,将计数周期数减去1,得到自动重装载值。根据上面的例子,每毫秒需要多少个计数周期:
计数周期数 = (1毫秒 / 计数周期时间) = (1毫秒 / 21.33纳秒)46882个计数周期
自动重装载值 = 计数周期数 - 146882 - 1 = 46881
- 因为定时器0是一个8位定时器,所以自动重装载值需要分为高8位(TH0)和低8位(TL0)。
TH0 = 自动重装载值 / 256 = 46881 / 256183
TL0 = 自动重装载值 % 256 = 46881 % 256 = 105

这样,将TH0设置为183,TL0设置为105,定时器0将每1毫秒触发一次中断。

  1. 计算各频率重装载值
    在这里插入图片描述
//音符与索引对应表,P:休止符,L:低音,M:中音,H:高音,下划线:升半音符号#
#define P	0
#define L1	1
#define L1_	2
#define L2	3
#define L2_	4
#define L3	5
#define L4	6
#define L4_	7
#define L5	8
#define L5_	9
#define L6	10
#define L6_	11
#define L7	12
#define M1	13
#define M1_	14
#define M2	15
#define M2_	16
#define M3	17
#define M4	18
#define M4_	19
#define M5	20
#define M5_	21
#define M6	22
#define M6_	23
#define M7	24
#define H1	25
#define H1_	26
#define H2	27
#define H2_	28
#define H3	29
#define H4	30
#define H4_	31
#define H5	32
#define H5_	33
#define H6	34
#define H6_	35
#define H7	36

//索引与频率对照表
unsigned int FreqTable[]={
	0,
	63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,	//低频
	64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,	//中频
	65058,65085,65110,65134,65157,65178,65198,65217,65235,65252,65268,65283,	//高频
};
  1. 编写 定时器0初始化函数Timer0Init()
/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
    TMOD &= 0xF0;       // 设置定时器模式
    TMOD |= 0x01;       // 设置定时器模式
    TL0 = 0x18;         // 设置定时初值
    TH0 = 0xFC;         // 设置定时初值
    TF0 = 0;            // 清除TF0标志
    TR0 = 1;            // 定时器0开始计时
    ET0 = 1;            // 允许定时器0中断
    EA = 1;             // 允许总中断
    PT0 = 0;            // 设置定时器0中断优先级
}
  • TMOD &= 0xF0;TMOD |= 0x01;:对定时器模式寄存器 TMOD 进行设置,保留高4位的原值,并将低4位设置为 0x01,表示将定时器0设置为 16位工作模式。
  • TL0 = 0x18;TH0 = 0xFC;:分别设置 Timer0 的低字节和高字节的初始值,用于定时器的计时。这些值根据具体的时钟频率和所需的定时周期进行设置。(因为后面会设置,所以此处初始化不存在影响)
  • TF0 = 0;:清除 Timer0 溢出标志,确保 Timer0 中断开始时不会立即触发。
  • TR0 = 1;:启动定时器0,开始计时。
  • ET0 = 1;:允许定时器0中断,使得当定时器0溢出时可以触发中断服务函数。
  • EA = 1;:允许总中断,使得系统能够响应所有中断请求。
  • PT0 = 0;:设置定时器0中断的优先级为最低优先级。

这个函数的目的是将定时器0设置为一个 1 毫秒的定时器,在12.000MHz的时钟频率下工作。通过设置相应的寄存器值和使能中断,可以让定时器0每隔1毫秒触发一次中断,从而执行相应的中断服务函数。

  1. 编写 Timer0 中断的处理函数
void Timer0_Routine() interrupt 1
{
    if (FreqTable[FreqSelect])    // 如果不是休止符
    {
        /* 取对应频率值的重装载值到定时器 */
        TL0 = FreqTable[FreqSelect] % 256;    // 设置定时初值
        TH0 = FreqTable[FreqSelect] / 256;    // 设置定时初值
        Buzzer = !Buzzer;    // 翻转蜂鸣器IO口
    }
}
  • void Timer0_Routine() interrupt 1:定义了一个中断服务函数 Timer0_Routine(),其中 interrupt 1 表示这个函数是针对中断号 1 的处理函数。
  • if (FreqTable[FreqSelect]):检查 FreqTable[FreqSelect] 的值是否非零,判断是否为休止符(停止蜂鸣器发声)。
  • TL0 = FreqTable[FreqSelect] % 256;TH0 = FreqTable[FreqSelect] / 256;:将 FreqTable[FreqSelect] 的值分别赋值给 TL0 和 TH0 寄存器,以设置定时器的计时初值。其中 % 表示取余操作,/ 表示整数除法。
  • Buzzer = !Buzzer;:通过对 Buzzer 变量进行逻辑取反操作,翻转蜂鸣器的 I/O 口状态。这样可以在定时器中断中控制蜂鸣器的开关,实现发声效果。

该中断服务函数根据 FreqTable[FreqSelect] 的值来控制蜂鸣器的频率和发声,当 FreqTable[FreqSelect] 不为零时,定时器的初值被设置为对应的频率值,同时蜂鸣器的 I/O 口状态被翻转,从而控制蜂鸣器的发声和停止。具体的频率和频率表的定义和赋值在代码中并未给出,你可以根据具体的需求自行添加或修改相应的代码。

  1. 编写main函数
//播放速度,值为四分音符的时长(ms)
#define SPEED	500

unsigned char FreqSelect,MusicSelect;

void main()
{
	Timer0Init();
	while(1)
	{
		if(Music[MusicSelect]!=0xFF)	//如果不是停止标志位
		{
			FreqSelect=Music[MusicSelect];	//选择音符对应的频率
			MusicSelect++;
			Delay(SPEED/4*Music[MusicSelect]);	//选择音符对应的时值
			MusicSelect++;
			TR0=0;
			Delay(5);	//音符间短暂停顿
			TR0=1;
		}
		else	//如果是停止标志位
		{
			TR0=0;
			while(1);
		}
	}
}

在这段代码中,main()函数是程序的主要入口点。以下是main()函数的解释:

  • 首先调用Timer0Init()函数进行定时器0的初始化,该函数会设置定时器0的模式、初值和使能定时器0的中断。
  • 进入一个无限循环(while(1)),用于不断地处理音乐的播放。
  • 在循环中,首先判断当前乐谱位置是否为终止标志(Music[MusicSelect] != 0xFF)。如果不是终止标志,说明还有音符需要播放。
  • 获取当前音符对应的频率值,通过读取Music数组中的值(FreqSelect = Music[MusicSelect])。然后递增MusicSelect的值,用于指向这一个音符的持续时间。
  • 使用延迟函数(Delay(SPEED/4*Music[MusicSelect]))来延迟一段时间,时长为当前音符的时值乘以播放速度。这个延迟函数是根据乐谱中音符的时值来控制音符的持续时间。
  • 在播放一个音符之前,先停止定时器0(TR0 = 0),然后进行一个短暂的停顿(Delay(5)),再重新启动定时器0(TR0 = 1)。这样可以在音符之间产生一个短暂的停顿,以区分不同音符。
  • 如果当前乐谱位置是终止标志,表示音乐播放完毕,这时停止定时器0(TR0 = 0),然后进入一个无限循环(while(1)),程序会一直停在这个循环中。

通过以上步骤,main()函数实现了根据乐谱数组中的音符和时值控制蜂鸣器的播放。不断循环播放乐谱中的音符,直到遇到终止标志为止。

  1. 定义乐谱即可
    这里放一首天空之城

//乐谱
unsigned char code Music[]={
	//音符,时值,
	
	//1
	P,	4,
	P,	4,
	P,	4,
	M6,	2,
	M7,	2,
	
	H1,	4+2,
	M7,	2,
	H1,	4,
	H3,	4,
	
	M7,	4+4+4,
	M3,	2,
	M3,	2,
	
	//2
	M6,	4+2,
	M5,	2,
	M6, 4,
	H1,	4,
	
	M5,	4+4+4,
	M3,	4,
	
	M4,	4+2,
	M3,	2,
	M4,	4,
	H1,	4,
	
	//3
	M3,	4+4,
	P,	2,
	H1,	2,
	H1,	2,
	H1,	2,
	
	M7,	4+2,
	M4_,2,
	M4_,4,
	M7,	4,
	
	M7,	8,
	P,	4,
	M6,	2,
	M7,	2,
	
	//4
	H1,	4+2,
	M7,	2,
	H1,	4,
	H3,	4,
	
	M7,	4+4+4,
	M3,	2,
	M3,	2,
	
	M6,	4+2,
	M5,	2,
	M6, 4,
	H1,	4,
	
	//5
	M5,	4+4+4,
	M2,	2,
	M3,	2,
	
	M4,	4,
	H1,	2,
	M7,	2+2,
	H1,	2+4,
	
	H2,	2,
	H2,	2,
	H3,	2,
	H1,	2+4+4,
	
	//6
	H1,	2,
	M7,	2,
	M6,	2,
	M6,	2,
	M7,	4,
	M5_,4,
	
	
	M6,	4+4+4,
	H1,	2,
	H2,	2,
	
	H3,	4+2,
	H2,	2,
	H3,	4,
	H5,	4,
	
	//7
	H2,	4+4+4,
	M5,	2,
	M5,	2,
	
	H1,	4+2,
	M7,	2,
	H1,	4,
	H3,	4,
	
	H3,	4+4+4+4,
	
	//8
	M6,	2,
	M7,	2,
	H1,	4,
	M7,	4,
	H2,	2,
	H2,	2,
	
	H1,	4+2,
	M5,	2+4+4,
	
	H4,	4,
	H3,	4,
	H3,	4,
	H1,	4,
	
	//9
	H3,	4+4+4,
	H3,	4,
	
	H6,	4+4,
	H5,	4,
	H5,	4,
	
	H3,	2,
	H2,	2,
	H1,	4+4,
	P,	2,
	H1,	2,
	
	//10
	H2,	4,
	H1,	2,
	H2,	2,
	H2,	4,
	H5,	4,
	
	H3,	4+4+4,
	H3,	4,
	
	H6,	4+4,
	H5,	4+4,
	
	//11
	H3,	2,
	H2,	2,
	H1,	4+4,
	P,	2,
	H1,	2,
	
	H2,	4,
	H1,	2,
	H2,	2+4,
	M7,	4,
	
	M6,	4+4+4,
	P,	4,
	
	0xFF	//终止标志
};

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

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

相关文章

【C++】关键字:static

关键字static 在这一章节&#xff0c;将对C中的关键字static做进一步介绍。 成员函数中的this指针 这里先附上之前写的一个complex类代码&#xff1a; //防卫式定义 #ifndef __MYCOMPLEX__ #define __MYCOMPLEX__//前置声明 class complex;//类声明 complex& __doapl (…

分享一个隐藏链接的样式

先上效果图&#xff1a; 再看代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>隐藏的链接按钮</title><style>.trapdoor {-webkit-transform: translateZ(0px);-webkit…

Unity Addressables热更流程

一、分组&#xff08;网上教程一大堆&#xff09; 二、构建 构建前设置&#xff1a; 1、分组设置。所有组做远端构建加载选择&#xff0c;RemoteBuildPath 。RemoteLoadPath 2、AddressableAssetSettings设置 3、构建 三、导出信息分析&#xff1a; 1、Assets同级目录下&#…

第十二届蓝桥杯国赛JavaB组题解

A. 整数范围 思路&#xff1a; 签到题。答案&#xff1a; 255 255 255 B. 纯质数 思路&#xff1a; 先用筛法筛出所有的质数&#xff0c;再根据题意判断&#xff0c;模板参考AcWing 数学知识。 代码&#xff1a; import java.io.BufferedReader; import java.io.IOExcepti…

Python相关环境变量配置和模拟手机app登录

【java环境变量配置】 接着&#xff0c;打开系统->高级系统设置->环境变量。新建一个JAVA_HOME C:\Program Files\Java\jdk1.8.0_201&#xff08;这里是你的安装路径&#xff0c;最好复制粘贴&#xff09; 然后在Path下添加 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; 然后…

【LeetCode每日一题】——1493.删掉一个元素以后全为 1 的最长子数组

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 滑动窗口 二【题目难度】 中等 三【题目编号】 1493.删掉一个元素以后全为 1 的最长子数组 …

wx.request net::ERR_TOO_MANY_REDIRECTS

文章目录 问题解决方法一&#xff1a;请求头里添加Cookies方法二&#xff1a;使用weapp-cookie 问题 使用微信小程序开发者工具开发小程序项目时&#xff0c;wx.request 返回总是报 net::ERR_TOO_MANY_REDIRECTS wx.request发起一个get请求&#xff0c;一直重定向直到请求失败…

Java Web——Session实现购物车

实验名称&#xff1a; Session实现购物车 实验目的&#xff1a; &#xff08;1&#xff09;掌握什么是Cookie对象&#xff0c;掌握Cookie对象的使用 &#xff08;2&#xff09;掌握什么是Session对象&#xff0c;掌握Session对象的使用 &#xff08;3&#xff09;掌握使用…

弗雷歇distanceDTW(动态时间规整)算法(附部分代码)

1、理论知识 1.1 什么是弗雷歇距离&#xff0c;它是用来干什么的&#xff1f; 费雷歇distance是求两个序列匹配之后的最大距离&#xff0c;这里需要明确a&#xff09;两个序列&#xff1b;b&#xff09;匹配过程&#xff1b;c&#xff09;最大距离的含义。 a&#xff09;两个…

【java】 【Springboot】 开发通用审核流程服务模块

完全自研一个极其轻量级 通用审核流程服务 可以进行流程&#xff0c;节点配置&#xff0c;流程&#xff0c;节点审核人权限配置 批量审核&#xff0c;批量驳回&#xff0c;审核&#xff0c;驳回&#xff0c;批量退回第一步&#xff0c;退回第一步等操作 涉及数据库表单字段

OSPF最优路径选择

路由比较 1、内部区域>区域间路由>NSSA1>Nssa2 2、如果只有Ex1、Ex2或者Nssa1、nNssa2开销类型。则Ex1>Ex2或者Nssa1>Nssa2 3、如果Ex1、Nssa1,Ex2和Nssa2,Ex1和Nssa1优于Ex2和Nssa2 4、如果外部开销加上内部开销,Ex1和Nssa1一样,则Ex1和Nssa1相同负载分担 5、如果外…

CVE-2016-1000027安全漏洞分析和解决方案

文章目录 前言复现问题漏洞分析解决办法相关阅读 前言 CVE-2016-1000027 安全漏洞&#xff0c;该漏洞在5.x的最新版本(5.3.27)依然存在,官方未给出任何解决办法。在spring-web6.0之后&#xff0c;则不存在该漏洞。 受影响范围:spring-web<6.0 解决办法&#xff1a;升级到sp…

【机器学习】分类问题和Logistic回归算法详解

在阅读本文前&#xff0c;请确保你已经掌握代价函数、假设函数等常用机器学习术语&#xff0c;最好已经学习线性回归算法&#xff0c;前情提要可参考https://blog.csdn.net/weixin_45434953/article/details/130593910 分类问题是十分广泛的一个问题&#xff0c;其代表问题是&…

图表控件LightningChart JS v.4.1已经发布!引入虚线模式

LightningChart JS是性能最高的JavaScript图表库&#xff0c;专注于实时数据可视化。是Web上性能最高的图表库具有出色的执行性能 - 使用高数据速率同时监控数十个数据源。 GPU加速和WebGL渲染确保您的设备的图形处理器得到有效利用&#xff0c;从而实现高刷新率和流畅的动画。…

固态硬盘基础知识:M.2 NVMe PCIe SATA的含义及区别

SATA接口 固态硬盘开始流行于笔记本电脑上&#xff0c;使用SATA接口&#xff0c;尺寸与笔记本硬盘相同&#xff0c;为2.5英寸。 那个时候&#xff0c;如果台式机需要加装固态硬盘&#xff0c;需要使用硬盘架&#xff0c;将固态硬盘安装在硬盘架上&#xff0c;然后再安装与机箱…

5.2.3 IP数据报(一)IP数据报的格式

5.2.3 IP数据报&#xff08;一&#xff09;IP数据报的格式 我们知道要想实现全球范围的通信除了地址要统一之外&#xff0c;数据格式也要统一&#xff0c;所以就有了IP分组&#xff0c;或者被称之为IP数据报&#xff0c;下面我们来学习IP分组的格式。如图 总体来说一个IP分组…

JetBrains的Java集成开发环境IntelliJ 2023版本在Linux系统的下载与安装配置教程

目录 前言一、IntelliJ安装二、使用配置总结 前言 IntelliJ IDEA Ultimate是一款功能强大的Java集成开发环境&#xff08;IDE&#xff09;。它提供了丰富的功能和工具&#xff0c;可以帮助开发人员更高效地编写、调试和部署Java应用程序。注&#xff1a;已在CentOS7.9和Ubuntu…

带大家来认识下SUMIF函数

如果您需要在Excel表格中对特定条件下的数据进行求和&#xff0c;那么SUMIF函数是一个非常有用的工具。SUMIF函数允许您在满足指定条件的情况下&#xff0c;将符合条件的单元格的值相加起来。在本文中&#xff0c;我们将向您介绍如何使用SUMIF函数来处理您的表格数据。 如下图…

想定制鞋子?先给脚部建模吧!

最近灌篮高手的电影正在火热上映中&#xff0c;湘北大战山王的比赛从漫画搬上了大荧幕&#xff0c;看得人热血沸腾&#xff0c;直呼“爷青回”&#xff0c;恨不得马上换上球衣球鞋&#xff0c;再去球场上挥汗如雨一番。 灌篮高手 同时NBA的季后赛也在如火如荼的进行中&#xf…

Cmake学习记录(九)--使用Cmake交叉编译Android .so库

文章目录 一、前言二、使用NDK进行编译的相关代码四、使用交叉工具链进行编译四、参考链接 一、前言 目前Android编译.so的话使用Android Studio比较简单&#xff0c;但是有时候时候Android Studio的话还需要创建一个Android的项目&#xff0c;这里记录下脱离Android Studio单…