2025寒假一起练 - 基于iCE40UP5K制作可定时的音乐时钟
该项目使用了Radiant软件,实现了一个ICE40UP5K的FPGA开发板的设计,它的主要功能为:通过内部时钟产生时间,并且将时间显示到OLED屏幕上,接着设定定时,时间到达定时蜂鸣器就会报警,并且彩灯闪烁。
标签
FPGA
2025寒假练
音乐时钟
长歌
更新2025-03-20
北京理工大学
34

一、功能描述

  1. 使用扩展板上的12颗彩灯对应于12个小时
  2. 核心板上的FPGA产生时钟,在OLED显示评上通过模拟或者数字的方式显示当前的时间 - 小时、分、秒
  3. 将“小时”的信息通过12颗彩灯来显示,效果自行设计
  4. 具有定时的功能,通过扩展板上的按键设置时间,到该时间点即(彩灯闪烁 + 音频播放),持续5秒钟时间
  5. 音频播放通过扩展板上的蜂鸣器来实现

二、硬件介绍

本设计基于Lattice的ICE40UP5K FPGA,板载LPC11U35下载器,可以通过USB-C接口进行FPGA的配置,支持在ICE40UP5K上对RISC-V软核的移植以及开源的FPGA开发工具链,板上RGB三色LED灯用于简单的调试,总计28个IO用于扩展使用。

三、设计思路

1.设计框图

2.实物展示

按下复位键后,设置的当前时间是11 59 54,定时时间是11 59 59,以正上方为0点,可以看到代表11的灯亮

上面一行时间到达11 59 59时,彩灯会转圈闪烁5秒钟,闪烁结束后,此时已经到达了0点(这里指的是小时信息),所以正上方彩灯亮起来

下面这张图片设置的初始时间分别把小时由11改成了7和3,可以看到对应位置彩灯亮起来

下面几张图片是将时间加快999倍后的结果(OLED上面出现一些小竖线,但是不影响正常流速时间的显示),

这么做是为了更好的展示小彩灯表示当前小时信息功能

3.资源利用报告

四、代码部分

本次设计是利用ICE40UP5K开发板来制作一个可定时的音乐播放器实现要求的相关功能,设计过程中主要参考了电子森林例程的相关思路,设计主要可分为六大模块来对其设计:top模块、oled模块、beeper模块、shakea(按键消抖)模块、WS2812模块和beeper模块。每个模块的都有其独特的作用,从而实现所要求的音乐播放器功能。下面对每个模块进行一一分析:

1.代码运行流程图如下:

image.png

其中,两个按键控定时功能的流程如下:
image.png

2.top模块

顶层top模块的设计和应用的编写方式就像C++语言中的头文件和函数一样,它使得很多开源的代码能够直接应用到一个很大的项目中去。该top模块包含了songlist音乐模块、shakea消抖模块、oled模块、WS2812B模块和control模块。

module top(
input clk ,
input rstn ,
input [1:0] key ,
output scl ,
output sda ,
output spi_rstn,
output spi_dorc,
output beep ,
output Data_out //WS2812B LED
);

wire oled_rst;
wire oled_dcn;
wire oled_clk;
wire oled_dat;
assign scl = oled_clk;
assign sda = oled_dat;
assign spi_rstn = oled_rst;
assign spi_dorc = oled_dcn;
wire [1:0] shape ;
wire [4:0] hour ;
wire [5:0] minute ;
wire [5:0] second ;
wire [2:0] T_cnt ;
wire [4:0] T_hour ;
wire [5:0] T_minute;
wire [5:0] T_second;
wire busyb ;

shakeA shakeA(
.clk (clk ), //input clk ,
.rstn (rstn ), //input rstn ,
.key (key ), //input [1:0] key ,
.shape (shape) //output reg [1:0] shape
);

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

oled_dri oled_dri
(
.clk (clk ), //input clk ,
.rst_n (rstn ), //input rst_n ,
.hour (hour ), //input [4:0] hour ,
.minute (minute ), //input [5:0] minute ,
.second (second ), //input [5:0] second ,
.T_cnt (T_cnt ), //input [2:0] T_cnt ,
.T_hour (T_hour ), //input [4:0] T_hour ,
.T_minute (T_minute ), //input [5:0] T_minute ,
.T_second (T_second ), //input [5:0] T_second ,
.oled_csn (oled_csn), //output reg oled_csn,
.oled_rst (oled_rst), //output reg oled_rst,
.oled_dcn (oled_dcn), //output reg oled_dcn,
.oled_clk (oled_clk), //output reg oled_clk,
.oled_dat (oled_dat) //output reg oled_dat
);

WS2812B_driver WS2812B_driver
(
.clk (clk), // input clk ,
.rst (rstn), // input rst ,
.hour (hour), // input [4:0] hour,
.busyb (busyb),
.led (Data_out) // output led

);
endmodule

3.OLED模块

oled模块主要就是用来显示当前时间和定时时间,该部分主要参考了硬禾学堂提供在github的开源代码。

module oled_dri
(
input clk , //12MHz
input rst_n ,
input [4:0] hour ,
input [5:0] minute ,
input [5:0] second ,
input [2:0] T_cnt ,
input [4:0] T_hour ,
input [5:0] T_minute,
input [5:0] T_second,
output reg oled_csn,
output reg oled_rst,
output reg oled_dcn,
output reg oled_clk,
output reg oled_dat
);
wire [127:0] words[11:0];//8*16
assign words[ 0] = 128'h00E010080810E000000F102020100F00;//0
assign words[ 1] = 128'h00001010F8000000000020203F202000;//1
assign words[ 2] = 128'h007008080808F0000030282422213000;//2
assign words[ 3] = 128'h00300808088870000018202121221C00;//3
assign words[ 4] = 128'h0000804030F8000000060524243F2424;//4
assign words[ 5] = 128'h00F88888880808000019202020110E00;//5
assign words[ 6] = 128'h00E0108888900000000F112020201F00;//6
assign words[ 7] = 128'h00180808886818000000003E01000000;//7
assign words[ 8] = 128'h0070880808887000001C222121221C00;//8
assign words[ 9] = 128'h00F008080810E0000001122222110F00;//9
assign words[10] = 128'h000000C0C00000000000003030000000;//:10
assign words[11] = 0;

