目录
1、实验目的
2、实验仪器设备
3、实验原理
4、实验要求
5、实验步骤
6、实验报告
7、实验过程
(1)矩阵按键原理
(2)音符发音原理
(3)电路连接
(4)文件烧录
本实验根据蜂鸣器工作频率不同,从而发出不同的音符的声音。故本实验是将主时钟进行分频,使其分别产生 7 种不同分频因子。通过4*4键盘选择不同的频率输出驱动蜂鸣器。
音调 |
低/Hz |
中/Hz |
高/Hz |
D0 |
262 |
523 |
1046 |
RE |
294 |
578 |
1175 |
MI |
330 |
698 |
1397 |
FA |
349 |
698 |
1397 |
SO |
392 |
784 |
1568 |
LA |
440 |
880 |
1760 |
SI |
494 |
988 |
1967 |
完整的顶层模块原理图如图所示
6. 将 keyarray.bdf 设置为顶层实体。对该工程文件进行全程编译处理,若在编译过程中出现 错误,则找出错误并更正,直至编译通过为止;
7. 将 USB-Blaster 下载电缆的两端分别连接到 PC 机的 USB 接口和 EDA 实验箱上的 JTAG 下载口上,打开电源,执行下载命令,把程序下载到 FPGA 器件中,此时,即可在 EDA 实 验箱上通过按下相应的按键使蜂鸣器发出对应的音符声响。
基本流程为创建项目、创建Verilog文件、写代码、进行波形仿真、画出电路图、设置管脚和三态、烧录文件。这里我就不去做演示了,下面主要去讲原理。
矩阵按键模块是先按行选取到某一行,然后再选列,跟矩阵选择某一个点的原理是一样的,如果按下这个按键的时候,此时两边的开关是接通的,这时候就会返回到一个矩阵按键回馈的信息,我们只需要去读取到这个信息,然后再根据行列的相关位置,把这个信息转换为相对于的数字返回即可。
Verilog代码(读取到矩阵按键按下的位置,输出相对于的数字):
module keyarraycontrol(clk,rst,row,col,keydata);
input clk;
input rst;
input [3:0] row;
output reg[3:0] col;
output reg[3:0] keydata;
reg keyint;
reg [19:0] cnt;
//分频获得键盘扫描频率
always @ (posedge clk, negedge rst)
if (!rst)
cnt <= 0;
else
cnt <= cnt + 1'b1;
//将计数的最高位赋给key_clk
wire key_clk = cnt[19]; // (2^20/50M = 21)ms
//设定扫描状态判断参数
parameter NO_KEY_PRESSED = 6'b000_001; // 如果没有按键按下的时候
parameter SCAN_COL0 = 6'b000_010; // 按下第一行按键
parameter SCAN_COL1 = 6'b000_100; // 按下第二行按键
parameter SCAN_COL2 = 6'b001_000; // 按下第三行按键
parameter SCAN_COL3 = 6'b010_000; // 按下第四行按键
parameter KEY_PRESSED = 6'b100_000; // 有按键按下状态
reg [5:0] current_state, next_state; // 当前状态,,,下一个状态
always @ (posedge key_clk, negedge rst)
if (!rst)
current_state <= NO_KEY_PRESSED;
else
current_state <= next_state;
//
always @ *
case (current_state)
NO_KEY_PRESSED : //
if (row != 4'hF)
next_state = SCAN_COL0;
else
next_state = NO_KEY_PRESSED;
SCAN_COL0 : //
if (row != 4'hF)
next_state = KEY_PRESSED;
else
next_state = SCAN_COL1;
SCAN_COL1 : //
if (row != 4'hF)
next_state = KEY_PRESSED;
else
next_state = SCAN_COL2;
SCAN_COL2 : //
if (row != 4'hF)
next_state = KEY_PRESSED;
else
next_state = SCAN_COL3;
SCAN_COL3 : //
if (row != 4'hF)
next_state = KEY_PRESSED;
else
next_state = NO_KEY_PRESSED;
KEY_PRESSED : //
if (row != 4'hF)
next_state = KEY_PRESSED;
else
next_state = NO_KEY_PRESSED;
endcase
reg [3:0] col_val, row_val; //
always @ (posedge key_clk, negedge rst)
if (!rst)
begin
col<= 4'h0;
keyint<=0;
end
else
case (next_state)
NO_KEY_PRESSED : //
begin
col <= 4'h0;
keyint <= 0; //
end
SCAN_COL0 : //
col <= 4'b1110;
SCAN_COL1 :
col <= 4'b1101;
SCAN_COL2 : //
col <= 4'b1011;
SCAN_COL3 : //
col <= 4'b0111;
KEY_PRESSED : //
begin
col_val<= col; // 得到列的值
row_val<= row; // 得到行的值
keyint <= 1; //
end
endcase
always @ (posedge key_clk, negedge rst)
if (!rst)
keydata <= 16'h0000;
else
if (keyint)
case ({col_val, row_val})
8'b1110_1110 : keydata <= 8'd0;
8'b1110_1101 : keydata <= 8'd4;
8'b1110_1011 : keydata <= 8'd8;
8'b1110_0111 : keydata <= 8'd12;
8'b1101_1110 : keydata <= 8'd1;
8'b1101_1101 : keydata <= 8'd5;
8'b1101_1011 : keydata <= 8'd9;
8'b1101_0111 : keydata <= 8'd13;
8'b1011_1110 : keydata <= 8'd2;
8'b1011_1101 : keydata <= 8'd6;
8'b1011_1011 : keydata <= 8'd10;
8'b1011_0111 : keydata <= 8'd14;
8'b0111_1110 : keydata <= 8'd3;
8'b0111_1101 : keydata <= 8'd7;
8'b0111_1011 : keydata <= 8'd11;
8'b0111_0111 : keydata <= 8'd15;
default: keydata <= keydata;
endcase
else
keydata <= keydata;
endmodule
以下是不同音符发音的频率:
音调 |
低/Hz |
中/Hz |
高/Hz |
D0 |
262 |
523 |
1046 |
RE |
294 |
578 |
1175 |
MI |
330 |
698 |
1397 |
FA |
349 |
698 |
1397 |
SO |
392 |
784 |
1568 |
LA |
440 |
880 |
1760 |
SI |
494 |
988 |
1967 |
前面我们创建了一个获取矩阵按键返回值的代码,这里我们需要去创建一个verilog文件来去对返回值进行分频操作,代码如下:
module note(clk, divcnt, out);
input clk;
input[3:0] divcnt;
output out;
reg out;
reg[15:0] cnt_0, cnt_4, cnt_8, cnt_12, cnt_1, cnt_5, cnt_9;
always@(posedge clk)
begin
if (divcnt == 8'd0)//do√
begin
if (cnt_0 == 4780)
begin
out = out + 1;
cnt_0 = 0;
end
else
begin
cnt_0 = cnt_0 + 1;
end
end
else if (divcnt == 8'd4)//re√
begin
if (cnt_4 == 4255)
begin
out = out + 1;
cnt_4 = 0;
end
else
begin
cnt_4 = cnt_4 + 1;
end
end
else if (divcnt == 8'd8)//mi√
begin
if (cnt_8 == 3794)
begin
out = out + 1;
cnt_8 = 0;
end
else
begin
cnt_8 = cnt_8 + 1;
end
end
else if (divcnt == 8'd12)//fa√
begin
if (cnt_12 == 3579)
begin
out = out + 1;
cnt_12 = 0;
end
else
begin
cnt_12 = cnt_12 + 1;
end
end
else if (divcnt == 8'd1)//so√
begin
if (cnt_1 == 3189)
begin
out = out + 1;
cnt_1 = 0;
end
else
begin
cnt_1 = cnt_1 + 1;
end
end
else if (divcnt == 8'd5)//la√
begin
if (cnt_5 == 2841)
begin
out = out + 1;
cnt_5 = 0;
end
else
begin
cnt_5 = cnt_5 + 1;
end
end
else if (divcnt == 8'd9)//si√
begin
if (cnt_9 == 2542)
begin
out = out + 1;
cnt_9 = 0;
end
else
begin
cnt_9 = cnt_9 + 1;
end
end
end
endmodule
写好了Verilog代码,就进行分析错误,分析无误后,我们就对这些代码生成子模块文件。然后就创建block文件开始连接电路图,电路图以及管脚配置如下:
弄好了之后就是最后一步操作了,把没用到的管脚设置三态,然后烧录文件。
点击Assignment, Device
然后点击这里,设置管脚。
这里我们会看到,下面有一个芯片,这个也就是我们写好了的sof文件,然后就是通过你的电脑接口去连接到开发板,如果你看到上面有一个No Hardware的时候,你点击旁边的按钮进行接口设置,设置为USB接口即可(USB线连接了你的开发板就会自动显示出来的)。最后点击start就可以进行烧录了。
以上就是本期的全部内容了,我们下次见!
分享一张壁纸: