21-FPGA实验-3-QuartusII工程-mySnd2-编制乐谱自动播放
FPGA实验-3-QuartusII工程-mySnd2-编制乐谱自动播放
(2012.4.20)
设学生学号为:11129999,学生操作时以自己实际学号替换。
【实验目的】
本实验在前2个实验的基础上,由学生编写可以弹奏的乐谱,并由硬件自动弹奏。 (1) 学习编制MIF格式的ROM表。
(2) 掌握ROM模块的生成与调用。
(3) 掌握编制乐谱的技艺与能力。
【实验准备】
1与下载线。 实验前QuartusII软件及驱动程序已安装,同时准备好开发板
关于开发板1的更多器件或连接信息,请参见“mySnd1”实验的相关说明。 1. 主要外部连接器件及引脚号
下载电缆
指示灯指示灯指示灯指示灯ASJTAG电源LED2LED3LED4LED5下载,J1下载,J2+5V,JP1USB电源
电源开USB关,SW1B型
JP2LED_B[1],#151LED_B[2],#152LED_B[3],#160LED_B[0],#150
VGAFPGA芯片,U3PS2_DAT_1,#146显示PS2_2EP2C8Q208C8JP4PS2_CLK_1,#145SYSCLK,#23
50MHzRST_B,#129UART晶振,IC2PS2_1BUZZER,#34串行键盘COM1蜂鸣器KEY_B[4],#28KEY_B[0],#130KEY_B[3],#131KEY_B[2],#27KEY_B[1],#132SP1IR按键按键按键按键按键按键红外SW7SW5SW3SW4SW6SW2
2. 更多声音频率的进一步编码与计算
制作Excel表格,可以计算出7个八度,每个八度12个音阶,共84个音阶的声音频率及其半周期长度,使用7位二进制对声音进行编码。设Snd[6:0]为音符编码,则:
Snd[6:4],3位,取值1到7,对应7个八度,其中标准音为第4个八度。
Snd[2:0],3位,取值1到7,对应Do-Re-Mi-Fa-Sol-La-Si共7个自然音。
Snd[3],1位,取值0或1,为0表示正常音,为1时表示升半音。
如1010110(16 进制56H)表示第5个八度的6-La音,再如0111010(16进制3AH)表示第3个八度的升2-Re音。
第 1 页 共 14 页 PS2键盘
3. 各音符的频率与半周期计算
参见文件“音符频率与半周期计算表.xls”,数据如下。 1/121.05946?212音钢琴键白键黑键白键黑键白键白键黑键白键黑键白键黑键白键自然音CDEFGAB简谱1234567DoReMiFaSolLaSi读音
超低频率555862更低频率4110117123低音频率标准频率高音频率更高频率6超高频率us4186设系统时钟为50MHz,声音周期=50M/f,声音半周期=25M/fBAA23超低半周期更低半周期低音半周期中音半周期950619高音半周期525310更高半周期712655超高半周期72超低编号1119121A13141C151D161E17更低编号2129222A23242C252D262E27低音编号3139323A33343C353D363E37标准编号4149424A43444C454D464E47高音编号5159525A53545C555D565E57更高编号6169626A63646C656D666E67超高编号7179727A73747C757D767E77
4. 声音-半周期查找表(tbSndFreq)
硬件通过查找ROM表方式可以取得相应的半周期长度,ROM表的数据最多128项(对应7位声音编码),每项使用20位二进制表示(对应最大的半周期值764451)。
按照Excel表格编制MIF格式的文件,文件命名为tbSndFreq.MIF,内容如下。
第 2 页 共 14 页
5. 乐谱-声音顺序表(tbMusic)
硬件通过查找ROM表方式可以取得乐谱中各个声音的长度与声音编码,ROM表的数据最多128项,每项使用16位二进制表示,高8位对应该声音的播放长度(一般用16进制10对应全音符/一拍时间),低8位为该声音的声音编码,取值11至7F。
【实验
】(设计参考,课后试着去理解代码设计)
1. 模块层次结构
(1) 工程顶层模块mySnd2,调用乐谱节拍控制模块(rjMusic)输出乐谱的当前
时间的声音,再调用声音播放模块(rjSndOut)输出至蜂鸣器; (2) 乐谱节拍控制模块rjMusic通过1毫秒的时间计数器(baseCT)产生基准时
间,进而计算当前音符的小拍长度(beatLen),并通过小拍计数器(playCT)
完成小拍计时,小拍完成后顺序(romAddr)从乐谱(tbMusic)中取得下一
音符的信息(romQ),其中包含声音编码与小拍长度。
(3) 模块tbMusic为ROM查找表,128位长,16位宽,通过QuartusII软件自动
生成,生成时指定数据来源为tbMusic.MIF。
(4) 声音播放模块rjSndOut根据当前声音(Snd)从声音半周期表(tbSndFreq)
取得保持时间(tone),由计数器(fCT)计时,计时完成后翻转蜂鸣器的振
荡信号,产生相应频率的声音。
第 3 页 共 14 页
U2,rjSndOutbaseCTromAddrKEY_B
[4:0]fCTtbMusic.MIFbeatLentbMusicSYSCLKtoneBUZZER
playCTromQRST_BtbSndFreq.MIFSndtbSndFreqU1,rjMusic
rjSnd2
【实验步骤】
一、 运行QuartusII软件(略)
二、 建立QuartusII工程
建立一个新的QuartusII工程(点击菜单“File | New Project Wizard”)。 1. 介绍页面(略)
2. 向导1,工程名称:mySnd2,工程目录:E:\11129999\Qts\mySnd2
3. 向导2,文件选择:略过(当前还没有任何现成的设计源文件) 4. 向导3,器件选择:EP2C8Q208C8
5. 向导4,EDA工具选择:略过(外部辅助设计工具) 6. 向导5,信息汇总:检查目录与工程名,检查器件型号
三、 设计电路代码
按照【实验设计】中的设计结果,在QuartusII软件上输入硬件程序代码。 1. 创建新的ROM表文件(File | New | Text File,tbSndFreq.MIF),输入查找表数据
并保存到工程的src子目录下。
MIF代码(tbSndFreq.MIF) 说明 DEPTH=128; 允许从复WIDTH=20; 制粘贴。 ADDRESS_RADIX=HEX; DATA_RADIX=DEC;
CONTENT
BEGIN
11: 764451 681049 606745 572691 510210 454545 404954;
19: 721546 642824 572691 540549 481574 429034 382226;
21: 382226 340524 303373 286346 255105 227273 202477;
29: 360773 321412 286346 270274 240787 214517 191113;
31: 191113 170262 151686 143173 127553 113636 101238;
39: 180386 160706 143173 135137 120394 107258 95556;
41: 95556 85131 75843 71586 63776 56818 50619;
49: 90193 80353 71586 67569 60197 53629 47778;
51: 47778 42566 37922 35793 31888 28409 25310;
59: 45097 40177 35793 33784 30098 26815 23889;
61: 23889 21283 18961 17897 15944 14205 12655;
69: 22548 20088 17897 16892 15049 13407 11945;
第 4 页 共 14 页
71: 11945 10641 9480 8948 7972 7102 6327;
79: 11274 10044 8948 8446 7525 6704 5972;
END;
代码输入后保存为:src\tbSndFreq.MIF
2. 使用QuartusII工具生成新的ROM表访问模块,模块名tbSndFreq.v
(1) 启动模块生成向导,Tools | MegaWizard Plug-In Manager
(2) 向导1,Create a new ……,创新新的模块
(3) 向导2,选择模块类别,并输入文件名:E:/11129999/Qts/mySnd2/src/tbSndFreq
(4) 向导3,设置ROM表的位宽=20,与地址数=128
第 5 页 共 14 页
(5) 向导4,设置端口,默认,Next
(6) 向导5,设置ROM表数据源
第 6 页 共 14 页
(7) 向导6,仿真设置,略,Next
(8) 向导7,生成列表显示,Finish
3. 创建新的ROM表文件(File | New | Text File,tbMusic.MIF),输入查找表数据并
保存到工程的src子目录下。
MIF代码(tbMusic.MIF) 说明
DEPTH=128; 允许从复WIDTH=16; 制粘贴。 ADDRESS_RADIX=DEC; DATA_RADIX=HEX;
CONTENT
BEGIN
0: D020;
1: 1041 1042 1043 1041;
5: 1041 1042 1043 1041;
9: 1043 1044 2045;
12: 1043 1044 2045;
15: 0C45 0446 0C45 0444 1043 1041;
21: 0C45 0446 0C45 0444 1043 1041;
27: 1041 1045 2041;
30: 1041 1045 2041;
33: 4000;
END;
代码输入后保存为:src\tbMusic.MIF
4. 使用QuartusII工具生成新的ROM表访问模块,模块名tbMusic.v
(1) 启动模块生成向导,Tools | MegaWizard Plug-In Manager
(2) 向导1,Create a new ……,创新新的模块
第 7 页 共 14 页
(3) 向导2,选择模块类别,并输入文件名:E:/11129999/Qts/mySnd2/src/tbMusic
(4) 向导3,设置ROM表的位宽=16,与地址数=128 (5) 向导4,设置端口,默认,Next
(6) 向导5,设置ROM表数据源,追加在线逻辑功能。
(7) 向导6,仿真设置,略,Next
(8) 向导7,生成列表显示,Finish
5. 创建新的设计文件(File | New | Verilog HDL File,rjMusic模块),输入程序代码
并保存到工程的src子目录下。该模块调用tbMusic取得当前声音及长度。
Verilog代码(rjMusic模块) 说明 //音乐播放模块,允许设置节奏 允许从复module rjMusic(SYSCLK,RST_B,EnaMusic,Snd); 制粘贴。 input SYSCLK; //系统时钟,50MHz,每周期=20ns
input RST_B; //系统复位,低电平有效
input EnaMusic; //允许音乐播放,高电平时播放,低电平时停止 中文可以 output [6:0] Snd; //输出的声音编号 粘贴,但
不能正常 //按SYSCLK=50MHz,每50000个时钟=1ms,基础计数
reg [15:0] baseCT; 显示。 wire baseEnd = (baseCT==16'D49999); always @ (posedge SYSCLK)
if (!RST_B || !EnaMusic || baseEnd)
baseCT <= 16'D0;
else //采用递增计数(为读取ROM预留时间)
baseCT <= baseCT + 1'B1;
wire [15:0] romQ; //ROM读取的输出端
reg [15:0] nextQ; //在baseEnd前读取的下一个ROM值
always @ (posedge SYSCLK)
nextQ <= romQ;
reg [17:0] playLen;
第 8 页 共 14 页
always @ (posedge SYSCLK)
playLen <= beatLen * nextQ[15:8];
wire nextSet = (nextQ[15:14]==2'B11);
wire setBeatLen = (nextQ[13:12]==2'B01);
//小小拍时间长度,1ms至1.023s,用于控制音乐播放的快慢
reg [9:0] beatLen;
always @ (posedge SYSCLK)
if (!RST_B)
beatLen <= 10'D37;
else if (baseEnd && nextSet && setBeatLen)
if (nextQ[9:0]==10'D0)
beatLen <= 10'D37;
else
beatLen <= nextQ[9:0];
//当前音符计数
reg [17:0] playCT;
wire playEnd = (playCT<=18'D1);
wire playGap = (playCT<=beatLen);
always @ (posedge SYSCLK)
if (!RST_B || !EnaMusic)
playCT <= 18'D0;
else if (baseEnd && playEnd && !nextSet)
playCT <= playLen;
else if (baseEnd && !playEnd)
playCT <= playCT - 1'B1;
//音谱地址
reg [7:0] romAddr;
always @ (posedge SYSCLK)
if (!RST_B || !EnaMusic)
romAddr <= 8'D0;
else if (baseEnd && (playEnd || nextSet))
romAddr <= romAddr + 1'B1;
//
tbMusic uMus (
.address(romAddr),
.clock(SYSCLK),
.q(romQ));
//
reg [6:0] Snd;
always @ (posedge SYSCLK)
if (!RST_B || !EnaMusic)
Snd <= 7'D0;
else if (baseEnd && playEnd)
if (nextSet)
Snd <= 7'D0;
else
Snd <= nextQ[6:0];
else if (baseEnd && playGap)
Snd <= 7'D0;
//模块输出Snd
endmodule
代码输入后保存为:src\rjMusic.v
6. 创建新的设计文件(File | New | Verilog HDL File,rjSndOut模块),输入程序代
码并保存到工程的src子目录下。该模块调用tbSndFreq读取声音对应的半周期。
Verilog代码(rjSndOut模块) 说明
//声音播放模块,根据给定的声音编号, 允许从复
//输出相应的声音频率到蜂鸣器上 制粘贴。
第 9 页 共 14 页
module rjSndOut(SYSCLK,Snd,BUZZER);
input SYSCLK; //系统时钟,50MHz,每周期=20ns
input [6:0] Snd; //声音编号,从21到67
output BUZZER; //蜂鸣器输出
//由声音编号取得声音频率/半周期时钟数
wire [19:0] tone; //声音频率对应的半周期时钟数
tbSndFreq uFreq ( //查找ROM表,查找得到对应的时钟数
.address(Snd),
.clock(SYSCLK),
.q(tone));
//对半周期时钟数循环计数
reg [19:0] fCT; //当前声音对应的时钟计数器
always @ (posedge SYSCLK)
if (fCT>20'D1) //fCT从tone递减至1,循环重复
fCT <= fCT - 1'B1;
else
fCT <= tone;
//按指定声音频率控制蜂鸣器发声
reg BUZZER;
always @ (posedge SYSCLK)
if (tone==20'D0) //半周期时钟数为0时停止声音
BUZZER <= 1'B0;
else if (fCT==20'D1)//计数器递减到1时,蜂鸣器驱动翻转
BUZZER <= !BUZZER;
//模块输出BUZZER
endmodule
代码输入后保存为:src\rjSndOut.v
7. 创建新的设计文件(File | New | Verilog HDL File,mySnd2模块),输入程序代码
并保存到工程的src子目录下。该模块调用乐谱rjMusic模块,和声音播放rjSndOut
模块。
Verilog代码(mySnd2模块) 说明 //乐谱播放模块 允许从module mySnd2(SYSCLK,RST_B,KEY_B,BUZZER); 复制粘 input SYSCLK; //系统时钟,50MHz,每周期=20ns 贴。 input RST_B; //系统复位,低电平有效 input [4:0] KEY_B; //开发板上按键,低电平有效
output BUZZER; //蜂鸣器输出
//来自音谱的音符
wire [6:0] Snd; //声音编号
rjMusic U1 (.SYSCLK(SYSCLK),.RST_B(RST_B),
.EnaMusic(!KEY_B[4]),.Snd(Snd));
//调用声音播放模块输出到蜂鸣器上
rjSndOut U2(.SYSCLK(SYSCLK),.Snd(Snd),.BUZZER(BUZZER));
//
endmodule
第 10 页 共 14 页
代码输入后保存为:src\mySnd2.v
四、 编译与绑定
设计完成后,首先进行语法检查,并将设计端口连接到具体引脚号上。 1. 执行语法检查与综合,菜单项“Processing | Start | Start Analysis & Synthesis”。 2. 检查语法编译结果,是否存在语法错误。
3. 使用记事本打开工程目录下的文件“mySnd2.qsf”,检查是否包含以下句子,如
果没有,将下列句子添加到文件末尾,并保存退出。
set_location_assignment PIN_34 -to BUZZER set_location_assignment PIN_28 -to KEY_B[4]
set_location_assignment PIN_131 -to KEY_B[3]
set_location_assignment PIN_27 -to KEY_B[2]
set_location_assignment PIN_132 -to KEY_B[1]
set_location_assignment PIN_130 -to KEY_B[0]
set_location_assignment PIN_129 -to RST_B
set_location_assignment PIN_23 -to SYSCLK
4. 验证引脚绑定,通过菜单项Assignment/Pin Planner或工具栏相应按钮,检查引脚
是否已绑定。
5. 设置不使用引脚为输入上拉方式,菜单项“Assignments | Device…”,按钮“Device
and Pin Options…”,选项Unused Pin,选择As input tri-stated with weak pull-up
6. 执行完整编译,菜单Processing/Start Compilation或工具栏相应按钮。 7. 检查完整编译结果,是否存在错误。
五、 设置波形观察
1. 菜单项 Tools | SignalTap II Logic Analyzer
2. 设置采样时钟。置 Clock 为 rjMusic:U1|baseCT[12]。
3. 设置采样深度,每次采集128组数据。置 Sample Depth 为 128 4. 设置待采集的信号为:BUZZER
5. 保存采集设置,菜单 File | Save,文件名为src\stp1.stp 6. 重新完整编译,回到QuartusII界面,Start Compilation,检查编译结果。
六、 工程归档与备份
当工程全部完成时,需要仔细备份/归档,归档是为便于保存与备份。 1. 工程归档,菜单Project/Archive Project 2. 归档文件,设置文件名为11129999-mySnd2 3. 点击Archive按钮,进行归档。归档成功后,弹出完成窗口。 4. 检查QuartusII工程目录中的文件是否包含11129999-mySnd2.qar文件。 5. 上传归档工程
请学生自己保存好归档工程(11129999-mySnd2.qar),
并上传至作业上传系统(home.ccshu.net)。
第 11 页 共 14 页
七、 下载与运行【本步骤需要准备好开发板与下载电缆】
工程完整编译无误后,编译结果下载到芯片上,实际运行检查设计效果。 1. 准备下载,菜单Tools/Programmer或工具栏相应按钮
2. 下载窗口,下载前检查电缆连接与方式。
3. 点击下载(Start按钮),检查进度是否“100%Successful”
4. 播放功能验证
(1) 按下KEY_B[4]键不放,开始播放乐谱声音,结束后自动循环。 (2) 放开KEY_B[4]键,乐谱播放停止。
(3) 再次按下KEY_B[4],乐谱又从头开始播放。
5. 改变播放速度
(1) 菜单项 Tools | In-System Memory Content Editor
(2) 读取芯片中的乐谱表。?选择下载线为USB-Blaster;?选择ROM单元为
Musc;?右击后选择“Read Data ……”或按F5快捷键。
(3) 将ROM表编辑区的“D0 20”修改为“D0 10”,再右击后选择“Write Data…”
或快捷键F7。
第 12 页 共 14 页
(4) 按下开发板上KEY_B[4],验证乐谱的播放速度是否提高。 (5) 再次将原ROM表编辑区的“D0 20”修改为“D0 40”,然后“Write Data…”,
比较播放速度的变化。
(6) 再次修改编辑区,声音部分改为“4011 4021 4031 …… 4071”,即依次播放各
八度的1-Do音,如下图所示,听听声音的高低变化。
6. 通过波形观察声音频率
(1) 菜单项 Tools | SignalTap II Logic Analyzer (2) 在 Hardware 处选择 USB-Blaster
(3) 菜单项 Processing | Autorun Analysis (4) 按下开发板上KEY_B[4],观察波形变化,如下图,当声音变高时,波形的
频率也产生了相应变化。
第 13 页 共 14 页
八、 思考与修改(供有能力的学生进一步练习,或课外思考) 1. 查找一个新的乐谱。
2. 根据乐谱修改tbMusic.MIF文件
(1) 完整编译,检查程序修改后是否存在语法错误。 (2) 下载运行,检查乐谱曲调是否正确。
3. 归档与上传
(3) 归档修改后的工程,归档工程为:11129999-mySnd2-XXX.qar,其中XXX为
乐谱名(中文乐谱请使用英文或拼音字母代替) (4) 备份并上传新生成的归档工程。
第 14 页 共 14 页