基于ICE40UP5K的FPGA学习平台设计音乐播放器
使用按键控制切换歌曲,ICE40UP5K核心板产生不同频率PWM信号驱动蜂鸣器播放歌曲,同时OLED显示屏模块显示歌曲名称
标签
FPGA
ICE40UP5K
2022寒假在家练
音乐播放器
ONE_PIECE
更新2022-03-02
西华大学
834

项目需求:

  1. 通过PWM产生不同的音调,并驱动板上蜂鸣器将音调输出
  2. 能够播放三首不同的曲子,每个曲子的时间长度为1分钟,可以切换播放
  3. 曲子的切换使用小脚丫核心板上的按键,需要有按键消抖的功能
  4. 播放的曲子的名字在OLED屏幕上显示出来(汉字显示)

设计思路:

FimQE2ChUxFfQ6YgTEib5I2lyJCb

管脚设计:

FjbO02utJHmnrtty5gLF9OZuDD7V

资源报告:

FtbWk3jGIXEWWOYwbIOZR3ST6PjF

Total CPU Time: 1 secs
Total REAL Time: 2 secs
Peak Memory Usage: 46 MB

使用模块:

  • OLED模块(v)                          (显示时间和汉字歌名)
  • music顶层模块(v) (将各个模块联系起来,并输出音乐到蜂鸣器)
  • 消抖模块 (v) (防止误判进行按键消抖,给予一个延时)

各个模块介绍:

OLED模块(v)

OLED模块是最重要的一个模块之一,也是我花了许久才完成的。这个模块也是我看了硬禾学堂给的例程之后想出来的,通过模仿硬禾学堂的程序,写出了我需要使用的OLED显示模块代码。

成果如下:

FjzK4OQzKCLeVyHKOyW0nETFvb-D

