FPGA——流水燈(一)


  對於FPGA的結構原理,先不進行全面的了解,先能根據教程程序看得懂,寫得出來跑起來。慢慢的了解程序運行的原理,各種語法的使用。

  今天對流水的程序有一個認識,熟悉軟件的使用,語法規則,原理。以正點原子的例程為例,代碼如下

 1 // Created by:          正點原子
 2 
 3 module flow_led(
 4     input               sys_clk  ,  //系統時鍾
 5     input               sys_rst_n,  //系統復位,低電平有效
 6      
 7     output  reg  [3:0]  led         //4個LED燈
 8     );
 9 
10 //reg define
11 reg [23:0] counter;
12 
13   //                main code                                                                                                                                                                                                                     
14 //計數器對系統時鍾計數,計時0.2秒
15 always @(posedge sys_clk or negedge sys_rst_n) begin
16     if (!sys_rst_n)
17         counter <= 24'd0;
18     else if (counter < 24'd1000_0000)
19         counter <= counter + 1'b1;
20     else
21         counter <= 24'd0;
22 end
23 
24 //通過移位寄存器控制IO口的高低電平,從而改變LED的顯示狀態
25 always @(posedge sys_clk or negedge sys_rst_n) begin
26     if (!sys_rst_n)
27         led <= 4'b0001;
28     else if(counter == 24'd1000_0000) 
29         led[3:0] <= {led[2:0],led[3]};
30     else
31         led <= led;
32 end
33 
34 endmodule 

 

  這個代碼的功能是點亮流水燈。代碼的內容是:用一個定時器計時,到了0.2s就自動清零,否則自動+1計數。另一方面,判斷是否到了0.2s,到了就換另一個led亮。程序寫好后,燒寫在芯片里,會形成這樣的電路,功能是並行的。不像是stm32需要用C語言寫代碼,生成指令,cpu取指執行。FPGA會快一些。

  代碼的整體結構,頭和尾有 module 和 endmodule 這是模塊的開始和結束。如果工程中有其他的功能代碼,寫在一個.v文件,也會有這個 module 。就是一個功能或者一個模塊卸載一個.v 文件,這樣便於管理。

  input                  sys_clk ,   可以理解為定義一個輸入類型的變量。

  output   reg [3:0]     led, 可以理解為,定義一個輸出類型的變量,他占據了4個bit。

  always @(posedge sys_clk or negedge sys_rst_n) begin   可理解為,復位了或者有新的始終進來就做下面的代碼。

  led <= 4'b0001;    這個是賦值,和C語言有些不一樣。

   4'b0001   是一個數,b:二進制表示,0001。 4' 是指這個數是4位的。

 

補充一下流水燈的形成  led[3:0] <= {led[2:0],led[3]};  意思是:4位循環右移。即,3位放到0位,210位放到321位。led初始化0001,用形象的描述如下:

位          3210

初始值   0001

第一次  0010

第二次  0100

第三次 1000

....................

高電平點亮。形成流水燈。

 

然后這個程序實現了點燈。但是有一點,他是怎么控制的引腳呢,led是接在引腳少了,這里面也沒涉及到引腳啊。在下面這里:

 

通過這個圖可以看到,我們在工程里面的變量,需要“綁定”引腳。使使之一一對應,舉個例子led變量是4個bit的,把0 1 2 3 分別對應板子上led連接的引腳上,操作led就相當於操作引腳了。

 

 

  幾天重新研究了一下這個流水燈的例程,覺得主要部分代碼還要再仔細的分析一下,時序代碼部分:

1 always @(posedge sys_clk or negedge sys_rst_n) begin
2     if (!sys_rst_n)
3         counter <= 24'd0;
4     else if (counter < 24'd1000_0000)
5         counter <= counter + 1'b1;
6     else
7         counter <= 24'd0;
8 end

  其中關鍵字 always 是時序邏輯電路,在這個語句的下面,賦值的話用非阻塞賦值 “ <= ” ,非阻塞可以理解為:相互不干擾、不堵塞,是並行的。而阻塞賦值是串行的,相互之間有順序干擾的,一個一個的。

  第一行解釋:如果有  sys_clk 時鍾信號上升沿或者 sys_rst_n 下降沿的話,就開始執行下面的代碼一直到 end 結束。

  這是一個或的關系,兩個條件滿足一個即可。第一條 if 判斷是時鍾信號上升沿還是復位重啟,如果是復位重啟的話,就給 counter 計數器賦初值 0 。如果不是復位那就是時鍾洗好上升沿,此時,是一個脈沖過來了,執行下一個(類似單片機的下一條指令),那么就看計數器是否達到最大,沒達到的話,就 繼續 +1 ,達到了最大的話,就置為0。以便於重新計數。

 

  流水燈部分:

1 always @(posedge sys_clk or negedge sys_rst_n) begin
2     if (!sys_rst_n)
3         led <= 4'b0001;
4     else if(counter == 24'd1000_0000) 
5         led[3:0] <= {led[2:0],led[3]};
6     else
7         led <= led;
8 end

  這段代碼看着和上一段時序部分非常像。主要功能是,實現流水燈,根據上面的時序部分“定時器”,克制外部晶振50MHz,周期是 20ns。0.2s流動一次的話,計數器就要計數到 10^7 個,從0 到10^7-1,就是 24'd1000_0000。在流水燈部分,判斷計數器是否為24'd1000_0000 是的話就是到了0.2s。流動一次。

 

總結:

1.  掌握verilog的語法:

  1.1 always 和 assign的區別

  1.2 阻塞賦值和非阻塞賦值的區別

  1.3 數據格式

  1.4 程序代碼的框架

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM