单片机课程设计说明书
14 届 电子信息工程 专业 82 班级 题 目 学 号 姓 名 指导教师
二О一六年 十二 月目 录
摘要………………………………………3 一、电子琴的基本原理…………………4 1.设计的内容 2.整体的工作原理 3.发音原理
二、电子时钟的硬件设计………………5 1.硬件原理图 2.键盘设计 3.时钟电路 4.复位电路 5.元件清单 6.数码管显示部分 7.发音部分设计
二十三
日8.硬件调试
三、电子时钟的软件设计………………9 1.键盘扫描程序 2.功能转移程序 3.琴键处理程序 4.自动播放歌曲程序 5.程序流程图 6.设计源程序
四、课程设计总结与指导教师评语…18
摘要
随着社会的发展进步,音乐逐渐成为我们生活中很重要的一部分,有人曾说喜欢音乐的人不会向恶。我们都会抽空欣赏世界名曲,作为对精神的洗礼。本论文设计一个基于单片机的简易电子琴。我们对于电子琴如何实现其功能,如音色选择、声音强弱控制、节拍器、自动放音功能等等也很好奇。
电子琴是现代电子科技与音乐结合的产物,是一种新型的键盘乐器。它在现代音乐扮演着重要的角色,单片机具有强大的控制功能和灵活的编程实现特性,它已经溶入现代人们的生活中,成为不可替代的一部分。本文的主要内容是用ATS51单片机为核心控制元件,设计一个电子琴。以单片机作为主控核心,与键盘、扬声器等模块组成核心主控制模块,在主控模块上设有16个按键和扬声器。本系统运行稳定,其优点是硬件电路简单,软件功能完善,控制系统可靠,性价比较高等,具有一定的实用和参考价值。
关键词:ATS51单片机 音色 节拍器 自动放音
一、电子琴的基本原理
1、本次设计的内容是:
利用所给键盘的16,15,14,13,12,11,10,9七个键,能够发出7个不同的音调,而且8,7,6按键可以自动播放歌曲,要求按键按下时发声,当系统扫描到键盘按下,则快速检测出是哪一个按键被按下,然后单片机的定时器启动,发出一定频率的脉冲,该频率的脉冲经喇叭驱动电路放大滤波后,就会发出相应的音调,p1.7控制着蜂鸣器发出声音,在此基础上我们组又增加了数码管显示部分,当发出1,2,3,4,5,6,7音调时通过p2口控制数码管是分别显示1,2,3,4,5,6,7当播放音乐时数码管分别显示1,2,3 。 2、整体工作原理:
采用ATC52单片机作为主控芯片,设置键盘、蜂鸣器等外围器件,另外还用到一些简单器件如:两位数码管,和NPN型三极管及电阻等。利用按键实现音符和音调的输入;两位的数码管进行被操作的按键显示;用NPN型三极管8550实现低音频功率放大;最后用蜂鸣器发音。ATC52单片机是大规模集成电路技术发展的产物,具有高性能、高速度、体积小、价格低廉、稳定可靠、应用广泛的特点。同时具有强大的控制功能和灵活的编程实现特性,由于本设计主要用于人们娱乐方面,因此在设计上尽量使其安全以及简单易操作。具有经济可行性、技术可行性、实物应用性。
3、发音原理:
若要产生音频脉冲,只要算出某一音频的周期(频率),再将此周期除以2,即为半周期的时间。利用定时器计时半周期时间,每当计时终止后就将P1.7反相,然后重复计时再反相。就可在P1.7引脚上得到此频率的脉冲。利用STCC52的内部定时器使其工作计数器模式(MODE1)下,改变计数值TH0及TL0以产生不同频率的方法产生不同音阶。?
计算举例,频率为523Hz,其周期T=1/523=1912μs,因此只要令计数器计时956μs/1μs=956,每计数956次时将I/O反相,就可得到中音DO(523Hz)。计数脉冲值与频率的关系式是:N=fi÷2÷fr,式中,N是计数值;fi是机器频率(晶体振荡器为12MHz时,其频率为1MHz);fr是想要产生的频率。其计数初值T的求法如下:T=65536-N=65536-fi÷2÷fr
例如:设K=65536,fi=1MHz,求中音DO(261Hz)。T=65536-N=65536-fi÷2÷fr=65536-1000000÷2÷fr=65536-500000/fr,中音DO的T=65536-500000/523=580?
STCC52单片机为12MHZ晶振,中音符与计数T0相关的计数值如表所示:
音符 频 率(HZ) 低1DO #1DO# 262 277 计数值(T值) 63628 63737 音符 #4FA# 中5SO 频率(HZ) 740 784 计数值(T值) 860? 8 低2RE #2RE# 低3MI 低FA #4FA# 低SO? #5SO# 低6LA #6LA# 低7SI 中1DO? #1DO# 中2RE #2RE# 中3MI 中4FA 294 311 330 349 370? 392 415 440 466 494 523 554 587 622 659 698 63835 63928 021 103 185 260 331 400 463 524 580 633 633 884 732 820 #5SO# 中6LA #中6LA# 中7SI 低1DO #1DO#? 高2RE #2RE# 高3MI 高4FA #4FA# 高5SO #5SO# 高6LA? #6LA# 高7SI 831 880 932 968 1046 1109 1175 1245 1318 1397 1490 1568 1661 1760 1865 1967 94934 948 494 65030 65058 65085 65110 65134 65157 65178 65198 65217 65235 65252 65268 65283? 用单片机播放音乐,或者弹奏电子琴,实际上是按照特定的频 率,输出一连串的方波。为了输出合适的方波,首先应该知道音符与频率的关系。
二、电子时钟的硬件设计
1、硬件原理图:
本系统有主控芯片STCC52、发音单元、显示模块、按键模块组成。硬件电路要以单片机作为主控芯片,实现按键输入音符和音调,四位数码管的显示以及低音频功率放大和蜂鸣器发音。 2、键盘设计
单片机系统中,若按键较多时,通常采用矩阵式(也称行列式)键盘。矩阵式键盘由行线和列线组成,按键位于行、列线的交叉点上。显然,在按键数量较多时,矩阵式键盘较之式按键键盘要节省很多I/O口。
矩阵式键盘中,行、列线分别连接到按键开关的两端,行线通过上拉电阻接到+5V上.当无键按下时,行线处于高电平状态;当有键按下时,行、列线将导通,此时,行线电平将由与此行线相连的列线电平决定。这是识别按键是否按下的关键。
图-矩阵键盘
3、时钟电路??
单片机内部具有一个高增益反相放大器,用于构成振荡器。通常在引脚Xl和X2跨接石英晶体和两个补偿电容构成自激振荡器,选择12MHz频率的
石英晶体,补偿电容通常选择20pF左右的瓷片电容。 4、复位电路
单片机小系统常采用上电自动复位和手动按键复位两种方式实现系统的
复位操作。上电复位要求接通电源后,自动实现复位操作。手动复位要求在电源接通的条件下,在单片机运行期间,用按钮开关操作使单片机复位。上电自动复位通过电容C3充电来实现。手动按键复位是通过按键将电阻R1与VCC接通来实现。 5、元件清单
6、 数码管显示部分
当发出1,2,3,4,5,6,7音调时通过p2口控制数码管是分别显示1,2,3,4,5,6,7当播放音乐时数码管分别显示1,2,3 。 7、发音部分设计
如下图所示,发音电路是由蜂鸣器、三极管、上拉电阻构成。由三极管来驱动扬声器发音的,同时加上拉电阻增强驱动电流,提高驱动能力。?
图4发音电路
8、硬件调试
硬件调试主要是针对单片机部分进行的调试。
在上电之前,先确保电路中不存在断路或短路情况,这一工作是整个调试工作的第一步,也是非常重要的一个步骤。在这部分调试中主要使用的工具是万用表,用来完成检测电路中是否存在断路或者短路情况的任务。注意焊点之间,确保焊点没有短接在一起,同时注意焊点的美观,确保没有开路以及短路的现象出现。
在确保硬件电路正常且无异常情况(断路或短路)的情况下方可上电调试,上电调试的目的是检验电路是否接错,同时还要检验原理是否正确,在本次设计中,上电调试主要是检测单片机控制部分、数码管点亮部分、和音频转换电路硬件调试, 三、电子时钟的软件设计 ?1、键盘扫描程序:
检测是否有按键按下,有按键按下则记录按下键的键值,并跳转至功能转移程序;无按键按下,则返回键盘扫描程序继续检测。? 2、功能转移程序:
对检测到的按键值进行判断,是琴键则跳转至琴键处理程序,是功能键则跳转至相应的功能程序,我们设计的功能程序有两种,即音色调节功能和自动播放乐曲的功能。? 3、琴键处理程序:
根据检测到的按键值,查询音调表,给计时器赋值,使发出相应频率的声音。?
4、自动播放歌曲程序:
检测到按键按下的是自动播放歌曲功能键后执行该程序,电子琴会自动播放事先已经存放的歌曲,歌曲播放完毕之后自动返回至键盘扫描程序,继续等待是否有按键按下。 5、程序流程图
图5 流程图
6、设计源程序:
/*说明*************************************************************************
曲谱存贮格式 unsigned char code MusicName{音高,音长,音高,音长...., 0,0}; 末尾:0,0 表示结束(Important)
音高由三位数字组成:个位是表示 1~7 这七个音符 ;十位是表示音符所在的音区:1-低音,2-中音,3-高音;百位表示这个音符是否要升半音: 0-不升,1-升半音。
音长最多由三位数字组成: 个位表示音符的时值,其对应关系是: |数值(n): |0 |1 |2 |3 | 4 | 5 | 6 |几分音符: |1 |2 |4 |8 |16 |32 | 音符=2^n
十位表示音符的演奏效果(0-2): 0-普通,1-连音,2-顿音 百位是符点位: 0-无符点,1-有符点 调用演奏子程序的格式 Play(乐曲名,调号,升降八度,演奏速度); |乐曲名 : 要播放的乐曲指针,结尾以(0,0)结束; |调号(0-11) : 是指乐曲升多少个半音演奏; |升降八度(1-3) : 1:降八度, 2:不升不降, 3:升八度; |演奏速度(1-12000): 值越大速度越快;
#define __SOUNDPLAY_H_REVISION_FIRST__ #include //************************************************************************** #define SOUND_SPACE 4/5 #define uchar unsigned char sbit P2_0 = P2^0; sbit P2_1 = P2^1; sbit P2_2 = P2^2; sbit P2_3 = P2^3; sbit P2_4 = P2^4; sbit P2_5 = P2^5; sbit P2_6 = P2^6; sbit P2_7 = P2^7; sbit BeepIO = P1^7; //定义输出管脚 uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82, 0xf8,0x80,0x90}; unsigned int code FreTab[12] = { 262,277,294,311,330,349,369,392,415,440,466,494 }; //原始频率表 unsigned char code SignTab[7] = { 0,2,4,5,7,9,11 }; unsigned char Sound_Temp_TH0,Sound_Temp_TL0; unsigned char Sound_Temp_TH1,Sound_Temp_TL1; void delay(uchar i) //1~7在频率表中的位置 unsigned char code LengthTab[7]= { 1,2,4,8,16,32, }; //定义普通音符演奏的长度分率,//每4分音符间隔 //音符定时器初值暂存 //音长定时器初值暂存 //************************************************************************** { uchar j,k; for(j=i;j>0;j--) for(k=125;k>0;k--); } void InitialSound(void) { } void BeepTimer0(void) interrupt 1 //音符发生中断 { } //************************************************************************** void Play(unsigned char *Sound,unsigned char Signature,unsigned Octachord,unsigned int Speed) { unsigned int NewFreTab[12]; unsigned char i,j; unsigned int Point,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength; unsigned char Tone,Length,SL,SH,SM,SLen,XG,FD; for(i=0;i<12;i++) { j = i + Signature; if(j > 11) { } else NewFreTab[i] = FreTab[j]; NewFreTab[i]>>=2; if(Octachord == 1) else if(Octachord == 3) j = j-12; NewFreTab[i] = FreTab[j]*2; // 根据调号及升降八度来生成新的频率表 //新的频率表 BeepIO = !BeepIO; TH0 = Sound_Temp_TH0; TL0 = Sound_Temp_TL0; BeepIO = 1; Sound_Temp_TH1 = (65535-(1/1200)*SYSTEM_OSC)/256; // 计算TL1应装入的初值 Sound_Temp_TL1 = (65535-(1/1200)*SYSTEM_OSC)%256; // 计算TH1应装入的初值 TH1 = Sound_Temp_TH1; TL1 = Sound_Temp_TL1; TMOD |= 0x11; ET0 = 1; ET1 = 0; TR0 = 0; TR1 = 0; EA = 1; (10ms的初装值) } NewFreTab[i]<<=2; SoundLength = 0; while(Sound[SoundLength] != 0x00) { } Point = 0; Tone = Sound[Point]; LDiv0 = 12000/Speed; LDiv4 = LDiv0/4; TR0 = 0; TR1 = 1; while(Point < SoundLength) { SL=Tone%10; SM=Tone/10%10; SH=Tone/100; if(SL!=0) { } SLen=LengthTab[Length%10]; //算出是几分音符 XG=Length/10%10; FD=Length/100; LDiv=LDiv0/SLen; if (FD==1) else LDiv=LDiv+LDiv/2; if(XG==0) else LDiv1=LDiv/2; //算出顿音的演奏长度 else LDiv1=LDiv*SOUND_SPACE; //算出普通音符的演奏长度 if(XG!=1) if (SLen<=4) //算出连音音符演奏的长度(多少个10ms) //算出音符类型(0普通1连音2顿音) if (SM==1) CurrentFre >>= 2; if (SM==3) CurrentFre <<= 2; //低音 //高音 //计算出音符 //计算出高低音 //计算出是否升半 // 读出第一个音符和它时时值 // 算出1分音符的长度(几个10ms) // 算出4分音符的长度 Length = Sound[Point+1]; SoundLength+=2; //计算歌曲长度 LDiv4 = LDiv4-LDiv4*SOUND_SPACE; // 普通音最长间隔标准 CurrentFre = NewFreTab[SignTab[SL-1]+SH]; //查出对应音符的频率 Sound_Temp_TH0 = Temp_T/256; Sound_Temp_TL0 = Temp_T%256; TH0 = Sound_Temp_TH0; TL0 = Sound_Temp_TL0 + 12; //加12是对中断延时的补偿 LDiv1=LDiv-LDiv4; } } { } LDiv1=LDiv; LDiv2=LDiv-LDiv1; //算出不发音的长度 if(SL==0) LDiv1=0; if (SL!=0) TR0=1; for(i=LDiv1;i>0;i--) //发规定长度的音 { } while(TF1==0); TH1 = Sound_Temp_TH1; TL1 = Sound_Temp_TL1; TF1=0; if(LDiv2!=0) { } Point+=2; Tone=Sound[Point]; Length=Sound[Point+1]; TR0=0; BeepIO=1; for(i=LDiv2;i>0;i--) //音符间的间隔 { } while(TF1==0); TH1 = Sound_Temp_TH1; TL1 = Sound_Temp_TL1; TF1=0; BeepIO = 1; //************************************************************************** #endif #include //*****************************Music**************************************** unsigned char code sound1[]={ 0x15,0x02, 0x00,0x00 };//1 unsigned char code sound2[]={ 0x16,0x02, 0x00,0x00 };//2 unsigned char code sound3[]={ 0x17,0x02, 0x00,0x00 };//3 unsigned char code sound4[]={ 0x18,0x02, 0x00,0x00 };//4 unsigned char code sound5[]={ 0x19,0x02, 0x00,0x00 };//5 unsigned char code sound6[]={ 0x1A,0x02, 0x00,0x00 };//6 unsigned char code sound7[]={ 0x1B,0x02, 0x00,0x00 };//7 unsigned char key; //小毛驴 unsigned char code Music_Xiao[]={0x15,0x03, 0x15,0x03, 0x15,0x03, 0x17,0x03, }; //找朋友 unsigned char code Music_Zhao[]={0x19,0x03, 0x1A,0x03, 0x19,0x03, 0x1A,0x03, 0x19,0x03, 0x1A,0x03, 0x19,0x02, 0x19,0x03, 0x1F,0x03,0x1B,0x03,0x1A,0x03,0x19,0x02, 0x17,0x02, 0x19,0x03, 0x19,0x03, 0x17,0x03, 0x18,0x03, 0x19,0x03, 0x19,0x03, 0x17,0x02, 0x19,0x03, 0x19,0x03, 0x17,0x03, 0x18,0x03, 0x19,0x03, 0x19,0x03, 0x17,0x02, 0x15,0x03, 0x18,0x03, 0x17,0x03, 0x16,0x03,0x15,0x03,0x16,0x03,0x15,0x02,0x00, 0x00,0x00}; 0x19,0x03, 0x19,0x03, 0x19,0x03, 0x19,0x03, 0x1A,0x03, 0x1A,0x03, 0x1A,0x03, 0x1F,0x03,0x19,0x02, 0x18,0x03, 0x18,0x03, 0x1A,0x03, 0x1A,0x03, 0x17,0x03, 0x17,0x03, 0x17,0x03, 0x17,0x03, 0x16,0x03, 0x16,0x03, 0x16,0x03, 0x16,0x03,0x6A,0x02, 0x19,0x02, 0x15,0x03, 0x15,0x03, 0x15,0x03, 0x17,0x03, 0x19,0x03, 0x19,0x03, 0x19,0x03, 0x19,0x03, 0x1A,0x03, 0x1A,0x03, 0x1A,0x03, 0x1F,0x03,0x19,0x02, 0x19,0x02, 0x18,0x03, 0x18,0x03, 0x1A,0x03, 0x1A,0x03, 0x17,0x03, 0x17,0x03, 0x17,0x03, 0x17,0x03, 0x16,0x03, 0x16,0x03, 0x16,0x03, 0x16,0x03,0x15,0x02,0x00,0x00,0x00, //两只老虎 unsigned char code Music_Two[] ={0x15,0x02, 0x16,0x02, 0x17,0x02, 0x15,0x02, 0x15,0x02, 0x16,0x02, 0x17,0x02, 0x15,0x02, 0x17,0x02, 0x18,0x02, 0x19,0x02, 0x17,0x02, 0x18,0x02, 0x19,0x02, 0x19,0x03, 0x1A,0x03, 0x19,0x02, 0x18,0x03, 0x17,0x02, 0x15,0x02, 0x15,0x02, 0x16,0x02, 0x17,0x02, 0x15,0x02, 0x15,0x02, 0x16,0x02, 0x17,0x02, 0x15,0x02, 0x17,0x02, 0x18,0x02, 0x19,0x02, 0x17,0x02, 0x18,0x02, 0x19,0x02, 0x19,0x03, 0x1A,0x03, 0x19,0x02, 0x18,0x03, 0x17,0x02, 0x15,0x02, 0x17,0x02, 0x0f,0x02, 0x15,0x02, 0x17,0x02, 0x0f,0x02, 0x15,0x02, 0x17,0x02, 0x0f,0x02, 0x15,0x02, 0x19,0x03, 0x1A,0x03, 0x19,0x02, 0x18,0x03, 0x17,0x02, 0x15,0x02, 0x19,0x03, 0x1A,0x03, 0x19,0x02, 0x18,0x03, 0x17,0x02, 0x15,0x02, 0x17,0x02, 0x0f,0x02, 0x15,0x02, 0x17,0x02, 0x0f,0x02, 0x15,0x02,0x00, 0x00,}; //*********************************************************************************** void delayms(unsigned int z) { } void keyscan()//矩阵键盘扫描函数 unsigned int x,y; for (x = z; x>0; x--) for(y=110; y>0; y-- ); { unsigned char x,y; { P0=table[1];P2_7 = 0;delay(5);P2_7 = 1; P0=table[1];P2_6 = 0;delay(5);P2_6 = 1; } Play(sound1,0,3,360); { P0=table[2];P2_6 = 0;delay(5);P2_6 = 1; P0=table[2];P2_5 = 0;delay(5);P2_5 = 1; } Play(sound2,0,3,360); { P0=table[3];P2_5 = 0;delay(5);P2_5= 1; P0=table[3];P2_4 = 0;delay(5);P2_4= 1; } Play(sound3,0,3,360); { P0=table[4];P2_4 = 0;delay(5);P2_4 = 1; P0=table[4];P2_3 = 0;delay(5);P2_3 = 1; } Play(sound4,0,3,360); { break; case 0xd7: key=12; break; case 0xee: key=13; break; case 0xed: key=14; break; case 0xeb: key=15; P3=0xf0; if (P3!=0xf0) { delayms(10); if (P3!=0xf0) { x=P3&0xf0; P3=0x8f; y=P3&0x8f; key=x|y; while(P3!=0x8f); switch (key) { case 0xe7: key=16; P0=table[5];P2_3 = 0;delay(5);P2_3 = 1; P0=table[5];P2_2 = 0;delay(5);P2_2 = 1; } Play(sound5,0,3,360); { P0=table[6];P2_2 = 0;delay(5);P2_2 = 1; P0=table[6];P2_1 = 0;delay(5);P2_1 = 1; } Play(sound6,0,3,360); { P0=table[7];P2_1 = 0;delay(5);P2_1 = 1; P0=table[7];P2_0 = 0;delay(5);P2_0 = 1; } Play(sound7,0,3,360); { P0=table[1];P2_7 = 0;delay(5);P2_7 = 0; P0=table[1];P2_6 = 0;delay(5);P2_6 = 0; P0=table[1];P2_5 = 0;delay(5);P2_5 = 0; P0=table[1];P2_4 = 0;delay(5);P2_4 = 0; P0=table[1];P2_3 = 0;delay(5);P2_3= 0; P0=table[1];P2_2 = 0;delay(5);P2_2 = 0; P0=table[1];P2_1 = 0;delay(5);P2_1 = 0; P0=table[1];P2_0 = 0;delay(5);P2_0 = 0; } Play(Music_Two,0,3,360); { P0=table[2];P2_7 = 0;delay(5);P2_7 = 0; P0=table[2];P2_6 = 0;delay(5);P2_6 = 0; P0=table[2];P2_5 = 0;delay(5);P2_5 = 0; P0=table[2];P2_4 = 0;delay(5);P2_4 = 0; P0=table[2];P2_3 = 0;delay(5);P2_3 = 0; P0=table[2];P2_2 = 0;delay(5);P2_2 = 0; P0=table[2];P2_1 = 0;delay(5);P2_1 = 0; P0=table[2];P2_0 = 0;delay(5);P2_0 = 0; } Play(Music_Xiao,0,3,360); break; break; case 0xbb: key=7; break; case 0xb7: key=8; break; case 0xdd: key=10; break; case 0xdb: key=11; case 0xbd: key=6; { P0=table[3];P2_7 = 0;delay(5);P2_7 = 0; P0=table[3];P2_6 = 0;delay(5);P2_6 = 0; P0=table[3];P2_5 = 0;delay(5);P2_5 = 0; P0=table[3];P2_4 = 0;delay(5);P2_4 = 0; P0=table[3];P2_3 = 0;delay(5);P2_3 = 0; P0=table[3];P2_2 = 0;delay(5);P2_2 = 0; P0=table[3];P2_1 = 0;delay(5);P2_1 = 0; P0=table[3];P2_0 = 0;delay(5);P2_0 = 0; } Play(Music_Zhao,0,3,360); } main() { } InitialSound(); while(1) { } keyscan(); break; break; } } } default: key=88; 四、课程设计总结与指导教师评语 为期一周的单片机课程设计结束了,在老师的悉心指导和我们小组成员的共同努力下,最终完成了这次课程设计的任务。通过本次课设,我学到了不少课本上没有的知识,也锻炼了自己的动手能力,将以前学过的零散的知识串到一起。我的小组课程设计的题目是电子琴设计,在过程中我的硬件和软件开发能力都获得了提高。首先硬件方面,基本了解了电子产品的开发流程和所要做的工作。并设计了外围电路。通过外围电路的设计和搭建的过程,使我对52系单片机的接口有了更深层次的理解,熟悉了一些单片机常用的外围电路引脚和连接方法。在软件方面,通过编写和调试程序,与仿真工具的使用,使我加深了对单片机理解,熟悉了52系列单片机内部的寄存器和编程规则,以及如何控制外围电路。总之,这次的课程设计让我们进步了很多,再次感谢老师的谆谆教导和小组成员的支持,希望我们以后能做得更好! 2.指导教师评语 成绩 指导教师签名
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- huatuo9.cn 版权所有 赣ICP备2023008801号-1
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务