基于iCE40UP5K的FPGA学习平台-利用PWM制作一个音乐播放器
完成了利用PWM制作一个音乐播放器,实现了通过PWM产生不同的音调,蜂鸣器将音调输出;能播放三首不同的曲子,时间长度为1分钟,可切换播放;使用扩展板的按键,有按键消抖的功能;曲子的名字在OLED屏幕上显示出来功能
标签
FPGA
ICE40UP5K
2022寒假在家练
千千3
更新2022-03-04
北京理工大学
1201

1 项目需求

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

2 完成的功能及达到的性能

2.1歌曲及时长的显示

将文件录入后,进入初始页面,如下图所示:

FvgWXCMUCaGKWO4ITtq4lOnS450I

按下"RUN”按键,执行“reset”指令,即可在64x128的OLED屏幕上显示出歌曲的汉字名称以及时长(距离歌曲结束所剩余的时间)。初始的歌曲为火影忍者的主题曲青鸟,如下图所示:

Fn5SJHNyLYWvO2FL25-7gI6Szz3d

2.2歌曲的切换

“K1”按键可执行“下一曲”的指令,按下“K1”键,由第一首歌曲切换到第二首歌曲“党歌”(即国际歌),其歌曲名及时长如下图所示:

FigWc6tOBLh81RrKZ9TvWZxuOy1l

再次按下“K1”键,由第二首歌曲切换到第三首歌曲——陈奕迅的“好久不见”,其歌曲名及时长如下图所示:

FiTy30CJO4domyxTfFXwIml24OVc

2.3歌曲的播放与暂停

“K2”按键可执行歌曲的播放与暂停功能,按下“K2”键,播放第一首歌曲“青鸟”一段时间后,如下图所示:

FrOKHFsso2nil46Tp5PpKxcRkLR5

经过一段时间后,再次按下“K2”键,即可实现暂停,如下图所示:

FhV1wMQg5jb3RG5TXqEH5t0mmRvs

3 实现思路

   1. 分别设计"beeper"(蜂鸣器)、"oled"(OLED屏幕)、"debounce"(消抖)、"timer"(计时器)四个模块,再通过"top"(顶层)模块将它们连接起来。

   2. "beeper"(蜂鸣器)模块用于实现歌曲的播放功能。运用PWM技术对占空比进行调制,从而产生不同的频率,并将其分为三个大段的七个音阶,实现对音符的调节。再通过音符表与节拍表的一一对应,即可实现播放功能。

   3. "oled"(OLED屏幕)模块用于实现歌曲名称的显示(汉字名称),以及歌曲时长的显示功能。其规格为64x128,运用小脚丫的基本程序代码,通过排列8x8的屏幕块,实现16x16的汉字、16x8的数字输入及显示。

   4. "debounce"(消抖)模块用于实现按键的消抖功能。这一部分可以直接运用小脚丫的程序代码,实现“K1”和“K2”两个按键的消抖。

   5. "timer"(计时器)模块用于实现计时功能。将时钟分为分、秒(十位)和秒(个位),初始时间需要计算并录入,之后每秒减1,实现对歌曲剩余时间的记录。

4 实现过程

4.1PWM产生音阶

根据不同的音节控制,选择对应的计数终值(分频系数)。低音1的频率为261.6Hz,蜂鸣器控制信号周期应为12MHz/261.6Hz = 45871.5,因为本设计中蜂鸣器控制信号是按计数器周期翻转的,所以几种终值 = 45871.5/2 = 22936,需要计数22936个,计数范围为0 ~ (22936-1),所以time_end = 22935

always@(tone) begin
	case(tone)
		5'd1:	time_end =	16'd22935;	//L1,
		5'd2:	time_end =	16'd20428;	//L2,
		5'd3:	time_end =	16'd18203;	//L3,
		5'd4:	time_end =	16'd17181;	//L4,
		5'd5:	time_end =	16'd15305;	//L5,
		5'd6:	time_end =	16'd13635;	//L6,
		5'd7:	time_end =	16'd12147;	//L7,
		5'd8:	time_end =	16'd11464;	//M1,
		5'd9:	time_end =	16'd10215;	//M2,
		5'd10:	time_end =	16'd9100;	//M3,
		5'd11:	time_end =	16'd8589;	//M4,
		5'd12:	time_end =	16'd7652;	//M5,
		5'd13:	time_end =	16'd6817;	//M6,
		5'd14:	time_end =	16'd6073;	//M7,
		5'd15:	time_end =	16'd5740;	//H1,
		5'd16:	time_end =	16'd5107;	//H2,
		5'd17:	time_end =	16'd4549;	//H3,
		5'd18:	time_end =	16'd4294;	//H4,
		5'd19:	time_end =	16'd3825;	//H5,
		5'd20:	time_end =	16'd3408;	//H6,
		5'd21:	time_end =	16'd3036;	//H7,
		default:time_end =	16'd65535;	
	endcase
end

4.2字幕选择数据

将汉字与数字通过choice分成8x8的小块排列输入并显示

always@(posedge clk or negedge rst_n)//字幕选择数据
begin
		if(!rst_n) begin
			choice[0] = 128'h0102_0000_0506_0000_0000_0000_0000_0000;
			choice[1] = 128'h0304_0000_0708_0000_0000_0000_0000_0000;
			choice[2] = time_1;
			choice[3] = time_2; end
		else if(flag==3'd1) begin
			choice[0] = 128'h0102_0000_0506_0000_0000_0000_0000_0000;
			choice[1] = 128'h0304_0000_0708_0000_0000_0000_0000_0000;
			choice[2] = time_1;
			choice[3] = time_2; end
		else if(flag==3'd2) begin
			choice[0] = 128'h090a_0000_0d0e_0000_0000_0000_0000_0000;
			choice[1] = 128'h0b0c_0000_0f10_0000_0000_0000_0000_0000;
			choice[2] = time_1;
			choice[3] = time_2; end
		else if(flag==3'd3) begin
			choice[0] = 128'h1112_0000_1516_0000_191a_0000_1d1e_0000;
			choice[1] = 128'h1314_0000_1718_0000_1b1c_0000_1f20_0000;
			choice[2] = time_1;
			choice[3] = time_2; end
		else begin
			choice[0] = 128'h0000_0000_0000_0000_0000_0000_0000_0000;
			choice[1] = 128'h0000_0000_0000_0000_0000_0000_0000_0000;
			choice[2] = 128'h0000_0000_0000_0000_0000_0000_0000_0000;
			choice[3] = 128'h0000_0000_0000_0000_0000_0000_0000_0000; end
end

4.3设置初始时间并实现计时

将时钟分为分、秒(十位)和秒(个位),每一首歌曲的总时长需要提前计时,并对每一位分别录入,设置flag_pre来存储前一步的flag状态,与现在flag相比较,如果发生变化则切换计时,计时过程中,由秒(个位)开始减1,以此类推。

always@(posedge clk or negedge rst) begin
	if(!rst) begin
		minute <= 2'd1; 
		second_ge <= 4'd4;
		second_shi <= 1'b0;
		flag_pre <= 3'd1;
		count <= 1'b0; end
	else if(flag_pre != flag) begin
		case(flag)
			3'd1:	begin second_ge <= 4'd4;second_shi <= 1'b0;minute <= 2'd1; end
			3'd2:	begin second_ge <= 4'd5;second_shi <= 1'b1;minute <= 2'd1; end
			3'd3:	begin second_ge <= 4'd1;second_shi <= 4'd4;minute <= 2'd1; end
		endcase
		flag_pre <= flag;
		count <= 1'b0;
		end
	else if(!ss) begin
		count <= count; 
		end
	else if((count >= 24'd12000000)&&(second_ge == 4'd0)&&(second_shi != 4'd0)) begin
		second_ge <= 4'd9;
		second_shi <= second_shi - 1'b1;
		count <= 1'b0;
		end
	else if((count >= 24'd12000000)&&(second_ge == 4'd0)&&(second_shi == 4'd0)&&(minute !=2'd0)) begin
		second_ge <= 4'd9;
		second_shi <= 4'd5;
		minute <= minute - 1'b1;
		count <= 1'b0;
		end
	else if((count >= 24'd12000000)&&(second_ge == 4'd0)&&(second_shi == 4'd0)&&(minute ==2'd0)) begin
		second_ge <= 1'b0; 
		second_shi <= 1'b0;  
		minute <= 1'b0;
		count <= 1'b0; end
	else if(count >= 24'd12000000) begin
		count <= 1'b0;
		second_ge <= second_ge - 1'b1; end
	else begin count <= count + 1'b1; end
end

5 遇到的主要难题

   1. PWM实现音阶的输出

   2. 歌曲节拍的计算

   3. 汉字和数字在OLED屏幕上的输入与显示

   4. 歌曲计时初值的设定

6 未来的计划建议

该项目已经成功实现了音乐播放器的功能,并达到了预期指标。然而通过更换硬件,还有许多可以提升与扩展的地方:

   1. 歌曲数目较少,可添加更多歌曲

   2. 可进行按键的调节,实现倍速播放

   3. 运用彩灯功能,实现播放歌曲的同时再增加彩灯效果

附件下载
music_player.rar
工程文件
团队介绍
团队成员
李千骥
北京理工大学大学生
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号