電實訓萬年歷項目:從74LS芯片到FPGA的完整設(shè)計與調(diào)試實錄)
你們實訓周應該也做過類似的東西吧數(shù)電這門課理論知識聽的時候覺得不過爾爾真正上手做項目才會發(fā)現(xiàn)全是坑。我這次數(shù)電實訓選的是萬年歷一個看似簡單實際上把組合邏輯、時序邏輯、譯碼顯示、異步清零、同步置數(shù)全串起來的經(jīng)典題目。從拿到題目到仿真通過再到面包板跑起來前后折騰了兩周中間燒過芯片、炸過電容、對著示波器懷疑人生。這篇就把整個項目的設(shè)計思路、電路細節(jié)、調(diào)試記錄和踩坑實錄完整寫出來給后面做這個題目的同學一個參考也歡迎已經(jīng)做完的朋友一起來討論。先說清楚這個項目是干什么的。萬年歷本質(zhì)上就是一個“帶日歷功能的數(shù)字鐘”要求用數(shù)字電路實現(xiàn)年、月、日、時、分、秒的計數(shù)與顯示并且日期要能根據(jù)大小月自動調(diào)整2月還要區(qū)分平年閏年。這個項目最合適的人群就是正在學數(shù)電的學生以及想通過一個完整項目鞏固時序邏輯知識的硬件愛好者。它不像單片機方案那樣寫幾行代碼就完事而是逼著你去理解每一個進位信號、每一個清零條件做完之后你對計數(shù)器的理解會徹底不一樣。1. 項目整體設(shè)計與思路拆解1.1 萬年歷實訓到底考什么需求拆解先把需求一條條列清楚這決定了后面的電路結(jié)構(gòu)。我給自己定的功能指標是這樣的顯示內(nèi)容年后兩位、月、日、時、分、秒共14位數(shù)字秒信號由555定時器產(chǎn)生1Hz基準脈沖這是整個系統(tǒng)的心臟時制24小時制23:59:59后回到00:00:00日期切換1、3、5、7、8、10、12月為31天4、6、9、11月為30天2月平年28天、閏年29天閏年判斷年份后兩位能被4整除即為閏年手動校準通過按鍵分別對時、分、日、月、年進行快速調(diào)整。這個需求里秒、分、時是常規(guī)計數(shù)器難度不大真正的分水嶺在日期部分——日計數(shù)器必須根據(jù)月份和閏年結(jié)果決定是30天、31天還是28/29天。也就是說日期部分不光是計數(shù)器還得有一塊“月底判斷”的組合邏輯。這部分做明白了整個項目的核心就拿下了一大半。1.2 方案選型為什么堅持用74系列芯片而不是單片機不少同學看到這個題目第一反應是“用STM32啊RTC模塊一開就完事了”但數(shù)電實訓的意義恰恰在于不讓你用處理器。如果走單片機路線就完全繞開了數(shù)電的核心知識——計數(shù)器、譯碼器、觸發(fā)器、門電路。所以我的方案用的是74LS系列的TTL小規(guī)模集成電路總共大概用了這些芯片74LS160×8十進制同步計數(shù)器秒/分/日/月/年的主體74LS08、74LS32、74LS04若干與門、或門、非門用于清零/置數(shù)邏輯和月底判斷74LS151×1數(shù)據(jù)選擇器用于校時脈沖切換74LS48×14BCD七段譯碼器驅(qū)動共陰數(shù)碼管555定時器×1產(chǎn)生1Hz秒脈沖。當然用FPGA也是可以的而且現(xiàn)在很多學校的數(shù)電實驗課已經(jīng)開始引入FPGA用Verilog寫一個萬年歷模塊更接近工程實踐。但從課程考核角度講用分立芯片搭電路能把每個信號都看得清清楚楚這是FPGA綜合之后看不到的東西。我的建議是如果你時間充裕先用74芯片搭一遍硬件再用FPGA寫一遍Verilog兩頭都通了數(shù)電基本上就過關(guān)了。1.3 頂層模塊劃分從整體到局部的拆解思路我習慣在動手前先把整個系統(tǒng)畫成功能模塊圖不是仿真圖是手繪框圖這樣接線時腦子不會亂。整個萬年歷我劃分成五個模塊第一個是時鐘源模塊給整個系統(tǒng)提供穩(wěn)定的1Hz脈沖第二個是時分秒模塊從秒計數(shù)器到分計數(shù)器到時計數(shù)器逐級進位第三個是日歷模塊這個最復雜包括日計數(shù)器、月計數(shù)器、年計數(shù)器外加一個“月底判斷”組合邏輯塊用于控制日計數(shù)器何時歸1第四個是譯碼顯示模塊把所有計數(shù)器的BCD碼送進74LS48驅(qū)動14位數(shù)碼管第五個是校時模塊用按鍵產(chǎn)生快調(diào)脈沖通過數(shù)據(jù)選擇器切換正常秒脈沖和手動脈沖。模塊劃分清楚之后就能一條一條地搭建每搭完一塊先單獨測試再逐級聯(lián)調(diào)。我見過很多人上來就一股腦把所有芯片插到面包板上結(jié)果出問題的時候根本不知道從哪查起。這個項目必須循序漸進。2. 核心電路設(shè)計與參數(shù)計算2.1 1Hz秒脈沖源555定時器振蕩電路的設(shè)計與校準整個系統(tǒng)的時間基準是1Hz這個信號如果飄了后面的計數(shù)全部不準。我用的是經(jīng)典的555無穩(wěn)態(tài)多諧振蕩器電路結(jié)構(gòu)是一個555定時器加兩個電阻一個電容。這里把參數(shù)計算說透一些。555輸出方波的周期公式是T 0.7 × (R1 2R2) × C其中R1是接在VCC和放電引腳之間的電阻R2接在放電引腳和觸發(fā)/閾值引腳之間C是定時電容。高電平持續(xù)時間為0.7×(R1R2)×C低電平持續(xù)時間為0.7×R2×C。要讓周期等于1秒就得選擇合適的R和C組合。我實際用的參數(shù)是R1取10kΩR2取68kΩC取10μF。代入公式算一下T 0.7 × (10k 2×68k) × 10μ 0.7 × 146k × 10μ ≈ 1.022秒這個誤差在百分之一左右用示波器看會稍微偏慢一點點。所以我在R2的位置串聯(lián)了一個10kΩ的多圈電位器實際調(diào)試時一邊用示波器看波形一邊微調(diào)電位器把周期調(diào)到1.000秒左右。這里要注意555的輸出波形占空比不是50%因為充放電回路不對稱但數(shù)字電路只關(guān)心脈沖的上升沿占空比無所謂只要能穩(wěn)定輸出1Hz就行。注意如果你手頭沒有示波器可以用萬用表頻率檔測量或者用LED燈觀察閃動頻率。但只用LED不太精確建議有條件還是借一臺示波器。2.2 模60計數(shù)器秒和分電路的兩種實現(xiàn)方式秒計數(shù)器和分計數(shù)器本質(zhì)相同都是模60。模60的意思是從0計數(shù)到59然后回到0并輸出一個進位脈沖給下一級。我用兩片74LS160實現(xiàn)一片做個位0~9一片做十位0~5。74LS160是同步十進制計數(shù)器高電平使能上升沿計數(shù)有異步清零(CLR)和同步置數(shù)(LOAD)功能。模60的接法有兩種我分別說清楚。第一種是個位RCO接十位時鐘的方式。74LS160的RCO進位輸出在計數(shù)到9且使能有效時輸出高電平到下一個時鐘上升沿變?yōu)榈碗娖?。這個下降沿剛好可以作為十位74LS160的時鐘。但是74LS160是上升沿觸發(fā)直接用RCO接CLK不行需要反相一下。這種級聯(lián)方式叫異步級聯(lián)接線簡單但時序不干凈。第二種更推薦是同步級聯(lián)方式把個位的RCO接到十位的ENT使能端兩片74LS160的CLK接同一個秒脈沖。個位計數(shù)到9的瞬間RCO變高十位使能打開下一個時鐘上升沿到達時個位從9回到0十位同時加1。這種方式?jīng)]有額外的邊沿問題級聯(lián)更可靠。我當時用的是同步級聯(lián)后面分到時的進位也是這樣處理的全部統(tǒng)一。關(guān)鍵問題來了秒計數(shù)到59后十位是50101下一個脈沖來的時候個位變0同時十位應該從5變成0。光靠使能級聯(lián)只能實現(xiàn)60進位的“加1”不能實現(xiàn)“到5就清零”。所以十位計數(shù)器需要反饋邏輯。我用的是同步置數(shù)法把十位的QA和QC對應二進制0101的bit0和bit2接入一個與非門輸出接到十位的LOAD端數(shù)據(jù)輸入端D0~D3全部接GND。這樣當十位計數(shù)到5時LOAD被拉低下一個時鐘上升沿到來時十位被置為0不會出現(xiàn)狀態(tài)6。這個方案比清零法好在不會產(chǎn)生毛刺因為同步置數(shù)是在時鐘邊沿才動作。2.3 模24計數(shù)器時電路的清零與置數(shù)設(shè)計時計數(shù)器同樣是兩片74LS160但計數(shù)范圍是0~23到23后下一脈沖回到00。這部分的反饋條件需要組合個位和十位。23這個狀態(tài)對應十位為20010個位為30011。我在設(shè)計中使用了反饋清零法把十位的QB2的權(quán)位和個位的QA與QB3的權(quán)位bit0和bit1相與產(chǎn)生清零信號送到兩片計數(shù)器的CLR端。當計數(shù)器到達23后如果下一脈沖本來應該到24但清零信號會在24狀態(tài)出現(xiàn)前把計數(shù)器復位——這里要小心74LS160是異步清零一瞬間會出現(xiàn)毛刺。所以我把清零信號同時送到兩片芯片的CLR端并且每個芯片的電源腳并行接一個0.1μF去耦電容把這個毛刺的影響壓到最低。如果你對毛刺特別敏感也可以改用置數(shù)法當計數(shù)器進入24狀態(tài)十位2、個位4時LOAD拉低在下一個時鐘將計數(shù)器置為0。這兩種方法我都在仿真里試過實際硬件上用清零法更常見因為反饋邏輯簡單但要說信號干凈置數(shù)法更優(yōu)。實訓項目里兩種都能通過關(guān)鍵是你要能解釋清楚為什么這么接。2.4 日歷模塊日/月/年計數(shù)器與閏年判斷的組合邏輯這是整個項目最值得詳細講的部分也是最容易寫崩的地方。日、月、年計數(shù)器各自都是模M計數(shù)器但“日”的模數(shù)是動態(tài)的取決于月份和閏年。先說月計數(shù)器和年計數(shù)器。月計數(shù)器從1計數(shù)到12用兩片74LS160當計數(shù)到13時置1注意不是清零置0因為月份從1開始。我的做法是用反饋置數(shù)法當十位為1、個位為3時產(chǎn)生LOAD信號將十位置0、個位置1。年計數(shù)器從00計數(shù)到99也是兩片74LS160比較簡單但要把年的十位和個位送到一個“閏年判斷”電路中去。閏年判斷是組合邏輯它根據(jù)當前年份產(chǎn)生一個信號供月底判斷使用。閏年判斷的實現(xiàn)思路是這樣的只判斷年份后兩位能否被4整除。為什么可以只看后兩位因為100是4的倍數(shù)所以一個四位年份能否被4整除只取決于后兩位。設(shè)年份十位為Y1個位為Y0那么年份N的末兩位是10×Y1Y0又因為10 mod 42所以N mod 4等價于(2×Y1Y0) mod 4。能被4整除的條件是當Y0為0、4、8時Y1必須是偶數(shù)當Y0為2、6時Y1必須是奇數(shù)。用邏輯門實現(xiàn)這個條件需要把Y1的奇偶判斷和Y0的取值判斷結(jié)合起來。Y1是偶數(shù)說明Y1的bit0為0Y0為0/4/8表示Y0的bit1為0且bit0為00、4、8的二進制分別是0000、0100、1000共同點是bit1和bit0都為0Y0為2/6表示Y0的bit1為1且bit0為0。把這些條件寫成布爾表達式LEAP (Y1.bit0 0) AND (Y0.bit0 0) AND (Y0.bit1 0) OR (Y1.bit0 1) AND (Y0.bit0 0) AND (Y0.bit1 1)化簡后會發(fā)現(xiàn)判斷的核心是Y0的bit1與Y1的bit0是否相等。這個用異或門就能做但我在實際電路中直接用了幾片與非門搭出來的沒有刻意化簡因為芯片管腳夠用。要提醒的是這個方法到2099年都是有效的因為2100年按公歷規(guī)則不算閏年但咱們這個萬年歷只做到兩位年份所以不用擔心100年例外。日計數(shù)器是日歷模塊的核心。日計數(shù)器從1開始計數(shù)到月底時下一個脈沖回到1也就是說它不是一個從0到M的計數(shù)器而是從1到M的計數(shù)器。所以不能用簡單的清零法必須用置數(shù)法把日計數(shù)器置成1。月底條件的判斷是整個項目核心中的核心邏輯如下大月1、3、5、7、8、10、12當日期計數(shù)到31時翻月小月4、6、9、11當日期計數(shù)到30時翻月2月平年日期計數(shù)到28時翻月2月閏年日期計數(shù)到29時翻月。我用組合邏輯實現(xiàn)這個判斷。月份要產(chǎn)生三個信號大月信號MONTH_BIG、小月信號MONTH_SMALL、二月信號MONTH_FEB。日計數(shù)器要產(chǎn)生兩種判斷日期是否等于30/31以及日期是否等于28/29。然后把它們組合起來月底信號 (MONTH_BIG AND DAY_EQ_31) OR (MONTH_SMALL AND DAY_EQ_30) OR (MONTH_FEB AND NOT LEAP AND DAY_EQ_28) OR (MONTH_FEB AND LEAP AND DAY_EQ_29)這個月底信號有兩個用途一是作為月計數(shù)器的時鐘或使能信號讓月加1二是讓日計數(shù)器在下一個脈沖到來時置為1。要知道這里為什么要用“置1”而不是“清零”因為日計數(shù)器的起始值是1不是0這是新手最容易犯的錯誤。我在實現(xiàn)日計數(shù)器時用了一個小技巧不需要真的去判斷“等于30還是31”可以簡化成“日期大于等于當月月底的天數(shù)”這個條件。但74LS160的輸出是BCD碼組合比較邏輯用門電路做也不復雜所以我直接按照上面的邏輯搭的。如果你覺得門電路太多也可以用74LS85四位比較器來做數(shù)值比較電路會清爽很多。2.5 譯碼顯示74LS48驅(qū)動共陰數(shù)碼管的接法計數(shù)器內(nèi)部都是BCD碼需要經(jīng)過譯碼器變成數(shù)碼管的段選信號。我用74LS48作為七段譯碼驅(qū)動器它輸出高電平有效所以只能驅(qū)動共陰數(shù)碼管。如果你用的是共陽數(shù)碼管就要換74LS47或者加反相器這個千萬不能搞錯我見過有人把共陽的插到74LS48上結(jié)果數(shù)碼管永遠不亮。接線方面74LS48的A、B、C、D分別接計數(shù)器輸出的BCD碼D是最高位a~g輸出接到數(shù)碼管的對應段引腳。74LS48自帶內(nèi)部上拉電阻同時還有燈測試LT和滅零RBI/RBO功能實訓中我直接把LT接高電平不需要滅零功能時把RBI接高電平即可。顯示部分我采用的是靜態(tài)顯示方案14位數(shù)字每一位都單獨用一片74LS48驅(qū)動也就是說14個數(shù)碼管對應14片譯碼器。這樣做芯片用量大但是電路簡單可靠不用處理動態(tài)掃描的刷新時序問題。如果你想省芯片可以用動態(tài)掃描加位選信號的方式但那樣要在掃描頻率和顯示亮度之間找平衡難度反而上去了。實訓項目追求的是穩(wěn)定可靠靜態(tài)顯示是最優(yōu)選。3. 實操過程與調(diào)試記錄3.1 仿真先行Multisim與Proteus的選型對比我之前一直用Proteus但這次做萬年歷我換成了Multisim。原因很簡單Multisim的74系列芯片模型更貼近真實器件的時序特性特別是RCO、LOAD這些引腳的時序關(guān)系仿真結(jié)果基本就是實際芯片的行為。Proteus畫原理圖更舒服但有時候仿真通過的東西到實際面包板上跑不起來模型過于理想化是一個重要原因。仿真時一定要按模塊搭不要一上來就把整個系統(tǒng)畫完。我的順序是先搭555秒脈沖用虛擬示波器看波形調(diào)整電位器讓周期穩(wěn)定在1Hz接著搭秒的模60計數(shù)用邏輯探針或者數(shù)碼管看0到59的變化再搭分的模60、時的模24逐級確認進位關(guān)系最后才是日歷模塊和閏年判斷。日歷模塊在仿真時有一個特別好的調(diào)試方法把555的秒脈沖暫時換成手動時鐘源用一個按鈕開關(guān)每次手動觸發(fā)一個脈沖這樣就能一步一步觀察日計數(shù)器從1到月底、再翻月到1的過程。手動觸發(fā)時一定要加消抖電路否則一次按鍵可能產(chǎn)生多個脈沖你會看到數(shù)字跳好幾下然后誤以為是邏輯錯誤。3.2 面包板搭建的接線原則電源、地線、去耦與防燒從仿真到實物是最容易翻車的一步。我先把所有芯片分布在面包板上規(guī)劃好位置再開始接線。這里有幾個原則供參考第一電源和地線要先鋪好。面包板上下兩排一般用作VCC和GND我用紅色跳線走VCC黑色跳線走GND中間芯片的電源腳就近連接。74LS160、74LS48這些芯片都是引腳14接VCC、引腳7接GND接之前最好對著數(shù)據(jù)手冊確認一遍不同型號管腳定義有細微差異。第二每個芯片的電源引腳都要并接一個0.1μF的陶瓷去耦電容電容要盡量靠近芯片。這個不是可選項是必須項。沒有去耦電容的時候芯片翻轉(zhuǎn)瞬間的電流沖擊會造成電源電壓波動嚴重時會讓計數(shù)器產(chǎn)生誤觸發(fā)表現(xiàn)出來就是亂計數(shù)、亂進位查半天查不到原因。第三接線順序上我先把時鐘源接好然后用LED觀察秒脈沖再依次接秒、分、時、日、月、年最后接譯碼顯示。每接好一級就通電測試一級不要等全部接完再上電否則出問題你真的會瘋掉的。3.3 分級上電調(diào)試從秒脈沖到日歷翻月的完整順序上電調(diào)試一定要有章法。我把自己當時的調(diào)試順序整理如下供參考第一步測試1Hz秒脈沖。用示波器看555輸出腳確認周期接近1秒高電平約2.8V以上TTL高電平標準是2V以上。沒有示波器的話用LED觀察正常應該一秒閃一次閃爍間隔穩(wěn)定。如果LED不閃或者常亮先檢查555的接法和電容是否接反電解電容是有極性的。第二步測試秒的模60計數(shù)。把秒脈沖接入個位CLK觀察兩位數(shù)碼管從00到59循環(huán)。常見問題是個位正常、十位不走或者走兩步就跳。這個問題十有八九出在同步級聯(lián)的使能信號上重點檢查RCO到ENT的連線。第三步測試分的模60和時的模24。為了讓測試加快我把分和時的測試脈沖從秒脈沖臨時換成手動脈沖幾秒鐘就能觀察一個完整的進位周期。測試完畢再換回正常秒脈沖。第四步測試日歷模塊。這個階段要特別關(guān)注月底翻月。我當時的做法是先用置數(shù)法把日期強行撥到月底前一天比如31號前一天然后手動加脈沖觀察日期是否正確翻到下月1號同時月份是否加1。要分別測大月、小月、2月平年和2月閏年四種情況這樣才能驗證月底判斷邏輯是完備的。第五步聯(lián)調(diào)整個系統(tǒng)。上電后先手動校準到當前時間日期然后讓它運行幾分鐘看時分秒運行是否正常日期翻月是否正常。我當時讓它連續(xù)跑了一整個晚上第二天早上起來看日期已經(jīng)自動翻了一天說明整個系統(tǒng)是穩(wěn)定可靠的。4. 常見問題與排查技巧實錄4.1 典型故障速查表做這個項目的過程中我遇到的問題基本可以整理成下面這個速查表建議收藏遇到類似問題先對照這個表排查。故障現(xiàn)象可能原因排查方法解決措施數(shù)碼管完全不亮譯碼器型號與數(shù)碼管不匹配查共陽/共陰極性共陰用74LS48共陽用74LS47秒脈沖有但秒計數(shù)器不走使能端ENT/ENP沒接高萬用表測使能腳電平將ENT、ENP接VCC59后變0但十位進位一次跳兩個反饋清零信號毛刺嚴重示波器看清零腳波形改用同步置數(shù)或加去耦電容日期翻月后日變成0不是1日計數(shù)用了清零法檢查置數(shù)端接線日計數(shù)必須置數(shù)到12月28號就直接跳到3月1號閏年判斷邏輯錯誤逐個驗證Y0、Y1條件重查閏年組合邏輯按鍵一下跳好幾個數(shù)按鍵沒有消抖示波器看按鍵輸出加RC低通或使用RS觸發(fā)器消抖芯片發(fā)燙電源接反或輸出短路斷電后萬用表測電阻檢查VCC/GND和輸出負載運行幾分鐘后時間越走越慢555定時電容老化或溫度漂移示波器長期監(jiān)測頻率換CBB電容或改用晶振分頻4.2 毛刺與競爭冒險清零信號的隱形殺手在用反饋清零法實現(xiàn)模60和模24的時候毛刺問題是繞不開的。什么是毛刺簡單說就是組合邏輯輸出的一瞬間出現(xiàn)的不期望的窄脈沖。比如十位計數(shù)到5時與非門輸出清零信號但這個信號在極短的時間內(nèi)可能有抖動。74LS160是異步清零只要CLR腳出現(xiàn)低電平不管維持多久計數(shù)器都會立刻被清零。這就帶來一個非常隱蔽的問題如果清零信號在5狀態(tài)剛建立時先出現(xiàn)了一個極窄的毛刺計數(shù)器會提前被清零導致你看到的計數(shù)序列是0、1、2、3、0、1、2、3……而不是0到5循環(huán)。這種故障用LED觀察時很難捕捉但用示波器或者邏輯分析儀看非常明顯。解決毛刺的三個常用手段我都試過。第一個是增加去耦電容效果有限第二個是在清零線上并聯(lián)一個小電容幾十pF到幾百pF可以濾掉高頻毛刺但電容太大會拖慢清零速度第三個最穩(wěn)妥改用同步置數(shù)法讓LOAD信號在時鐘邊沿才起作用不給毛刺發(fā)作的機會。如果你在仿真里沒問題、一上實物就亂優(yōu)先考慮換同步置數(shù)。4.3 按鍵消抖的RC方案與RS觸發(fā)器方案校時和校歷功能必須用按鍵而按鍵抖動是必現(xiàn)問題。機械按鍵在按下和釋放的瞬間觸點會反復通斷幾毫秒到十幾毫秒如果不做消抖一次按壓會變成好幾個脈沖日歷直接快進到不知道哪一年去了。最簡單的消抖方法是RC低通濾波加施密特觸發(fā)器。按鍵一端接VCC另一端通過一個10kΩ電阻接GND同時并聯(lián)一個10μF電容這樣按鍵未按下時輸出低電平按下后電容充電電壓緩慢上升再經(jīng)過施密特觸發(fā)器整形輸出干凈的上升沿。這個方案的缺點是RC時間常數(shù)不能太大否則按鍵響應太慢。我在項目里用的是更經(jīng)典的RS觸發(fā)器消抖用兩個與非門交叉耦合構(gòu)成一個RS鎖存器。按鍵接到R和S端按下和釋放時RS鎖存器會鎖住第一個有效的電平變化完全消除抖動。這個方案在數(shù)電課本里就有正好和課程知識對應上而且不依賴電容值響應速度快。4.4 電源供電面包板上的“隱形地雷”我最后單獨提一下電源問題。面包板供電我一開始用的是一根USB線轉(zhuǎn)5V結(jié)果系統(tǒng)一動起來數(shù)碼管亮度就開始不穩(wěn)計數(shù)器也頻繁出問題。后來用萬用表一量5V在芯片翻轉(zhuǎn)時波動能到幾百毫伏這就是典型的供電能力不足。后面我換成了實驗室的直流穩(wěn)壓電源限流1A穩(wěn)定得很。如果你手上只有USB供電至少要做到兩點一是盡量縮短電源線用粗一點的杜邦線二是在面包板電源軌的兩端各加一個100μF的電解電容和0.1μF的陶瓷電容起到儲能和濾波作用。數(shù)碼管點亮時電流比較大14位數(shù)碼管全亮起來峰值電流可能接近幾百毫安供電一定要留足余量。5. 項目擴展用FPGA與Verilog重新實現(xiàn)萬年歷做完74芯片版本之后我其實還做了一版FPGA實現(xiàn)因為很多學校數(shù)電實驗課開始在往FPGA方向轉(zhuǎn)。這一節(jié)算是一個擴展思路給有興趣的同學參考。用Verilog寫萬年歷模塊比搭面包板快得多而且邏輯清晰核心模塊就是一個計數(shù)器加一個狀態(tài)判斷。頂層思路是先用分頻器把開發(fā)板上的50MHz時鐘分頻得到1Hz脈沖。然后秒、分、時、日、月、年各定義成獨立的計數(shù)變量時鐘到達時遞進。日計數(shù)器的遞進條件同樣要看月份和閏年用case語句判斷當前月份的天數(shù)這個比搭門電路直觀多了。一個簡潔的日期遞進偽代碼邏輯大致是這樣當日計數(shù)小于當月天數(shù)時日加1否則日回1月加1當月到12且日到月底時月回1年加1當年到99時回0。時分秒的進位邏輯同理。整個工程用狀態(tài)機做統(tǒng)一控制比一堆計數(shù)器散著寫要清晰得多。FPGA方案的典型優(yōu)勢是時序可控、邏輯修改方便、仿真速度快劣勢是需要開發(fā)板和仿真工具對純數(shù)電原理的體現(xiàn)不如74芯片直觀。我的建議是課程要求用芯片搭電路的就老老實實搭時間充裕的情況下再用Verilog實現(xiàn)一版作為擴展練習對你理解數(shù)字系統(tǒng)的層次化設(shè)計非常有幫助。最后再分享一個小技巧這次實訓最大的體會是做硬件項目最忌“一氣呵成”。我親眼見過同學花一個下午把所有線接完通電之后屏幕全亂然后拆掉重來來回折騰三四天。正確做法是每完成一個小模塊就測試一個小模塊測試完的性能和現(xiàn)象記錄下來再接下一塊。做萬年歷尤其如此因為模塊多、信號多、相互依賴多分模塊推進看起來慢實際上是最快的路徑。另外一個很實用的小技巧調(diào)試日歷部分時不要真的從1月1日開始一秒一秒等下去。我的做法是把秒脈沖換成手動脈沖手動把日期撥到月底前一天然后快速驗證翻月邏輯。把日期撥到2月27日測平年28天再撥到閏年的2月28日測閏年29天。這樣十分鐘就能把所有邊界情況測完而不是等上幾個月。這個思路我沒有在任何教程里看到過但實測非常高效分享給大家。