(学习日记)2023.4.22

news/2024/10/23 3:40:30/

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


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


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

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	500unsigned 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[]={//音符,时值,//1P,	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,//2M6,	4+2,M5,	2,M6, 4,H1,	4,M5,	4+4+4,M3,	4,M4,	4+2,M3,	2,M4,	4,H1,	4,//3M3,	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,//4H1,	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,//5M5,	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,//6H1,	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,//7H2,	4+4+4,M5,	2,M5,	2,H1,	4+2,M7,	2,H1,	4,H3,	4,H3,	4+4+4+4,//8M6,	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,//9H3,	4+4+4,H3,	4,H6,	4+4,H5,	4,H5,	4,H3,	2,H2,	2,H1,	4+4,P,	2,H1,	2,//10H2,	4,H1,	2,H2,	2,H2,	4,H5,	4,H3,	4+4+4,H3,	4,H6,	4+4,H5,	4+4,//11H3,	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.ppmy.cn/news/118529.html

相关文章

蒸茄子(微波炉版)

茄子先切稍厚片然后在片上划经纬线但不要切断&#xff08;好难控制啊&#xff09; 码碗里加点水&#xff08;一说过凉水&#xff09;防止太干 微波高火10min 微波的时候盐酒醋生抽糖麻油一点水调汁&#xff0c;大蒜切末备用 微波结束取出先拌拌 锅放油烧热倒入调料汁小火烧开加…

计算机作业微波炉工作的原理,微波炉的工作原理和原理图解析

微波炉是利用食物在微波场中吸收微波能量而使自身加热的烹饪器具。在微波炉微波发生器产生的微波在微波炉腔建立起微波电场&#xff0c;并采取一定的措施使这一微波电场在炉腔中尽量均匀分布&#xff0c;将食物放入该微波电场中&#xff0c;由控制中心控制其烹饪时间和微波电场…

各种塑料材质说明,哪些可以加热,哪些可以放入微波炉

什么是塑料 塑料是以单体为原料,通过加聚或缩聚反应聚合而成的高分子化合物(macromolecules),其抗形变能力中等,介于纤维和橡胶之间,由合成树脂及填料、增塑剂、稳定剂、润滑剂、色料等添加剂组成。 塑料分类以及哪些可以加热 通用塑颗粒料有五大品种,即聚乙烯(PE)、聚丙…

谨慎使用微波炉!!

癌细胞最爱吃用微波炉煮热的食物 一定要看 :请大家注意身体!! 癌细胞最爱吃用微波炉煮热的食物 为了自己的健康&#xff0c;请相信以下的论说~~以下的内容摘录自"疾病的形成与防范"一书&#xff0c;作者为洪山本博士 (新加坡营养 学博士) 首先令我们好奇的是何以微…

饭否微波炉

饭否微波炉&#xff0c;一个匿名聊天站 [url]http://chat.fanfouapps.com[/url] 用几百行tornado/python代码写成&#xff0c;性价比很高。

计算机作业微波炉工作的原理,微波炉工作电路原理图及功能图解

分享微波炉的工作电路原理图&#xff0c;微波炉的电路组成与工作原理&#xff0c;家用微波炉基本上都采用箱式结构&#xff0c;一种普及型微波炉电路的电路结构与电路原理图。 微波炉工作电路的原理图 微波炉是一种利用微波加热的现代化烹饪厨具。 用微波炉烹饪食品的最大优点是…

[转]使用微波炉的坏处

去德国的确看到他们国家的家庭中几乎看不到微波炉&#xff0c;大家都知道微波炉的危害之大&#xff0c;所以都不用&#xff0c;女儿告诉我不要再用了&#xff0c;我还不当回事&#xff0c;习惯吃热饭&#xff0c;又懒得蒸&#xff0c;看到下面这篇微波炉的害处&#xff0c;决定…

使用微波炉的十大忌讳(转)

一、忌超时加热&#xff1a;食品放入微波炉解冻或加热&#xff0c;若忘记取出&#xff0c;如果时间超过2小时&#xff0c;则应丢掉不要&#xff0c;以免引起食物中毒。 二、忌将普通塑料容器放入微波炉加热&#xff1a;一是热的食物会使容器变形&#xff0c;二是普通塑 料会放出…