NEXYS 3開發板練手--LED與數碼管時鐘

  作科研的時候從學校拿到一塊基於Xilinx公司Spartan-6主芯片的FPGA開發板,由於以前一直在用Altera公司的FPGA,一開始接觸它還真有點不太習慣。但畢竟核心的東西仍是不會變的,因而按照慣例,先仔細瞄了瞄這塊開發板,看看有哪些可用的資源--撥碼開關、按鍵、LED、七段數碼管、USB Host、USB UART、VGA、以太網接口,嗯哼,雖然比不上友晶的DE2那麼強大,可是看來作通常的開發仍是綽綽有餘的。ide

  瞄完就是上網找資料了,首先找是板子的製造商--digilent,下載原理圖,下載能用的開發工具,下載DEMO,而後就是學着怎麼操做Xilinx的開發工具,將DEMO下載上去,肯定板子有沒有問題(這其間從熟悉的quartus轉到陌生的Xilinx ISE着實花了我一番功夫,這裏就不羅嗦了)。digilent上有一個DEMO挺有意思的,叫Nexys3_ISE_GPIO_UART的工程,它將撥碼開關、按鍵、LED、七段數碼管、USB UART這幾種板子上的基礎資源寫進了一個工程裏,效果好象是撥碼開關控制LED,數碼管循環顯示幾個單詞,而後用USB數據線將UART口跟電腦相連,能經過按鍵控制向電腦發送特定的字符串,而後能在電腦上的超級終端接收到這個字符,看着挺牛的嘛!不過那老是人家的,要變成本身的還得本身動手!說幹就幹,那就拿他練手吧。工具

  按理來講這也不難吧,畢竟有現成的東西在,我開始也這麼想的,不過當我打開那個DEMO裏面的代碼一看,頓時有種想罵人的衝動--竟然是VHDL!我一開始學的就是Verilog,VHDL壓根就沒接觸過,這兩種語言差異還有點大呢!看這裏面的代碼,就像天書!要我看懂這些傢伙我還不如本身研究呢(其實也沒那麼恐怖)!因而就準備本身寫一份測試的DEMO,就當是練手了。性能

  本來的DEMO功能有點多,因而我就想把它分兩部分來完成,把比較複雜的USB UART這部分單獨拿出來,其餘的放在一個DEMO裏面。後來又想,既然有4個數碼管,那就作個時鐘吧,雖然沒有小時部分,但做爲練手仍是無傷大雅的。這篇文章先說說這個數碼管時鐘,USB UART部分將在後面的文章中討論。開發工具

  數碼管時鐘我想對於不少學電子的同窗來講都不陌生了,特別是學過單片機的,這個東西是入門練手必備的。閒話很少說,先來講說這個原理。怎麼點亮單個數碼管我就不說了,無非分清共陰共陽,而後就是置高置低的問題。可是對於4個一塊兒的數碼管,要怎麼控制他們看起來好像是在同時點亮的並且還能顯示不一樣的內容就比較麻煩了。先上原理圖:測試

                                                          

  顯然要控制一個數碼管須要兩部分的端口--CA...DP和AN0...AN3,我通常叫左邊的爲段選,右邊的爲位選。從原理圖上來看,位選端接在PNP管的B極,要先讓C、E極導通,相應的位選端應該是低電平,好比AN3...AN0四位爲1110,就是選擇了最後一個數碼管。而當數碼管選中時(即相應的三極管導通),數碼管公共端接的是高電平,顯然這些數碼管應該是共陽的,因而CA...DP端的編碼就能夠按共陽數碼管的編碼方式作了。轉換成Verilog代碼,能夠是一下的常數定義:編碼

parameter AN1 = 4'b1110,AN2 = 4'b1101,AN3 = 4'b1011,AN4 = 4'b0111;//數碼管位選定義
parameter zero = 8'b0000_0011,one = 8'b1001_1111,two = 8'b0010_0101,three = 8'b0000_1101,four = 8'b1001_1001,
             five = 8'b0100_1001,six = 8'b0100_0001,seven = 8'b0001_1111,eigth = 8'b0000_0001,nine = 8'b0000_1001;//數碼管段選定義

  好了,如今搞清楚了第一個問題--怎麼將0-9幾個數顯示出來,接下來的問題是怎麼讓4個數碼管看起來是一塊兒顯示的,並且還能顯示不一樣的內容。這個問題相信作過單片機數碼管實驗的同窗立刻就猜到了,沒錯,原理就是利用人眼視覺的暫留性(我是這麼叫的,再專業點就不是我研究的問題了)--當兩個數碼管之間的變化小於100ms(貌似是這麼長時間)時,咱們的眼睛是看不到他們之間的閃爍的。因而,當咱們要顯示1234這4個數時,咱們能夠在1ms時顯示1,25ms時顯示2,50ms時顯示3,75ms時顯示4,而後循環,看起來就是一塊兒顯示1234這4個數了。固然,咱們的硬件能夠作的更快,這個時間間隔能夠根據實際狀況選擇更短。把它翻譯成Verilog語言就有下面的程序段了:spa