localparam INIT_DEPTH = 16'd23;
localparam IDLE = 7'h1, MAIN = 7'h2, INIT = 7'h4, SCAN = 7'h8, WRITE = 7'h10, DELAY = 7'h20,CHINESE=7'h40;
localparam HIGH = 1'b1, LOW = 1'b0;
localparam DATA = 1'b1, CMD = 1'b0;

reg [7:0] cmd [22:0];
reg [39:0] mem [122:0];
reg [127:0] mem_hanzi[16:0];

reg [7:0] mem_hanzi_num;
reg [7:0] y_p, x_ph, x_pl;
reg [(8*21-1):0] char;
reg [7:0] num, char_reg;
reg [4:0] cnt_main, cnt_init, cnt_scan, cnt_write;
reg [5:0] cnt_chinese;
reg [15:0] num_delay, cnt_delay, cnt;
reg [6:0] state, state_back;

reg [7:0] data_0;
reg [7:0] data_1;
reg [7:0] data_2;
reg [7:0] data_3;
reg [7:0] data_4;
reg [7:0] data_5;
reg [7:0] data_6;
reg [7:0] data_7;
reg [7:0] data_8;
reg [7:0] data_9;
reg [7:0] data_10;
reg [7:0] data_11;

reg [23:0] cntt;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)begin
cntt <= 0;
end else begin
cntt <= cntt+1;
end
end

always@(posedge clk or negedge rst_n)
begin
if(!rst_n)begin
data_0 <= 0;
data_1 <= 0;
data_2 <= 0;
data_3 <= 0;
data_4 <= 0;
data_5 <= 0;
data_6 <= 0;
data_7 <= 0;
data_8 <= 0;
data_9 <= 0;
data_10 <= 0;
data_11 <= 0;
end else begin
data_0 <= hour/10;
data_1 <= hour%10;
data_2 <= minute/10;
data_3 <= minute%10;
data_4 <= second/10;
data_5 <= second%10;
data_6 <= (T_cnt==1 && cntt[23]) ? 11 : T_hour/10;
data_7 <= (T_cnt==1 && cntt[23]) ? 11 : T_hour%10;
data_8 <= (T_cnt==2 && cntt[23]) ? 11 : T_minute/10;
data_9 <= (T_cnt==2 && cntt[23]) ? 11 : T_minute%10;
data_10 <= (T_cnt==3 && cntt[23]) ? 11 : T_second/10;
data_11 <= (T_cnt==3 && cntt[23]) ? 11 : T_second%10;
end
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_main <= 1'b0; cnt_init <= 1'b0; cnt_scan <= 1'b0; cnt_write <= 1'b0;cnt_chinese <= 1'b0;
y_p <= 1'b0; x_ph <= 1'b0; x_pl <= 1'b0;
num <= 1'b0; char <= 1'b0; char_reg <= 1'b0;
num_delay <= 16'd5; cnt_delay <= 1'b0; cnt <= 1'b0;
oled_csn <= HIGH; oled_rst <= HIGH; oled_dcn <= CMD; oled_clk <= HIGH; oled_dat <= LOW;
state <= IDLE; state_back <= IDLE;
end else begin
case(state)
IDLE:begin
cnt_main <= 1'b0; cnt_init <= 1'b0; cnt_scan <= 1'b0; cnt_write <= 1'b0;
y_p <= 1'b0; x_ph <= 1'b0; x_pl <= 1'b0;
num <= 1'b0; char <= 1'b0; char_reg <= 1'b0;
num_delay <= 16'd5; cnt_delay <= 1'b0; cnt <= 1'b0;mem_hanzi_num<=8'd0;
oled_csn <= HIGH; oled_rst <= HIGH; oled_dcn <= CMD; oled_clk <= HIGH; oled_dat <= LOW;
state <= MAIN; state_back <= MAIN;
end
MAIN:begin
if(cnt_main >= 5'd21) cnt_main <= 5'd9;//
else cnt_main <= cnt_main + 1'b1;
case(cnt_main) //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 <= data_0; state <= CHINESE; end
5'd10: begin y_p <= 8'hb0; x_ph <= 8'h12; x_pl <= 8'h00; mem_hanzi_num <= data_1; state <= CHINESE; end
5'd11: begin y_p <= 8'hb0; x_ph <= 8'h13; x_pl <= 8'h00; mem_hanzi_num <= data_2; state <= CHINESE; end
5'd12: begin y_p <= 8'hb0; x_ph <= 8'h14; x_pl <= 8'h00; mem_hanzi_num <= data_3; state <= CHINESE; end
5'd13: begin y_p <= 8'hb0; x_ph <= 8'h15; x_pl <= 8'h00; mem_hanzi_num <= data_4; state <= CHINESE; end
5'd14: begin y_p <= 8'hb0; x_ph <= 8'h16; x_pl <= 8'h00; mem_hanzi_num <= data_5; state <= CHINESE; end

5'd15: begin y_p <= 8'hb2; x_ph <= 8'h11; x_pl <= 8'h00; mem_hanzi_num <= data_6; state <= CHINESE; end
5'd16: begin y_p <= 8'hb2; x_ph <= 8'h12; x_pl <= 8'h00; mem_hanzi_num <= data_7; state <= CHINESE; end
5'd17: begin y_p <= 8'hb2; x_ph <= 8'h13; x_pl <= 8'h00; mem_hanzi_num <= data_8; state <= CHINESE; end
5'd18: begin y_p <= 8'hb2; x_ph <= 8'h14; x_pl <= 8'h00; mem_hanzi_num <= data_9; state <= CHINESE; end
5'd19: begin y_p <= 8'hb2; x_ph <= 8'h15; x_pl <= 8'h00; mem_hanzi_num <= data_10; state <= CHINESE; end
5'd20: begin y_p <= 8'hb2; x_ph <= 8'h16; x_pl <= 8'h00; mem_hanzi_num <= data_11; state <= CHINESE; end

5'd21: begin y_p <= 8'hb4; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= " ";state <= SCAN; end
// 5'd22: begin y_p <= 8'hb5; x_ph <= 8'h12; x_pl <= 8'h08; num <= 5'd6; char <= " ";state <= SCAN; end

default:begin
state <= IDLE; end
endcase
end
INIT:begin
case(cnt_init)
5'd0: begin oled_rst <= LOW; cnt_init <= cnt_init + 1'b1; end
5'd1: begin num_delay <= 16'd25000; state <= DELAY; state_back <= INIT; cnt_init <= cnt_init + 1'b1; end
5'd2: begin oled_rst <= HIGH; cnt_init <= cnt_init + 1'b1; end
5'd3: begin num_delay <= 16'd25000; state <= DELAY; state_back <= INIT; cnt_init <= cnt_init + 1'b1; end
5'd4: begin
if(cnt>=INIT_DEPTH) begin
cnt <= 1'b0;
cnt_init <= cnt_init + 1'b1;
end else begin
cnt <= cnt + 1'b1; num_delay <= 16'd5;
oled_dcn <= CMD; char_reg <= cmd[cnt]; state <= WRITE; state_back <= INIT;
end
end
5'd5: begin cnt_init <= 1'b0; state <= MAIN; end
default: state <= IDLE;
endcase
end
SCAN:begin
if(cnt_scan == 5'd11) begin
if(num) cnt_scan <= 5'd3;
else cnt_scan <= cnt_scan + 1'b1;
end
else if(cnt_scan == 5'd12) cnt_scan <= 1'b0;
else cnt_scan <= cnt_scan + 1'b1;
case(cnt_scan)
5'd 0: begin oled_dcn <= CMD; char_reg <= y_p; state <= WRITE; state_back <= SCAN; end
5'd 1: begin oled_dcn <= CMD; char_reg <= x_pl; state <= WRITE; state_back <= SCAN; end
5'd 2: begin oled_dcn <= CMD; char_reg <= x_ph; state <= WRITE; state_back <= SCAN; end

5'd 3: begin num <= num - 1'b1;end
5'd 4: begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end
5'd 5: begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end
5'd 6: begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end
5'd 7: begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][39:32]; state <= WRITE; state_back <= SCAN; end
5'd 8: begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][31:24]; state <= WRITE; state_back <= SCAN; end
5'd 9: begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][23:16]; state <= WRITE; state_back <= SCAN; end
5'd10: begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][15: 8]; state <= WRITE; state_back <= SCAN; end
5'd11: begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][ 7: 0]; state <= WRITE; state_back <= SCAN; end
5'd12: begin state <= MAIN; end
default: state <= IDLE;
endcase
// state <= IDLE;
end
CHINESE:begin

if(cnt_chinese == 6'd22) cnt_chinese <= 1'b0;
else cnt_chinese <= cnt_chinese+1'b1;
case(cnt_chinese)
6'd 0: begin oled_dcn <= CMD; char_reg <= y_p; state <= WRITE; state_back <= CHINESE; end
6'd 1: begin oled_dcn <= CMD; char_reg <= x_pl; state <= WRITE; state_back <= CHINESE; end
6'd 2: begin oled_dcn <= CMD; char_reg <= x_ph; state <= WRITE; state_back <= CHINESE; end

6'd3 : begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][127:120]; state <= WRITE; state_back <= CHINESE; end
6'd4 : begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][119:112]; state <= WRITE; state_back <= CHINESE; end
6'd5 : begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][111:104]; state <= WRITE; state_back <= CHINESE; end
6'd6 : begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][103:96] ; state <= WRITE; state_back <= CHINESE; end
6'd7 : begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][95:88] ; state <= WRITE; state_back <= CHINESE; end
6'd8 : begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][87:80] ; state <= WRITE; state_back <= CHINESE; end
6'd9 : begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][79:72] ; state <= WRITE; state_back <= CHINESE; end
6'd10: begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][71:64] ; state <= WRITE; state_back <= CHINESE; end

// 6'd11: begin oled_dcn <= DATA; char_reg <= words[0][63:56]; state <= WRITE; state_back <= CHINESE; end
// 6'd12: begin oled_dcn <= DATA; char_reg <= words[0][55:48]; state <= WRITE; state_back <= CHINESE; end
// 6'd13: begin oled_dcn <= DATA; char_reg <= words[0][47:40]; state <= WRITE; state_back <= CHINESE; end
// 6'd14: begin oled_dcn <= DATA; char_reg <= words[0][39:32]; state <= WRITE; state_back <= CHINESE; end
// 6'd15: begin oled_dcn <= DATA; char_reg <= words[0][31:24]; state <= WRITE; state_back <= CHINESE; end
// 6'd16: begin oled_dcn <= DATA; char_reg <= words[0][23:16]; state <= WRITE; state_back <= CHINESE; end
// 6'd17: begin oled_dcn <= DATA; char_reg <= words[0][15: 8]; state <= WRITE; state_back <= CHINESE; end
// 6'd18: begin oled_dcn <= DATA; char_reg <= words[0][ 7: 0]; state <= WRITE; state_back <= CHINESE; end

6'd11: begin oled_dcn <= CMD; char_reg <= y_p+1; state <= WRITE; state_back <= CHINESE; end
6'd12: begin oled_dcn <= CMD; char_reg <= x_pl; state <= WRITE; state_back <= CHINESE; end
6'd13: begin oled_dcn <= CMD; char_reg <= x_ph; state <= WRITE; state_back <= CHINESE; end
// 6'd22: begin oled_dcn <= DATA; char_reg <= words[0][127:120]; state <= WRITE; state_back <= CHINESE; end
// 6'd23: begin oled_dcn <= DATA; char_reg <= words[0][119:112]; state <= WRITE; state_back <= CHINESE; end
// 6'd24: begin oled_dcn <= DATA; char_reg <= words[0][111:104]; state <= WRITE; state_back <= CHINESE; end
// 6'd25: begin oled_dcn <= DATA; char_reg <= words[0][103:96] ; state <= WRITE; state_back <= CHINESE; end
// 6'd26: begin oled_dcn <= DATA; char_reg <= words[0][95:88] ; state <= WRITE; state_back <= CHINESE; end
// 6'd27: begin oled_dcn <= DATA; char_reg <= words[0][87:80] ; state <= WRITE; state_back <= CHINESE; end
// 6'd28: begin oled_dcn <= DATA; char_reg <= words[0][79:72] ; state <= WRITE; state_back <= CHINESE; end
// 6'd29: begin oled_dcn <= DATA; char_reg <= words[0][71:64] ; state <= WRITE; state_back <= CHINESE; end
6'd14: begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][63:56]; state <= WRITE; state_back <= CHINESE; end
6'd15: begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][55:48]; state <= WRITE; state_back <= CHINESE; end
6'd16: begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][47:40]; state <= WRITE; state_back <= CHINESE; end
6'd17: begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][39:32]; state <= WRITE; state_back <= CHINESE; end
6'd18: begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][31:24]; state <= WRITE; state_back <= CHINESE; end
6'd19: begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][23:16]; state <= WRITE; state_back <= CHINESE; end
6'd20: begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][15: 8]; state <= WRITE; state_back <= CHINESE; end
6'd21: begin oled_dcn <= DATA; char_reg <= words[mem_hanzi_num][ 7: 0]; state <= WRITE; state_back <= CHINESE; end

6'd22: begin state <= MAIN; end
default: state <= IDLE;
endcase
end



WRITE:begin
if(cnt_write >= 5'd17) cnt_write <= 1'b0;
else cnt_write <= cnt_write + 1'b1;
case(cnt_write)
5'd 0: begin oled_csn <= LOW; end
5'd 1: begin oled_clk <= LOW; oled_dat <= char_reg[7]; end
5'd 2: begin oled_clk <= HIGH; end
5'd 3: begin oled_clk <= LOW; oled_dat <= char_reg[6]; end
5'd 4: begin oled_clk <= HIGH; end
5'd 5: begin oled_clk <= LOW; oled_dat <= char_reg[5]; end
5'd 6: begin oled_clk <= HIGH; end
5'd 7: begin oled_clk <= LOW; oled_dat <= char_reg[4]; end
5'd 8: begin oled_clk <= HIGH; end
5'd 9: begin oled_clk <= LOW; oled_dat <= char_reg[3]; end
5'd10: begin oled_clk <= HIGH; end
5'd11: begin oled_clk <= LOW; oled_dat <= char_reg[2]; end
5'd12: begin oled_clk <= HIGH; end
5'd13: begin oled_clk <= LOW; oled_dat <= char_reg[1]; end
5'd14: begin oled_clk <= HIGH; end
5'd15: begin oled_clk <= LOW; oled_dat <= char_reg[0]; end
5'd16: begin oled_clk <= HIGH; end
5'd17: begin oled_csn <= HIGH; state <= DELAY; end //
default: state <= IDLE;
endcase
end
DELAY:begin
if(cnt_delay >= num_delay) begin
cnt_delay <= 16'd0; state <= state_back;
end else cnt_delay <= cnt_delay + 1'b1;
end
default:state <= IDLE;
endcase
end
end


always@(posedge rst_n)
begin
cmd[0 ] = {8'hae};
cmd[1 ] = {8'hd5};
cmd[2 ] = {8'h80};
cmd[3 ] = {8'ha8};
cmd[4 ] = {8'h3f};
cmd[5 ] = {8'hd3};
cmd[6 ] = {8'h00};
cmd[7 ] = {8'h40};
cmd[8 ] = {8'h8d};
cmd[9 ] = {8'h14};
cmd[10] = {8'h20};
cmd[11] = {8'h02};
cmd[12] = {8'hc8};
cmd[13] = {8'ha1};
cmd[14] = {8'hda};
cmd[15] = {8'h12};
cmd[16] = {8'h81};
cmd[17] = {8'hcf};
cmd[18] = {8'hd9};
cmd[19] = {8'hf1};
cmd[20] = {8'hdb};
cmd[21] = {8'h40};
cmd[22] = {8'haf};

end

//ASCII瀛楃琛�
always@(posedge rst_n)
begin
mem[ 0] = {8'h3E, 8'h51, 8'h49, 8'h45, 8'h3E}; // 48 0
mem[ 1] = {8'h00, 8'h42, 8'h7F, 8'h40, 8'h00}; // 49 1
mem[ 2] = {8'h42, 8'h61, 8'h51, 8'h49, 8'h46}; // 50 2
mem[ 3] = {8'h21, 8'h41, 8'h45, 8'h4B, 8'h31}; // 51 3
mem[ 4] = {8'h18, 8'h14, 8'h12, 8'h7F, 8'h10}; // 52 4
mem[ 5] = {8'h27, 8'h45, 8'h45, 8'h45, 8'h39}; // 53 5
mem[ 6] = {8'h3C, 8'h4A, 8'h49, 8'h49, 8'h30}; // 54 6
mem[ 7] = {8'h01, 8'h71, 8'h09, 8'h05, 8'h03}; // 55 7
mem[ 8] = {8'h36, 8'h49, 8'h49, 8'h49, 8'h36}; // 56 8
mem[ 9] = {8'h06, 8'h49, 8'h49, 8'h29, 8'h1E}; // 57 9
mem[ 10] = {8'h7C, 8'h12, 8'h11, 8'h12, 8'h7C}; // 65 A
mem[ 11] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h36}; // 66 B
mem[ 12] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h22}; // 67 C
mem[ 13] = {8'h7F, 8'h41, 8'h41, 8'h22, 8'h1C}; // 68 D
mem[ 14] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h41}; // 69 E
mem[ 15] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h01}; // 70 F

mem[ 32] = {8'h00, 8'h00, 8'h00, 8'h00, 8'h00}; // 32 sp
mem[ 33] = {8'h00, 8'h00, 8'h2f, 8'h00, 8'h00}; // 33 !
mem[ 34] = {8'h00, 8'h07, 8'h00, 8'h07, 8'h00}; // 34
mem[ 35] = {8'h14, 8'h7f, 8'h14, 8'h7f, 8'h14}; // 35 #
mem[ 36] = {8'h24, 8'h2a, 8'h7f, 8'h2a, 8'h12}; // 36 $
mem[ 37] = {8'h62, 8'h64, 8'h08, 8'h13, 8'h23}; // 37 %
mem[ 38] = {8'h36, 8'h49, 8'h55, 8'h22, 8'h50}; // 38 &
mem[ 39] = {8'h00, 8'h05, 8'h03, 8'h00, 8'h00}; // 39 '
mem[ 40] = {8'h00, 8'h1c, 8'h22, 8'h41, 8'h00}; // 40 (
mem[ 41] = {8'h00, 8'h41, 8'h22, 8'h1c, 8'h00}; // 41 )
mem[ 42] = {8'h14, 8'h08, 8'h3E, 8'h08, 8'h14}; // 42 *
mem[ 43] = {8'h08, 8'h08, 8'h3E, 8'h08, 8'h08}; // 43 +
mem[ 44] = {8'h00, 8'h00, 8'hA0, 8'h60, 8'h00}; // 44 ,
mem[ 45] = {8'h08, 8'h08, 8'h08, 8'h08, 8'h08}; // 45 -
mem[ 46] = {8'h00, 8'h60, 8'h60, 8'h00, 8'h00}; // 46 .
mem[ 47] = {8'h20, 8'h10, 8'h08, 8'h04, 8'h02}; // 47 /
mem[ 48] = {8'h3E, 8'h51, 8'h49, 8'h45, 8'h3E}; // 48 0
mem[ 49] = {8'h00, 8'h42, 8'h7F, 8'h40, 8'h00}; // 49 1
mem[ 50] = {8'h42, 8'h61, 8'h51, 8'h49, 8'h46}; // 50 2
mem[ 51] = {8'h21, 8'h41, 8'h45, 8'h4B, 8'h31}; // 51 3
mem[ 52] = {8'h18, 8'h14, 8'h12, 8'h7F, 8'h10}; // 52 4
mem[ 53] = {8'h27, 8'h45, 8'h45, 8'h45, 8'h39}; // 53 5
mem[ 54] = {8'h3C, 8'h4A, 8'h49, 8'h49, 8'h30}; // 54 6
mem[ 55] = {8'h01, 8'h71, 8'h09, 8'h05, 8'h03}; // 55 7
mem[ 56] = {8'h36, 8'h49, 8'h49, 8'h49, 8'h36}; // 56 8
mem[ 57] = {8'h06, 8'h49, 8'h49, 8'h29, 8'h1E}; // 57 9
mem[ 58] = {8'h00, 8'h36, 8'h36, 8'h00, 8'h00}; // 58 :
mem[ 59] = {8'h00, 8'h56, 8'h36, 8'h00, 8'h00}; // 59 ;
mem[ 60] = {8'h08, 8'h14, 8'h22, 8'h41, 8'h00}; // 60 <
mem[ 61] = {8'h14, 8'h14, 8'h14, 8'h14, 8'h14}; // 61 =
mem[ 62] = {8'h00, 8'h41, 8'h22, 8'h14, 8'h08}; // 62 >
mem[ 63] = {8'h02, 8'h01, 8'h51, 8'h09, 8'h06}; // 63 ?
mem[ 64] = {8'h32, 8'h49, 8'h59, 8'h51, 8'h3E}; // 64 @
mem[ 65] = {8'h7C, 8'h12, 8'h11, 8'h12, 8'h7C}; // 65 A
mem[ 66] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h36}; // 66 B
mem[ 67] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h22}; // 67 C
mem[ 68] = {8'h7F, 8'h41, 8'h41, 8'h22, 8'h1C}; // 68 D
mem[ 69] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h41}; // 69 E
mem[ 70] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h01}; // 70 F
mem[ 71] = {8'h3E, 8'h41, 8'h49, 8'h49, 8'h7A}; // 71 G
mem[ 72] = {8'h7F, 8'h08, 8'h08, 8'h08, 8'h7F}; // 72 H
mem[ 73] = {8'h00, 8'h41, 8'h7F, 8'h41, 8'h00}; // 73 I
mem[ 74] = {8'h20, 8'h40, 8'h41, 8'h3F, 8'h01}; // 74 J
mem[ 75] = {8'h7F, 8'h08, 8'h14, 8'h22, 8'h41}; // 75 K
mem[ 76] = {8'h7F, 8'h40, 8'h40, 8'h40, 8'h40}; // 76 L
mem[ 77] = {8'h7F, 8'h02, 8'h0C, 8'h02, 8'h7F}; // 77 M
mem[ 78] = {8'h7F, 8'h04, 8'h08, 8'h10, 8'h7F}; // 78 N
mem[ 79] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h3E}; // 79 O
mem[ 80] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h06}; // 80 P
mem[ 81] = {8'h3E, 8'h41, 8'h51, 8'h21, 8'h5E}; // 81 Q
mem[ 82] = {8'h7F, 8'h09, 8'h19, 8'h29, 8'h46}; // 82 R
mem[ 83] = {8'h46, 8'h49, 8'h49, 8'h49, 8'h31}; // 83 S
mem[ 84] = {8'h01, 8'h01, 8'h7F, 8'h01, 8'h01}; // 84 T
mem[ 85] = {8'h3F, 8'h40, 8'h40, 8'h40, 8'h3F}; // 85 U
mem[ 86] = {8'h1F, 8'h20, 8'h40, 8'h20, 8'h1F}; // 86 V
mem[ 87] = {8'h3F, 8'h40, 8'h38, 8'h40, 8'h3F}; // 87 W
mem[ 88] = {8'h63, 8'h14, 8'h08, 8'h14, 8'h63}; // 88 X
mem[ 89] = {8'h07, 8'h08, 8'h70, 8'h08, 8'h07}; // 89 Y
mem[ 90] = {8'h61, 8'h51, 8'h49, 8'h45, 8'h43}; // 90 Z
mem[ 91] = {8'h00, 8'h7F, 8'h41, 8'h41, 8'h00}; // 91 [
mem[ 92] = {8'h55, 8'h2A, 8'h55, 8'h2A, 8'h55}; // 92 .
mem[ 93] = {8'h00, 8'h41, 8'h41, 8'h7F, 8'h00}; // 93 ]
mem[ 94] = {8'h04, 8'h02, 8'h01, 8'h02, 8'h04}; // 94 ^
mem[ 95] = {8'h40, 8'h40, 8'h40, 8'h40, 8'h40}; // 95 _
mem[ 96] = {8'h00, 8'h01, 8'h02, 8'h04, 8'h00}; // 96 '
mem[ 97] = {8'h20, 8'h54, 8'h54, 8'h54, 8'h78}; // 97 a
mem[ 98] = {8'h7F, 8'h48, 8'h44, 8'h44, 8'h38}; // 98 b
mem[ 99] = {8'h38, 8'h44, 8'h44, 8'h44, 8'h20}; // 99 c
mem[100] = {8'h38, 8'h44, 8'h44, 8'h48, 8'h7F}; // 100 d
mem[101] = {8'h38, 8'h54, 8'h54, 8'h54, 8'h18}; // 101 e
mem[102] = {8'h08, 8'h7E, 8'h09, 8'h01, 8'h02}; // 102 f
mem[103] = {8'h18, 8'hA4, 8'hA4, 8'hA4, 8'h7C}; // 103 g
mem[104] = {8'h7F, 8'h08, 8'h04, 8'h04, 8'h78}; // 104 h
mem[105] = {8'h00, 8'h44, 8'h7D, 8'h40, 8'h00}; // 105 i
mem[106] = {8'h40, 8'h80, 8'h84, 8'h7D, 8'h00}; // 106 j
mem[107] = {8'h7F, 8'h10, 8'h28, 8'h44, 8'h00}; // 107 k
mem[108] = {8'h00, 8'h41, 8'h7F, 8'h40, 8'h00}; // 108 l
mem[109] = {8'h7C, 8'h04, 8'h18, 8'h04, 8'h78}; // 109 m
mem[110] = {8'h7C, 8'h08, 8'h04, 8'h04, 8'h78}; // 110 n
mem[111] = {8'h38, 8'h44, 8'h44, 8'h44, 8'h38}; // 111 o
mem[112] = {8'hFC, 8'h24, 8'h24, 8'h24, 8'h18}; // 112 p
mem[113] = {8'h18, 8'h24, 8'h24, 8'h18, 8'hFC}; // 113 q
mem[114] = {8'h7C, 8'h08, 8'h04, 8'h04, 8'h08}; // 114 r
mem[115] = {8'h48, 8'h54, 8'h54, 8'h54, 8'h20}; // 115 s
mem[116] = {8'h04, 8'h3F, 8'h44, 8'h40, 8'h20}; // 116 t
mem[117] = {8'h3C, 8'h40, 8'h40, 8'h20, 8'h7C}; // 117 u
mem[118] = {8'h1C, 8'h20, 8'h40, 8'h20, 8'h1C}; // 118 v
mem[119] = {8'h3C, 8'h40, 8'h30, 8'h40, 8'h3C}; // 119 w
mem[120] = {8'h44, 8'h28, 8'h10, 8'h28, 8'h44}; // 120 x
mem[121] = {8'h1C, 8'hA0, 8'hA0, 8'hA0, 8'h7C}; // 121 y
mem[122] = {8'h44, 8'h64, 8'h54, 8'h4C, 8'h44}; // 122 z
end
//16*16
always@(posedge rst_n)
begin
mem_hanzi[ 0 ] = {8'h04,8'h84,8'hE4,8'h5C,8'h44,8'hC4,8'h00,8'hF2,8'h92,8'h92,8'hFE,8'h92,8'h92,8'hF2,8'h02,8'h00};
mem_hanzi[ 1 ] = {8'h02,8'h01,8'h7F,8'h10,8'h10,8'h3F,8'h80,8'h8F,8'h54,8'h24,8'h5F,8'h44,8'h84,8'h87,8'h80,8'h00};
mem_hanzi[ 2 ] = {8'h00,8'h40,8'h44,8'h44,8'h44,8'h44,8'hC4,8'hFC,8'hC2,8'h42,8'h42,8'h43,8'h42,8'h40,8'h00,8'h00};
mem_hanzi[ 3 ] = {8'h20,8'h20,8'h10,8'h08,8'h04,8'h03,8'h00,8'hFF,8'h00,8'h03,8'h04,8'h08,8'h10,8'h20,8'h20,8'h00};
mem_hanzi[ 4 ] = {8'h40,8'h30,8'h11,8'h96,8'h90,8'h90,8'h91,8'h96,8'h90,8'h90,8'h98,8'h14,8'h13,8'h50,8'h30,8'h00};
mem_hanzi[ 5 ] = {8'h04,8'h04,8'h04,8'h04,8'h04,8'h44,8'h84,8'h7E,8'h06,8'h05,8'h04,8'h04,8'h04,8'h04,8'h04,8'h00};
mem_hanzi[ 6 ] = {8'h20,8'h18,8'h08,8'hEA,8'h2C,8'h28,8'h28,8'h2F,8'h28,8'h28,8'h2C,8'hEA,8'h08,8'h28,8'h18,8'h00};
mem_hanzi[ 7 ] = {8'h40,8'h40,8'h48,8'h49,8'h49,8'h49,8'h49,8'h7F,8'h49,8'h49,8'h49,8'h49,8'h48,8'h40,8'h40,8'h00};
end
endmodule

4.WS2812B彩灯控制模块

主要控制彩灯显示当前小时信息,并且在定时时间达到时闪烁

module WS2812B_driver
(
input clk,
input rst,
input [4:0] hour,
input busyb,
output led

);
//clk 12M
parameter T0H = 6'd4;
parameter T0L = 6'd12;
parameter T1H = 6'd12;
parameter T1L = 6'd4;
parameter cnt_time_max = 1_500_000;
parameter RST = 14'd3600;
parameter LED_1 = 25'b00000_0000_0000_0000_0001_0000;//绿
parameter LED_2 = 25'b00000_0000_0000_0000_0001_0000;
parameter LED_3 = 25'b00000_0000_0000_0000_0001_0000;
parameter LED_4 = 25'b00000_0000_0001_0000_0000_0000;//红
parameter LED_5 = 25'b00000_0000_0001_0000_0000_0000;
parameter LED_6 = 25'b00000_0000_0001_0000_0000_0000;
parameter LED_7 = 25'b00001_0000_0000_0000_0000_0000;//蓝
parameter LED_8 = 25'b00001_0000_0000_0000_0000_0000;
parameter LED_9 = 25'b00001_0000_0000_0000_0000_0000;

parameter IDLE = 16'b0000_0000_0000_0000;
parameter LED_one = 16'b0000_0000_0000_0001;//LED1
parameter LED_two = 16'b0000_0000_0000_0010;
parameter LED_thr = 16'b0000_0000_0000_0100;
parameter LED_fou = 16'b0000_0000_0000_1000;
parameter LED_fiv = 16'b0000_0000_0001_0000;
parameter LED_six = 16'b0000_0000_0010_0000;
parameter LED_sev = 16'b0000_0000_0100_0000;
parameter LED_eig = 16'b0000_0000_1000_0000;
parameter LED_nin = 16'b0000_0001_0000_0000;
parameter LED_ten = 16'b0000_0010_0000_0000;
parameter LED_ele = 16'b0000_0100_0000_0000;
parameter LED_twe = 16'b0000_1000_0000_0000;//LED12
parameter RST_FSM = 16'b1100_0000_0000_0000;
reg [15:0] state;
reg [15:0] state_n;

reg [6:0] cycle_cnt;
reg led_pwm;
reg shift;
reg state_tran;
reg state_tran_rst;
reg [13:0] rst_cnt;
reg [4:0] bit_cnt;
reg [23:0] cnt_time;
reg [24:0] ledcolor1,ledcolor2,ledcolor3,ledcolor4,ledcolor5,ledcolor6;

always@(posedge clk or negedge rst ) begin
if(!rst)begin
cnt_time<=24'b0;
ledcolor1<=LED_1;
ledcolor2<=LED_2;
ledcolor3<=LED_3;
ledcolor4<=LED_4;
ledcolor5<=LED_5;
ledcolor6<=LED_6;
end
else if(cnt_time == cnt_time_max - 1'b1)begin
cnt_time<=24'b0;
ledcolor1<=ledcolor6;
ledcolor2<=ledcolor1;
ledcolor3<=ledcolor2;
ledcolor4<=ledcolor3;
ledcolor5<=ledcolor4;
ledcolor6<=ledcolor5;
end
else
cnt_time<=cnt_time+1'b1;
end
always @(posedge clk or negedge rst)
begin
if(!rst)
cycle_cnt <= 7'd0;
else if(cycle_cnt == (T0H + T0L - 6'd1))
cycle_cnt <= 7'd0;
else if(state != RST_FSM)
cycle_cnt <= cycle_cnt + 1'b1;
else
cycle_cnt <= 7'd0;
end
always @ (posedge clk or negedge rst)
begin
if(!rst)
state <= IDLE;
else
state <= state_n;
end


always @ (posedge clk or negedge rst)
begin
if(!rst)
begin
led_pwm <= 1'b0;
shift <= 1'b0;
end
else
begin
case(state)

IDLE :
begin
led_pwm <= 1'b1;
end
LED_one:
begin
shift <= (busyb == 1) ? ledcolor1[bit_cnt] : ((hour != 1) ? 0 : LED_9[bit_cnt]);
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_two:
begin
shift <= (busyb == 1) ? ledcolor1[bit_cnt] : ((hour != 2) ? 0 : LED_9[bit_cnt]);
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_thr:
begin
shift <= (busyb == 1) ? ledcolor2[bit_cnt] : ((hour != 3) ? 0 : LED_9[bit_cnt]);
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_fou:
begin
shift <= (busyb == 1) ? ledcolor2[bit_cnt] : ((hour != 4) ? 0 : LED_9[bit_cnt]);
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_fiv:
begin
shift <= (busyb == 1) ? ledcolor3[bit_cnt] : ((hour != 5) ? 0 : LED_9[bit_cnt]);
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_six:
begin
shift <= (busyb == 1) ? ledcolor3[bit_cnt] : ((hour != 6) ? 0 : LED_9[bit_cnt]);
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_sev:
begin
shift <= (busyb == 1) ? ledcolor4[bit_cnt] : ((hour != 7) ? 0 : LED_9[bit_cnt]);
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_eig:
begin
shift <= (busyb == 1) ? ledcolor4[bit_cnt] : ((hour != 8) ? 0 : LED_9[bit_cnt]);

if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_nin:
begin
shift <= (busyb == 1) ? ledcolor5[bit_cnt] : ((hour != 9) ? 0 : LED_9[bit_cnt]);
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_ten:
begin
shift <= (busyb == 1) ? ledcolor5[bit_cnt] : ((hour != 10) ? 0 : LED_9[bit_cnt]);
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_ele:
begin
shift <= (busyb == 1) ? ledcolor6[bit_cnt] : ((hour != 11) ? 0 : LED_9[bit_cnt]);
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end
LED_twe:
begin
shift <= (busyb == 1) ? ledcolor6[bit_cnt] : ((hour != 0) ? 0 : LED_9[bit_cnt]);
if(shift == 1'b1)
begin
if(cycle_cnt == T1H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
else
begin
if(cycle_cnt == T0H)
led_pwm <= 1'b0;
else if(cycle_cnt == (T1H + T0H - 6'd1))
led_pwm <= 1'b1;
else
led_pwm <= led_pwm;
end
end

RST_FSM:
begin
led_pwm <= 1'b0;
end

default:
begin
led_pwm <= 1'b0;
end
endcase
end
end

assign led = led_pwm;
always @ (*)
begin
case (state)
IDLE:
state_n = LED_one;
LED_one:
begin
if(state_tran)
state_n = LED_two;
else
state_n = state;
end
LED_two:
begin
if(state_tran)
state_n = LED_thr;
else
state_n = state;
end
LED_thr:
begin
if(state_tran)
state_n = LED_fou;
else
state_n = state;
end
LED_fou:
begin
if(state_tran)
state_n = LED_fiv;
else
state_n = state;
end
LED_fiv:
begin
if(state_tran)
state_n = LED_six;
else
state_n = state;
end
LED_six:
begin
if(state_tran)
state_n = LED_sev;
else
state_n = state;
end
LED_sev:
begin
if(state_tran)
state_n = LED_eig;
else
state_n = state;
end
LED_eig:
begin
if(state_tran)
state_n = LED_nin;
else
state_n = state;
end
LED_nin:
begin
if(state_tran)
state_n = LED_ten;
else
state_n = state;
end
LED_ten:
begin
if(state_tran)
state_n = LED_ele;
else
state_n = state;
end
LED_ele:
begin
if(state_tran)
state_n = LED_twe;
else
state_n = state;
end
LED_twe:
begin
if(state_tran)
state_n = RST_FSM;
else
state_n = state;
end

RST_FSM:
begin
if(state_tran_rst)
state_n = IDLE;
else
state_n = state;
end
default:
state_n =RST_FSM;
endcase
end

always @(posedge clk or negedge rst)
begin
if(!rst)
begin
bit_cnt <= 5'd0;
state_tran <= 1'b0;
end
else if (bit_cnt == 5'd24)
begin
bit_cnt <= 5'd0;
state_tran <= 1'b1;
end
else if(cycle_cnt == (T0H + T0L - 6'd1))
begin
bit_cnt <= bit_cnt + 1'b1;
state_tran <= 1'b0;
end
else
begin
bit_cnt <= bit_cnt;
state_tran <= 1'b0;
end
end

always @(posedge clk or negedge rst)
begin
if(!rst)
rst_cnt <= 14'd0;
else if(state == RST_FSM)
rst_cnt <= rst_cnt + 1'b1;
else
rst_cnt <= 14'd0;
end

always @(posedge clk or negedge rst)
begin
if(!rst)
state_tran_rst <= 1'b0;
else if(rst_cnt == RST)
state_tran_rst <=1'b1;
else
state_tran_rst <= 1'b0;
end
endmodule

5.sonlist模块

主要存储闹钟响起时蜂鸣器的音乐信息

module SongList(
input [5:0] addr ,
output reg [2:0] music
);

always@(*)
begin
case(addr)
0: music <= 0;
1: music <= 1;
2: music <= 2;
3: music <= 3;
4: music <= 3;
5: music <= 2;
6: music <= 3;
7: music <= 2;
8: music <= 1;
9: music <= 7;
10: music <= 6;
11: music <= 6;
12: music <= 3;
13: music <= 6;
14: music <= 5;
15: music <= 6;
16: music <= 7;
17: music <= 6;
18: music <= 5;
19: music <= 6;
20: music <= 1;
21: music <= 7;
22: music <= 6;
23: music <= 7;
24: music <= 6;
25: music <= 3;
26: music <= 7;
27: music <= 7;
28: music <= 6;
29: music <= 7;
30: music <= 6;
31: music <= 1;
32: music <= 2;
33: music <= 3;
34: music <= 3;
35: music <= 2;
36: music <= 3;
37: music <= 2;
38: music <= 3;
39: music <= 5;
40: music <= 1;
41: music <= 1;
42: music <= 3;
43: music <= 2;
44: music <= 2;
45: music <= 2;
46: music <= 1;
47: music <= 7;
48: music <= 1;
49: music <= 1;
50: music <= 1;
51: music <= 1;
52: music <= 1;
53: music <= 1;
54: music <= 1;
55: music <= 1;
56: music <= 1;
57: music <= 1;
58: music <= 1;
59: music <= 1;
60: music <= 1;
61: music <= 1;
62: music <= 1;
63: music <= 1;
endcase
end
endmodule

6.shakea模块
用于消抖,参考电子森林提供的例程

module shakeA(
input clk ,
input rstn ,
input [1:0] key ,
output reg [1:0] shape
);
parameter bit = 1;
reg [bit:0] key_d1;
reg [bit:0] key_d2;
reg [bit:0] key_d3;
reg [bit:0] key_d4;
reg [19:0] cnt ;
reg flag ;
parameter num = 250000;
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
cnt <= 0;
end else if(cnt >= num)begin
cnt <= 0;
end else begin
cnt <= cnt+1;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
flag <= 0;
end else if(cnt >= num)begin
flag <= 1;
end else begin
flag <= 0;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
key_d1 <= ~0;
key_d2 <= ~0;
end else if(flag)begin
key_d1 <= key;
key_d2 <= key_d1;
end else begin
key_d1 <= key_d1;
key_d2 <= key_d2;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
key_d3 <= ~0;
end else begin
key_d3 <= key_d1 | key_d2;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
key_d4 <= ~0;
end else begin
key_d4 <= key_d3;
end
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
shape <= 0;
end else begin
shape <= key_d3 & (~key_d4);
end
end
endmodule

7.control控制模块

用于控制蜂鸣器的报警市场,并且控制按下复位键后当前时间和定时时间的初值

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
);

reg [25:0] cnt1s;
parameter num1s = 11999999;
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;
assign flag = (cnt1s >= num1s) ? 1 : 0;

always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
second <= 54;
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 <= 59;
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 <= 11;
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

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 <= 11;
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 <= 59;
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
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
T_second <= 59;
end else if(T_cnt==3 && T_second>=59 && shape[1])begin
T_second <= 0;
end else if(T_cnt==3 && shape[1])begin
T_second <= T_second+1;
end else begin
T_second <= T_second;
end
end
// 瑙﹀彂铚傞福閫昏緫锛氬綋瀹氭椂鏃堕棿鍒拌揪褰撳墠鏃堕棿涓擳_cnt=0鏃讹紝鍚姩铚傞福鍣�
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
// 铚傞福鎸佺画鏃堕棿璁℃暟锛氭瘡绉抯econd_b澧�1
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
// 闊充箰鎾斁鎺у埗锛氫粠SongList妯″潡璇诲彇闊崇搴忓垪
reg [5:0] addr;
wire [2:0] music;
SongList SongList(
.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 <= 95602;
2: freq_num <= 85178;
3: freq_num <= 75872;
4: freq_num <= 71633;
5: freq_num <= 63775;
6: freq_num <= 56818;
7: freq_num <= 50607;
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
// 鐢熸垚铚傞福淇″彿锛�50%鍗犵┖姣旀柟娉�
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
endmodule

五、完成的功能

在经过设计调试后,本项目完成了题目要求的全部功能

六、遇到的难题

本次设计是我首次接触FPGA开发,在完成软件安装后对项目实现缺乏明确方向,这成为寒假实践项目的首要挑战。通过系统学习电子森林平台提供的FPGA基础视频教程和技术文档,特别是深入研究平台公开的PWM音乐播放器工程案例后,逐步形成了模块化设计思路。其中顶层模块(top)与功能子模块的分层架构设计理念,为项目的实现路径提供了重要启发。

在代码实现阶段,首先通过电子森林的Verilog语法专题课程系统掌握了硬件描述语言的核心要素,同时结合平台提供的多个外设驱动范例代码进行实践分析。重点研究了电子森林开源库中的OLED显示驱动模块,通过对照技术手册逐行解析通信协议实现方式,并针对屏幕初始化时序参数进行适应性调整,最终成功解决了显示输出难题。在PWM音频生成部分,参考平台提供的波形发生器工程模板,结合乐理频率计算实现了音阶合成功能。

整个开发过程中,电子森林平台丰富的开源项目资源发挥了关键作用,其模块化代码结构和详尽的接口注释显著降低了学习门槛。特别是在外设驱动实现方面,平台提供的可复用IP核设计极大提升了开发效率,使得初次接触FPGA的开发者也能基于成熟架构快速构建系统原型。通过本次实践,不仅掌握了硬件描述语言的基本设计方法,更深入理解了数字系统层次化设计思想在工程实践中的具体应用。

七未来展望

首先我希望通过以后的学习可以改善OLED代码,不要再出现将时间加快OLED显示屏上就会弧线无意义的竖线,其次通过本次实践深刻认识到持续深化FPGA知识体系的重要性。后续计划系统性地参与电子森林等平台组织的开发挑战赛与主题训练营,通过项目驱动的实战模式加速技能成长,此类沉浸式学习方式既能提升时间利用效率,更能形成扎实的工程思维。未来研习过程中,将着重加强对开源社区优质代码资源(如电子森林代码库中经过验证的模块化工程案例)的研读与重构实践,通过深度解析标准化的接口设计与状态机实现方案,有效攻克技术理解盲区。这种基于成熟架构的逆向工程学习方法,不仅能快速积累典型电路设计模式,更能培养规范化开发意识,为独立构建复杂数字系统奠定坚实基础。




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