2025寒假练 - 基于ice40up5k实现可定时的音乐时钟
该项目使用了ice40up5k,实现了可定时的音乐时钟的设计,它的主要功能为:可定时的音乐时钟。
标签
FPGA
数字逻辑
开发板
fly_lv
更新2025-03-25
18

基于ice40up5k实现可定时的音乐时钟


任务要求:

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

硬件部分

image.png

核心板主要功能特性:

  • 基于Lattice的FPGA - ICE40UP5K
  • 通过LPC11U35进行下载及UART配置/通信
  • 板上一颗R、G、B三色LED,分别连接FPGA的三根专用于驱动LED的管脚39、40、41,可以用于状态显示及数字逻辑实验
  • 一个RESET按键,用于对RISC-V系统进行复位
  • 总计28根输入/输出可用于扩展
  • 同USB直接连接的5V输出以及经板上LDO产生的3.3V直流电压输出,可以给扩展板供电,电流为200mA
  • 板上晶体振荡器时钟产生12MHz供FPGA和LPC11U35工作,FPGA可以通过内部锁相环工作于48MHz。

image.png

扩展板上有:

  • 2个按键输入
  • 4个单色LED
  • 12个WS2812B RGB三色灯
  • 1个姿态传感器
  • 1个128*64 OLED显示屏
  • 1个蜂鸣器
  • 1个可调电位计(用于电压表)
  • 1路音频信号输入(用于示波器)
  • 8位R-2R电阻网络构成的DAC(用于DDS信号发生器)

设计思路

方案框图

image.png

设计思路

1、时间提供:通过12Mhz晶振提供时钟的基准时间

2、闹钟设置:通过扩展板上的按键进行闹钟的设置

3、界面显示:ICE40UP5K通过SPI接口把时间发送到OLED屏幕上。OLED屏幕进行实现的显示时间,WS2812根据时间亮对应的灯

4、音乐播放:通过扩展板上的蜂鸣器进行音乐的播放。

流程图

image.png



界面显示部分

以oled作为显示界面

代码编写

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'd1;//鎺ヤ笅鏉ユ墽琛岀┖鎿嶄綔锛屽疄鐜版暟鎹彧鍒锋柊涓€娆
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'd1 : begin y_p <= 8'hb0; x_ph <= 8'h10; x_pl <= 8'h00;
case(hour_bcd[7:4])
6'd0 : mem_hanzi_num <= 6'd0;
6'd1 : mem_hanzi_num <= 6'd2;
6'd2 : mem_hanzi_num <= 6'd4;
default: mem_hanzi_num <= 6'd0;
endcase
state <= CHINESE; end
5'd2: begin y_p <= 8'hb0; x_ph <= 8'h11; x_pl <= 8'h00;
case(hour_bcd[3:0])
6'd0 : mem_hanzi_num <= 6'd0 ;
6'd1 : mem_hanzi_num <= 6'd2 ;
6'd2 : mem_hanzi_num <= 6'd4 ;
6'd3 : mem_hanzi_num <= 6'd6 ;
6'd4 : mem_hanzi_num <= 6'd8 ;
6'd5 : mem_hanzi_num <= 6'd10 ;
6'd6 : mem_hanzi_num <= 6'd12 ;
6'd7 : mem_hanzi_num <= 6'd14 ;
6'd8 : mem_hanzi_num <= 6'd16 ;
6'd9 : mem_hanzi_num <= 6'd18 ;
default: mem_hanzi_num <= 6'd0;
endcase
state <= CHINESE; end
5'd3 : begin y_p <= 8'hb0; x_ph <= 8'h13; x_pl <= 8'h00;
case(min_bcd[7:4])
6'd0 : mem_hanzi_num <= 6'd0 ;
6'd1 : mem_hanzi_num <= 6'd2 ;
6'd2 : mem_hanzi_num <= 6'd4 ;
6'd3 : mem_hanzi_num <= 6'd6 ;
6'd4 : mem_hanzi_num <= 6'd8 ;
6'd5 : mem_hanzi_num <= 6'd10 ;
6'd6 : mem_hanzi_num <= 6'd12 ;
default: mem_hanzi_num <= 6'd0;
endcase
state <= CHINESE; end
5'd4 : begin y_p <= 8'hb0; x_ph <= 8'h14; x_pl <= 8'h00;
case(min_bcd[3:0])
6'd0 : mem_hanzi_num <= 6'd0 ;
6'd1 : mem_hanzi_num <= 6'd2 ;
6'd2 : mem_hanzi_num <= 6'd4 ;
6'd3 : mem_hanzi_num <= 6'd6 ;
6'd4 : mem_hanzi_num <= 6'd8 ;
6'd5 : mem_hanzi_num <= 6'd10 ;
6'd6 : mem_hanzi_num <= 6'd12 ;
6'd7 : mem_hanzi_num <= 6'd14 ;
6'd8 : mem_hanzi_num <= 6'd16 ;
6'd9 : mem_hanzi_num <= 6'd18 ;
default: mem_hanzi_num <= 6'd0;
endcase
state <= CHINESE; end
5'd5 : begin y_p <= 8'hb0; x_ph <= 8'h16; x_pl <= 8'h00;
case(sec_bcd[7:4])
6'd0 : mem_hanzi_num <= 6'd0 ;
6'd1 : mem_hanzi_num <= 6'd2 ;
6'd2 : mem_hanzi_num <= 6'd4 ;
6'd3 : mem_hanzi_num <= 6'd6 ;
6'd4 : mem_hanzi_num <= 6'd8 ;
6'd5 : mem_hanzi_num <= 6'd10 ;
6'd6 : mem_hanzi_num <= 6'd12 ;
default: mem_hanzi_num <= 6'd0;
endcase
state <= CHINESE; end
5'd6 : begin y_p <= 8'hb0; x_ph <= 8'h17; x_pl <= 8'h00;
case(sec_bcd[3:0])
6'd0 : mem_hanzi_num <= 6'd0 ;
6'd1 : mem_hanzi_num <= 6'd2 ;
6'd2 : mem_hanzi_num <= 6'd4 ;
6'd3 : mem_hanzi_num <= 6'd6 ;
6'd4 : mem_hanzi_num <= 6'd8 ;
6'd5 : mem_hanzi_num <= 6'd10 ;
6'd6 : mem_hanzi_num <= 6'd12 ;
6'd7 : mem_hanzi_num <= 6'd14 ;
6'd8 : mem_hanzi_num <= 6'd16 ;
6'd9 : mem_hanzi_num <= 6'd18 ;
default: mem_hanzi_num <= 6'd0;
endcase
state <= CHINESE; end

