久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4687|回復: 1
收起左側

基于FPGA的硬件電子琴設計-by楠妹

[復制鏈接]
ID:77367 發表于 2015-4-19 01:25 | 顯示全部樓層 |閱讀模式


作者:13電信二楠妹

本實驗通過檢測電腦鍵盤,根據不同鍵值來控制數碼管的段選變化以及位選變化,并且通過分頻器控制蜂鳴器輸出不同的音調(⊙o⊙)哦!

先來了解一些關于PS2電腦鍵盤的通碼吧:

  
KEY
  
通碼
斷碼
KEY
通碼
斷碼
KEY
通碼
斷碼
A
1C
F0 1C
9
46
F0 46
[
54
F0 54
B
32
F0 32
`
0E
F0 0E
INSERT
E0 70
E0 F0 70
C
21
F0 21
-
4E
F0 4E
HOME
E0 6C
E0 F0 6C
D
23
F0 23
=
55
F0 55
PG UP
E0 7D
E0 F0 7D
E
24
F0 24
\
5D
F0 5D
DELETE
E0 71
E0 F0 71
F
2B
F0 2B
BKSP
66
F0 66
END
E0 69
E0 F0 69
G
34
F0 34
SPACE
29
F0 29
PG DN
E0 7A
E0 F0 7A
H
33
F0 33
TAB
0D
F0 0D
U ARROW
E0 75
E0 F0 75
I
43
F0 43
CAPS
58
F0 58
L ARROW
E0 6B
E0 F0 6B
J
3B
F0 3B
L SHFT
12
F0 12
D ARROW
E0 72
E0 F0 72
K
42
F0 42
L CTRL
14
F0 14
R ARROW
E0 74
E0 F0 74
L
4B
F0 4B
L GUI
E0 1F
E0 F0 1F
NUM
77
F0   77
M
3A
F0 3A
L ALT
11
F0 11
KP /
E0 4A
E0 F0 4A
N
31
F0 31
R SHFT
59
F0 59
KP *
7C
F0   7C
O
44
F0 44
R CTRL
E0 14
E0 F0 14
KP -
7B
F0 7B
P
4D
F0 4D
R GUI
E0 27
E0 F0 27
KP +
79
F0 79
Q
15
F0 15
R ALT
E0 11
E0 F0 11
KP EN
E0 5A
E0 F0 5A
R
2D
F0 2D
APPS
E0 2F
E0 F0 2F
KP
71
F0 71
S
1B
F0 1B
ENTER
5A
F0 5A
KP 0
70
F0 70
T
2C
F0 2C
ESC
76
F0 76
KP 1
69
F0 69
U
3C
F0 3C
F1
5
F0 05
KP 2
72
F0 72
V
2A
F0 2A
F2
6
F0 06
KP 3
7A
F0 7A
W
1D
F0 1D
F3
4
F0 04
KP 4
6B
F0 6B
X
22
F0 22
F4
0C
F0 0C
KP 5
73
F0 73
Y
35
F0 35
F5
3
F0 03
KP 6
74
F0 74
Z
1A
F0 1A
F6
0B
F0 0B
KP 7
6C
F0 6C
0
45
F0 45
F7
83
F0 83
KP 8
75
F0 75
1
16
F0 16
F8
0A
F0 0A
KP 9
7D
F0 7D
2
1E
F0 1E
F9
1
F0 01
]
58
F0 58
3
26
F0 26
F10
9
F0 09
;
4C
F0 4C
4
25
F0 25
F11
78
F0 78
'
52
F0 52
5
2E
F0 2E
F12
7
F0 07
,
41
F0 41
6
36
F0 36
PRNTSCRN
E0 12 E0 7C
E0 F0 7C E0 F0 12
.
49
F0 49
7
3D
F0 3D
SCROLL
7E
F0,7E
/
4A
F0 4A
8
3E
F0 3E
PAUSE
E1 14 77
-NONE-
E1 F0 14
F0 77


以下是關于音調的知識:

頻率的高低決定了音調的高低。音樂的十二平均率規定:每兩個8度音(如簡譜中的中音1與高音1)之間的頻率相差一倍。在兩個8度音之間,又可分為12個半音,每兩個半音的頻率比為122?另外,音名A(簡譜中的低音6)的頻率為440Hz,音名BC之間、EF之間為半音,其余為全音[4]。由此可以計算出簡譜中從低音1至高音1之間每個音名對應的頻率,如下表所示:
                              
所有不同頻率的信號都是從同一個基準頻率分頻得到的。由于音階頻率多為非整數,而分頻系數又不能為小數,故必須將計算得到的分頻數四舍五入取整。若基準頻率過低,則由于分頻比太小,四舍五入取整后的誤差較大;若基準頻率過高,雖然誤差變小,但分頻數將變大。實際的設計綜合考慮這兩方面的因素,在盡量減小頻率誤差的前提下取合適的基準頻率[4]。本例中選取500kHz為基準頻率。若無500kHz的基準頻率,則可以先分頻得到500kHz,或換一個新的基準頻率。實際上,只要各個音名間的相對頻率關系不變,演奏出的樂曲聽起來都不會"走調"

下面來看看頂層設計模塊吧!O(∩_∩)O~~


下面給出各個模塊的代碼:

//     電子琴的頂層設計模塊

module electronic_organ_top(
       clk,
       rst_n,
       ps2_clk,
       ps2_data,
       wela,
       dula,
       fre_out
       );

input clk;                                    //     系統時鐘,50MHz
input rst_n;                                 //     復位信號,低電平有效
input ps2_clk;                             //     PS2鍵盤的時鐘信號
input ps2_data;                            //     PS2鍵盤的數據信號

output [7:0] wela;                 //     位選信號,高電平有效
output [7:0] dula;                 //     段選信號
output fre_out;

wire [4:0] ps2_byte_wire;

ps2_scan ps2_scan_exam(
       .clk(clk),
       .rst_n(rst_n),
       .ps2_clk(ps2_clk),
       .ps2_data(ps2_data),
       .ps2_byte(ps2_byte_wire)
       );

shumaguan shumaguan_exam(
       .clk(clk),
       .rst_n(rst_n),
       .wela(wela),
       .dula(dula),
       .key_in(ps2_byte_wire)
);

frequency_control frequency_control_exam(
       .clk(clk),
       .rst_n(rst_n),
       .fre_out(fre_out),
       .fre_control(ps2_byte_wire)
       );

endmodule


//     PS2鍵盤掃描模塊

module ps2_scan(
       clk,
       rst_n,
       ps2_clk,
       ps2_data,
       ps2_byte
       );

input clk;                                    //     系統時鐘,50MHz
input rst_n;                                 //     復位信號,低電平有效
input ps2_clk;                             //     PS2鍵盤的時鐘信號
input ps2_data;                            //     PS2鍵盤的數據信號
output reg [4:0] ps2_byte; //  PS2鍵盤掃描模塊輸出的5位數據

//-------------------------------------------------------

reg [2:0] ps2_clk_r;
wire ps2_clk_neg;

always @ (posedge clk or negedgerst_n)begin
       if(!rst_n)
              ps2_clk_r<= 3'b000;
       else
              ps2_clk_r<= {ps2_clk_r[1:0] , ps2_clk};
end

assign ps2_clk_neg = ~ps2_clk_r[1] &ps2_clk_r[2];

//-------------------------------------------------------

reg [7:0] data_temp;
reg [3:0] num;

always @ (posedge clk or negedgerst_n)begin
       if(!rst_n)begin
              num<= 4'd0;
              data_temp<= 8'd0;
       end
       elsebegin
              if(ps2_clk_neg)begin
                     num<= num + 1'b1;
                     case(num)
                            4'd1: data_temp[0] <= ps2_data;//第一位是起始位
                            4'd2: data_temp[1] <= ps2_data;
                            4'd3: data_temp[2] <= ps2_data;
                            4'd4: data_temp[3] <= ps2_data;
                            4'd5: data_temp[4] <= ps2_data;
                            4'd6: data_temp[5] <= ps2_data;
                            4'd7: data_temp[6] <= ps2_data;
                            4'd8: data_temp[7] <= ps2_data;
                            default: ;
                     endcase
              end
              else;//不做校驗
              if(num== 4'd11)
                     num<= 4'd0;
              else;
              end
end

//-------------------------------------------------------

reg [8:0] ps2_byte_r;

always @ (posedge clk or negedgerst_n)begin
       if(!rst_n)
              ps2_byte_r<= 4'h00;
       elseif(num == 4'd11)begin
              if(data_temp!= 4'hf0)
                     ps2_byte_r<= data_temp;
              end
end

//-------------------------------------------------------

always @ (ps2_byte_r)begin
       case(ps2_byte_r)
              8'h16:ps2_byte <= 5'd1;       //1(鍵盤值)
              8'h1e:ps2_byte <= 5'd2; //2
              8'h26:ps2_byte <= 5'd3;       //3
              8'h25:ps2_byte <= 5'd4;       //4
              8'h2e:ps2_byte <= 5'd5; //5
              8'h36:ps2_byte <= 5'd6;       //6
              8'h3d:ps2_byte <= 5'd7;       //7

              8'h15:ps2_byte <= 5'd8;       //q   
              8'h1d:ps2_byte <= 5'd9;       //w
              8'h24:ps2_byte <= 5'd10;      //e
              8'h2d:ps2_byte <= 5'd11;      //r
              8'h2c:ps2_byte <= 5'd12;      //t
              8'h35:ps2_byte <= 5'd13;      //y
              8'h3c:ps2_byte <= 5'd14;      //u

              8'h1c:ps2_byte <= 5'd15;      //a   
              8'h1b:ps2_byte <= 5'd16;      //s
              8'h23:ps2_byte <= 5'd17;      //d
              8'h2b:ps2_byte <= 5'd18;      //f
              8'h34:ps2_byte <= 5'd19;      //g
              8'h33:ps2_byte <= 5'd20;      //h
              8'h3b:ps2_byte <= 5'd21;      //j

              default: ps2_byte <= 5'd22;
              endcase
end

endmodule

//     數碼管驅動模塊

module shumaguan (
       clk,
       rst_n,
       wela,
       dula,
       key_in
);

input clk;                                    //     系統時鐘,50MHz
input rst_n;                                 //     復位信號,低電平有效
input [4:0] key_in;

//wire [3:0] key_in;
//assign key_in = 4'd4;

output reg [7:0] wela;           //     位選信號,高電平有效
output reg [7:0] dula;            //     段選信號

//-------------------------------------------------------

parameter seg0 = ~8'h3f,
                      seg1 = ~8'h06,
                      seg2 = ~8'h5b,
                      seg3 = ~8'h4f,
                      seg4 = ~8'h66,
                      seg5 = ~8'h6d,
                      seg6 = ~8'h7d,
                      seg7 = ~8'h07,
                      xiao_ying = 8'hff;

parameter T_FULL = 20'd625000; //     80Hz的動態掃描
parameter T_HALF = 20'd312500;

//-------------------------------------------------------

reg [19:0] cnt;               //用于產生動態掃描的延時

always @ (posedge clk or negedge rst_n)
       if(!rst_n)
              cnt<= 20'd0;
       elseif(cnt <= T_FULL)
              cnt<= cnt + 1'b1;
       else
              cnt<= 20'd0;

//-------------------------------------------------------

always @ (posedge clk or negedge rst_n)
begin
       if(!rst_n)
       begin
              wela<= 8'h11;
              dula<= xiao_ying;
       end
       else
       begin
              seg_dongtai(key_in);
       end
end

//-------------------------------------------------------

task seg_dongtai;                  //     動態掃描任務

       input[4:0] seg_num;
       if(seg_num== 1 || seg_num == 8 || seg_num == 15)begin
              if(cnt<= T_HALF)begin
              wela<= 8'h01;
              dula<= xiao_ying;
              end
              elseif((cnt > T_HALF)&&(cnt <= T_FULL))begin
              wela<= 8'hfe;
              dula<= seg1;
              end
       end
       if(seg_num== 2 || seg_num == 9 || seg_num == 16)begin
              if(cnt<= T_HALF)begin
              wela<= 8'h10;
              dula<= xiao_ying;
              end
              elseif((cnt > T_HALF)&&(cnt <= T_FULL))begin
              wela<= 8'hfd;
              dula<= seg2;
              end
       end
       if(seg_num== 3 || seg_num == 10 || seg_num == 17)begin
              if(cnt<= T_HALF)begin
              wela<= 8'h04;
              dula<= xiao_ying;
              end
              elseif((cnt > T_HALF)&&(cnt <= T_FULL))begin
              wela<= 8'hfb;
              dula<= seg3;
              end
       end
       if(seg_num== 4 || seg_num == 11 || seg_num == 18)begin
              if(cnt<= T_HALF)begin
              wela<= 8'h08;
              dula<= xiao_ying;
              end
              if((cnt> T_HALF)&&(cnt <= T_FULL))begin
              wela<= 8'hf7;
              dula<= seg4;
              end
       end
       if(seg_num== 5 || seg_num == 12 || seg_num == 19)begin
              if(cnt<= T_HALF)begin
              wela<= 8'h10;
              dula<= xiao_ying;
              end
              elseif((cnt > T_HALF)&&(cnt <= T_FULL))begin
              wela<= 8'hef;
              dula<= seg5;
              end
       end
       if(seg_num== 6 || seg_num == 13 || seg_num == 20)begin
              if(cnt<= T_HALF)begin
              wela<= 8'h20;
              dula<= xiao_ying;
              end
              if((cnt> T_HALF)&&(cnt <= T_FULL))begin
              wela<= 8'hdf;
              dula<= seg6;
              end
       end
       if(seg_num== 7 || seg_num == 14 || seg_num == 21)begin
              if(cnt<= T_HALF)begin
              wela<= 8'h40;
              dula<= xiao_ying;
              end
              if((cnt> T_HALF)&&(cnt <= T_FULL))begin
              wela<= 8'hbf;
              dula<= seg7;
              end
       end
       if(seg_num== 22)begin
              wela<= 8'h11;
              dula<= xiao_ying;
       end

endtask           //     注意這是任務的結尾

//-------------------------------------------------------

Endmodule


//     頻率控制模塊

module frequency_control(
       clk,
       rst_n,
       fre_out,
       fre_control
       );

input clk;                                    //     系統時鐘,50MHz
input rst_n;                                 //     復位信號,低電平有效
input [4:0] fre_control;  //     頻率控制信號

output reg fre_out;               //     頻率輸出信號

//-------------------------------------------------------

parameter low1               = 18'd191131,//   低音1
                      low1_half = 18'd95566,               
                      low2              = 18'd170242,//  低音2
                      low2_half = 18'd85121,
                      low3              = 18'd151699,//  低音3
                      low3_half = 18'd75850,
                      low4              = 18'd143184,//  低音4
                      low4_half = 18'd71592,
                      low5              = 18'd127551,//  低音5
                      low5_half = 18'd63776,
                      low6              = 18'd113636,//   低音6
                      low6_half = 18'd56818,
                      low7              = 18'd101235,//  低音7
                      low7_half = 18'd50618,        
                      mid1      = 18'd95547,      //     中音1
                  mid1_half = 18'd47773,
                      mid2     = 18'd85135,    //     中音2
                      mid2_half = 18'd42568,
                      mid3     = 18'd75838,    //     中音3
                      mid3_half = 18'd37919,
                      mid4     = 18'd71480,    //     中音4
                      mid4_half = 18'd35740,
                      mid5     = 18'd63776,    //     中音5
                      mid5_half = 18'd31888,      
                      mid6     = 18'd56818,    //     中音6
                      mid6_half = 18'd28409,
                      mid7     = 18'd50618,    //     中音7
                      mid7_half = 18'd23509,
                      high1      = 18'd47778,      //     高音1
                      high1_half = 18'd23889,      
                      high2      = 18'd42586,      //     高音2
                      high2_half = 18'd21293,
                      high3      = 18'd37893,      //     高音3
                      high3_half = 18'd18947,
                      high4      = 18'd35794,      //     高音4
                      high4_half = 18'd17897,
                      high5      = 18'd31888,      //     高音5
                      high5_half = 18'd15944,
                      high6      = 18'd28409,      //     高音6
                      high6_half = 18'd14205,
                      high7      = 18'd25310,      //     高音7
                      high7_half = 18'd12655;

//-------------------------------------------------------

reg [17:0] fre_reg;
reg [17:0] fre_half_reg;
reg [17:0] fre_reg_r;
reg [17:0] fre_half_reg_r;

always @ (posedge clk or negedge rst_n)
begin
       if(!rst_n)
       begin
              fre_reg_r<= 18'd0;
              fre_half_reg_r<= 18'd0;
       end
       else
       begin
              case(fre_control)
                     5'd1: begin fre_reg_r <= mid1; fre_half_reg_r <= mid1_half; end
                     5'd2: begin fre_reg_r <= mid2; fre_half_reg_r <= mid2_half; end
                     5'd3: begin fre_reg_r <= mid3; fre_half_reg_r <= mid3_half; end
                     5'd4: begin fre_reg_r <= mid4; fre_half_reg_r <= mid4_half; end
                     5'd5: begin fre_reg_r <= mid5; fre_half_reg_r <= mid5_half; end
                     5'd6: begin fre_reg_r <= mid6; fre_half_reg_r <= mid6_half; end
                     5'd7: begin fre_reg_r <= mid7; fre_half_reg_r <= mid7_half; end

                     5'd8: begin fre_reg_r <= low1; fre_half_reg_r <= low1_half; end
                     5'd9: begin fre_reg_r <= low2; fre_half_reg_r <= low2_half; end
                     5'd10: begin fre_reg_r <= low3; fre_half_reg_r <= low3_half; end
                     5'd11: begin fre_reg_r <= low4; fre_half_reg_r <= low4_half; end
                     5'd12: begin fre_reg_r <= low5; fre_half_reg_r <= low5_half; end
                     5'd13: begin fre_reg_r <= low6; fre_half_reg_r <= low6_half; end
                     5'd14: begin fre_reg_r <= low7; fre_half_reg_r <= low7_half; end                 

                     5'd15: begin fre_reg_r <= high1; fre_half_reg_r <= high1_half; end
                     5'd16: begin fre_reg_r <= high2; fre_half_reg_r <= high2_half; end
                     5'd17: begin fre_reg_r <= high3; fre_half_reg_r <= high3_half; end
                     5'd18: begin fre_reg_r <= high4; fre_half_reg_r <= high4_half; end
                     5'd19: begin fre_reg_r <= high5; fre_half_reg_r <= high5_half; end
                     5'd20: begin fre_reg_r <= high6; fre_half_reg_r <= high6_half; end
                     5'd21: begin fre_reg_r <= high7; fre_half_reg_r <= high7_half; end
                     5'd22       : begin fre_reg_r <= 17'd0;fre_half_reg_r <= 17'd0;       end
                     default: ;
                     endcase
       end
end

always @ (fre_control)
begin
       fre_reg<= fre_reg_r;
       fre_half_reg<= fre_half_reg_r;
end

//-------------------------------------------------------

reg [17:0] cnt;

always @ (posedge clk or negedge rst_n)
begin
       if(!rst_n)
       begin
              cnt<= 18'd0;
       end
       elseif(cnt == fre_reg)
       begin
              cnt<= 18'd0;
       end
       else
       begin
              cnt<= cnt + 1'b1;
       end
end

//-------------------------------------------------------

always @ (posedge clk or negedge rst_n)
begin
       if(!rst_n)
       begin
              fre_out= 1'b0;
       end
       elseif(cnt <= fre_half_reg)
       begin
              fre_out= 1'b1;
       end
       else
       begin
              fre_out= 1'b0;
       end
end

//-------------------------------------------------------

endmodule


回復

使用道具 舉報

ID:620580 發表于 2019-10-8 20:47 | 顯示全部樓層
管腳分配能看一下嗎
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 成人午夜视频在线观看 | 国产美女视频 | 欧美日韩国产在线 | 久久精品免费观看 | 欧美精品国产一区二区 | 亚洲欧美一区二区三区国产精品 | 亚洲在线| 亚洲精品久久区二区三区蜜桃臀 | 免费亚洲网站 | 一区二区三区免费在线观看 | 国产a级黄色录像 | av中文字幕在线观看 | 天天操天天插天天干 | 国产精品久久久久久一级毛片 | 在线一区 | www.日本精品 | 神马影院一区二区三区 | 欧美视频网 | 99综合 | 国产精品一级 | 性高湖久久久久久久久3小时 | 成人av在线播放 | 亚洲精品美女在线观看 | 蜜臀久久99精品久久久久久宅男 | 综合色导航 | 欧美日韩国产精品一区 | 国产欧美一区二区三区日本久久久 | 凹凸日日摸日日碰夜夜 | av一级久久| 国产日韩av一区二区 | 免费在线观看一区二区 | 理伦毛片 | 国产一区二区三区四区在线观看 | 亚洲成人精品 | 国产精品av久久久久久久久久 | 国产三级| 亚洲精品乱码久久久久久按摩 | 羞视频在线观看 | 天天做日日做 | 欧美激情视频一区二区三区在线播放 | 久久精品久久综合 |