单片机课程设计报告电子琴.docx

上传人:b****6 文档编号:7903763 上传时间:2023-01-27 格式:DOCX 页数:32 大小:201.17KB
下载 相关 举报
单片机课程设计报告电子琴.docx_第1页
第1页 / 共32页
单片机课程设计报告电子琴.docx_第2页
第2页 / 共32页
单片机课程设计报告电子琴.docx_第3页
第3页 / 共32页
单片机课程设计报告电子琴.docx_第4页
第4页 / 共32页
单片机课程设计报告电子琴.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

单片机课程设计报告电子琴.docx

《单片机课程设计报告电子琴.docx》由会员分享,可在线阅读,更多相关《单片机课程设计报告电子琴.docx(32页珍藏版)》请在冰豆网上搜索。

单片机课程设计报告电子琴.docx

单片机课程设计报告电子琴

 

电子音调发生器

一、实验目的

1.了解计算机发声原理。

2.熟悉定时器和键盘扫描电路的工作原理及编程方法。

二、实验完成的功能

1.利用键盘1~7进行音调选择,即按下音符产生对应音调。

2.事先存储三首歌曲,并可进行选择播放。

3.谱曲功能:

通过按键对LCD菜单选项进行选择,进入谱曲界面,通过按键1~7分别输入音高与几分音符类型,由按键输入若干数据完成谱曲。

4.在播放存储歌曲与谱曲播放时,对应音符及其节奏LCD显示对应频谱。

5.在播放音乐时按“返回”键出现返回界面,由键盘按“确认”键选择返回主菜单或循环播放。

三、实验原理

1.音节由不同频率的方波产生,音节与频率的关系如表

(1)所示。

要产生音频方波,只要计算出某一音频的周期(1/频率),然后将此周期除以2,即为半周期的时间。

利用计时器计时此半周期时间,每当计时到后就将输出方波的I/O(P1.7)反相,然后重复计时此半周期时间再对I/O反相,就可在P1.7脚得到此频率的方波。

将P1.7经过驱动电路与蜂鸣器相连,随着P1.7口输出不同频率的方波,蜂鸣器便会发出不同的声音。

音乐的节拍是由延时实现的,如果1拍的时间为0.4秒,1/4拍是0.1秒。

只要设定延时时间,就可得到节拍的时间。

延时实现基本延时时间,节拍值只能是它的整数倍。

每个音节相应的定时器初值计算公式如下:

(1/2)*(1/f)=(12/fose)*(216-x)

即x=216-(fose/24f)

其中,f是音调频率,当晶振fosc=11.0592MHz时,音节“1”相应的定时器初值为x,则可得到x=63777D=F921H,其它的可同样得到。

(1)音节与频率的关系

音调

频率(Hz)

X(HEX)

1

262

F921

2

294

F9E1

3

330

FA8C

4

349

FAD8

5

392

FB68

6

440

FBE9

7

494

FC5B

i

523

FC8F

 

在编写歌曲代码过程中,音高由三位数字组成:

个位是表示1~7这七个音符;十位是表示音符所在的音区:

1-低音,-中音,-高音;百位表示这个音符是否要升半音:

0-不升,-升半音。

音长最多由三位数字组成:

个位表示音符的时值,其对应关系是:

|数值(n):

|0|1|2|3|4|5|6

|几分音符:

|1|2|4|8|16|32|64音符=2^n

十位表示音符的演奏效果(0-2):

0-普通,-连音,-顿音,百位是符点位:

0-无符点,1-有符点。

2.键盘扫描

将单片机P1.0~P1.7(引脚1~8)与键盘上对应引脚相连,其中P1.0~P1.3控制键盘的行,P1.4~P1.7控制键盘的列,这次使用的键盘是4行4列,键盘上的第一行到第四行由8位十六进制代码的低四位控制,即第一行若有键按下,则8位十六进制代码的后四位为0x8,第二行有按键按下,则后四位代码为0x4,依此规律类推;键盘上的第一列到第四列由8位十六进制代码的高四位控制,即第一列若有键按下,则8位十六进制代码的前四位为0x8,第二列有按键按下,则前四位代码为0x4,依此规律类推。

综上所述,可以根据8位十六进制的高四位和低四位数据,分别确定按下的键处于第几行第几列,从而确定按键的位置,实现键盘扫描的功能。

3.LCD显示

根据写命令函数wrcomd和写数据函数wrdata分别控制LCD的命令写入和数据写入。

具体操作方法是由写命令函数wrcomd编程控制数据输入的行列,再由写数据函数wrdata编程写入需要在LCD上显示的数据或应执行的操作,结合两个命令一起控制LCD显示。

四.产品展示

五.实验程序

#ifndef_DRIVEFUTION_H_

#define_DRIVEFUTION_H_

/*********************EEPROM函数*******************/

/**************************************************/

/******************关闭ISP,IAP功能**************/

voidISP_IAP_disable(void)

{

ISP_CONTR=0X00;

ISP_CMD=0X00;

ISP_TRIG=0x00;

}

/*******************字节读***************************/

ucharByte_read(uintbyte_addr)