下面是核心代码:

				MAIN:begin
					case(qu)
						2'd0:begin
							if(cnt_main >= 5'd14) cnt_main <= 5'd15;
							else cnt_main <= cnt_main + 1'b1;
							case(cnt_main)
								5'd0 :	begin state <= INIT; end
								5'd1 :	begin y_p <= 8'hb0; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd2 :	begin y_p <= 8'hb1; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end												
							    5'd3 :	begin y_p <= 8'hb2; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd4 :	begin y_p <= 8'hb3; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd5 :	begin y_p <= 8'hb4; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd6 :	begin y_p <= 8'hb5; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd7 :	begin y_p <= 8'hb6; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd8 :	begin y_p <= 8'hb7; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end							
							    5'd9 :	begin y_p <= 8'hb0; x_ph <= 8'h10; x_pl <= 8'h00; mem_hanzi_num <= 8'd0;  state <= CHINESE; end
							    5'd10:	begin y_p <= 8'hb0; x_ph <= 8'h11; x_pl <= 8'h00; mem_hanzi_num <= 8'd2;  state <= CHINESE; end
							    5'd11:	begin y_p <= 8'hb0; x_ph <= 8'h12; x_pl <= 8'h00; mem_hanzi_num <= 8'd4;  state <= CHINESE; end
							    5'd12:	begin y_p <= 8'hb0; x_ph <= 8'h13; x_pl <= 8'h00; mem_hanzi_num <= 8'd6;  state <= CHINESE; end
							    5'd13:	begin y_p <= 8'hb0; x_ph <= 8'h14; x_pl <= 8'h00; mem_hanzi_num <= 8'd8;  state <= CHINESE; end
							    5'd14:	begin y_p <= 8'hb0; x_ph <= 8'h15; x_pl <= 8'h00; mem_hanzi_num <= 8'd10; state <= CHINESE; end
							endcase	
						end
						2'd1:begin
							if(cnt_main >= 5'd12) cnt_main <= 5'd13;
							else cnt_main <= cnt_main + 1'b1;
							case(cnt_main)
								5'd0 :	begin state <= INIT; end
								5'd1 :	begin y_p <= 8'hb0; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd2 :	begin y_p <= 8'hb1; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end												
							    5'd3 :	begin y_p <= 8'hb2; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd4 :	begin y_p <= 8'hb3; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd5 :	begin y_p <= 8'hb4; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd6 :	begin y_p <= 8'hb5; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd7 :	begin y_p <= 8'hb6; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd8 :	begin y_p <= 8'hb7; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end							
							    5'd9 :	begin y_p <= 8'hb0; x_ph <= 8'h12; x_pl <= 8'h00; mem_hanzi_num <= 8'd12;  state <= CHINESE; end
							    5'd10:	begin y_p <= 8'hb0; x_ph <= 8'h13; x_pl <= 8'h00; mem_hanzi_num <= 8'd14;  state <= CHINESE; end
							    5'd11:	begin y_p <= 8'hb0; x_ph <= 8'h14; x_pl <= 8'h00; mem_hanzi_num <= 8'd16;  state <= CHINESE; end
							    5'd12:	begin y_p <= 8'hb0; x_ph <= 8'h15; x_pl <= 8'h00; mem_hanzi_num <= 8'd18;  state <= CHINESE; end
							endcase
						end
						2'd2:begin
							if(cnt_main >= 5'd13) cnt_main <= 5'd14;
							else cnt_main <= cnt_main + 1'b1;
							case(cnt_main)
								5'd0 :	begin state <= INIT; end
								5'd1 :	begin y_p <= 8'hb0; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd2 :	begin y_p <= 8'hb1; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end												
							    5'd3 :	begin y_p <= 8'hb2; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd4 :	begin y_p <= 8'hb3; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd5 :	begin y_p <= 8'hb4; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd6 :	begin y_p <= 8'hb5; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd7 :	begin y_p <= 8'hb6; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
							    5'd8 :	begin y_p <= 8'hb7; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end							
							    5'd9 :	begin y_p <= 8'hb0; x_ph <= 8'h11; x_pl <= 8'h00; mem_hanzi_num <= 8'd20;  state <= CHINESE; end
							    5'd10:	begin y_p <= 8'hb0; x_ph <= 8'h12; x_pl <= 8'h00; mem_hanzi_num <= 8'd22;  state <= CHINESE; end
							    5'd11:	begin y_p <= 8'hb0; x_ph <= 8'h13; x_pl <= 8'h00; mem_hanzi_num <= 8'd24;  state <= CHINESE; end
							    5'd12:	begin y_p <= 8'hb0; x_ph <= 8'h14; x_pl <= 8'h00; mem_hanzi_num <= 8'd26;  state <= CHINESE; end
							    5'd13:	begin y_p <= 8'hb0; x_ph <= 8'h15; x_pl <= 8'h00; mem_hanzi_num <= 8'd28;  state <= CHINESE; end
							endcase
						end
						//default: state <= IDLE;   //如果你需要动态刷新一些信息,此行应该取消注释
					    endcase
					end

要切换歌曲时,每按下一次按键,改变寄存器qu的值,从而使其更改显示歌曲

接下来就是字库,这里我输入了十五个汉字:友,谊,地,久,天,长,两,只,老,虎 ,金,森,狂,想,曲 .

			mem_hanzi[ 0 ]  = {8'h08,8'h08,8'h08,8'h08,8'hC8,8'h78,8'hCF,8'h48,8'h48,8'h48,8'h48,8'hC8,8'h08,8'h08,8'h08,8'h00};
			mem_hanzi[ 1 ]  = {8'h10,8'h88,8'h84,8'h43,8'h40,8'h20,8'h21,8'h16,8'h08,8'h14,8'h22,8'h41,8'h40,8'h80,8'h80,8'h00};/*"友",0*/
			mem_hanzi[ 2 ]  = {8'h40,8'h40,8'h42,8'hCC,8'h00,8'h10,8'h0C,8'hE4,8'h24,8'h25,8'h26,8'h24,8'hE4,8'h14,8'h0C,8'h00};
			mem_hanzi[ 3 ]  = {8'h00,8'h00,8'h00,8'h3F,8'h10,8'h48,8'h40,8'h7F,8'h49,8'h49,8'h49,8'h49,8'h7F,8'h40,8'h40,8'h00};/*"谊",1*/
			mem_hanzi[ 4 ]  = {8'h20,8'h20,8'h20,8'hFF,8'h20,8'h20,8'h80,8'hF8,8'h80,8'h40,8'hFF,8'h20,8'h10,8'hF0,8'h00,8'h00};
			mem_hanzi[ 5 ]  = {8'h10,8'h30,8'h10,8'h0F,8'h08,8'h08,8'h00,8'h3F,8'h40,8'h40,8'h5F,8'h42,8'h44,8'h43,8'h78,8'h00};/*"地",2*/
			mem_hanzi[ 6 ]  = {8'h00,8'h00,8'h80,8'h40,8'h30,8'h0F,8'h08,8'h08,8'h08,8'hC8,8'h38,8'h00,8'h00,8'h00,8'h00,8'h00};
			mem_hanzi[ 7 ]  = {8'h80,8'h81,8'h40,8'h40,8'h20,8'h10,8'h08,8'h04,8'h03,8'h0C,8'h10,8'h20,8'h40,8'h80,8'h80,8'h00};/*"久",3*/
			mem_hanzi[ 8 ]  = {8'h40,8'h40,8'h42,8'h42,8'h42,8'h42,8'h42,8'hFE,8'h42,8'h42,8'h42,8'h42,8'h42,8'h40,8'h40,8'h00};
			mem_hanzi[ 9 ]  = {8'h80,8'h80,8'h40,8'h20,8'h10,8'h0C,8'h03,8'h00,8'h03,8'h0C,8'h10,8'h20,8'h40,8'h80,8'h80,8'h00};/*"天",4*/
			mem_hanzi[ 10 ] = {8'h80,8'h80,8'h80,8'h80,8'hFF,8'h80,8'h80,8'hA0,8'h90,8'h88,8'h84,8'h82,8'h80,8'h80,8'h80,8'h00};
			mem_hanzi[ 11 ] = {8'h00,8'h00,8'h00,8'h00,8'hFF,8'h40,8'h21,8'h12,8'h04,8'h08,8'h10,8'h20,8'h20,8'h40,8'h40,8'h00};/*"长",5*/
			mem_hanzi[ 12 ] = {8'h02,8'hE2,8'h22,8'h22,8'h22,8'hFE,8'h22,8'h22,8'h22,8'hFE,8'h22,8'h22,8'h22,8'hE2,8'h02,8'h00};
			mem_hanzi[ 13 ] = {8'h00,8'hFF,8'h00,8'h08,8'h06,8'h01,8'h16,8'h08,8'h06,8'h01,8'h02,8'h4C,8'h80,8'h7F,8'h00,8'h00};/*"两",0*/
			mem_hanzi[ 14 ] = {8'h00,8'h00,8'h00,8'hFE,8'h02,8'h02,8'h02,8'h02,8'h02,8'h02,8'h02,8'hFE,8'h00,8'h00,8'h00,8'h00};
			mem_hanzi[ 15 ] = {8'h00,8'h80,8'h40,8'h23,8'h19,8'h01,8'h01,8'h01,8'h01,8'h01,8'h09,8'h13,8'h20,8'hC0,8'h00,8'h00};/*"只",1*/
			mem_hanzi[ 16 ] = {8'h20,8'h20,8'h24,8'h24,8'h24,8'h24,8'hBF,8'h64,8'h24,8'h34,8'h28,8'h24,8'h22,8'h20,8'h20,8'h00};
			mem_hanzi[ 17 ] = {8'h10,8'h08,8'h04,8'h02,8'h3F,8'h45,8'h44,8'h44,8'h42,8'h42,8'h42,8'h41,8'h78,8'h00,8'h00,8'h00};/*"老",2*/
			mem_hanzi[ 18 ] = {8'h00,8'h00,8'hF8,8'h08,8'h48,8'h48,8'h48,8'hFF,8'h4A,8'h2A,8'h2A,8'h0A,8'hCA,8'h18,8'h00,8'h00};
			mem_hanzi[ 19 ] = {8'h80,8'h60,8'h1F,8'h80,8'h40,8'h20,8'h1C,8'h04,8'h05,8'h05,8'h7D,8'h81,8'h81,8'hE0,8'h00,8'h00};/*"虎",3*/
			mem_hanzi[ 20 ] = {8'h80,8'h80,8'h40,8'h20,8'h50,8'h48,8'h44,8'hC3,8'h44,8'h48,8'h50,8'h20,8'h40,8'h80,8'h80,8'h00};
			mem_hanzi[ 21 ] = {8'h40,8'h40,8'h42,8'h4A,8'h72,8'h42,8'h42,8'h7F,8'h42,8'h42,8'h62,8'h5A,8'h42,8'h40,8'h40,8'h00};/*"金",0*/
			mem_hanzi[ 22 ] = {8'h40,8'h44,8'h24,8'h24,8'h94,8'h0C,8'h04,8'h7F,8'h04,8'h0C,8'h94,8'h24,8'h24,8'h44,8'h40,8'h00};
			mem_hanzi[ 23 ] = {8'h20,8'h22,8'h12,8'h0A,8'hFF,8'h0A,8'h12,8'h20,8'h12,8'h0A,8'hFF,8'h06,8'h0A,8'h12,8'h20,8'h00};/*"森",1*/
			mem_hanzi[ 24 ] = {8'h40,8'h22,8'h14,8'h08,8'hF4,8'h02,8'h00,8'h04,8'h04,8'h04,8'hFC,8'h04,8'h04,8'h04,8'h00,8'h00};
			mem_hanzi[ 25 ] = {8'h08,8'h44,8'h82,8'h41,8'h3F,8'h00,8'h40,8'h41,8'h41,8'h41,8'h7F,8'h41,8'h41,8'h41,8'h40,8'h00};/*"狂",2*/
			mem_hanzi[ 26 ] = {8'h00,8'h08,8'h88,8'h68,8'hFF,8'h48,8'h88,8'h00,8'hFE,8'h52,8'h52,8'h52,8'hFE,8'h00,8'h00,8'h00};
			mem_hanzi[ 27 ] = {8'h40,8'h31,8'h00,8'h00,8'h3B,8'h40,8'h40,8'h44,8'h5B,8'h42,8'h42,8'h72,8'h03,8'h08,8'h30,8'h00};/*"想",3*/
			mem_hanzi[ 28 ] = {8'h00,8'hF0,8'h10,8'h10,8'h10,8'hFF,8'h10,8'h10,8'h10,8'hFF,8'h10,8'h10,8'h10,8'hF0,8'h00,8'h00};
			mem_hanzi[ 29 ] = {8'h00,8'hFF,8'h42,8'h42,8'h42,8'h7F,8'h42,8'h42,8'h42,8'h7F,8'h42,8'h42,8'h42,8'hFF,8'h00,8'h00};/*"曲",4*/

我是通过PCtoLCD2002软件,输入汉字,然后得到的字模,再放到字库里面

FjyGvLQmCylA7Bd2gmDFMJzJYnMa

Fpn4y7Jd90_QF0LnVe7O3WBDelZw

消抖模块 (key_fliter.v)

Frjs2a4uC1ZAtYVuWaM8B9CJIgSM

我们可以看到,但按键按下的那一刻,存在一段时间的抖动,同时在释放按键的一段时间里也是存在抖动的,这就可能导致状态在识别的时候可能检测为多次的按键,因为运行过程中普通的检测一次状态key为1就执行一次按键操作。所以我们在使用按键时往往需要消抖。消抖方式有很多种,这里我提供一种相对而言比较简单容易理解的方式,通过延时来消抖。我们知道,抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。大家看原理图,其实我们要做的就是,但按键按下去后,只在中间稳定的某一个时刻(10ms)取一个真正按键的使能值就好了(只不过为了更加准确,我取的是20ms)。

module key_fliter//按键消抖
#(
parameter CNT_MAX=17'd239_999
)
(
input wire clk,
input wire rst,
input wire key_in,
output reg key_flag
);
reg [16:0] cnt_20ms;
always@(posedge clk or negedge rst)
	if(rst == 1'b0)
		cnt_20ms<=17'd0;
	else if(key_in == 1'b1)
		cnt_20ms<=17'd0;
	else if(cnt_20ms == CNT_MAX)
		cnt_20ms<=CNT_MAX;
	else
		cnt_20ms<=cnt_20ms+17'd1;
always@(posedge clk or negedge rst)
	if(rst == 1'b0)
		key_flag<=1'b0;
	else if(cnt_20ms == CNT_MAX-17'd1)
		key_flag<=1'b1;
	else
		key_flag<=1'b0;
endmodule

music顶层模块(v)

在这个模块中,我将各模块的代码进行整合,同时将蜂鸣器的那部分代码一起写在了这里,主要就是设置每个音符的对应参数,以及按照乐谱写出音符的排列顺序。

每个音符最大计数:

parameter L_1=16'd45802,
parameter L_2=16'd40816,
parameter L_3=16'd36364,
parameter L_4=16'd34384,
parameter L_5=16'd30612,
parameter L_6=16'd27273,
parameter L_7=16'd24291,
parameter M_1=16'd22931,
parameter M_2=16'd20432,
parameter M_3=16'd18201,
parameter M_4=16'd17180,
parameter M_5=16'd15306,
parameter M_6=16'd13636,
parameter M_7=16'd12148,
parameter H_1=16'd11434,
parameter H_2=16'd10215,
parameter H_3=16'd9101,
parameter H_4=16'd8590,
parameter H_5=16'd7653,
parameter H_6=16'd6818,
parameter H_7=16'd6074

歌曲代码:

FhPBDdvo0EuR6QgVXlIERKl96eTy

always@(posedge clk or negedge rst)	begin			
	case(cnt_250ms)
	   //曲目1:友谊地久天长
	    8'd0,8'd1:                                              freq_data <= L_5;
        8'd2,8'd3,8'd4,8'd5,8'd6,8'd7,8'd8:                     freq_data <= M_1;
        8'd9,8'd10:                                             freq_data <= M_3;
        8'd11,8'd12,8'd13,8'd14:                                freq_data <= M_2;
        8'd15:                                                  freq_data <= M_1;
        8'd16,8'd17:                                            freq_data <= M_2;
        8'd18,8'd19:                                            freq_data <= M_3;
        8'd20,8'd21,8'd22,8'd23,8'd24:                          freq_data <= M_1;
        8'd25,8'd26:                                            freq_data <= M_3;
        8'd27,8'd28:                                            freq_data <= M_5;
        8'd29,8'd30,8'd31,8'd32,8'd33:                          freq_data <= M_6;
        8'd34,8'd35,8'd36,8'd37,8'd38:                          freq_data <= M_6;
        8'd39,8'd40,8'd41,8'd42:                                freq_data <= M_5;
        8'd43,8'd44,8'd45:                                      freq_data <= M_3;
        8'd46,8'd47:                                            freq_data <= M_1;
        8'd48,8'd49,8'd50,8'd51:                                freq_data <= M_2;
        8'd52:                                                  freq_data <= M_1;
        8'd53,8'd54:                                            freq_data <= M_2;
        8'd55,8'd56:                                            freq_data <= M_3;
        8'd57,8'd58,8'd59,8'd60:                                freq_data <= M_1;
        8'd61,8'd62,8'd63:                                      freq_data <= L_6;
        8'd64,8'd65:                                            freq_data <= M_5;
        8'd66,8'd67,8'd68,8'd69:                                freq_data <= M_1;
        8'd70,8'd71,8'd72,8'd73:                                freq_data <= M_1;
        8'd74,8'd75:                                            freq_data <= M_6;
        8'd76,8'd77,8'd78,8'd79:                                freq_data <= M_5;
        8'd80,8'd81,8'd82:                                      freq_data <= M_3;
        8'd83,8'd84:                                            freq_data <= M_1;
        8'd85,8'd86,8'd87,8'd88:                                freq_data <= M_2;
        8'd89:                                                  freq_data <= M_1;
        8'd90,8'd91:                                            freq_data <= M_2;
        8'd92,8'd93:                                            freq_data <= M_6;
        8'd94,8'd95,8'd96,8'd97:                                freq_data <= M_5;
        8'd98,8'd99,8'd100:                                     freq_data <= M_3;
        8'd101,8'd102:                                          freq_data <= M_5;
        8'd103,8'd104,8'd105,8'd106:                            freq_data <= M_6;
        8'd107,8'd108,8'd109,8'd110:                            freq_data <= M_6;
        8'd111,8'd112:                                          freq_data <= H_1;
        8'd113,8'd114,8'd115,8'd116:                            freq_data <= M_5;
        8'd117,8'd118,8'd119:                                   freq_data <= M_3;
        8'd120,8'd121:                                          freq_data <= M_1;
        8'd122,8'd123,8'd124,8'd125:                            freq_data <= M_2;
        8'd126:                                                 freq_data <= M_1;
        8'd127,8'd128:                                          freq_data <= M_2;
        8'd129,8'd130:                                          freq_data <= M_3;
        8'd131,8'd132,8'd133,8'd134:                            freq_data <= M_1;
        8'd135,8'd136,8'd137:                                   freq_data <= L_6;
        8'd138,8'd139:                                          freq_data <= M_5;
        8'd140,8'd141,8'd142,8'd143:                            freq_data <= M_1;
        8'd144,8'd145,8'd146,8'd147:                            freq_data <= M_1;			
	    //曲目2:两只老虎                                                  
        8'd148:                                                 freq_data <= M_1;
	    8'd149:                                                 freq_data <= M_2;
	    8'd150:                                                 freq_data <= M_3;
	    8'd151:                                                 freq_data <= M_1;
	    8'd152:                                                 freq_data <= M_1;
	    8'd153:                                                 freq_data <= M_2;
	    8'd154:                                                 freq_data <= M_3;
	    8'd155:                                                 freq_data <= M_1;
	    8'd156:                                                 freq_data <= M_3;
	    8'd157:                                                 freq_data <= M_4;
	    8'd158:                                                 freq_data <= M_5;
	    8'd159:                                                 freq_data <= M_3;
	    8'd160:                                                 freq_data <= M_4;
	    8'd161:                                                 freq_data <= M_5;
	    8'd162:                                                 freq_data <= M_5;
	    8'd163:                                                 freq_data <= M_6;
	    8'd164:                                                 freq_data <= M_5;
	    8'd165:                                                 freq_data <= M_4;
	    8'd166:                                                 freq_data <= M_3;
	    8'd167:                                                 freq_data <= M_1;
	    8'd168:                                                 freq_data <= M_5;
	    8'd169:                                                 freq_data <= M_6;
	    8'd170:                                                 freq_data <= M_5;
	    8'd171:                                                 freq_data <= M_4;
	    8'd172:                                                 freq_data <= M_3;
	    8'd173:                                                 freq_data <= M_1;
	    8'd174:                                                 freq_data <= M_2;
	    8'd175:                                                 freq_data <= M_5;
	    8'd176:                                                 freq_data <= M_1;
	    8'd177:                                                 freq_data <= M_2;
	    8'd178:                                                 freq_data <= M_5;
	    8'd179:                                                 freq_data <= M_1;
		//曲目3:金森狂想曲                                        
        8'd180:                                                 freq_data <= L_6;  
	    8'd181:                                                 freq_data <= M_1;
	    8'd182:                                                 freq_data <= M_3;
	    8'D183:                                                 freq_data <= M_5;
	    8'D184,8'D185:                                          freq_data <= M_3;
	    8'D186:                                                 freq_data <= M_3;
	    8'D187:                                                 freq_data <= M_2;
	    8'D188,8'D189:                                          freq_data <= M_3;
	    8'D190:                                                 freq_data <= M_3;
	    8'D191:                                                 freq_data <= M_2;
	    8'D192,8'D193:                                          freq_data <= M_3;
	    8'D194:                                                 freq_data <= L_6;
	    8'D195:                                                 freq_data <= L_7;	    
	    8'D196:                                                 freq_data <= M_1;
	    8'D197:                                                 freq_data <= M_3;
	    8'D198:                                                 freq_data <= M_2;
	    8'D199:                                                 freq_data <= M_1;
	    8'D200,8'D201:                                          freq_data <= L_6;
	    8'D202,8'D203:                                          freq_data <= L_5;	    
	    8'D204,8'D205,8'D206,8'D207,8'D208,8'D209,8'D210,8'D211:freq_data <= L_3;
	    8'd212:                                                 freq_data <= L_6;  
	    8'd213:                                                 freq_data <= M_1;
	    8'd214:                                                 freq_data <= M_3;
	    8'D215:                                                 freq_data <= M_5;
	    8'D216,8'D217:                                          freq_data <= M_3;
	    8'D218:                                                 freq_data <= M_3;
	    8'D219:                                                 freq_data <= M_2;
	    8'D220,8'D221:                                          freq_data <= M_3;
	    8'D222:                                                 freq_data <= M_3;
	    8'D223:                                                 freq_data <= M_2;
	    8'D224,8'D225:                                          freq_data <= M_3;
	    8'D226:                                                 freq_data <= L_6;
	    8'D227:                                                 freq_data <= L_7;
	    8'D228:                                                 freq_data <= M_1;
	    8'D229:                                                 freq_data <= M_3;
	    8'D230:                                                 freq_data <= M_2;
	    8'D231:                                                 freq_data <= M_1;
	    8'D232,8'D233:                                          freq_data <= L_6;
	    8'D234,8'D235:                                          freq_data <= L_5;
	    8'D236,8'D237,8'D238,8'D239,8'D240,8'D241:              freq_data <= L_6;
	    8'D242:                                                 freq_data <= L_6;
	    8'D243:                                                 freq_data <= L_7;
		default:freq_data=16'hffff;	
	endcase
end	

切换歌曲代码:

always@(posedge clk or negedge rst) 
	if(!rst) 
		begin cnt_250ms_min=8'd0;  cnt_250ms_max<=8'd147; end
	else if(key_flag_1) 
		begin cnt_250ms_min=8'd148;cnt_250ms_max<=8'd179; end
	else if(key_flag_2)			
		begin cnt_250ms_min=8'd180;cnt_250ms_max<=8'd243; end
	else if(!f_1min)
		begin cnt_250ms_min=8'd254;cnt_250ms_max<=8'd254; end
	else
		begin cnt_250ms_min=cnt_250ms_min;cnt_250ms_max<=cnt_250ms_max; end

一分钟计时代码:

always@(posedge clk or negedge rst)
	if(rst == 1'b0)
		f_1min<=1'b1;
	else if(key_flag_1 || key_flag_2)
		f_1min<=1'b1;
	else if(cnt_1min == CNT_1MIN_MAX)
		f_1min<=1'b0;
	else
		f_1min<=f_1min;		
always@(posedge clk or negedge rst)
	if(rst == 1'b0)
		cnt_1min<=30'd0;
	else if(key_flag_1 || key_flag_2)
		cnt_1min<=30'd0;
	else if(cnt_1min == CNT_1MIN_MAX-30'd1)
		cnt_1min<=CNT_1MIN_MAX;
	else if(f_1min)
		cnt_1min<=cnt_1min+30'd1;		
	else 
		cnt_1min<=30'd0;	

任意一个按键按下后,选择相应歌曲从头开始播放,同时1分钟计时从头开始,1分钟时间到后蜂鸣器停止发声,使得歌曲单曲循环持续时间达到1分钟。

固定每一个音节持续时间为250ms:

always@(posedge clk or negedge rst)
	if(rst == 1'b0)
		cnt<=0;
	else if(cnt == CNT_MAX)
		cnt<=0;
	else
		cnt<=cnt+23'b1;
always@(posedge clk or negedge rst)	begin
	if(!rst)
		cnt_250ms<=8'd0;
	else if(key_flag_1)
		cnt_250ms<=8'd148;
	else if(key_flag_2)
		cnt_250ms<=8'd180;		
	else if((cnt_250ms == cnt_250ms_max) && (cnt == CNT_MAX))
		cnt_250ms<=cnt_250ms_min;
	else if(cnt == CNT_MAX)
		cnt_250ms<=cnt_250ms+3'd1;
	else
		cnt_250ms<=cnt_250ms;
end	

蜂鸣器代码:

assign duty_data=freq_data>>1;
always@(posedge clk or negedge rst)
	if(rst == 1'b0)
		beep<=1'b0;
	else if((freq_cnt>=duty_data)&&(f_1min))
		beep<=1'b1;
	else
		beep<=1'b0;

引例整合部分代码:

key_fliter key_fliter_u1
(
.clk(clk),
.rst(rst),
.key_in(key_in_1),
.key_flag(key_flag_1)
);
key_fliter key_fliter_u2
(
.clk(clk),
.rst(rst),
.key_in(key_in_2),
.key_flag(key_flag_2)
);
OLED12864	OLED12864_u1 
(
.clk     (clk) ,		
.rst_n   (rst),		
.key_flag_1(key_flag_1),
.key_flag_2(key_flag_2),

//.oled_csn(oled_csn),			
.oled_rst(oled_rst),			
.oled_dcn(oled_dcn),	
.oled_clk(oled_clk),	
.oled_dat(oled_dat)		
);

使占空比为50%,只需改变最大计数值,使频率计数大于占空比计数时蜂鸣器输出高电平,其余时刻输出低电平,产生周期不同,占空比相同的PWM。

以上就是代码部分的全部内容。

完成情况:

所有要求已全部完成,但某些方面还需要完善,比如说OLED显示部分用ROM,IP核来实现存储器可能效果更好,看到一些人将顶层写得很简单,模块化很多,所以我觉得我对模块化编程还不能应用自如,代码文件已经全部上传附件,里面还有一些不完美的代码,希望可以和大家互相交流学习。

遇到的问题:

最主要的是OLED显示的问题,一直没想好怎么切换歌曲名称,曾经想过采用刷新的方式,在刷新的时候检测按键状态来进行切换,后失败,改用一次显示,检测按键状态,根据其状态来一次显示应该显示的歌曲名称。

其次遇到的问题就是无论按下哪一个按键都是第一首歌播放,后面发现是初值没有改。

总结:

这次实践项目我完成了基本的内容,因为是初学FPGA,所以先花了一部分时间将基础的一些程序比如构建一些数字电路,点亮LED,使蜂鸣器响等等,等把那些基础程序都跑过之后才开始做的项目,所以花了不少时间来学习,虽然很累当时但确实学到了许多知识,也在网站上参考学习了很多别人的代码思路,对我做出这个任务有了很大的启发,当然这次也有很多是我没有找到相似思路的问题,但经过思考最终也得到了解决,这次的项目包含了几个小任务,需要一个个解决,也锻炼了我解决项目问题的能力。我觉得我模块化编程的能力还需要再加强,希望以后可以继续学习,把本次实践学到知识加以利用,更上一层楼!。

 

 

附件下载
music.zip
团队介绍
罗继成
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号