//數碼管刷新顯示模塊
always@(posedge div1000hz)
begin
    if(rest)
    begin
        seg_count <= 0;
        an <= 4'b0000;
        seg <= 8'b0000_0000;
    end
    else
    begin
    case(seg_count)
    0 : begin
            case(sec1)
            0 : seg <= zero;
            1 : seg <= one;
            2 : seg <= two;
            3 : seg <= three;
            4 : seg <= four;
            5 : seg <= five;
            6 : seg <= six;
            7 : seg <= seven;
            8 : seg <= eigth;
            9 : seg <= nine;
            endcase
            an <= AN1;
         end
    1 : begin
            case(sec2)
            0 : seg <= zero;
            1 : seg <= one;
            2 : seg <= two;
            3 : seg <= three;
            4 : seg <= four;
            5 : seg <= five;
            6 : seg <= six;
            7 : seg <= seven;
            8 : seg <= eigth;
            9 : seg <= nine;
            endcase
            an <= AN2;
         end
    2 : begin
            case(min1)
            0 : seg <= zero;
            1 : seg <= one;
            2 : seg <= two;
            3 : seg <= three;
            4 : seg <= four;
            5 : seg <= five;
            6 : seg <= six;
            7 : seg <= seven;
            8 : seg <= eigth;
            9 : seg <= nine;
            endcase
            an <= AN3;
         end
    3 : begin
            case(min2)
            0 : seg <= zero;
            1 : seg <= one;
            2 : seg <= two;
            3 : seg <= three;
            4 : seg <= four;
            5 : seg <= five;
            6 : seg <= six;
            7 : seg <= seven;
            8 : seg <= eigth;
            9 : seg <= nine;
            endcase
            an <= AN4;
         end
    endcase
    seg_count <= seg_count + 1;
    end
end

  好,如今剩最後一個問題了,那就是時鐘控制部分。熟悉C的同窗會說,那還不簡單,分頻計數,而後整除求餘,將秒、分的十位各位分開不就能夠了嗎?沒錯,這是最簡單的方式,可是,你們千萬不要忽略了咱們最後的代碼是要變成硬件電路的。先不說Xilinx的IDE內嵌的XST綜合器不支持對除號的綜合,要實現除法必需要設計除法器(調用IP或本身設計),就算是設計出來了,一個除法器佔用的硬件資源可能會比咱們剩餘部分電路佔用的資源還多。從這方面出發考慮,咱們要想一想是否是有更好的方法實現它。其實只要咱們稍微思考一下仍是不難的,下面的代碼就能很簡潔的完成這部分的設計:翻譯

//時鐘模塊
always@(posedge div1hz)
begin
    if(rest)
    begin
        sec1 <= 0;
        sec2 <= 0;
        min1 <= 0;
        min2 <= 0;
    end
    else
    begin
    sec1 <= sec1 + 1;
    if(sec1 == 9)
    begin
        sec2 <= sec2 + 1;
        sec1 <= 0;
    end
    if(sec2 == 5 && sec1 == 9)
    begin
        min1 <= min1 + 1;
        sec2 <= 0;
    end
    if(min1 == 9)
    begin
        min2 <= min2 + 1;
        min1 <= 0;
    end
    if(min2 == 5 && min1 == 9)
    begin
        min2 <= 0;
    end
    end
end

可能咱們會多寫幾行代碼,可是最後設計出來的電路的性能每每會有大的飛躍,這是咱們在作硬件開發時須要時常提醒本身的。設計

  好了,以上就是這個DEMO的關鍵部分,其實也是至關基礎的,把它拿出來做爲個人第一篇技術文章與你們分享,有不當之處還請你們指出。下面是完整的程序,中間還將LED顯示加進去了,讓八個LED間隔1s亮滅:rest

  1 `timescale 1ns / 1ps
  2 //////////////////////////////////////////////////////////////////////////////////
  3 // Company: 
  4 // Engineer:         lwy
  5 // 
  6 // Create Date:    00:33:08 11/09/2013 
  7 // Design Name: 
  8 // Module Name:    segclk 
  9 // Project Name: 
 10 // Target Devices: 
 11 // Tool versions: 
 12 // Description:NEXYS3開發板測試程序,用數碼管實現時鐘功能
 13 //
 14 // Dependencies: 
 15 //
 16 // Revision: 
 17 // Revision 0.01 - File Created
 18 // Additional Comments: 
 19 //
 20 //////////////////////////////////////////////////////////////////////////////////
 21 module segclk(
 22     clk,//時鐘輸入,100M
 23     rest,//時鐘復位信號,BTNU,高電平時復位
 24     seg,//數碼管段選
 25     an,//數碼管位選
 26     led//8個LED
 27     );
 28 
 29 input clk,rest;
 30 output reg [7:0] seg;
 31 output reg [3:0] an;
 32 output reg [7:0] led;
 33 
 34 parameter AN1 = 4'b1110,AN2 = 4'b1101,AN3 = 4'b1011,AN4 = 4'b0111;//數碼管位選定義
 35 parameter zero = 8'b0000_0011,one = 8'b1001_1111,two = 8'b0010_0101,three = 8'b0000_1101,four = 8'b1001_1001,
 36              five = 8'b0100_1001,six = 8'b0100_0001,seven = 8'b0001_1111,eigth = 8'b0000_0001,nine = 8'b0000_1001;//數碼管段選定義
 37 parameter led_on = 8'b1111_1111,led_off = 8'b0000_0000;//LED亮滅定義
 38              
 39 reg [25:0] div1hz_temp;//1秒分頻計數
 40 reg [12:0] div1000hz_temp;//數碼管刷新時間分頻計數
 41 reg div1hz;//1Hz時鐘
 42 reg div1000hz;//數碼管刷新時鐘,頻率爲(100M/2^13)Hz
 43 reg led_temp;//LED亮滅
 44 
 45 reg [3:0] sec1;//秒個位
 46 reg [3:0] sec2;//秒十位
 47 reg [3:0] min1;//分個位
 48 reg [3:0] min2;//分十位
 49 
 50 reg [1:0] seg_count;//數碼管位選定位
 51 
 52 //1秒分頻模塊
 53 always@(posedge clk)
 54 begin
 55     div1hz_temp <= div1hz_temp + 1;
 56     if(div1hz_temp == 50000000)
 57     begin
 58         div1hz_temp <= 0;
 59         div1hz <= ~div1hz;
 60     end
 61 end
 62 
 63 //數碼管刷新時間分頻模塊
 64 always@(posedge clk)
 65 begin
 66     div1000hz_temp <= div1000hz_temp + 1;
 67     if(div1000hz_temp == 8191)
 68     begin
 69         div1000hz <= ~div1000hz;
 70     end
 71 end
 72 
 73 //時鐘模塊
 74 always@(posedge div1hz)
 75 begin
 76     if(rest)
 77     begin
 78         sec1 <= 0;
 79         sec2 <= 0;
 80         min1 <= 0;
 81         min2 <= 0;
 82     end
 83     else
 84     begin
 85     sec1 <= sec1 + 1;
 86     if(sec1 == 9)
 87     begin
 88         sec2 <= sec2 + 1;
 89         sec1 <= 0;
 90     end
 91     if(sec2 == 5 && sec1 == 9)
 92     begin
 93         min1 <= min1 + 1;
 94         sec2 <= 0;
 95     end
 96     if(min1 == 9)
 97     begin
 98         min2 <= min2 + 1;
 99         min1 <= 0;
100     end
101     if(min2 == 5 && min1 == 9)
102     begin
103         min2 <= 0;
104     end
105     end
106 end
107 
108 //LED亮滅控制模塊
109 always@(posedge div1hz)
110 begin
111     led_temp = ~led_temp;
112     if(led_temp)
113         led <= led_on;
114     else
115         led <= led_off;
116 end
117 
118 //數碼管刷新顯示模塊
119 always@(posedge div1000hz)
120 begin
121     if(rest)
122     begin
123         seg_count <= 0;
124         an <= 4'b0000;
125         seg <= 8'b0000_0000;
126     end
127     else
128     begin
129     case(seg_count)
130     0 : begin
131             case(sec1)
132             0 : seg <= zero;
133             1 : seg <= one;
134             2 : seg <= two;
135             3 : seg <= three;
136             4 : seg <= four;
137             5 : seg <= five;
138             6 : seg <= six;
139             7 : seg <= seven;
140             8 : seg <= eigth;
141             9 : seg <= nine;
142             endcase
143             an <= AN1;
144          end
145     1 : begin
146             case(sec2)
147             0 : seg <= zero;
148             1 : seg <= one;
149             2 : seg <= two;
150             3 : seg <= three;
151             4 : seg <= four;
152             5 : seg <= five;
153             6 : seg <= six;
154             7 : seg <= seven;
155             8 : seg <= eigth;
156             9 : seg <= nine;
157             endcase
158             an <= AN2;
159          end
160     2 : begin
161             case(min1)
162             0 : seg <= zero;
163             1 : seg <= one;
164             2 : seg <= two;
165             3 : seg <= three;
166             4 : seg <= four;
167             5 : seg <= five;
168             6 : seg <= six;
169             7 : seg <= seven;
170             8 : seg <= eigth;
171             9 : seg <= nine;
172             endcase
173             an <= AN3;
174          end
175     3 : begin
176             case(min2)
177             0 : seg <= zero;
178             1 : seg <= one;
179             2 : seg <= two;
180             3 : seg <= three;
181             4 : seg <= four;
182             5 : seg <= five;
183             6 : seg <= six;
184             7 : seg <= seven;
185             8 : seg <= eigth;
186             9 : seg <= nine;
187             endcase
188             an <= AN4;
189          end
190     endcase
191     seg_count <= seg_count + 1;
192     end
193 end
194 
195 endmodule
View Code 
相關文章
相關標籤/搜索