【IoT】智能小产品:简易电子琴设计

news2024/11/20 16:27:49

说明

随着电子技术的发展,电子技术正在逐渐改善着人们的学习、生活、工作,因此开发本系统希望能够给人们多带来一点生活上的乐趣,电子技术与音乐的结合不断加深。

由此而产生的电子琴在这种形势下,因其体积小,易于携带,经济适用,对初学者,尤其对识谱的人来说是很容易弹奏的,一首简单的曲子灵感好的人甚至不用很多的练习和教师的指导就能很快的弹奏出来。是一般家庭都能承受得了的经济投入,而且电子琴键盘操作直观易于掌握。

这样就强烈地激发了学习者的学习兴趣,迅速地提高了电子琴的普及率。电子琴使用简单。深受广大音乐爱好者推崇。

设计电子琴包含的知识基本上覆盖了模拟电子技术基础、数字电子技术基础、EDA技术、电子线路、单片机基础以及接口技术课程的重要章节。

采用集成电路设计,基于stc89c52单片机设计一款简易的电子琴,采用4*4距阵键盘,鉴于传统电子琴可以用键盘上的“k0”到“k16”键演奏从低So到高DO等16个音,从而可以用来弹奏喜欢的乐曲。

硬件设计

系统组成及总体框图

由单片机控制电子琴,单片机工作于约11.0592MHZ时钟频率,使用其定时/计数器T0,工作模式为1,改变计数值TH0和TL0可以产生不同频率的脉冲信号有七首内置音乐。

该设计具有16个音节的键盘节拍300ms,用户可以根据乐谱在键盘上进行演奏,音乐发生器会根据使用者的弹奏,通过扬声器将音乐播放出来。

由于本例实现的音乐发生器是由使用者通过键盘输入弹奏乐曲的,所以节拍由使用者掌握,不由程序控制。用单片机产生的音频脉冲直接驱动扬声器并不能产生所要实现的音乐,因此采用蜂鸣器来构成发声。

 

STC89C52

功能特性: STC89C52是一种低功耗、高性能CMOS8位微控制器,具有 8K 在系统可编程Flash 存储器。在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。

具有以下标准功能: 8k字节Flash,512字节RAM, 32 位I/O 口线,看门狗定时器,内置4KB EEPROM,MAX810复位电路,2个16 位定时器/计数器,一个6向量2级中断结构,全双工串行口。另外 STC89X52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。

空闲模式下,CPU 停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。最高运作频率35MHz,6T/12T可选。

硬件各模块原理

STC89S52最小系统

单的上电复位电路由电容和电阻串联构成,如图所示。 上电瞬间,由于电容两端电压不能突变,则相当于电容短路即RST 引脚电压端为VR 为VCC,随着 对电容的充电, RST 引脚的电压呈指数规律下降。

经过时间t1 后,VR 降为高电平所需电压的下限3.6V,随着对电容充电的进行,VR 最后将接 近0V。为了确保单片机复位,t1 必须大于两个机器周期的时间,机器周期取决 于单片机系统采用的晶振频率,图(a)中,R 不能取得太小,典型值10kΩ;t1 与RC 电路的时间常数有关,由晶振频率和R 可以算出C 的取值。

 

STC89S52模块电路原理图

单片机主程序模块通过对键盘扫描程序信号的读取,在通过对应的表,取出定时器初始值以产生不同的声音信号。在这一过程中,对声音信号是通过中断程序进行控制。

键盘扫描模块电路原理图

对键盘扫描电路的扫描方式有行扫描法和线反转法,在此次程序编写中,采用行扫描法,通过在p1_0,p1_2,p1_4,p1_6上循环送出0扫描信号,p1_1,p1_3,p1_5,p1_7输入按键上的高低电平信息给单片机,经处理程序,判断出是哪个开关按下,并送主程序以实现功能。

 

蜂鸣器电路原理图

发声部分采用有源蜂鸣器来实现“多来米发索拉西”的效果,实现音乐的播放。而且蜂鸣器的程序控制方便。

整体电路图

 

软件设计

   本软件设计关键是要实现一种由单片机控制的简单音乐发生器,它由16个音节组成的的键盘,用户可以根据乐谱在键盘上进行演奏,音乐发生器会根据用户的弹奏,将音乐播放出来。

音乐相关知识

   乐音听起来有的高,有的低,这就叫音高,音高是由发音物体振动频率的高低决定的,频率高声音就高,频率低声音就低,不同音商的乐音是用C、D、E、F、G、A、B表示的,这7个字母就是乐音的音名,它们一般依次唱成DO、RE、MI、FA、SO、LA、SI,这是唱曲时乐音的发音,所以叫唱名。

音持续时间的长短即时值,一般用拍数表示,休止符表示暂停发音。

一首音乐是由许多不同的音符组成的,而每个音符对应着不同的频率,这样就可以利用不同频率的组合,加以与拍数对应的延时,构成音乐。

如何用单片机实现音乐的节拍

  除了音符以外,节拍也是音乐的关键组成部分。

   节拍实际上就是音持续时间的长短,在单片机系统中可以用延时来实现,如果1/4拍的延时是0.4秒,则1拍的延时是1.6秒,只要知道1/4拍的延时时间,其余的节拍延时时间就是它的陪数。如果单片机要自己播放音乐,那么必须在程序设计中考虑到节拍的设置,由于本例实现的音乐发生器是由用户通过键盘输入弹奏乐曲的,所以节拍由用户掌握,不由程序控制。对于不同的曲调我们也可以用单片机的另外一个定时/计数器来完成。音乐的音拍,一个节拍为单位(C调)具体如下表:

 

如何用单片机产生音频脉冲

了解音乐的一些基本知识后可知,产生不同频率的音频脉冲即能产生音乐,对于单片机而言,产生不同频率有脉冲非常方便,可以利用它的定时/计数器来产生这样的方波频率信号,因此,需要弄清楚音乐中的音符和对应的频率,以及单片机定时计数的关系。

在本实验中,单片机工作于12MHZ时钟频率,使用其定时/计数器T0,工作模式为1,改变计数值TH0和TL0可以产生不同频率的脉冲信号,在此情况下,C调的各音符频率与计数值T的对照如下表:

 

系统总体功能流程图

该程序设计思路比较清晰既从开始到声明变量与函数再到读取按钮开关,判断是否按下,然后就是一个一个按钮的动作。其主程序如下:  

                             

按键子程序流程图如下:

 

 

系统调试

  电路调试是整个系统功能否实现的关键步骤,我们将整个调试过程分为三大部分:硬件调试、软件调试和综合调试。

硬件调试

硬件调试主要是针对单片机部分进行调试。

在上电前,先确保电路中不在断路或短路情况,这一工作是整个调试工作的第一步,也是非常重要的一个步骤。在这部分调试中主要使用的工具是万用表,用来完成检测电路中是否存在断路或者短路情况等。注意焊点之间,确保焊点没有短接在一起,同时注意焊点的美观,确保没有开路以及短路的现象出现。

在确保硬件电路正常,无异常情况(断路或短路)方可上电调试,上电调试的目的是检验电路是否接错,同时还要检验原理是否正确,在本次设计中,上电调试主要键盘单片机控制部分、和音频转换电路硬件调试。

键盘单片机控制部分调试:上电后,随机按动键盘可以发现各个按键对应的音正确。

软件调试

    整个程序是一个主程序调用各个子程序实现功能的过程,要使主程序和整个程序都能平稳运行,各个模块的子程序的正确与平稳运行必不可少,所以在软件调试的最初阶段就是把各个子程序模块进行分别调试。

 

程序清单

 

