一、项目介绍
要求使用基于iCE40UP5K的FPGA学习平台完成可定时的音乐时钟,并且实现扩展板上的12颗彩灯对应于12个小时,通过FPGA产生时钟,在OLED显示屏上显示包含时、分、秒的时间信息。同时要求实现闹钟功能,即通过可控的手段设定闹钟时间和当前时间,在当前时间到达设定闹钟时,触发蜂鸣器播放音乐,同时彩灯闪烁,共计5s。
二、硬件介绍
本设计基于 Lattice 的 ICE40UP5K FPGA,板载 LPC11U35 下载器,可以通过 USB-C 接口进行 FPGA 的配置,支持在 ICE40UP5K 上对 RISC-V 软核的移植以及开源的 FPGA 开发工具链,板上 RGB 三色 LED 灯用于简单的调试,总计 28 个 IO 用于扩展使用。
三、方案框图及设计思路
首先处理整个项目,将其分为时间时钟、OLED显示及操控、彩灯显示、蜂鸣器触发四个大部分。
四、关键代码及软件流程
软件流程图如下
用top.v文件起到整合各个模块的功能,时间时钟部分包含了diff_time.v,time_contrl.v两部分代码;OLED显示与操作包括了debounce.v,key.v,oled.v三部分代码;彩灯闪烁通过WS2812.v实现;beeper.v及b_contrl.v完成了蜂鸣器实现音乐的内容。下面是一些关键部分实现的代码。
计算可用于在OLED屏幕显示的二位时间:
always @(posedge clk or negedge rst) begin
if (!rst) begin
diff_hour1 <= 0; diff_hour0 <= 0;
diff_min1 <= 0; diff_min0 <= 0;
diff_sec1 <= 0; diff_sec0 <= 0;
end else begin
diff_hour1 <= diff_hour / 10;
diff_hour0 <= diff_hour % 10;
diff_min1 <= diff_min / 10;
diff_min0 <= diff_min % 10;
diff_sec1 <= diff_sec / 10;
diff_sec0 <= diff_sec % 10;
end
end
文字显示的实现,此处仅截取部分代码供参考,主要思路是通过定位的思想用点阵书写汉字,参考了开源平台上的代码得到的结果。
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 <= choice[0];state <= CHINESE;end
5'd2:begin y_p <= 8'hb1;x_ph <= 8'h10;x_pl <= 8'h00;num <= 5'd16;char <= choice[1];state <= CHINESE;end
5'd3:begin y_p <= 8'hb2;x_ph <= 8'h10;x_pl <= 8'h00;num <= 5'd16;char <= {" ",curr_hour1,curr_hour0,"h",curr_min1,curr_min0,"m",curr_sec1,curr_sec0,"s "};state <= SCAN;end
5'd4:begin y_p <= 8'hb3;x_ph <= 8'h10;x_pl <= 8'h00;num <= 5'd16;char <= choice[4];state <= CHINESE;end
5'd5:begin y_p <= 8'hb4;x_ph <= 8'h10;x_pl <= 8'h00;num <= 5'd16;char <= choice[5];state <= CHINESE;end
5'd6:begin y_p <= 8'hb5;x_ph <= 8'h10;x_pl <= 8'h00;num <= 5'd16;char <= {" ",next_hour1,next_hour0,"h",next_min1,next_min0,"m",next_sec1,next_sec0,"s "};state <= SCAN;end
5'd7:begin y_p <= 8'hb6;x_ph <= 8'h10;x_pl <= 8'h00;num <= 5'd16;char <= choice[6];state <= CHINESE;end
5'd8:begin y_p <= 8'hb7;x_ph <= 8'h10;x_pl <= 8'h00;num <= 5'd16;char <= choice[7];state <= CHINESE;end
蜂鸣器设计音乐节拍的节奏:
always@(tcon) begin
case(tcon)
5'd 1: time_delay = 28'd2250000;
5'd 2: time_delay = 28'd4500000;
5'd 3: time_delay = 28'd6750000;
5'd 4: time_delay = 28'd9_000_000;
5'd 6: time_delay = 28'd13500000;
5'd 8: time_delay = 28'd18000000;
5'd12: time_delay = 28'd27000000;
5'd16: time_delay = 28'd36000000;
5'd24: time_delay = 28'd72000000;
default:time_delay = 28'd0;
endcase
end
以及通过tone变量控制蜂鸣器的发声:
always@(posedge clk_in or negedge rst_n_in) begin
if(rst_n_in == 1'b0) begin
piano_out <= 1'b0;
end else if(tone==5'd0) begin
piano_out <= 1'b0;
end else if(time_cnt==time_end) begin
piano_out <= ~piano_out;
end else begin
piano_out <= piano_out;
end
end
五、功能展示及说明
具体内容已在视频中展示,下面简述一下操作:通过复位按钮开始,起始的时间为00h00m00s,起始的闹钟为00h00m00s。为了防止调闹钟过程中意外触发闹钟,操作面板共计有七个内容:当前时刻的时、分、秒设置,闹钟的时、分、秒设置,以及空白就绪态。闹钟仅会在空白就绪态触发。左侧按钮调整操作面板内容,右侧按钮使得数值增加。当闹钟响起后,再次按下右侧按钮将停止彩灯闪烁,音乐会在触发后5s自动停止。
六、遇到的难题及解决方案
主要难题在音乐播放以及文字展示上,文字展示通过上学习平台查询相关代码得以理解学习,通过工具将汉字点阵化,再输入到板子中,通过将所有需要使用到的汉字预先载入,就可以实现汉字的展示。音乐播放则是需要将音乐片段的节奏以及音调使用蜂鸣器实现,该部分在实现过程中遇到的问题较多,例如板载资源不足以完整复现歌曲,需要通过降低歌曲的连续性来做到复现。
附:资源占用情况