致谢
经过数多月的设计,本毕业设计已经完成。
通过本次毕业设计,使我对单片机的了解进一步加深,无论在硬件还是在软件方面使我对电子产业都有了更深的了解,也使我拥有了查阅资料和解决设计过程中遇到的实际问题的能力,这些都将成为我以后工作道路上不可或缺的经验。
首先,感谢一些专家学者等同志的专著文献和网上的一些发表资料。
其次,感谢系里的领导和老师们,感谢他们在毕业设计论文阶段对自己的严格要求和关心支持。
还要感谢所有帮助过自己的同学们,与他们的讨论和交流给了自己很多有益的启迪,对自己掌握学科知识、完成设计任务和论文写作给予了很大帮助。
最后感谢本人的设计论文指导老师。本设计论文是在他悉心指导下完成了,老师特别注重工作方法、工作方向的指导,使自己的工作能力得到了很大的提高。指导老师严谨的治学态度,谦逊和蔼的风范对自己产生的深远影响,使自己受益终生。他严谨的治学态度和宽厚、坦诚的人生原则,为自己所深深敬佩。衷心地感谢老师的悉心指导。并对我以后走向工作岗位还是很受帮助的,他的精神将激励着我不断的成长。
参考文献
[1] 张齐,朱宁西.单片机系统设计与开发[M].广州:华南理工大学出版社.2008:
16-41,199-202.
[2] 谭浩强. C语言程序设计[M]. 北京:清华大学出版社.2000:14-21,87-91.
[3] 宋杰 ,汪志宏, 江敏.微机原理及接口技术设计[M].机械工业出版社.2005-4.
[4] 孙涵芳.MCS-51系列单片机原理及应用.北京:北京航空航天大学出版
社.1996:184-190.
[5] 谢嘉奎.电子线路[M]. 北京:高等教育出版社.2003:91-100.
[6] 马忠梅等.单片机的C语言应用程序设计[M].北京航空航天大学出版社.2006. [7] 赖麒文.C语言开发环境实物与设计[M].北京:科学出版社.2002.
附录
#include
#define uchar unsigned char //宏定义 #define uint unsigned int //宏定义 uchar STH0; //定时器计数初值 uchar STL0;
bit FY=0; //放乐曲时FY=1,电子琴弹奏时FY=0 uchar Song_Index=0,Tone_Index=0; //放音乐的参数 uchar k, key;
sbit SPK=P3^7 ; //定义蜂鸣器端口 sbit LED1=P1^0 ; //LED1端口定义 sbit LED2=P1^1 ; //led2端口定义
uchar code DSY_CODE[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71};
uchar code Song[][50]= //歌曲的旋律
{ {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,4,5,5,5,5,6,5,3,5,3,2,1,5,6,5,3,3,2,1,1,-1},
{3,2,1,3,2,1,1,2,3,2,1,2,3,1,3,4,5,3,4,5,5,6,5,3,5,3,2,1,3,2,1,1,-1}, {10,10,10,9,10,9,10,9,9,6,6,7,8,9,8,7,6,5,6,-1},
{10,10,10,9,10,13,12,13,12,12,9,9,10,11,12,11,10,9,8,10,10,-1}, {13,14,13,12,12,10,12,10,12,9,13,12,10,9,10,10.-1},
{9,13,13,13,8,13,13,13,13,14,15,14,13,14,13,14,10,10,-1}, {13,14,13,12,12,10,12,10,12,13,14,13,14,13,14,10,-1}, {9,13,13,13,8,13,13,13,13,14,15,14,13,13,14,12,13,-1}, {5,5,10,9,8,5,5,5,5,10,9,8,6,6,6,11,10,9,6,-1}, {6,12,12,11,9,10,8,5,5,10,9,8,5,5,5,10,9,8,6,-1}, {6,6,11,10,9,12,12,12,12,13,12,11,9,8,10,10,10,-1},
{10,10,10,10,12,8,9,10,11,1,11,11,11,10,10,10,10,10,9,9,8,9,12,12,12,11, 9,8,-1}, {13,13,8,13,13,13,13,14,15,14,13,14,13,14,10,10,13,14,13,12,12,10,12,10,
12,13,14,13,14,13,14,10,9,13,13,13,8,13,13,13,13,14,15,14,13,13,14,12,13,-1},
{6,6,11,10,9,12,12,12,12,13,12,11,9,8,10,10,10,10,10,10,10,12,8,9,10,11,11,11,11,11,10,10,10,10,10,9,9,8,9,12,12,12,11,9,8,-1},
{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,-1} };
uchar code Len[][50]= //上面对应的节拍,间隔时间 {{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,2,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,1,1,2,1,1,1,1,0,1,1,0,1,1,0,1,1,2,1},
{1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,0,1,1,3,1,-1}, {0,1,1,0,1,1,2,1,1,0,1,1,0,1,1,2,-1}, {0,1,1,2,0,1,1,0,1,1,0,1,1,0,1,1,2,1,-1}, {0,1,1,0,1,1,2,1,1,0,1,1,0,1,1,4,-1}, {0,1,1,2,0,1,1,0,1,1,0,1,1,0,1,4,-1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1},
{1,1,2,0,1,1,0,1,1,0,1,1,0,1,1,2,1,0,1,1,0,1,1,2,1,1,0,1,1,0,1,1,4,0,1,1,2,0,1,1,0,1,1,0,1,1,0,1,4,-1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1} };
/*音符与计数值班对应表*/ uint code tab[]=
{0,63628,63835,64021,64103,64260,64400,64524, 64580,64684,64777,64820,64898,64968,65030, 65058,65110,65157,65178,65217,65252,65283 };
void delay1 (uint ms) //播放歌曲时实现节拍的延时函数 {
uchar t;
while (ms--) for (t=0;t<120;t++); }
/*键消抖延时函数*/ void delay(void) {
uchar i;
for (i=300;i>0;i--); }
/*键扫描函数*/
uchar getkey(void) {
uchar scancode,tmpcode; if ((P0&0xf0)==0xf0) return (0); scancode = 0xfe;
while((scancode&0x10)!=0) //逐行扫描 {
P0=scancode; //输出行扫描码 if((P0&0xf0)!=0xf0) //本行有键按下 {
tmpcode = (P0&0xf0)|0x0f;
/*返回特征字节码,为1的位即对应于行和列*/
return((~scancode)+(~tmpcode)); }
else scancode=(scancode<<1)|0x01; //行扫描码左移一位 } }
/*外部中断0,这里是弹唱按键*/ void EXO_IXT() interrupt 0 {
FY=0;LED1=1;LED2=0; }
/*外部中断线,这里是播放按键*/ void EX1_INT() interrupt 2 {
FY=1;LED1=0;LED2=1; }
/*定时器0中断服务子程序*/
void time0_int(void) interrupt 1 using 0 {
/*设置计数初值*/ TH0 = STH0; TL0 = STL0;
SPK=!SPK; //反相,产生输出脉冲*/ P2=DSY_CODE[k]; }
void main(void) { LED1=1; LED2=0; P2=0x3f; IE=0x87; TMOD=0x01; IT0=1; IT1=1; while(1) {
P0=0xf0; //发全0列扫描码 if((P0&0xf0)!=0xf0) //若有键按下 {
delay(); //延时去抖动
if((P0&0xf0)!=0xf0) //延时后再判断一次,去除抖动影响 {
key=getkey(); //调用键盘扫描函数
switch(key) //根据获取的按键位置得到K值 {
case 0x88: