數碼管動態掃描 led數碼管(LED Segment Displays)是由多個發光二極管封裝在一起組成“8”字型的器件,引線已在內部連接完成,只引出它們的各個筆劃,公共電極。led數碼管常用段數一般為7段,如上圖中的abcdefg,有的還會有一個小數點,如圖中的h。 file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image002.png 數碼管要正常顯示,就要用驅動電路來驅動數碼管的各個段碼,從而顯示出我們要的數字。按發光二極管單元連接方式可分為共陽極數碼管和共陰極數碼管。共陽數碼管是指將所有發光二極管的陽極接到一起形成公共陽極(COM)的數碼管,共陽數碼管在應用時應將公共極COM接到+5V,當某一字段發光二極管的陰極為低電平時,相應字段就點亮,當某一字段的陰極為高電平時,相應字段就不亮。共陰數碼管是指將所有發光二極管的陰極接到一起形成公共陰極(COM)的數碼管,共陰數碼管在應用時應將公共極COM接到地線GND上,當某一字段發光二極管的陽極為高電平時,相應字段就點亮,當某一字段的陽極為低電平時,相應字段就不亮。 下表列出了要顯示的數字,以及對應的abcdefg的值。
例如,共陽數碼管中,abcdefg的值分別是1001111時,也就是b和c字段亮,其他字段不亮,這時就顯示了數字“1”。 如果要顯示多個數碼管,根據數碼管的驅動方式的不同,可以分為靜態式和動態式兩類。 靜態驅動也稱直流驅動。靜態驅動是指每個數碼管的每一個段碼都由一個單片機的I/O端口進行驅動,或者使用如BCD碼二-十進制譯碼器譯碼進行驅動。靜態驅動的優點是編程簡單,顯示亮度高,缺點是占用I/O端口多,如驅動5個數碼管靜態顯示則需要5×8=40根I/O端口來驅動,要知道一個89S51單片機可用的I/O端口才32個,實際應用時必須增加譯碼驅動器進行驅動,增加了硬件電路的復雜性。 數碼管動態顯示接口是應用最為廣泛的一種顯示方式之一,動態驅動是將所有數碼管的8個顯示筆劃"a,b,c,d,e,f,g,dp"的同名端連在一起,另外為每個數碼管的公共極COM增加位選通控制電路,位選通由各自獨立的I/O線控制,當要輸出字形碼時,所有數碼管都接收到相同的字形碼,但究竟是哪個數碼管會顯示出字形,取決于單片機對位選通COM端電路的控制,所以我們只要將需要顯示的數碼管的選通控制打開,該位就顯示出字形,沒有選通的數碼管就不會亮。通過分時輪流控制各個數碼管的的COM端,就使各個數碼管輪流受控顯示,這就是動態驅動。在輪流顯示過程中,每位數碼管的點亮時間為1~2ms,由于人的視覺暫留現象及發光二極管的余輝效應,盡管實際上各位數碼管并非同時點亮,但只要掃描的速度足夠快,給人的印象就是一組穩定的顯示數據,不會有閃爍感,動態顯示的效果和靜態顯示是一樣的,能夠節省大量的I/O端口,而且功耗更低。 明德揚開發板上一共有2組4位的共陽數碼管,也就是說一共有8個共陽數碼管。數碼管的配置電路如下。 file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg 圖中的SEG_A,SEG_B~SEG_DP,是段選信號,這些信號都是8個數碼管共用的。 DIG1~DIG8是位選信號,分別對應8個數碼管。對應的位選信號為0,就表示將段選信號的值賦給該數碼管。例如DIG3為0,表示將段選信號SEG_A~SEG_DP的值賦給數碼管3。 SEG_A~SEG_DP,DIG1~DIG8,都是連接到電阻,如下圖。 file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image006.jpg 由此可見,SEG_A~SEG_DP是由SEG0~SEG7產生的,DIG1~DIG8是由DIG_EN1~DIG_EN8產生的。 而SEG0~SEG7和DIG_EN1~DIG_EN8直接連到FPGA的IO上。 file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image007.png 這些信號與FPGA管腳的對應關系如下表。
也就是說,FPGA通過控制上面中的管腳,就控制了數碼管的顯示。 開發板或者模塊是有 8 位數碼管,本次設計需要使用 8 個數碼管,實現數碼管顯示功能,具體要求如下: 復位后,數碼管 0 顯示數字 0;1 秒后,輪到數碼管 1 顯示數字 1;1 秒后,輪到數碼管 2 顯示數字 2;以此類推,每隔 1 秒變化,最后是數碼管 7 顯示數字 7。然后再次循環。 上板效果圖如下圖所示。 上板的演示效果,請登陸網址查看:www.mdy-edu.com/xxxx。 file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image009.jpgfile:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image011.jpgfile:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image013.jpgfile:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image015.jpg file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image017.jpgfile:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image019.jpgfile:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image021.jpgfile:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image023.jpg 三、模塊設計我們要實現的功能,概括起來就是控制8個數碼管,讓數碼管顯示不同的數字。要控制8個數碼管,就需要控制位選信號,即FPGA要輸出一個8位的位選信號,設為seg_sel,其中seg_sel[0]對應數碼管0,seg_sel[1]對應數碼管1,以此類推,seg_sel[7]對應數碼管7。 要顯示不同的數字,就需要控制段選信號,不需要用到DP,一共有7根線,即FPGA要輸出一個7位的段選信號,設為seg_ment,seg_ment[6]~segm_ment[0]分別對應數碼管的abcdefg(注意對應順序)。 我們還需要時鐘信號和復位信號來進行工程控制。 綜上所述,我們這個工程需要4個信號,時鐘clk,復位rst_n,輸出的位選信號seg_sel和輸出的段選信號seg_ment。其中,seg_sel和seg_ment的對應關系下如下:
我們先分析要實現的功能,數碼管0顯示數字0,翻譯成信號就是seg_sel的值為8’b1111_1110,seg_ment的值為7’b000_0001。數碼管1顯示數字1,也就是說seg_sel的值為8’b1111_1101,seg_ment的值為7’b100_1111。以此類推,數碼管7顯示數字7,就是seg_sel的值為8’b0111_1111,seg_ment的值為7’b000_1111。 再留意下,以上都是每隔1秒進行變化,并且是8個數碼管輪流顯示,那么波形示意圖如下圖所示。 file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image025.png 上圖就是seg_sel和seg_seg信號的變化波形圖。在顯示第1個時,seg_sel=8’hfe,seg_ment=7’h01并持續1秒;在第1個時,seg_sel=8’hfd,seg_ment=7’h4f并持續1秒;以此類推,第8個時,seg_sel=8’h7f,seg_ment=7’h0f并持續1秒。然后又再次重復。 由波形圖可知,我們需要1個計數器用來計算1秒的時間。本工程的工作時鐘是50MHz,即周期為20ns,計數器計數到1_000_000_000/20=50_000_000個,我們就能知道1秒時間到了。另外,由于該計數器是不停地計數,永遠不停止的,可以認為加1條件一直有效,可寫成:assignadd_cnt==1。綜上所述,該計數器的代碼如下。 file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image027.jpg 再次觀察波形圖,我們發現有第1個,第2個直到第8個,說明這還需要另外一個計數器來表示第幾個。該計數器表示第幾個,自然是完成1秒就加1,因為加1條件可為end_cnt0。該計數器一共要數8次。所以代碼為: file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image029.jpg 有了兩個計數器,我們來思考輸出信號seg_sel的變化。概括起來,在第1次的時候輸出值為8’hfe;在第2次的時候輸出值為8’hfd;以此類推,在第8次的時候輸出值為8’h7f。我們用信號cnt1來代替第幾次,也就是:當cnt1==0的時候,輸出值為8’hfe;在cnt1==1的時候輸出值為8’hfd;以此類推,在cnt1==7的時候輸出值為8’h7f。再進一步翻譯成代碼,就變成如下: file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image030.png 讀者有沒有發現,上面代碼基本上和文字描述是一模一樣的,這進一步展現了verilog是“硬件描述語言”。上面的代碼是能正確實現seg_sel功能的,從實現角度和資源角度來說,都挺好。但代碼進一步概括,可以化簡如下: file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image031.png 對上面代碼解釋一下,第131行是指先將8’b1向左移位,再取反后的值,賦給seg_sel。假設此時cnt1等于0,那么8’b1<<0的結果是8’b0000_0001,取反的值為8’hfe;假設cnt1等于3,那么8’b1<<3的結果為8’b000_1000,取反后的結果為8’b1111_0111,即8’hf7。與第一種寫法的結果都是相同的。 我們來思考輸出信號seg_ment的變化。概括起來,在第1次的時候輸出值為7’h01;在第2次的時候輸出值為7’h4f;以此類推,在第8次的時候輸出值為7’h0f。我們用信號cnt1來代替第幾次,也就是:當cnt1==0的時候,輸出值為7’h01;在cnt1==1的時候輸出值為7’h4f;以此類推,在cnt1==7的時候輸出值為7’h0f。再進一步翻譯成代碼,就變成如下: file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image032.png 上面的代碼正確地實現了seg_ment的功能,對于本工程說已經完美。但我們分析一下,就知道上面代碼實現了類似譯碼的功能,將數字設成數碼管顯示的值,代碼里只對0~7進行譯碼。很自然的,我先做一個通用的譯碼模塊,將0~9都進行譯碼,以后就方便調用了。例如改成下面代碼。 file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image033.png 然后我們只要控制好data就能實現想要在數碼管顯示的數字,如下面代碼。 file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image034.png 當cnt1=0,則數碼管會顯示0。當cnt1=1,則數碼管會顯示1。 在代碼的最后一行寫下endmodule file:///C:/Users/pan/AppData/Local/Temp/msohtmlclip1/01/clip_image035.png 至此,主體程序已經完成。接下來是將module補充完整。 將module的名稱定義為my_seg。并且我們已經知道該模塊有4個信號:clk、rst_n、seg_sel和seg_ment,代碼如下: |
1.4 MB, 下載積分: 積分 -1