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

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

电子音调发生器

一、实验目的

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)音节与频率的关系

在编写歌曲代码过程中,音高由三位数字组成:个位是表示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 功能 **************/

void ISP_IAP_disable(void)

{

ISP_CONTR = 0X00;

ISP_CMD = 0X00;

ISP_TRIG = 0x00;

}

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

uchar Byte_read(uint byte_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);

}

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

void Byte_program(uint byte_addr, uchar isp_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; //开中断

}

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

void Sector_erase(uint sector_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;

}

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

void EEPROM_write(uint addr, uchar in_data)

{

Sector_erase(addr);

Byte_program(addr,in_data);

}

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

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

相关文档
最新文档