2025寒假练-基于iCE40UP5K的FPGA学习平台完成可定时的音乐时钟
该项目使用了基于iCE40UP5K的FPGA学习平台、verilog语言,实现了可定时的音乐时钟的设计,它的主要功能为:核心板上的FPGA产生时钟,在OLED显示屏显示当前的时间,具有定时的功能。。
标签
FPGA
RGB
更新2025-03-24
19

一、项目介绍

本项目基于硬禾科技iCE40UP5K FPGA学习平台,结合OLED显示屏、12RGB彩灯、蜂鸣器及按键模块,设计了一款兼具实用性与趣味性的智能时钟。核心功

能包括:FPGA生成实时时钟信号,通过OLED显示时间(时、分、秒)。12RGB彩灯对应12小时制时间,通过动态光效直观展示当前小时。可以设置定时时间,触发后彩灯闪烁+蜂鸣器播放音乐,持续5秒。


二、使用到的硬件介绍

主控芯片:Lattice iCE40UP5K FPGA

采用低功耗40nm工艺,静态功耗低至数十微瓦,适合电池供电或低功耗场景。提供多达56个可编程GPIO,支持多种电平标准(1.2V/3.3V),兼容常见外设接口。支持开源工具链和Lattice官方软件,降低开发门槛。

硬件平台特性

可以直接通过USB端口对FPGA的串行Flash进行配置,并可以通过同一个USB端口支持UART通信;GPIO布局与树莓派Pico完全兼容,可直接使用Pico生态的扩展板(如传感器、显示屏模块)。板载LED、按键、复位电路等调试必备组件。内置12MHz晶振,支持外部时钟输入扩展高频应用。

扩展板

2个按键输入;4个单色LED12WS2812B RGB三色灯;1个姿态传感器;1128*64 OLED显示屏;1个蜂鸣器等等。

这块板子兼顾了FPGA的硬件可编程性与树莓派生态的扩展性。从工具链到软核均支持开源,适合学习与二次开发。

 

三、方案框图和项目设计思路介绍

时钟生成模块

输入:12MHz晶振时钟信号。

输出:1Hz秒脉冲(驱动时间计数器)、时//秒寄存器值。

功能:通过分频链生成精准时钟信号,维护当前时间数据。

 

OLED显示驱动

接口:I2C协议。

输入:当前时间、定时设置状态。

输出:数字时钟界面

 

按键处理模块

接口:GPIO输入,带硬件消抖。

输入:物理按键动作。

输出:时间校准指令、定时设置参数。

 

PWM控制模块

RGB彩灯驱动,生成WS2812B协议时序。

蜂鸣器音乐合成,输出PWM方波控制音调与音量。

 

外设硬件层

树莓派Pico扩展板,提供物理接口,包括:

12WS2812B彩灯,显示当前时刻,在定时时刻产生流水灯效果。

两个按键用于调整当前时间,设置定时时间

蜂鸣器模块:通过PWM信号驱动发声。

 

四、关键代码介绍

下面是关于核心模块contol的介绍,该模块实现了:

实时时钟生成与维护(时、分、秒)。

定时器设置与触发(最多3组定时)。

蜂鸣器音乐播放控制(通过PWM频率合成音调)。

1、输入输出信号

module control(
input clk ,
input rstn ,
input [1:0] shape ,
output reg [4:0] hour ,
output reg [5:0] minute ,
output reg [5:0] second ,
output reg [2:0] T_cnt ,
output reg [4:0] T_hour ,
output reg [5:0] T_minute,
output reg [5:0] T_second,
output reg busyb ,
output reg beep
);

2、1秒定时生成

reg [25:0] cnt1s;
parameter num1s = 12000000;
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
cnt1s <= 0;
end else if(cnt1s >= num1s)begin
cnt1s <= 0;
end else begin
cnt1s <= cnt1s+1;
end
end
wire flag;

每1秒产生一个脉冲(flag信号),用于更新时分秒。

3、时间计数器(时、分、秒)

always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
second <= 0;
end else if(second>=59 && flag)begin
second <= 0;
end else if(flag)begin
second <= second+1;
end else begin
second <= second;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
minute <= 0;
end else if(minute>=59 && second>=59 && flag)begin
minute <= 0;
end else if(second>=59 && flag)begin
minute <= minute+1;
end else begin
minute <= minute;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
hour <= 3;
end else if(hour>=11 && minute>=59 && second>=59 && flag)begin
hour <= 0;
end else if(minute>=59 && second>=59 && flag)begin
hour <= hour+1;
end else begin
hour <= hour;
end
end

秒、分、时级联更新,依赖flag信号。

4、定时器设置逻辑

always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
T_cnt <= 0;
end else if(T_cnt>=3 && shape[0])begin
T_cnt <= 0;
end else if(shape[0])begin
T_cnt <= T_cnt+1;
end else begin
T_cnt <= T_cnt;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
T_hour <= 3;
end else if(T_cnt==1 && T_hour>=11 && shape[1])begin
T_hour <= 0;
end else if(T_cnt==1 && shape[1])begin
T_hour <= T_hour+1;
end else begin
T_hour <= T_hour;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
T_minute <= 0;
end else if(T_cnt==2 && T_minute>=59 && shape[1])begin
T_minute <= 0;
end else if(T_cnt==2 && shape[1])begin
T_minute <= T_minute+1;
end else begin
T_minute <= T_minute;
end
end