#include"reg52.h"
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit SPK = P2^3;		//蜂鸣器
sbit led1=P2^0;			 //绿灯
sbit led2=P2^1;			 //红灯
sbit K2=P3^2;			 //内部歌曲选择
sbit K1=P3^3; 			//播放和停止键
uchar Song_Index=0,Tone_Index=0;	//当前音乐段索引,音符索引
uchar code HI_LIST[]={208,211,216,220,224,226,229,232,233,236,238,239,241,242,244,244};	   //存放计时器高八位
uchar code LO_LIST[]={21,8,5,16,12,4,13,10,20,3,8,28,2,23,5,27};						   //存放计时器低五位节
//三段音乐的音符,表示每个音符位于哪个度,一共七首音乐
uchar code Song[][100]=
{
	{1,2,3,1,1,2,3,1,3,4,5,3,4,5,5,6,5,3,5,6,5,3,5,3,2,1,2,1,-1},
	{3,3,3,4,5,5,5,5,6,5,3,5,3,2,1,5,6,5,3,2,1,1,-1},
	{3,2,1,3,2,1,1,2,3,1,1,2,3,1,3,4,5,3,4,5,5,6,5,3,5,3,2,1,3,2,1,1,-1},
	{3,3,4,3,6,5,3,3,4,3,7,6,3,3,10,8,6,5,4,9,9,8,6,7,6,-1},
	{9,9,9,9,7,9,5,10,9,9,9,9,9,7,6,5,7,6,6,7,9,9,9,7,7,6,5,5,6,7,5,5,3,2,3,2,9,9,9,9,7,6,5,10,9,9,4,5,6,5,6,7,6,5,5,-1},
	{5,5,5,7,9,9,9,9,10,10,11,9,8,8,10,10,7,7,7,7,6,6,6,6,9,9,5,5,5,7,9,9,9,9,10,10,11,9,8,8,8,10,7,7,7,7,6,6,6,7,5,-1},
	{9,10,10,9,9,7,9,10,10,9,9,10,9,7,6,6,7,9,7,6,7,5,10,9,10,9,7,10,9,9,9,7,6,5,5,5,6,7,5,-1}
};
//三段音乐的节拍,表示每个音符的时间
uchar code Len[][100]=
{
	{1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,2,1,2,-1},
	{1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,2,2,-1},
	{1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,1,2,1,1,2,2,-1},
	{1,1,2,2,2,4,1,1,2,2,2,4,1,1,2,2,2,2,3,1,1,2,2,3,4,-1},
	{1,1,1,1,1,2,1,1,2,1,1,1,1,1,2,1,1,2,1,1,1,1,2,1,1,1,1,2,1,1,2,1,1,1,1,1,3,1,1,1,1,2,1,1,1,2,1,2,1,1,1,2,1,1,2,2,-1},
	{1,1,1,1,1,1,1,1,1,2,1,3,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,3,1,1,1,1,1,1,1,1,1,1,1,1,2,-1},
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,-1}
};
uint FreqTemp;
unsigned int code Freqtab[] = { //定时半周期的初始值
     64021,64103,64260,64400,      //低音3 4 5 6
     64524,64580,64633,64723,      //低音7,中音1 2 3
     64820,64898,64968,65030,      //中音4 5 6 7
     65058,65110,65157,65178};     //高音1 2 3 4

uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e}; //七段数码管显示码
void DelayMS(uint ms)//毫秒延时
{
	uchar t;
	while(ms--) for(t=0;t<120;t++);
}
//外部中断0用于切换歌曲和停止播放
void EX0_INT() interrupt 0
{
	SPK=1;
	TR1=0;	//播放结束或者播放中途切换歌曲时停止播放
	DelayMS(20);
	if(K2==0)
	{
		Song_Index=(Song_Index+1)%7;	//跳到下一首的开头
		Tone_Index=0;
		P0=DSY_CODE[Song_Index+1]; 		//数码管显示当前音乐段号
	}
	
}
//外部中断1用于控制播放内置音乐
void EX1_INT() interrupt 2
{
		P0=DSY_CODE[Song_Index+1];
	 	led1=1;			   //green off
		TR1=1;				//开始播放
		led2=0;				 //red 	on
		Tone_Index=0;		//从第0个音符开始
		//若切换音乐段会触发外部中断,导致TR1=0,播放也会停止
		while(Song[Song_Index][Tone_Index]!=-1&&TR1==1)
		{
			DelayMS(300*Len[Song_Index][Tone_Index]);	//播放延时(节拍)
			Tone_Index++;		//当前音乐段的下一音符索引
		}
		TR1=0;
		SPK=1;
		led2=1;			//停止播放 red off
}
//定时器1中断函数  播放内置音乐
void T1_INT(void) interrupt 3
{
	TL1=LO_LIST[Song[Song_Index][Tone_Index]];
	TH1=HI_LIST[Song[Song_Index][Tone_Index]];
	SPK=~SPK;
	
}
//定时器0中断函数  按键音
void T0_INT(void) interrupt 1
{
     TL0 = FreqTemp;                //载入定时半周期的初始值
     TH0 = FreqTemp >> 8;
     SPK = ~SPK;                    //发音
}


uchar Keyscan(void) 
{ 
     uchar i, j, temp, Buffer[4] = {0xfe, 0xfd, 0xfb, 0xf7}; 
     for(j = 0; j < 4; j++) {    //循环四次,扫描四行
       P1 = Buffer[j];           //在低四位分别输出一个低电平
       _nop_(); 
       temp = 0x80;              //计划先读出P1.7位
       for(i = 0; i < 4; i++) { //循环四次,检查四列
         if(!(P1 & temp)) {      //从高四位,截取1位
           return (i + j * 4); //返回取得的按键值 
         }
         temp >>= 1;             //换右边一位
     } }
     return 16;                  //没有键按下就返回16
} 
void Display(uchar i)
{								 //数码管显示当前按键以及当前播放音乐序号
	P0=	DSY_CODE[i];
}
void main()
{
	uchar Key_Value = 16, Key_Temp1, Key_Temp2;//读出的键值 
	TMOD = 0x01;                   //T0定时方式1 T1方式0
	ET0 = 1;                       //允许T0中断
	ET1 = 1; 					   //允许T1中断
	EX0 = 1;                       //允许X0中断
	EX1=1;						    //允许X1中断
	EA = 1;						   //开总中断
	IT0=1;							//下降沿触发
	IT1 = 1; 						//下降沿触发
	IP=0x09;						//中断优先级,定时器1高优先,外部中断1高优先
	TR1=0;							//定时器1初始关闭
	while(1)
	{
		TR0 = 0;                     //暂不发音
		SPK=1;						 //蜂鸣器置高
		if(TR1==0)
		{
			led1=0;					  //green on
	       Key_Temp1 = Keyscan();       //读入按键
	       if(Key_Temp1 != 16&&TR1==0) {        //有键按下
		         Display(Key_Value);        //显示键值、延时消抖 
		         Key_Temp2 = Keyscan();     //再读一次
		         if (Key_Temp1 == Key_Temp2) {//两次相等
			           Key_Value = Key_Temp1; //就确认下来
			           FreqTemp = Freqtab[Key_Value]; //根据键值,取出定时半周期的初始值
			           Display(Key_Value);      //显示
			           TR0 = 1;                 //启动定时器,发音
			           while (Keyscan() < 16); //等待释放
			           SPK = 1;                 //停止发音
					} 
			}
		 }
	}
}

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

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

相关文章

芯科EFRBG22C112 empty工程创建

目录 1.使用工具 2.创建工程 2.1进入welcome,选择芯片&#xff0c;点击start ​编辑 2.2选择sdk4.2.0版本 2.3点击Create New Project 2.4同步步骤创建引导程序bootloader-apploader 3.遇到问题 1.使用工具 ARM仿真器 EFR32BG22C112芯片开发板 pc 使用ARM仿真器连接BG22…

PMP考试多少分算通过?

PMP 是没有具体分数的&#xff0c;只有等级&#xff0c; PASS 就是通过了这张成绩单就是 PASS&#xff0c;3A。主要看头部这里&#xff0c;PASS 就是通过了&#xff0c;FAIL 就是没通过。至于说的 3A&#xff0c;2A1T 啥的&#xff0c;是对应的每个模块的成绩&#xff0c;PMP 的…

【leetcode - 基础】编程能力( 4 / 20天 )

目录 Day - 1 896. 单调数列 - 简单ac 28. 找出字符串中第一个匹配项的下标 - KMP 1、kmp模板 2、java api Day - 2 110. 平衡二叉树 - 递归 1、自顶向下 - 暴力 459. 重复的子字符串 - 暴力 Day - 3 150. 逆波兰表达式求值 - 栈 后缀表达式 66.加一 - 模拟 Day…

Tensorflow 基础与实战

目录 一、线性回归实现 1.1 数据加载与查看绘图 1.2 模型建立、训练与预测 二、神经网络实现 2.1 数据加载与查看绘图 2.2 模型建立、训练与预测 三、逻辑回归实现 3.1 数据加载与查看绘图 3.2 模型建立、训练与预测 四、softmax分类 4.1 数据加载 4.2 数据归一化 …

ReadyAPI x64bit 3.43.0 Crack

ReadyAPI 允许团队在一个集中的界面中创建、管理和执行自动化的功能、安全和性能测试——为敏捷和 DevOps 软件团队提高 API 质量。 ReadyAPI 在单一平台上提供三个模块&#xff1a; 在ReadyAPI 测试模块中&#xff0c;您创建功能测试以验证您的服务是否按预期工作。您可以使用…

高频数组算法

1.二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], target 9 输…

程序员的职业生涯个人规划(附上学习资料)

目录 前言 1.程序员的规划 2.程序员的进化路径 3.IT行业的难度 4.你的选择 5.再谈谈资本、工具人和内卷 总结&#xff1a; 前言 今天不讲技术也不讲干货&#xff0c;来聊一聊程序员职业生涯的个人规划。希望对不管是想入门的还是已经在这条路上的朋友能有一个帮助。 1.程…

opencv之直方图绘制及均衡化

直方图均衡化优势&#xff1a;增强图像对比度&#xff0c;使对比度较低的局部区域获得高对比度。当图像非常暗或者非常亮&#xff0c;并且背景和前景之间的差异非常小时&#xff0c;此方法非常有效&#xff0c;能够解决暴露过度或暴露不足的问题。直方图均衡化缺陷&#xff1a;…

多彩的书写工具,画图写字更好看,米家液晶小黑板多彩版上手

平时临时记些信息&#xff0c;或者是教小朋友认字的时候&#xff0c;液晶小黑板都是特别实用的工具&#xff0c;我之前就用过米家液晶小黑板&#xff0c;最近我发现米家新出了一款彩色笔迹的小黑板&#xff0c;书写效果更加好看&#xff0c;比以前单色款的更好用。 这款米家液晶…

【技术分享】MA21日均线交易策略

文章目录1.前言1.1.相关术语1.2.MA均线系统设置分类1.3.斐波那契数列2.MA21日均线2.1.MA21日均线2.2.MA21日均线交易策略2.3.MA21日均线案例分析1.前言 1.1.相关术语 空头市场&#xff08;Bear Market&#xff09;&#xff1a;亦称熊市&#xff0c;指价格长期呈 下跌 趋势的证…

操作系统权限提升(十)之系统错误配置-计划任务提权

系列文章 操作系统权限提升(一)之操作系统权限介绍 操作系统权限提升(二)之常见提权的环境介绍 操作系统权限提升(三)之Windows系统内核溢出漏洞提权 操作系统权限提升(四)之系统错误配置-Tusted Service Paths提权 操作系统权限提升(五)之系统错误配置-PATH环境变量提权 操作…

VUE3.0学习

一、父子传值 父组件向子组件传值和vue2.0相比区别不大&#xff0c;区别在于api的使用&#xff0c;让接收参数的写法多样化。父组件::::: <template><div class"about"><div><main><TheWelcome :info"parMsg"/></main>…

【react】理解Fiber

FiberFiber概念结构Fiber 树的遍历是这样发生的【深度遍历】。window.requestIdleCallback()requestAnimationFrameFiber 是如何工作的结论有react fiber&#xff0c;为什么不需要vue fiberFiber 概念 JavaScript引擎和页面渲染引擎两个线程是互斥的&#xff0c;当其中一个线…

12月 被大厂以“人员优化”的名义 无情的辞退了...

前几天&#xff0c;一个认识了好几年在大厂工作的测试员朋友&#xff0c;年近30了&#xff0c;却被大厂以“人员优化”的名义无情被辞&#xff0c;据他说&#xff0c;有一个月散伙饭都吃了好几顿…… 在很多企业&#xff0c;都有KPI考核&#xff0c;然后在此基础上还会弄个“…

IB EE 学习干货,从选学科/课题/写稿/对稿/交稿几个方面入手分享

本文从选学科&#xff0c;选课题&#xff0c;写稿&#xff0c;对稿&#xff0c;交稿几个方面入手分享。关于不同学科的EE&#xff0c;本文涵盖了数学和物理EE&#xff08;因为我们猜很多同学们都选了这两个学科的EE&#xff09;。 文中分享的学习方法都是我们从个人经历出发&am…

微服务 @SentinelResource 服务网关

微服务 SentinelResource 服务网关SentinelResourceFeign整合Sentinel什么场景下需要Feign集合Sentinel呢&#xff1f;服务网关为什么需要网关网关组件Gateway快速入门什么是Gateway操作示例自定义路由规则SentinelResource 自定义异常返回是对所有的情况进行统一处理&#xf…

DTC补货实战:从算法到落地

本文作者&#xff1a;凡飞&#xff0c;从快递到快消&#xff0c;一个平凡的供应链算法深耕者。“ 我希望衡量我们ai团队价值的&#xff0c;不是创造了多么精深的算法&#xff0c;而是跨越算法到落地间距离的能力。”近年来随着电商行业从增量市场逐步成长到了存量市场&#xff…

第二章.神经网络—激活函数

第二章.神经网络 感知机存在如何设置合适的权重问题&#xff0c;神经网络的出现就是为了解决感知机存在的问题&#xff0c;神经网络的一个重要性质&#xff1a;它可以自动的从数据中学习到合适的权重参数。 2.1.从感知机到神经网络 1.神经网络示例 1).示意图&#xff1a; 网络…

《技术领导力:程序员如何才能带团队》 读书笔记

技术管理工作 管理者能力 作为技术团队管理者&#xff0c;无论具体管几个人&#xff0c;最好能够拥有以下能力&#xff0c;才能满足各个需求方提出的需求&#xff1a; 深入理解一门或多门编程语言深入理解多种流行的框架系统架构能力强&#xff0c;拥有复杂系统的设计经验积…

Hystrix高可用框架

Hystrix是什么 Hystrix Home,Hystrix是高可用性保障的一个框架。Netflix的API团队从2011年开始做一些提升系统可用性和稳定性的工作,Hystrix就是从那时候开始发展的。在2012年的时候,Hystrix就变得比较成熟和稳定了,Netflix中除了API团队以外,很多其他的团队都开始使用Hy…