在上次的文章 - 淺談“數(shù)字電路”的學習(8)- 編碼器、譯碼器、多路復用器、解復用器的關系和應用 - 中,我梳理了一下數(shù)字電路教程中組合邏輯部分的一些典型邏輯應用和他們之間的關系,并通過一個簡單的2:4譯碼器、3:8譯碼器來學習了一下用Verilog代碼如何實現(xiàn)這些邏輯。
作為組合邏輯部分的總結篇,我們用小腳丫FPGA核心板來實現(xiàn)一個4位加法器的功能,正巧小腳丫板上有:
4個開關 - 可以做加法器的4位二進制的加數(shù),可以實現(xiàn)十進制0、1、2.。.15的輸入;
4個按鍵 - 可以做加法器的4位二進制的加數(shù),在組合邏輯部分還沒有涉及到按鍵的消抖功能,且同時按多個鍵相對于開關困難一些,因此我們至少可以用這4個按鍵的任意一個實現(xiàn)十進制的0、1、2、4、8的輸入;
2個數(shù)碼管 - 即便4個按鍵同時按下,最大輸入的值也就15,因此此加法器能夠產(chǎn)生的最大輸出值為30,用一個數(shù)碼管顯示個位數(shù),會顯示0-9;另一個數(shù)碼管顯示十位數(shù),會顯示0-3;
8個分立的LED - 可以選擇其中的4個作為4位二進制加法器的進位顯示,發(fā)生進位的時候相應的LED就會亮。
板上的硬件條件齊全,就要用Verilog代碼來實現(xiàn)邏輯了。
相對于前期我們講述的例子,這個項目復雜的地方在于它包含了以下幾個部分的知識點:
加法器 - 如何使用1位的全加器、1位的半加器構成一個4位的二進制加法器;
二進制轉BCD碼的解碼 - 我們用4位二進制加法器實現(xiàn)的結果,在我們?nèi)祟惖恼J知里其實是十進制的,要用數(shù)碼管以十進制的方式在兩個數(shù)碼管上將結果顯示出來,這就需要我們先將二進制的加法結果(加上進位共5位二進制數(shù)據(jù))轉換為兩個十進制的數(shù)值來表示;
7段(加上小數(shù)點8段)數(shù)碼管的顯示驅動 - 點亮數(shù)碼管上的7根LED,通過這7根LED的組合生成我們認知的數(shù)字0、1、2、3、4、5、6、7、8、9,將要顯示的數(shù)字映射到這7段LED上就需要一個編碼的過程,有的文章也說是解碼(decoder),總之是碼制的轉換過程
所以,這算是一個綜合性的項目,用FPGA通過Verilog編程來實現(xiàn)也能體會到由一個項目由多個Module構成的方式,并能夠理解我們常說的“并行”處理的含義
代碼的架構如下面的框圖所示:
頂層功能模塊add_4bits調(diào)用其它的幾個并行執(zhí)行的module,并定義了與外界打交道的輸入輸出管腳。代碼如下:
module adder_4bits(sw,key,seg_led_1,seg_led_2,led_carry);input [3:0] sw;input [3:0] key;output [8:0] seg_led_1;output [8:0] seg_led_2;output [3:0] led_carry;
wire [3:0] input1;wire [3:0] input2;wire [3:0] answer;
wire carry_out;wire [3:0] carry; assign input1 = sw;assign input2 = ~key; genvar i;generate for(i=0;i《4;i=i+1) begin: generate_N_bit_Adder if(i==0) half_adder f(input1[0],input2[0],answer[0],carry[0]);
else full_adder f(input1[i],input2[i],carry[i-1],answer[i],carry[i]); end assign carry_out = carry[3];
endgenerate assign led_carry = ~carry; wire [4:0] sum;assign sum = {carry_out,answer};
wire [3:0] seg1_input;
wire [3:0] seg2_input; binary2bcd b2b(sum,seg1_input,seg2_input); LED display_answer(seg1_input,seg2_input,seg_led_1,seg_led_2); endmodule module half_adder(x,y,s,c);input x,y;output s,c;
assign s=x^y;assign c=x&y;endmodule // half adder module full_adder(x,y,c_in,s,c_out);input x,y,c_in;output s,c_out;
assign s = (x^y) ^ c_in;assign c_out = (y&c_in)| (x&y) | (x&c_in);endmodule // full_adder
要注意的是,在小腳丫FPGA板上,出于讓同學們遇到問題才能學習的考慮,我們特別將開關和按鍵的缺省狀態(tài)設置成了兩種不同的方式,4個開關缺省狀態(tài)為低電平,開關閉合時該管腳電平拉高;4個按鍵缺省狀態(tài)為高電平,按下時該管腳電平為低;故在代碼中做了取反~的處理(體會開關的狀態(tài)以及Verilog對反相信號的處理方式,在使用中體會開關和按鍵的不同)。
二進制轉BCD碼在網(wǎng)上有很多文章介紹,常用的方法為移位3的方式,只需要短短幾行代碼就可以實現(xiàn),關于其原理大家可以自行搜索一下,我也在下面的代碼的注釋部分附上了這部分代碼供同學們參考。考慮到兩個4位加法輸出的結果只有5位二進制、對應的最多31種結果,我們要做的就是將這5位二進制映射到2個10進制的數(shù)字上,有點類似5-32的譯碼操作,在這里我們使用查找表的方式來構建,主要也是讓同學們體會查找表的靈活性、構建方法和Verilog的語法。要知道的是FPGA內(nèi)部的邏輯都是基于查找表的方式來實現(xiàn)的。
module binary2bcd(binary_data,tens,ones);input [4:0] binary_data;output reg [3:0] tens;output reg [3:0] ones; always @*case(binary_data) 5‘d0: begin tens = 4’d0; ones = 4‘d0; end 5’d1:
begin tens = 4‘d0; ones = 4’d1; end 5‘d2: begin tens = 4’d0; ones = 4‘d2; end 5’d3:
begin tens = 4‘d0; ones = 4’d3; end 5‘d4: begin tens = 4’d0; ones = 4‘d4; end 5’d5: begin tens = 4‘d0;
ones = 4’d5; end 5‘d6: begin tens = 4’d0; ones = 4‘d6; end 5’d7: begin tens = 4‘d0; ones = 4’d7; end 5‘d8: begin tens = 4’d0; ones = 4‘d8; end 5’d9: begin tens = 4‘d0; ones = 4’d9; end 5‘d10: begin tens = 4’d1; ones = 4‘d0; end 5’d11: begin tens = 4‘d1; ones = 4’d1;
end 5‘d12: begin tens = 4’d1; ones = 4‘d2; end 5’d13: begin tens = 4‘d1; ones = 4’d3;
end 5‘d14: begin tens = 4’d1; ones = 4‘d4; end 5’d15: begin tens = 4‘d1; ones = 4’d5; end 5‘d16: begin tens = 4’d1; ones = 4‘d6; end 5’d17: begin tens = 4‘d1; ones = 4’d7; end 5‘d18: begin tens = 4’d1; ones = 4‘d8; end 5’d19: begin tens = 4‘d1; ones = 4’d9; end 5‘d20: begin tens = 4’d2; ones = 4‘d0; end 5’d21: begin tens = 4‘d2; ones = 4’d1; end 5
‘d22: begin tens = 4’d2; ones = 4‘d2; end 5’d23: begin tens = 4‘d2; ones = 4’d3; end 5
‘d24: begin tens = 4’d2; ones = 4‘d4; end 5’d25: begin tens = 4‘d2; ones = 4’d5; end 5
‘d26: begin tens = 4’d2; ones = 4‘d6; end 5’d27: begin tens = 4‘d2; ones = 4’d7; end 5
‘d28: begin tens = 4’d2; ones = 4‘d8; end 5’d29: begin tens = 4‘d2; ones = 4’d9; end 5
‘d30: begin tens = 4’d3; ones = 4‘d0; end 5’d31: begin tens = 4‘d3; ones = 4’d1; endendcase /*integer i; always @(binary_data)begin tens = 4‘d0; ones = 4’d0; for (i=7; i 》= 0; i=i-1) begin if (tens》=5) tens = tens +3; if (ones 》= 5) ones = ones +3; tens = tens 《《 1; tens[0] = ones[3]; ones = ones 《《 1; ones[0] = binary_data[i]; endend*/ endmodule
至于2個7段數(shù)碼管的顯示驅動,由于小腳丫FPGA核心板上管腳比較富裕,采用了直接映射的方式,在很多管腳受限的應用場景需要用到動態(tài)掃描的方式或通過專用的芯片來擴展,在后面時序邏輯部分的示例中會再講。
2個7段數(shù)碼管的顯示驅動代碼如下:
// ********************************************************************// 》》》》》》》》》》》》》》》》》》》》》》》》》 COPYRIGHT NOTICE 《《《《《《《《《《《《《《《《《《《《《《《《《//
********************************************************************// File name : segment.v// Module name : segment// Author : STEP// Description : segment initial// Web : www.stepfpga.com// // --------------------------------------------------------------------// Code Revision History : // --------------------------------------------------------------------// Version: |Mod. Date: |Changes Made:// V1.0 |2021/10/08 |Initial ver// --------------------------------------------------------------------// Module Function:數(shù)碼管的譯碼模塊初始化
module LED (seg_data_1,seg_data_2,seg_led_1,seg_led_2); input [3:0] seg_data_1; //數(shù)碼管需要顯示0~9十個數(shù)字,所以最少需要4位輸入做譯碼
input [3:0] seg_data_2; //小腳丫上第二個數(shù)碼管 output [8:0] seg_led_1; //在小腳丫上控制一個數(shù)碼管需要9個信號 MSB~LSB=DIG、DP、G、F、E、D、C、B、A output [8:0] seg_led_2; //在小腳丫上第二個數(shù)碼管的控制信號 MSB~LSB=DIG、DP、G、F、E、D、C、B、A reg [8:0] seg [9:0]; //定義了一個reg型的數(shù)組變量,相當于一個10*9的存儲器,存儲器一共有10個數(shù),每個數(shù)有9位寬
initial //在過程塊中只能給reg型變量賦值,Verilog中有兩種過程塊always和initial //initial和always不同,其中語句只執(zhí)行一次 begin seg[0] = 9‘h3f; //對存儲器中第一個數(shù)賦值9’b00_0011_1111,相當于共陰極接地,DP點變低不亮,7段顯示數(shù)字 0 seg[1] = 9‘h06; //7段顯示數(shù)字 1 seg[2] = 9’h5b; //7段顯示數(shù)字 2 seg[3] = 9‘h4f;
//7段顯示數(shù)字 3 seg[4] = 9’h66; //7段顯示數(shù)字 4 seg[5] = 9‘h6d; //7段顯示數(shù)字 5 seg[6] = 9’h7d; //7段顯示數(shù)字 6 seg[7] = 9‘h07; //7段顯示數(shù)字
7 seg[8] = 9’h7f; //7段顯示數(shù)字 8 seg[9] = 9‘h6f; //7段顯示數(shù)字 9 end assign seg_led_1 = seg[seg_data_1]; //連續(xù)賦值,這樣輸入不同四位數(shù),就能輸出對于譯碼的9位輸出assign seg_led_2 = seg[seg_data_2]; endmodule
大家看到了這段代碼有詳細的注釋,是不是感覺可讀性增加了很多?這是我們Web IDE中的案例代碼,可以直接復制到你自己的項目中來使用,作為一種示例,也是希望大家能夠體會到注釋的重要性,以后在自己的項目中加強這方面的規(guī)范性。
** 由于微信的編輯器對Verilog代碼的格式識別和支持不夠,顯示的效果與我們Web IDE上不同。
代碼編寫完畢,在Web IDE中點擊“邏輯綜合”,系統(tǒng)會根據(jù)你的頂層文件自動提取端口的管腳,讓你非常便捷給相應的信號綁定器件的管腳,如下圖示。
綁定完管腳,點擊保存 - -》 FPGA映射,生成可以下載的jed文件,鼠標指向下載JED文件的圖標,右鍵保存到StepFPGA16的盤里,就完成了對FPGA的編程,你手里的小腳丫FPGA就成了一個4位的加法器。
搞定!
如果你也能夠獨立完成這個項目,那你:
對數(shù)字電路部分的組合邏輯有了非常深刻的認識;
對FPGA的使用,尤其是管腳的配置、外設的狀態(tài)、顯示器件的使用有了深刻的認識;
對Verilog的語法使用有了更多、更深入的體會,包括多module的設計思路、module之間的接口、并行執(zhí)行等。
來試一試吧。
責任編輯:haq
-
電路
+關注
關注
172文章
5936瀏覽量
172484 -
Verilog
+關注
關注
28文章
1351瀏覽量
110158 -
加法器
+關注
關注
6文章
183瀏覽量
30160
原文標題:淺談“數(shù)字電路”的學習(9) - 小腳丫上實現(xiàn)4位加法器并數(shù)碼管顯示結果
文章出處:【微信號:xiaojiaoyafpga,微信公眾號:電子森林】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論