T_cnt控制设置步骤(0:未设置,1:设置小时,2:设置分钟,3:设置秒)。

shape[0]用于切换步骤,shape[1]用于增减数值。

5、定时触发逻辑

reg [5:0] second_b;
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
busyb <= 0;
end else if(T_hour==hour && T_minute==minute && T_second==second && T_cnt==0)begin
busyb <= 1;
end else if(second_b >= 5)begin
busyb <= 0;
end else begin
busyb <= busyb;
end
end
reg [25:0] cntb;
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
cntb <= 0;
end else if(busyb)begin
if(cntb >= num1s)begin
cntb <= 0;
end else begin
cntb <= cntb+1;
end
end else begin
cntb <= 0;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
second_b <= 0;
end else if(busyb)begin
if(cntb >= num1s)begin
second_b <= second_b+1;
end else begin
second_b <= second_b;
end
end else begin
second_b <= 0;
end
end

当定时时间(T_hour/T_minute/T_second)与当前时间匹配时,触发busyb信号。

second_b计数5秒后关闭提醒。

6、蜂鸣器音乐合成

reg [5:0] addr;
wire [2:0] music;
Song Song(
.addr (addr ), //input [5:0] addr ,
.music (music) //output reg [2:0] music
);
reg [25:0] cnt1;
parameter num1 = 3500000;
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
cnt1 <= 0;
end else if(busyb)begin
if(cnt1 >= num1)begin
cnt1 <= 0;
end else begin
cnt1 <= cnt1+1;
end
end else begin
cnt1 <= 0;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
addr <= 0;
end else if(busyb)begin
if(cnt1 >= num1)begin
addr <= addr+1;
end else begin
addr <= addr;
end
end else begin
addr <= 0;
end
end
reg [19:0] freq_num;
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
freq_num <= 0;
end else begin
case(music)
1: freq_num <= 22944;
2: freq_num <= 20442;
3: freq_num <= 18209;
4: freq_num <= 17191;
5: freq_num <= 15306;
6: freq_num <= 13636;
7: freq_num <= 12145;
default:
freq_num <= 0;
endcase
end
end
reg [19:0] freq_cnt;
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
freq_cnt <= 0;
end else if(freq_cnt >= freq_num)begin
freq_cnt <= 0;
end else begin
freq_cnt <= freq_cnt+1;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
beep <= 0;
end else if(busyb)begin
beep <= (freq_cnt >= freq_num[19:1]) ? 1 : 0;
end else begin
beep <= 0;
end
end

Song模块通过addr读取音符序列,生成music编码。

freq_num决定音调频率,freq_cnt生成PWM波形。



五、功能展示图及说明

1、时间显示

如图1OLED屏幕上显示当前时间,030119代表三点过一分十九秒,RGB灯显示为三点钟。

1

2、定时功能

       如图2,第一行为当前时间,第二行为设定的定时时刻,当到达定时时刻时,触发动态流水灯与蜂鸣器播放效果。

2

 3、定时调整功能

       可以通过k1,k2按钮调整定时的时刻。此处不太方便配图,可以下载我上传的文件进行尝试。


六、 项目中遇到的难题和解决方法

       在整个项目过程中,我遇到了两个主要的问题,Verilog代码不熟悉和Lattice Radiant软件的使用问题。

       面对Verilog代码的不熟悉,首先我重新了解FPGA设计的基础和Verilog的基本概念,包括模块、总线、端口等。通过在线课程或教学视频学习更进一步的内容,增强对Verilog编程的理解。利用已有的代码样本进行实践,帮助我理解Verilog代码的结构和功能,也通过改进或重构这些代码以获得更深的理解。

       在软件使用上,我尝试了阅读并理解Lattice Radiant的官方文档,包括用户指南、教程和示例,这有助于我了解软件的基本操作和使用方法。此外我还搜索和参考网上的社区论坛和问答平台上的相关帖子,在其他用户的问题和解答中找到了我遇到的问题的解决方案。


七、对本次活动的心得体会

       在这次“硬禾科技2025寒假在家一起练活动”中,我选择了基于iCE40UP5KFPGA学习平台,并成功完成了一个可定时的音乐时钟。我认识到,这个过程并不是轻而易举的,但这的确是一个非常宝贵的学习经验。

       当我开始动手操作时,我首次意识到我对Verilog代码的理解较差,而这对于我完成项目至关重要。我开始深入阅读文档,查看在线教程,并频繁实践,通过编写和重构代码,逐步加深我的理解。这个过程教会了我理论知识和实际应用之间存在着巨大的差距,但是通过不懈的努力和实践,我可以促使自己的理论知识转化为实践技能。

       总的来说,我从这次活动中获得了丰富的知识和经验。无论是掌握了新的编程语言,还是学会了使用复杂的开发工具,我都感到自己的能力有了显著的提高。我对自己克服困难,成功完成项目感到非常自豪,这次经验让我更强烈地意识到,专注、耐心和坚韧不拔的精神才是成功的关键。

       最后衷心感谢硬禾学堂的此次活动,祝硬禾学堂越办越好!

附件下载
final_project.7z
工程源文件压缩包
ex2_impl_1.rbt
导出的rbt文件
团队介绍
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号