{

EA=0;//关中断

ISP_CONTR=En_Wait_TIME;//开启ISP/IAP;并送等待时间

ISP_CMD=Read_COM;//送字节读命令字

ISP_ADDRH=(uchar)(byte_addr>>8);//送地址高字节

ISP_ADDRL=(uchar)(byte_addr&0X00FF);//送地址低字节

ISP_TRIG=0X46;//送触发命令字0X46、0XB9

ISP_TRIG=0XB9;

_nop_();

ISP_IAP_disable();//关闭ISP/IAP功能

EA=1;//开中断

return(ISP_DATA);

}

/********************字节编程***********************/

voidByte_program(uintbyte_addr,ucharisp_iap_data)

{

EA=0;//关中断

ISP_CONTR=En_Wait_TIME;//开启ISP/IAP;并送等待时间

ISP_CMD=Prog_COM;//送字节编程命令字

ISP_ADDRH=(uchar)(byte_addr>>8);//送地址高字节

ISP_ADDRL=(uchar)(byte_addr&0X00FF);//送地址低字节

ISP_DATA=isp_iap_data;//送数据进ISP_DATA

ISP_TRIG=0X46;//送触发命令字0X46、0XB9

ISP_TRIG=0XB9;

_nop_();

ISP_IAP_disable();//关闭ISP/IAP功能

EA=1;//开中断

}

/*********************扇区擦除*********************/

voidSector_erase(uintsector_addr)

{

EA=0;//关中断

ISP_CONTR=En_Wait_TIME;//开启ISP/IAP;并送等待时间

ISP_CMD=Dele_COM;//送扇区擦除命令字

ISP_ADDRH=(uchar)(sector_addr>>8);//送地址高字节

ISP_ADDRL=(uchar)(sector_addr&0X00FF);//送地址低字节

ISP_TRIG=0X46;//送触发命令字0X46、0XB9

ISP_TRIG=0XB9;

_nop_();

ISP_IAP_disable();//关闭ISP/IAP功能

EA=1;

}

/*********************写入函数**********************/

voidEEPROM_write(uintaddr,ucharin_data)

{

Sector_erase(addr);

Byte_program(addr,in_data);

}

/*********************EEPROM函数*******************/

/**************************************************/

/***************音乐播放相关子函数*******************/

/****************************************************/

voidInitialSound(void)//初始化定时器

{

BeepIO=0;

Sound_Temp_TH1=(65535-(1/1200)*SYSTEM_OSC)/256;//计算TL1应装入的初值(10ms的初装值)

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;

}

voidBeepTimer0(void)interrupt1//音符发生中断函数

{

BeepIO=!

BeepIO;

TH0=Sound_Temp_TH0;

TL0=Sound_Temp_TL0;

}

/*********************END****************************/

/****************************************************/

/*****************LCD操作子函数**********************/

/****************************************************/

voidwrcomd(charcomd)//写入命令

{

cs=0;_nop_();

rs=0;_nop_();

e=1;_nop_();

rw=0;_nop_();

P0=comd;_nop_();

rw=0;_nop_();_nop_();

rw=1;_nop_();_nop_();_nop_();_nop_();

}

voidwrdata(chardata_wri)//往液晶中写入数据

{

cs=0;_nop_();

rs=1;_nop_();

e=1;_nop_();

rw=0;_nop_();

P0=data_wri;_nop_();

rw=0;_nop_();_nop_();

rw=1;_nop_();_nop_();_nop_();_nop_();

}

voidbmp(chardata_write,introw_start,introw_end,ucharcolumn_start,ucharcolumn_end)//刷屏子函数

//初始化设置,对屏幕清零,默认值,为0,0,8,2,132

{

unsignedchari,j;

intnum_3;

charnum_0=0xb0;

//ucharcolumn_h,column_l;

num_0+=row_start;

for(i=row_start;i

{

num_3=column_end;

wrcomd(num_0);//写入命令设置页,从0页开始,0xb0=10110000;delay(time_def);//设置页

wrcomd(0x10|(0xf0&column_start)>>4);//设置列,先写入高4位再写入低四位

wrcomd(0x00|(0x0f&column_start));

for(j=column_start;j

{

wrdata(data_write);

}

num_0++;

}

}

voiddelay(longinttime_delay)//延时子程序,执行time_delay个_nop_()延时

{

longinti;

for(i=0;i

_nop_();

}

voidwrite_word(char*p_word,intnum,intpos_x,intpos_y,intwidth,intheight)//写汉字/字符子函数

//对应参数数据数组名,数组中位置,行位置,列位置,宽,高

{

charpage;//页号

unsignedinti,j,k,p;

p=(unsignedint)num*2*width;//p确定汉字字模数据初始位置

i=height%8;

k=(i)?

(height/8+1):

(height/8);

page=0xb0+pos_y;

for(i=0;i<2;i++)

{

wrcomd(page);

wrcomd(0x10|(0xf0&pos_x)>>4);

wrcomd(0x00|(0x0f&pos_x));

for(j=0;j

{

wrdata(p_word[j+p]);

}

p=p+width;

page++;

if(page-(unsignedchar)0xb0>7||page-(unsignedchar)0xb0<0)

return;

}

}

/**************************END***********************/

/****************************************************/

/******************键盘扫描函数*********************/

/****************************************************/

/****************判断是否有键盘输入*********************/

bitCheckState(void)//键盘状态判断子函数

{

bitstate=0;

P1=0x0F;//键盘扫描

if(P1!

=0x0F)state=1;//检测是否有按键输入

elsestate=0;

return(state);

}

/******************获取键盘输入值*****************/

ucharGetKeys(void)//键盘值获取子函数

{

ucharcolumn,line;

scan=0xFE;

while((scan&0x10)!

=0)

{

P1=scan;

if((P1&0xF0)!

=0xF0)//line1havekeypressed

{

column=~(P1|0x0F);

line=~(scan|0xF0);

key=column+line;

return(key);

}

elsescan=(scan<<1)|0x01;

}

return(0);

}

/******************应用子函数*****************/

/*********************************************/

voidcsh(void)//初始化,清屏

{

inti;

res=0;

delay(time_def);

delay(time_def);

res=1;

delay(time_def);

cs=0;//片选一直有效

delay(time_def);

delay(time_def);

for(i=0;i<12;i++)//初始命令写入

{

wrcomd(tab1[i]);

delay(time_def);

}

bmp(0,0,8,0,132);

}

voidstart_print(void)//开机显示画面子函数

{

inti,j;

for(i=0;i<4;i++)

{

write_word(star_welcome,i,36+i*16,2,16,16);

if((i+4)<7)

{

write_word(star_welcome,i+4,44+i*16,4,16,16);

if((i+7)<10)

{

write_word(star_welcome,i+7,36+i*16,6,16,16);

}

}

}

write_word(number,10,4+5*16,6,8,16);

for(j=5;j>=0;j--)

{

write_word(number,j,12+5*16,6,8,16);

delay(5000);

}

}

voidmenu_first_symbol(intchoose)//菜单选择符刷新子函数,即“打钩项”

{

bmp(0,0,8,4,18);

write_word(menu_one,20,4,choose*2,16,16);

}

/*********************音乐播放显示函数******************/

/*******************************************************/

voidmusic_display_one(unsignedchars,unsignedintx)//显示最底层子函数

{

inti;

bmp(0,2,8,18+x*16,34+x*16);

for(i=3;i>0;i--)

{

if(s!

=0)

{

write_word(display,1,20+16*x,2*i,16,16);

s=s-1;

}

else

{

write_word(display,0,20+16*x,2*i,16,16);

//delay(200);

}

}

}

voidmusic_display_two(unsignedintp_x)//显示次底层子函数

{

intsign;

sign=mc_size[p_x][0];

if(sign)

{

if(!

size[p_x])

{

sign=0;

mc_size[p_x][0]=sign;

mc_size[p_x][1]=0;

}

else

{

music_display_one(size[p_x],p_x);

mc_size[p_x][1]+=1;

if(mc_size[p_x][1]>3)

size[p_x]-=1;

else

size[p_x]+=1;

}

}

/*************************************/

else

{

bmp(0,2,8,18+p_x*16,34+p_x*16);

write_word(display,2,20+16*p_x,6,16,16);

//delay(500);

}

/************************************/

}

voidmusic_display_three(unsignedintmc)//音符状态置位函数

{

mc_size[mc-1][0]=1;

mc_size[mc-1][1]=1;

size[mc-1]=1;

}

voidmusic_display_four(void)//显示次顶层子函数

{

inti;

for(i=0;i<7;i++)

{

music_display_two(i);

}

}

voidmusic_display_five()//显示顶层子函数

{

inti;

allsize=0;

for(i=0;i<7;i++)

allsize+=mc_size[i][0];

music_display_four();

}

/*

voidmusic_display(void)//显示主函数

{

inti;

for(i=0;i<10;i++)

{

music_display_three(music_code[i]);

music_display_five();

}

while(allsize)

music_display_five();

}*/

voiddisplay_between_musicplay(unsignedinttone)//播放音乐同时显示音符显示界面

{

music_display_three(tone);

music_display_five();

}

/****************************************************/

 

/*********************播放子程序*********************/

voidmusic_play_one(uint*NewFreTab,ucharTone,ucharLength,uintLDiv0,uintLDiv1)

//频率表,音符,音长,12000/Speed,((12000/Speed)/4)-((12000/Speed)/4)*SOUND_SPACE

{

unsignedcharSL,SH,SM,SLen,XG,FD;

uinti,Temp_T,CurrentFre,LDiv,LDiv2,LDiv3;

SL=Tone%10;//计算出音符

SM=Tone/10%10;//计算出高低音

SH=Tone/100;//计算出是否升半

CurrentFre=NewFreTab[SignTab[SL-1]+SH];//查出对应音符的频率

if(SL!

=0)

{

if(SM==1)CurrentFre>>=2;//低音

if(SM==3)CurrentFre<<=2;//高音

Temp_T=65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);//计算计数器初值

Sound_Temp_TH0=Temp_T/256;

Sound_Temp_TL0=Temp_T%2

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 工学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1