5'd7 : begin y_p <= 8'hb2; x_ph <= 8'h12; x_pl <= 8'h00; mem_hanzi_num <= 6'd30 ;state <= CHINESE; end
5'd8 : begin y_p <= 8'hb2; x_ph <= 8'h13; x_pl <= 8'h00; mem_hanzi_num <= 6'd32 ;state <= CHINESE; end
5'd9 : begin y_p <= 8'hb2; x_ph <= 8'h14; x_pl <= 8'h00; mem_hanzi_num <= 6'd38 ;state <= CHINESE; end
5'd10 : begin y_p <= 8'hb2; x_ph <= 8'h15; x_pl <= 8'h00; mem_hanzi_num <= 6'd40 ;state <= CHINESE; end
5'd11 : begin y_p <= 8'hb0; x_ph <= 8'h12; x_pl <= 8'h00; mem_hanzi_num <= 6'd20 ;state <= CHINESE; end
5'd12 : begin y_p <= 8'hb0; x_ph <= 8'h15; x_pl <= 8'h00; mem_hanzi_num <= 6'd20 ;state <= CHINESE; end
5'd13 : begin y_p <= 8'hb6; x_ph <= 8'h12; x_pl <= 8'h00; mem_hanzi_num <= 6'd46 ;state <= CHINESE; end
5'd14 : begin y_p <= 8'hb6; x_ph <= 8'h13; x_pl <= 8'h00; mem_hanzi_num <= 6'd48 ;state <= CHINESE; end
5'd15 : begin y_p <= 8'hb6; x_ph <= 8'h14; x_pl <= 8'h00; mem_hanzi_num <= 6'd38 ;state <= CHINESE; end
5'd16 : begin y_p <= 8'hb6; x_ph <= 8'h15; x_pl <= 8'h00; mem_hanzi_num <= 6'd40 ;state <= CHINESE; end
// 娣诲姞闂归挓鏄剧ず閮ㄥ垎
5'd17 : begin y_p <= 8'hb4; x_ph <= 8'h10; x_pl <= 8'h00;
case(alarm_hour / 6'd10)
6'd0 : mem_hanzi_num <= 6'd0;
6'd1 : mem_hanzi_num <= 6'd2;
6'd2 : mem_hanzi_num <= 6'd4;
default: mem_hanzi_num <= 6'd0;
endcase
state <= CHINESE;
end

5'd18 : begin y_p <= 8'hb4; x_ph <= 8'h11; x_pl <= 8'h00;
case(alarm_hour % 6'd10)
6'd0 : mem_hanzi_num <= 6'd0;
6'd1 : mem_hanzi_num <= 6'd2;
6'd2 : mem_hanzi_num <= 6'd4;
6'd3 : mem_hanzi_num <= 6'd6 ;
6'd4 : mem_hanzi_num <= 6'd8 ;
6'd5 : mem_hanzi_num <= 6'd10 ;
6'd6 : mem_hanzi_num <= 6'd12 ;
6'd7 : mem_hanzi_num <= 6'd14 ;
6'd8 : mem_hanzi_num <= 6'd16 ;
6'd9 : mem_hanzi_num <= 6'd18 ;
// ... 琛ュ厖0-9鐨勫畬鏁存槧灏
endcase
state <= CHINESE;
end

5'd19 : begin y_p <= 8'hb4; x_ph <= 8'h13; x_pl <= 8'h00;
case(alarm_minute / 6'd10)
6'd0 : mem_hanzi_num <= 6'd0;
6'd1 : mem_hanzi_num <= 6'd2;
6'd2 : mem_hanzi_num <= 6'd4;
6'd3 : mem_hanzi_num <= 6'd6 ;
6'd4 : mem_hanzi_num <= 6'd8 ;
6'd5 : mem_hanzi_num <= 6'd10 ;
// ... 琛ュ厖0-5鐨勬槧灏
endcase
state <= CHINESE;
end

5'd20 : begin y_p <= 8'hb4; x_ph <= 8'h14; x_pl <= 8'h00;
case(alarm_minute % 6'd10)
6'd0 : mem_hanzi_num <= 6'd0;
6'd1 : mem_hanzi_num <= 6'd2;
6'd2 : mem_hanzi_num <= 6'd4;
6'd3 : mem_hanzi_num <= 6'd6 ;
6'd4 : mem_hanzi_num <= 6'd8 ;

6'd5 : mem_hanzi_num <= 6'd10 ;
6'd6 : mem_hanzi_num <= 6'd12 ;
6'd7 : mem_hanzi_num <= 6'd14 ;
6'd8 : mem_hanzi_num <= 6'd16 ;
6'd9 : mem_hanzi_num <= 6'd18 ;
// ... 琛ュ厖0-9鐨勫畬鏁存槧灏
endcase
state <= CHINESE;
end
5'd21 : begin y_p <= 8'hb4; x_ph <= 8'h12; x_pl <= 8'h00; mem_hanzi_num <= 6'd20 ;state <= CHINESE; end
default: state <= IDLE; //濡傛灉浣犻渶瑕佸姩鎬佸埛鏂颁竴浜涗俊鎭紝姝よ搴旇鍙栨秷娉ㄩ噴
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 //寤舵椂澶т簬3us
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 //寤舵椂澶т簬220us
5'd4: begin
if(cnt>=INIT_DEPTH) begin //褰5鏉℃寚浠ゅ強鏁版嵁鍙戝嚭鍚庯紝閰嶇疆瀹屾垚
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 //鍒濆鍖栧畬鎴愶紝杩斿洖MAIN鐘舵€
default: state <= IDLE;
endcase
end
SCAN:begin //鍒峰睆鐘舵€侊紝浠嶳AM涓鍙栨暟鎹埛灞
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 //灏*8鐐归樀缂栫▼8*8
5'd 5: begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end //灏*8鐐归樀缂栫▼8*8
5'd 6: begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end //灏*8鐐归樀缂栫▼8*8
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
end




CHINESE:begin //鏄剧ず姹夊瓧

if(cnt_chinese == 6'd38) 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 <= mem_hanzi[mem_hanzi_num][127:120]; state <= WRITE; state_back <= CHINESE; end
6'd4 : begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][119:112]; state <= WRITE; state_back <= CHINESE; end
6'd5 : begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][111:104]; state <= WRITE; state_back <= CHINESE; end
6'd6 : begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][103:96] ; state <= WRITE; state_back <= CHINESE; end
6'd7 : begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][95:88] ; state <= WRITE; state_back <= CHINESE; end
6'd8 : begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][87:80] ; state <= WRITE; state_back <= CHINESE; end
6'd9 : begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][79:72] ; state <= WRITE; state_back <= CHINESE; end
6'd10: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][71:64] ; state <= WRITE; state_back <= CHINESE; end
6'd11: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][63:56]; state <= WRITE; state_back <= CHINESE; end
6'd12: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][55:48]; state <= WRITE; state_back <= CHINESE; end
6'd13: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][47:40]; state <= WRITE; state_back <= CHINESE; end
6'd14: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][39:32]; state <= WRITE; state_back <= CHINESE; end
6'd15: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][31:24]; state <= WRITE; state_back <= CHINESE; end
6'd16: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][23:16]; state <= WRITE; state_back <= CHINESE; end
6'd17: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][15: 8]; state <= WRITE; state_back <= CHINESE; end
6'd18: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num][ 7: 0]; state <= WRITE; state_back <= CHINESE; end

6'd19: begin oled_dcn <= CMD; char_reg <= y_p+1; state <= WRITE; state_back <= CHINESE; end //瀹氫綅鍒楅〉鍦板潃
6'd20: begin oled_dcn <= CMD; char_reg <= x_pl; state <= WRITE; state_back <= CHINESE; end //瀹氫綅琛屽湴鍧€浣庝綅
6'd21: begin oled_dcn <= CMD; char_reg <= x_ph; state <= WRITE; state_back <= CHINESE; end //瀹氫綅琛屽湴鍧€楂樹綅
6'd22: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][127:120]; state <= WRITE; state_back <= CHINESE; end
6'd23: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][119:112]; state <= WRITE; state_back <= CHINESE; end
6'd24: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][111:104]; state <= WRITE; state_back <= CHINESE; end
6'd25: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][103:96] ; state <= WRITE; state_back <= CHINESE; end
6'd26: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][95:88] ; state <= WRITE; state_back <= CHINESE; end
6'd27: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][87:80] ; state <= WRITE; state_back <= CHINESE; end
6'd28: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][79:72] ; state <= WRITE; state_back <= CHINESE; end
6'd29: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][71:64] ; state <= WRITE; state_back <= CHINESE; end
6'd30: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][63:56]; state <= WRITE; state_back <= CHINESE; end
6'd31: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][55:48]; state <= WRITE; state_back <= CHINESE; end
6'd32: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][47:40]; state <= WRITE; state_back <= CHINESE; end
6'd33: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][39:32]; state <= WRITE; state_back <= CHINESE; end
6'd34: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][31:24]; state <= WRITE; state_back <= CHINESE; end
6'd35: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][23:16]; state <= WRITE; state_back <= CHINESE; end
6'd36: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][15: 8]; state <= WRITE; state_back <= CHINESE; end
6'd37: begin oled_dcn <= DATA; char_reg <= mem_hanzi[mem_hanzi_num+1][ 7: 0]; state <= WRITE; state_back <= CHINESE; end

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



WRITE:begin //WRITE鐘舵€侊紝灏嗘暟鎹寜鐓PI鏃跺簭鍙戦€佺粰灞忓箷
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 //9浣嶆暟鎹渶楂樹綅涓哄懡浠ゆ暟鎹帶鍒朵綅
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

时钟部分

module clock (
input wire rst_n,
input wire clk,
output wire [7:0] hour,
output wire [7:0] min,
output wire [7:0] sec
);

wire min_clk;
wire hour_clk;

counter sec_cnt (
.rst_n(rst_n),
.clk(clk),
.carry(min_clk),
.count(sec)
);

counter min_cnt (
.rst_n(rst_n),
.clk(min_clk),
.carry(hour_clk),
.count(min)
);

counter #(
.MAX_COUNT(24)
) hour_cnt (
.rst_n(rst_n),
.clk(hour_clk),
.count(hour)
);

endmodule


ws2812部分

WS2812B-2020是一个集控制电路与发光电路于一体的智能外控LED光源;其外型采用最新的molding封装工 艺,将IC与发光芯片封装在一个2020的封装尺寸中,每个元件即为一个像素点;像素点内部包含了智能数字接口 数据锁存信号整形放大驱动电路,还包含有高精度的内部振荡器和可编程定电流控制部分,有效保证了像素点光 的颜色高度一致。


对应的时序

image.png


对应的代码编写

always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
ws <= 1'b0; // 瀹夊叏鍒濆鍖
bit_cnt <= 9'd0;
cycle_cnt <= 4'd0;
shift_reg <= 288'd0;
th <= 4'd0;
reset_cnt <= 10'd0;
end else begin
case (state)
IDLE: begin
if (led_num_changed || (en != 0 && en != led_num_prev)) begin // 鏂板en瑙﹀彂鏉′欢
// 淇鎷兼帴椤哄簭锛堝ぇ绔ā寮忥級
shift_reg <= {
led0_color, led1_color, led2_color, led3_color,
led4_color, led5_color, led6_color, led7_color,
led8_color, led9_color, led10_color, led11_color
};
bit_cnt <= 9'd287; // 浠庢渶楂樹綅寮€濮嬪彂閫
state <= SENDING;
end
ws <= 1'b0; // 鏄惧紡椹卞姩杈撳嚭
end

SENDING: begin
// 璁$畻褰撳墠浣嶇殑楂樼數骞虫椂闂
if (cycle_cnt == 4'd0)
th <= shift_reg[bit_cnt] ? 4'd10 : 4'd5;

// 鐢熸垚WS淇″彿锛堝叧閿祴鍊硷級
ws <= (cycle_cnt < th) ? 1'b1 : 1'b0;

// 鏃堕挓鍛ㄦ湡璁℃暟
if (cycle_cnt == 4'd14) begin
cycle_cnt <= 4'd0;
bit_cnt <= bit_cnt - 1;

if (bit_cnt == 9'd0) begin
state <= RESET;
reset_cnt <= 10'd0;
end
end else begin
cycle_cnt <= cycle_cnt + 1;
end
end

RESET: begin
ws <= 1'b0; // 鐩存帴璧嬪€紃eg绫诲瀷
if (reset_cnt < 10'd600)
reset_cnt <= reset_cnt + 1;
else
state <= IDLE;
end
endcase
end
end


时钟所对应的ws2812会变红,其他不亮



按键消抖部分

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

音频部分

以蜂鸣器作为音频


驱动代码如下


reg [19:0] time_end;

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 = 20'd1048575;
endcase
end


资源图

image.png

实物图

807542c567ee274ecb8ab03ff55dec53_720.jpg

心得体会


感谢电子森林举办的寒假练活动,我从中学习到了许多fpga的知识,把这些知识也成功的实践了,

祝电子森林越办越好

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