一、 軟件平臺與硬件平臺
軟件平臺:
1、操作系統(tǒng):Windows-8.1
2、開發(fā)套件:ISE14.7
硬件平臺:
1、FPGA型號:XC6SLX45-2CSG324
二、 原理介紹
我的開發(fā)板上有4個LED燈,原理圖如下:

由原理圖可知僅當(dāng)FPGA的對應(yīng)管腳輸入低電平時LED才會亮,流水燈的效果可以輪流讓四個對應(yīng)管腳輸出低電平來產(chǎn)生。
三、 目標任務(wù)
編寫四個LED流水的Verilog代碼并用ModelSim進行仿真,仿真通過以后下載到開發(fā)板進行測試,要求開發(fā)板上每個LED亮的時間為1s。
四、 設(shè)計思路與Verilog代碼編寫
由于每個LED亮的時間為1s,所以首先很自然想到產(chǎn)生一個1s的時鐘用來驅(qū)動后續(xù)邏輯,有了這個1s的時鐘以后,就可以在這個1s時鐘的節(jié)拍下對LED的輸出進行以移位操作來產(chǎn)生流水燈的效果。
1、1s時鐘的分頻邏輯
由于主時鐘是50MHz,周期為20ns,所以可以利用50MHz主時鐘驅(qū)動一個計數(shù)器,當(dāng)計數(shù)器的值每次到達24999999時,消耗的時間為25000000*20ns=0.5s,這時把分頻器的輸出反轉(zhuǎn),并把計數(shù)值清0,這樣分頻器的輸出就會每隔0.5s翻轉(zhuǎn)一次,產(chǎn)生了一個1s的時鐘。
Verilog代碼如下:
////////////////////////////////////////////////////////////////// // 功能:產(chǎn)生1s的時鐘 ////////////////////////////////////////////////////////////////// always @(posedge I_clk or negedge I_rst_n) begin if(!I_rst_n) begin R_cnt_ls <= 32'd0 ; R_clk_ls_reg <= 1'b1 ; end else if(R_cnt_ls == 32'd24_999_999) begin R_cnt_ls <= 32'd0 ; R_clk_ls_reg <= ~R_clk_ls_reg ; end else R_cnt_ls <= R_cnt_ls + 1'b1 ; end assign W_clk_ls = R_clk_ls_reg ;
2、移位邏輯
有了1s的時鐘信號以后,就在這個1s時鐘信號的驅(qū)動下對輸出的LED寄存器進行移位操作產(chǎn)生流水效果。
Verilog代碼如下:
//////////////////////////////////////////////////////////////////
// 功能:對輸出寄存器進行移位產(chǎn)生流水效果
//////////////////////////////////////////////////////////////////
always @(posedge W_clk_ls or negedge I_rst_n)
begin
if(!I_rst_n)
R_led_out_reg <= 4'b0001 ;
else if(R_led_out_reg == 4'b1000)
R_led_out_reg <= 4'b0001 ;
else
R_led_out_reg <= R_led_out_reg << 1 ;
end
assign O_led_out = ~R_led_out_reg ;
五、 ModelSim仿真
寫好邏輯以后,為了確定時序是正確的,最好寫一個測試文件對功能進行仿真,為了加快仿真速度,修改分頻邏輯計數(shù)器的計數(shù)值為24,然后編寫測試文件,測試文件中激勵產(chǎn)生的Verilog代碼如下:
initial begin // Initialize Inputs I_clk = 0; I_rst_n = 0; // Wait 100 ns for global reset to finish #100; I_rst_n = 1; // Add stimulus here end always #10 I_clk = ~I_clk ;
仿真的時序圖如下圖所示:

可以看到時序完全正確,接下來就是綁定管腳,生成bit文件下載到開發(fā)板測試了。
六、 進一步思考——C語言流水燈與Verilog流水燈區(qū)別
看完網(wǎng)上《Verilog那些事》系列博文以后,作者提出了一種“仿順序操作”方法,其實以前自己寫代碼的時候無形之中一直在用這種思想,但是一直沒有提煉出來,看完作者的介紹以后才發(fā)現(xiàn)確實是有那個“仿順序”的味道。詳細的博文請參考博客園博主akuei2的系列博文。這里我在總結(jié)一遍,給以后留個印象。
C語言實現(xiàn)流水燈的大致代碼框架如下:
while(1)
{
1、讓第1個LED亮,其他的滅;
2、延時1s
3、讓第2個LED亮,其他的滅
4、延時1s
5、讓第3個LED亮,其他的滅;
6、延時1s
7、讓第4個LED亮,其他的滅
8、延時1s
}
在while(1)里面代碼是一行一行的執(zhí)行,最后一行執(zhí)行完畢以后在回到第一行重新開始新一輪的執(zhí)行。就這樣產(chǎn)生了流水的效果。
看到這里,有人應(yīng)該突然明白了吧,這不正好就是Verilog中的一個狀態(tài)機么。對應(yīng)的Verilog代碼也可以寫出來了
always @(posedge I_clk)
begin
case(R_state)
第1個狀態(tài):讓第1個LED亮,其他的滅,下一狀態(tài)是第2個狀態(tài);
第2個狀態(tài):延時1s,下一狀態(tài)是第3個狀態(tài);
第3個狀態(tài):讓第2個LED亮,其他的滅,下一狀態(tài)是第4個狀態(tài);
第4個狀態(tài):延時1s,下一狀態(tài)是第5個狀態(tài);
第5個狀態(tài):讓第3個LED亮,其他的滅,下一狀態(tài)是第6個狀態(tài);
第6個狀態(tài):延時1s,下一狀態(tài)是第7個狀態(tài);
第7個狀態(tài):讓第4個LED亮,其他的滅,下一狀態(tài)是第8個狀態(tài);
第8個狀態(tài):延時1s,下一狀態(tài)是第1個狀態(tài);
default :;
endcase
end
具體的代碼如下:
//////////////////////////////////////////////////////////////////
// 功能:“仿順序操作”
//////////////////////////////////////////////////////////////////
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
begin
R_state <= 3'b000 ;
R_cnt_ls <= 32'd0 ;
end
else
begin
case(R_state)
C_S0:
begin
R_led_out_reg <= 4'b0001 ;
R_state <= C_S1 ;
end
C_S1:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 32'd0 ;
R_state <= C_S2 ;
end
else
R_cnt_ls <= R_cnt_ls + 1'b1 ;
end
C_S2:
begin
R_led_out_reg <= 4'b0010 ;
R_state <= C_S3 ;
end
C_S3:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 32'd0 ;
R_state <= C_S4 ;
end
else
R_cnt_ls <= R_cnt_ls + 1'b1 ;
end
C_S4:
begin
R_led_out_reg <= 4'b0100 ;
R_state <= C_S5 ;
end
C_S5:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 32'd0 ;
R_state <= C_S6 ;
end
else
R_cnt_ls <= R_cnt_ls + 1'b1 ;
end
C_S6:
begin
R_led_out_reg <= 4'b1000 ;
R_state <= C_S7 ;
end
C_S7:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 32'd0 ;
R_state <= C_S0 ;
end
else
R_cnt_ls <= R_cnt_ls + 1'b1 ;
end
default: R_state <= 3'b000 ;
endcase
end
end
assign O_led_out = ~R_led_out_reg ;
時序圖如下圖:

時序圖仍然正確,實現(xiàn)了流水燈的效果
七、 總結(jié)
1、所謂的“仿順序操作”實際上就是一個狀態(tài)機,通過狀態(tài)的跳變實現(xiàn)“順序執(zhí)行”的效果。這種思想在后面寫接口時序的時候還是挺管用的,今后可以多多琢磨琢磨。
2、 C語言的while(1)和Verilog語言的always @(posedge I_clk)有類似的地方,只要CPU的時鐘存在,它們就一直執(zhí)行下去。書上都說C語言是一種串行語言,Verilog是一種并行語言,實際上這里也能有體會:C語言里只能有1個while(1)語句,進入while(1)以后CPU就出不來了,而Verilog中可以有多個always @(posedge I_clk)語句,并且每個always @(posedge I_clk)同時運行的,這就是兩種語言最大的區(qū)別吧。
八、 附錄
1、分頻1s產(chǎn)生流水燈的完整代碼
module led_work_top
(
input I_clk ,
input I_rst_n ,
output [3:0] O_led_out
);
reg [31:0] R_cnt_ls ;
wire W_clk_ls ;
reg R_clk_ls_reg ;
reg [3:0] R_led_out_reg ;
//////////////////////////////////////////////////////////////////
// 功能:產(chǎn)生1s的時鐘
//////////////////////////////////////////////////////////////////
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
begin
R_cnt_ls <= 32'd0 ;
R_clk_ls_reg <= 1'b1 ;
end
else if(R_cnt_ls == 32'd24_999_999)
begin
R_cnt_ls <= 32'd0 ;
R_clk_ls_reg <= ~R_clk_ls_reg ;
end
else
R_cnt_ls <= R_cnt_ls + 1'b1 ;
end
assign W_clk_ls = R_clk_ls_reg ;
//////////////////////////////////////////////////////////////////
// 功能:對輸出寄存器進行移位產(chǎn)生流水效果
//////////////////////////////////////////////////////////////////
always @(posedge W_clk_ls or negedge I_rst_n)
begin
if(!I_rst_n)
R_led_out_reg <= 4'b0001 ;
else if(R_led_out_reg == 4'b1000)
R_led_out_reg <= 4'b0001 ;
else
R_led_out_reg <= R_led_out_reg << 1 ;
end
assign O_led_out = ~R_led_out_reg ;
endmodule
2、 “仿順序操作”產(chǎn)生流水燈完整代碼
module led_work_top
(
input I_clk ,
input I_rst_n ,
output [3:0] O_led_out
);
reg [31:0] R_cnt_ls ;
reg [3:0] R_led_out_reg ;
reg [2:0] R_state ;
parameter C_CNT_1S = 32'd49_999_999 ;
parameter C_S0 = 3'b000 ,
C_S1 = 3'b001 ,
C_S2 = 3'b010 ,
C_S3 = 3'b011 ,
C_S4 = 3'b100 ,
C_S5 = 3'b101 ,
C_S6 = 3'b110 ,
C_S7 = 3'b111 ;
//////////////////////////////////////////////////////////////////
// 功能:仿順序操作
//////////////////////////////////////////////////////////////////
always @(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
begin
R_state <= 3'b000 ;
R_cnt_ls <= 32'd0 ;
end
else
begin
case(R_state)
C_S0:
begin
R_led_out_reg <= 4'b0001 ;
R_state <= C_S1 ;
end
C_S1:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 32'd0 ;
R_state <= C_S2 ;
end
else
R_cnt_ls <= R_cnt_ls + 1'b1 ;
end
C_S2:
begin
R_led_out_reg <= 4'b0010 ;
R_state <= C_S3 ;
end
C_S3:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 32'd0 ;
R_state <= C_S4 ;
end
else
R_cnt_ls <= R_cnt_ls + 1'b1 ;
end
C_S4:
begin
R_led_out_reg <= 4'b0100 ;
R_state <= C_S5 ;
end
C_S5:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 32'd0 ;
R_state <= C_S6 ;
end
else
R_cnt_ls <= R_cnt_ls + 1'b1 ;
end
C_S6:
begin
R_led_out_reg <= 4'b1000 ;
R_state <= C_S7 ;
end
C_S7:
begin
if(R_cnt_ls == C_CNT_1S)
begin
R_cnt_ls <= 32'd0 ;
R_state <= C_S0 ;
end
else
R_cnt_ls <= R_cnt_ls + 1'b1 ;
end
default: R_state <= 3'b000 ;
endcase
end
end
assign O_led_out = ~R_led_out_reg ;
endmodule
3、測試記錄文件完整代碼
module tb_led_work_top;
// Inputs
reg I_clk;
reg I_rst_n;
// Outputs
wire [3:0] O_led_out;
// Instantiate the Unit Under Test (UUT)
led_work_top U_led_work_top (
.I_clk(I_clk),
.I_rst_n(I_rst_n),
.O_led_out(O_led_out)
);
initial begin
// Initialize Inputs
I_clk = 0;
I_rst_n = 0;
// Wait 100 ns for global reset to finish
#100;
I_rst_n = 1;
// Add stimulus here
end
always #5 I_clk = ~I_clk ;
endmodule
審核編輯:湯梓紅
-
FPGA
+關(guān)注
關(guān)注
1659文章
22365瀏覽量
632993 -
led
+關(guān)注
關(guān)注
243文章
24533瀏覽量
689368 -
Verilog
+關(guān)注
關(guān)注
30文章
1373瀏覽量
114325 -
C語言
+關(guān)注
關(guān)注
183文章
7642瀏覽量
145122 -
流水燈
+關(guān)注
關(guān)注
21文章
435瀏覽量
61449
原文標題:【接口時序】2、Verilog實現(xiàn)流水燈及與C語言的對比
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
基于Verilog FPGA 流水燈設(shè)計_流水燈源碼_明德?lián)P資料
如何使用c語言實現(xiàn)LED流水燈
C語言的基礎(chǔ)知識及流水燈的實現(xiàn)程序免費下載
使用51單片機實現(xiàn)流水燈C語言的程序?qū)嵗赓M下載
使用51單片機實現(xiàn)流水燈的C語言程序免費下載
LED流水燈的Verilog設(shè)計實例資料合集免費下載
使用verilog HDL實現(xiàn)狀態(tài)機8位流水燈的程序和工程文件免費下載
使用單片機實現(xiàn)24C02存儲花樣流水燈的C語言實例免費下載
基于AT89C51的單片機簡易流水燈設(shè)計(C語言)
單片機實驗:使用c語言實現(xiàn)LED流水燈
Verilog實現(xiàn)流水燈及與C語言的對比
評論