【FPGA】数码管电子时钟
目錄
- 一丶數(shù)碼管介紹
- 二丶任務(wù)描述
- 三丶系統(tǒng)框圖
- 四丶模塊調(diào)用
- 五丶模塊原理圖
- 六丶工程源碼
- 1.計(jì)數(shù)器模塊
- 2.數(shù)碼管驅(qū)動(dòng)模塊
- 3.頂層模塊
- 七丶仿真測(cè)試
- 1.TestBench
- 2.仿真結(jié)果
- 八丶管腳信息
- 九丶上板驗(yàn)證
- 十丶源碼
一丶數(shù)碼管介紹
Cyclone IV開(kāi)發(fā)板上的數(shù)碼管一共有6個(gè),我們每次只能選擇其中一個(gè)顯示,怎么解決電子時(shí)鐘時(shí)、分、秒同時(shí)顯示呢?要實(shí)現(xiàn)電子時(shí)鐘首先要了解什么是余暉效應(yīng)。
余暉效應(yīng)一般指視覺(jué)暫留。 視覺(jué)暫留現(xiàn)象即視覺(jué)暫停現(xiàn)象(Persistence of vision,Visual staying phenomenon,duration of vision)又稱“余暉效應(yīng)”。只要數(shù)碼管位選信號(hào)切換得足夠快,數(shù)碼管由亮到滅這一過(guò)程是需要一段時(shí)間的,由于時(shí)間很短,我們的眼睛是沒(méi)有辦法分清此時(shí)此刻數(shù)碼管的狀態(tài),給人的感覺(jué)就是數(shù)碼管是一直亮的。以此來(lái)達(dá)到欺騙人眼的效果,這樣就可以實(shí)現(xiàn)同時(shí)顯示時(shí)、分、秒。
二丶任務(wù)描述
使用數(shù)碼管設(shè)計(jì)電子時(shí)鐘,計(jì)數(shù)器部分有3種實(shí)現(xiàn)方法:
①.采用1個(gè)計(jì)數(shù)器,模為24x60x60;
②.采用3個(gè)計(jì)數(shù)器,模分別為24、60、60;
③.采用6個(gè)計(jì)數(shù)器分別計(jì)數(shù)時(shí)、分、秒的個(gè)位、十位;
方法1:計(jì)數(shù)器個(gè)數(shù)少,設(shè)計(jì)簡(jiǎn)單,但是后面數(shù)碼管譯碼時(shí),需要對(duì)計(jì)數(shù)值取余、取整,分離出時(shí)、分、秒的個(gè)位和十位,比較耗費(fèi)組合邏輯資源;
方法2:3個(gè)計(jì)數(shù)器,后面數(shù)碼管譯碼時(shí),需要對(duì)時(shí)、分、秒計(jì)數(shù)值取余、取整,分離出時(shí)、分、秒的個(gè)位和十位,比較耗費(fèi)組合邏輯資源;
方法3:6個(gè)計(jì)數(shù)器,相對(duì)復(fù)雜一點(diǎn),但是計(jì)數(shù)值直接就是時(shí)、分、秒的個(gè)位和十位值,不需要除法器進(jìn)行取余、取整操作,使用的觸發(fā)器資源略多,但節(jié)省組合邏輯資源。
因?yàn)楸疚氖亲鳛樽髡遱tark-lin: 數(shù)碼管電子時(shí)鐘的拓展,原文使用了方法1,我們這里選擇方法3
最后實(shí)現(xiàn)上面圖片的效果,由于開(kāi)發(fā)板上的數(shù)碼管沒(méi)有冒號(hào)(:),所以我們用小數(shù)點(diǎn)代替
三丶系統(tǒng)框圖
計(jì)時(shí)器模塊:我們把計(jì)時(shí)器模塊細(xì)分了6個(gè)計(jì)時(shí)器,分別計(jì)時(shí)整個(gè)時(shí)間的小時(shí)的十位和個(gè)位,分鐘的十位和個(gè)位,秒的十位和個(gè)位,最后將6個(gè)計(jì)時(shí)器拼接成一個(gè)dout_time輸出給數(shù)碼管驅(qū)動(dòng)。與stark-lin的方法1不同,我們不需要對(duì)計(jì)數(shù)器做運(yùn)算,只需要在數(shù)碼管驅(qū)動(dòng)中取出對(duì)應(yīng)數(shù)碼管的數(shù)字
(對(duì)應(yīng)dout_time[x:y]的第x到y(tǒng)位,比如我要取出小時(shí)的十位,由于小時(shí)的十位最大能計(jì)時(shí)到2,換算成2進(jìn)制數(shù)就是2位的,因?yàn)橐惶?4小時(shí)嘛,所以應(yīng)該對(duì)應(yīng)dout_time[19:18])
數(shù)碼管驅(qū)動(dòng):對(duì)dout_time數(shù)值進(jìn)行譯碼,產(chǎn)生驅(qū)動(dòng)數(shù)碼管動(dòng)態(tài)顯示數(shù)字的位選信號(hào)和段選信號(hào)。
四丶模塊調(diào)用
五丶模塊原理圖
六丶工程源碼
1.計(jì)數(shù)器模塊
counter.v:
module counter (input wire clk ,input wire rst_n ,output reg [19:0] dout_time //輸出時(shí)間 HH:MM:SS ); //計(jì)數(shù)器 reg [25:0] cnt ; wire add_cnt; wire end_cnt; //S計(jì)時(shí)器//個(gè)位 (0~9) reg [3:0] cnt_s_bit; wire add_cnt_s_bit; wire end_cnt_s_bit; //十位 (0~5) reg [2:0] cnt_s_ten; wire add_cnt_s_ten; wire end_cnt_s_ten;//M計(jì)時(shí)器//個(gè)位 (0~9) reg [3:0] cnt_m_bit; wire add_cnt_m_bit; wire end_cnt_m_bit; //十位 (0~5) reg [2:0] cnt_m_ten; wire add_cnt_m_ten; wire end_cnt_m_ten;//H計(jì)時(shí)器//個(gè)位 (0~9) reg [3:0] cnt_h_bit; wire add_cnt_h_bit; wire end_cnt_h_bit; //十位 (0~2) reg [1:0] cnt_h_ten; wire add_cnt_h_ten; wire end_cnt_h_ten;reg [3:0] flag; parameter MAX_CNT=26'd50_000_000;//計(jì)數(shù)器 always @(posedge clk or negedge rst_n) beginif(!rst_n) begincnt<=0;endelse if (add_cnt) beginif (end_cnt) begincnt<=0;endelsecnt<=cnt+1;end endassign add_cnt=1'b1; assign end_cnt=add_cnt&&cnt==MAX_CNT-1;//秒計(jì)時(shí)器---個(gè)位(0~9) always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_s_bit<=0;endelse if (add_cnt_s_bit) beginif (end_cnt_s_bit) begincnt_s_bit<=0;endelsecnt_s_bit<=cnt_s_bit+1;endendassign add_cnt_s_bit=end_cnt; assign end_cnt_s_bit=add_cnt_s_bit&&cnt_s_bit==9;//秒計(jì)時(shí)器---十位(0~5) always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_s_ten<=0;endelse if (add_cnt_s_ten) beginif (end_cnt_s_ten) begincnt_s_ten<=0;endelsecnt_s_ten<=cnt_s_ten+1;endendassign add_cnt_s_ten=end_cnt_s_bit; assign end_cnt_s_ten=add_cnt_s_ten&&cnt_s_ten==5;//分計(jì)時(shí)器---個(gè)位(0~9) always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_m_bit<=9;endelse if (add_cnt_m_bit) beginif (end_cnt_m_bit) begincnt_m_bit<=0;endelsecnt_m_bit<=cnt_m_bit+1;endendassign add_cnt_m_bit=end_cnt_s_ten; assign end_cnt_m_bit=add_cnt_m_bit&&cnt_m_bit==9;//分計(jì)時(shí)器---十位(0~5) always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_m_ten<=5;endelse if (add_cnt_m_ten) beginif (end_cnt_m_ten) begincnt_m_ten<=0;endelsecnt_m_ten<=cnt_m_ten+1;endendassign add_cnt_m_ten=end_cnt_m_bit; assign end_cnt_m_ten=add_cnt_m_ten&&cnt_m_ten==5;//時(shí)計(jì)時(shí)器---個(gè)位(0~9) always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_h_bit<=3;endelse if (add_cnt_h_bit) beginif (end_cnt_h_bit) begincnt_h_bit<=0;endelsecnt_h_bit<=cnt_h_bit+1;endendassign add_cnt_h_bit=end_cnt_m_ten; assign end_cnt_h_bit=add_cnt_h_bit&&cnt_h_bit==flag;//時(shí)計(jì)時(shí)器---十位(0~2) always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_h_ten<=2;endelse if (add_cnt_h_ten) beginif (end_cnt_h_ten) begincnt_h_ten<=0;endelsecnt_h_ten<=cnt_h_ten+1;endendassign add_cnt_h_ten=end_cnt_h_bit; assign end_cnt_h_ten=add_cnt_h_ten&&cnt_h_ten==2;//判斷小時(shí)計(jì)時(shí)器十位是否記到 2 always @(*) beginif (cnt_h_ten==2) beginflag=4'd3;endelseflag=4'd9; end//dout_time輸出 always @(posedge clk or negedge rst_n) beginif (!rst_n) begindout_time<=20'b0;endelsedout_time<={cnt_h_ten,cnt_h_bit,cnt_m_ten,cnt_m_bit,cnt_s_ten,cnt_s_bit}; //拼接成 HH:MM:SS end endmodule //counter2.數(shù)碼管驅(qū)動(dòng)模塊
seg_driver:
module seg_driver (input wire clk,input wire rst_n,input wire [19:0] dout_time,output reg [5:0] sel,output reg [7:0] seg ); reg [3:0] seg_flag; reg dot; //小數(shù)點(diǎn) 用來(lái)顯示 HH.MM.SS 這樣的格式//10ms計(jì)時(shí)器---用來(lái)切換數(shù)碼管位選,以達(dá)到輪流顯示時(shí)間的各位(肉眼可以看到動(dòng)態(tài)的時(shí)間計(jì)數(shù)) reg [15:0] cnt; wire add_cnt; wire end_cnt;parameter MAX_CNT =50_000 ,ZERO =7'b100_0000,ONE =7'b111_1001,TWO =7'b010_0100,THREE =7'b011_0000,FOUR =7'b001_1001,FIVE =7'b001_0010,SIX =7'b000_0010,SEVEN =7'b111_1000,EIGHT =7'b000_0000,NINE =7'b001_0000;//計(jì)時(shí)器 always @(posedge clk or negedge rst_n) beginif(!rst_n) begincnt<=0;endelse if(add_cnt) beginif (end_cnt) begincnt<=0;endelsecnt<=cnt+1;end end assign add_cnt=1'b1; assign end_cnt=add_cnt&&cnt==MAX_CNT-1;//切換數(shù)碼管位選 always @(posedge clk or negedge rst_n) beginif (!rst_n) beginsel<=6'b111_110;endelse if(cnt==MAX_CNT-1) beginsel<={sel[4:0],sel[5]};end end //切換數(shù)碼管段選 always @(posedge clk or negedge rst_n) beginif (!rst_n) beginseg_flag<=0;endelse begincase (sel)6'b111_110: begin seg_flag<=dout_time[19:18]; dot<=1'b1;end //小時(shí) 十位6'b111_101: begin seg_flag<=dout_time[17:14]; dot<=1'b0;end //小時(shí) 個(gè)位6'b111_011: begin seg_flag<=dout_time[13:11]; dot<=1'b1;end //分鐘 十位6'b110_111: begin seg_flag<=dout_time[10:7]; dot<=1'b0;end //分鐘 個(gè)位6'b101_111: begin seg_flag<=dout_time[6:4]; dot<=1'b1;end //秒 十位6'b011_111: begin seg_flag<=dout_time[3:0]; dot<=1'b1;end //秒 個(gè)位default :seg_flag<=0;endcaseend end//段選譯碼 always @(posedge clk or negedge rst_n) beginif (!rst_n) beginseg<=8'b1111_1111;endelse begincase (seg_flag) 0: seg<={dot,ZERO} ;1: seg<={dot,ONE} ;2: seg<={dot,TWO} ;3: seg<={dot,THREE} ;4: seg<={dot,FOUR} ;5: seg<={dot,FIVE} ;6: seg<={dot,SIX} ;7: seg<={dot,SEVEN} ;8: seg<={dot,EIGHT} ;9: seg<={dot,NINE} ;default: seg<=8'b1111_1111;endcaseend endendmodule //seg_driver3.頂層模塊
top.v:
module top (input wire clk , //系統(tǒng)時(shí)鐘input wire rst_n , //復(fù)位信號(hào)output wire [5:0] sel , //數(shù)碼管位選output wire [7:0] seg //數(shù)碼管段選 ); wire [19:0] dout_time;//例化計(jì)時(shí)模塊 counter u_counter(.clk (clk) ,.rst_n (rst_n) ,.dout_time (dout_time) //輸出時(shí)間 HH:MM:SS );//例化數(shù)碼管驅(qū)動(dòng) seg_driver u_seg_driver(.clk (clk) ,.rst_n (rst_n) ,.sel (sel) ,.seg (seg) ,.dout_time (dout_time) ); endmodule //top七丶仿真測(cè)試
1.TestBench
`timescale 1ns/1ns module tb_top(); reg clk; reg rst_n; wire [5:0] sel; wire [7:0] seg; top u_top(.clk (clk) ,.rst_n (rst_n) ,.sel (sel) ,.seg (seg) ); defparam u_top.u_counter.MAX_CNT=2; defparam u_top.u_seg_driver.MAX_CNT=2;always #10 clk=~clk; initial beginclk=1;rst_n=1;#100;rst_n=0;#100;rst_n=1;#200000;$stop; endendmodule2.仿真結(jié)果
八丶管腳信息
九丶上板驗(yàn)證
數(shù)碼管電子時(shí)鐘
十丶源碼
https://github.com/xuranww/digital_clock.git
總結(jié)
以上是生活随笔為你收集整理的【FPGA】数码管电子时钟的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: FPGA 十进制 转化为二进制
- 下一篇: 分享一篇写的非常好的文章《如何掌握企业级