設(shè)計(jì)規(guī)劃
8個數(shù)碼管顯示從十進(jìn)制0開始計(jì)數(shù),每0.1s加1,一直加到十進(jìn)制數(shù)9999_9999,然后回到0重新計(jì)數(shù)。
理論基礎(chǔ)
上一節(jié)介紹了靜態(tài)顯示,每個數(shù)碼管顯示的數(shù)字是一樣的,但是實(shí)際生活中遠(yuǎn)遠(yuǎn)不能滿足需求。因此我們要學(xué)習(xí)顯示不同字符的數(shù)碼管驅(qū)動方式-動態(tài)驅(qū)動。靜態(tài)驅(qū)動的原理是位選信號為1111_1111,即8個數(shù)碼管同時選中,再用段選信號讓數(shù)碼管顯示理想數(shù)值,那么8個數(shù)碼管的字符就一樣。那么如果我們每次只選中一個數(shù)碼管,再利用段選信號讓它顯示理想數(shù)值,就可以顯示不同數(shù)值了。由于視覺暫留以及數(shù)碼管的余暉效應(yīng) 即使數(shù)碼管不是同時點(diǎn)亮,我們在視覺效果上看到的也是同時點(diǎn)亮。(視覺暫留:視覺影像不會立即消失,動畫就是利用這個原理,當(dāng)一秒內(nèi)幀數(shù)達(dá)到24就會感覺比較流暢。余暉效應(yīng):停止供電發(fā)光二極管亮度會維持一段時間。)實(shí)驗(yàn)證明,掃描間隔為1ms,即一秒點(diǎn)亮1000次,不會有閃爍感。那么我們只需要第1ms點(diǎn)亮第一個數(shù)碼管,第2ms點(diǎn)亮第二個數(shù)碼管…
BCD碼:2-10進(jìn)制碼,將1位十進(jìn)制數(shù)和4位二進(jìn)制數(shù)對應(yīng)的碼。8421碼比較常見,第0位權(quán)重為1,第1位權(quán)重為2,第三位權(quán)重為4,第4位權(quán)重為8,0對應(yīng)0000,1對應(yīng)0001,...,9對應(yīng)1001。那么例如一個二進(jìn)制數(shù)10010,對應(yīng)十進(jìn)制是18,對應(yīng)BCD碼是0001_1000。
編寫代碼
通過系統(tǒng)框圖可以看出,分為6個模塊:數(shù)據(jù)生成模塊,二進(jìn)制轉(zhuǎn)BCD模塊,數(shù)碼管動態(tài)顯示驅(qū)動模塊,74HC595模塊,數(shù)碼管動態(tài)顯示模塊,頂層模塊。
1、數(shù)據(jù)生成模塊data_gen
應(yīng)該具有輸入:時鐘和復(fù)位,輸出:數(shù)據(jù)data和使能seg_en。中間信號有100ms計(jì)數(shù)器cnt_100ms,標(biāo)志位cnt_flag。
module data_gen
#(
parameter CNT_MAX = 23'd4999_999, //100ms計(jì)數(shù)值
parameter DATA_MAX= 27'd9999_9999 //顯示的最大值
)
(
input wire sys_clk , //系統(tǒng)時鐘,頻率50MHz
input wire sys_rst_n , //復(fù)位信號,低電平有效
output reg [26:0] data , //數(shù)碼管要顯示的值
output reg seg_en //數(shù)碼管使能信號,高電平有效
);
//reg define
reg [22:0] cnt_100ms ; // 100ms計(jì)數(shù)器
reg cnt_flag ; //100ms標(biāo)志信號
//cnt_100ms:用50MHz時鐘從0到4999_999計(jì)數(shù)即為100ms
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_100ms <= 23'd0;
else if(cnt_100ms == CNT_MAX)
cnt_100ms <= 23'd0;
else
cnt_100ms <= cnt_100ms + 1'b1;
//cnt_flag:每100ms產(chǎn)生一個標(biāo)志信號
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_flag <= 1'b0;
else if(cnt_100ms == CNT_MAX - 1'b1)
cnt_flag <= 1'b1;
else
cnt_flag <= 1'b0;
//數(shù)碼管顯示的數(shù)據(jù):0-9999_9999
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 27'd0;
else if((data == DATA_MAX) && (cnt_flag == 1'b1))
data <= 27'd0;
else if(cnt_flag == 1'b1)
data <= data + 1'b1;
else
data <= data;
//數(shù)碼管使能信號給高即可
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg_en <= 1'b0;
else
seg_en <= 1'b1;
endmodule
參數(shù)定義:首先確定計(jì)數(shù)和顯示的最大值,計(jì)數(shù)100ms,用50MHz的時鐘需要從0記到4999_999,顯示的最大值是999_999,前者是23位,后者是27位。
cnt_100ms:復(fù)位有效和記滿時歸零,其他情況+1
cnt_flag:復(fù)位有效時歸0,計(jì)滿時拉高,其他情況都是保持低電平
data:復(fù)位有效時歸0,數(shù)據(jù)達(dá)到最大值且標(biāo)志位拉高時+1(數(shù)據(jù)要在999_999保持0.1ms,如果計(jì)滿就+1就只能維持一個時鐘周期,這就是flag的意義),其他情況保持
seg_en:復(fù)位有效時歸0,其他情況都是高電平有效。
2、BCD模塊bcd_8421
輸入是時鐘、復(fù)位和數(shù)據(jù)data,data是2進(jìn)制數(shù),要先轉(zhuǎn)換成10進(jìn)制,再將10進(jìn)制的每一位轉(zhuǎn)換成BCD碼,才能使每一個數(shù)碼管顯示對應(yīng)的字符。我們看二進(jìn)制碼如何變?yōu)锽CD碼。輸出是8個數(shù)碼管對應(yīng)8位,每位轉(zhuǎn)換BCD碼是4位。輸出是:個位,十位,百位,千位,萬位,十萬位,百萬位,千萬位。中間信號是移位判斷計(jì)數(shù)器cnt_shift,移位判斷數(shù)據(jù)寄存器data_shift,移位判斷標(biāo)志信號shift_flag。
以十進(jìn)制數(shù)234為例,二進(jìn)制是1110_1010,BCD碼應(yīng)該是0010_0011_1000,那么先進(jìn)行補(bǔ)0操作,輸入的二進(jìn)制碼不足12位,在高位補(bǔ)0。再將二進(jìn)制碼的最高位作為BCD的最低位進(jìn)行移位,并判斷每一個BCD碼其對應(yīng)的十進(jìn)制數(shù)是否大于4,如果大于4就對BCD碼做加3操作,若小于等于4就讓其值保持不變。然后繼續(xù)移位,每次移位后都要進(jìn)行判斷。
module bcd_8421(
input wire sys_clk , //系統(tǒng)時鐘,頻率50MHz
input wire sys_rst_n , //復(fù)位信號,低電平有效
input wire [26:0] data , //輸入需要轉(zhuǎn)換的數(shù)據(jù)
output reg [3:0] unit , //個位BCD碼
output reg [3:0] ten , //十位BCD碼
output reg [3:0] hun , //百位BCD碼
output reg [3:0] tho , //千位BCD碼
output reg [3:0] t_tho , //萬位BCD碼
output reg [3:0] h_hun , //十萬位BCD碼
output reg [3:0] t_hun , //百萬位BCD碼
output reg [3:0] h_tho //千萬位BCD碼
);
//reg define
reg [4:0] cnt_shift ; //移位判斷計(jì)數(shù)器
reg [58:0] data_shift ; //移位判斷數(shù)據(jù)寄存器
reg shift_flag ; //移位判斷標(biāo)志信號
//cnt_shift:從0到28循環(huán)計(jì)數(shù)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_shift <= 5'd0;
else if((cnt_shift == 5'd28) && (shift_flag == 1'b1))
cnt_shift <= 5'd0;
else if(shift_flag == 1'b1)
cnt_shift <= cnt_shift + 1'b1;
else
cnt_shift <= cnt_shift;
//data_shift:計(jì)數(shù)器為0時賦初值,計(jì)數(shù)器為1~27時進(jìn)行移位判斷操作
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_shift <= 59'b0;
else if(cnt_shift == 5'd0)
data_shift <= {32'b0,data};
else if((cnt_shift <= 27) && (shift_flag == 1'b0))
begin
data_shift[30:27] <= (data_shift[30:27] > 4) ?
(data_shift[30:27] + 2'd3) : (data_shift[30:27]);
data_shift[34:31] <= (data_shift[34:31] > 4) ?
(data_shift[34:31] + 2'd3) : (data_shift[34:31]);
data_shift[38:35] <= (data_shift[38:35] > 4) ?
(data_shift[38:35] + 2'd3) : (data_shift[38:35]);
data_shift[42:39] <= (data_shift[42:39] > 4) ?
(data_shift[42:39] + 2'd3) : (data_shift[42:39]);
data_shift[46:43] <= (data_shift[46:43] > 4) ?
(data_shift[46:43] + 2'd3) : (data_shift[46:43]);
data_shift[50:47] <= (data_shift[50:47] > 4) ?
(data_shift[50:47] + 2'd3) : (data_shift[50:47]);
data_shift[54:51] <= (data_shift[54:51] > 4) ?
(data_shift[54:51] + 2'd3) : (data_shift[54:51]);
data_shift[58:55] <= (data_shift[58:55] > 4) ?
(data_shift[58:55] + 2'd3) : (data_shift[58:55]);
end
else if((cnt_shift <= 27) && (shift_flag == 1'b1))
data_shift <= data_shift < < 1;
else
data_shift <= data_shift;
//shift_flag:移位判斷標(biāo)志信號,用于控制移位判斷的先后順序
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
shift_flag <= 1'b0;
else
shift_flag <= ~shift_flag;
//當(dāng)計(jì)數(shù)器等于28時,移位判斷操作完成,對各個位數(shù)的BCD碼進(jìn)行賦值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
unit <= 4'b0;
ten <= 4'b0;
hun <= 4'b0;
tho <= 4'b0;
t_tho <= 4'b0;
h_hun <= 4'b0;
t_hun <= 4'b0;
h_tho <= 4'b0;
end
else if(cnt_shift == 5'd28)
begin
unit <= data_shift[30:27];
ten <= data_shift[34:31];
hun <= data_shift[38:35];
tho <= data_shift[42:39];
t_tho <= data_shift[46:43];
h_hun <= data_shift[50:47];
t_hun <= data_shift[54:51];
h_tho <= data_shift[58:55];
end
endmodule
cnt_shift:移位判斷計(jì)數(shù)器,data有27位,一共要判斷27次,cnt_shift位數(shù)為5位,從0開始計(jì)數(shù)到28,其中1-27是移位判斷操作。復(fù)位有效時歸0,計(jì)滿且flag為高點(diǎn)平(移位結(jié)束)時歸0,flag為高點(diǎn)平(每次移位結(jié)束)都+1,其他情況保持不變
data_shift:移位判斷數(shù)據(jù)寄存器,移位數(shù)據(jù)放在高位,data數(shù)據(jù)放在低位,輸出數(shù)據(jù)一共要32位,data有27位,一共需要59位。計(jì)數(shù)器cnt_shift為0時賦初值,計(jì)數(shù)器為1-27時移位判斷。復(fù)位有效時歸0,計(jì)數(shù)器為0時賦初值,高32位為0,后27位是data初值。當(dāng)計(jì)數(shù)器不到27且flag為低電平(還沒開始判斷時),就要開始判斷移位了,具體是:判斷data_shift[30:27]是否大于4(0-26是data,27-30是移位數(shù)據(jù)的低4位),大于4則將[30:27]+3,不滿足就保持原值。...判斷data_shift[58:55]是否大于4,大于4則+3,不滿足保持原值,判斷結(jié)束后,data_shift左移一位,其他情況維持不變
shift_flag:隨著時鐘周期高低變化的移位判斷標(biāo)志信號,復(fù)位有效時歸0,其他情況取反,即一個時鐘周期內(nèi)為低電平表示判斷,下一個時鐘周期內(nèi)為高點(diǎn)平表示移位
輸出:復(fù)位有效時,個位-千萬位的輸出都為0。由于data有27位,要判斷移位27次,計(jì)數(shù)器計(jì)數(shù)到27時結(jié)束最后一次判斷移位,計(jì)數(shù)到28時進(jìn)行輸出的賦值。個位的4位BCD碼是移位數(shù)據(jù)的低四位data_shift[31:27],千萬位的4位BCD碼是移位數(shù)據(jù)的高4位data_shift[58:55]
3、數(shù)碼管動態(tài)顯示驅(qū)動模塊seg_dynamic
我們由上一節(jié)知道數(shù)碼管是由位選和段選信號進(jìn)行選擇和控制的,那么這個模塊里要將輸入的data轉(zhuǎn)換成對應(yīng)的段選位選信號。因此,輸入為時鐘、復(fù)位、data、seg_en,輸出為sel,seg。因?yàn)榈?ms第一個數(shù)碼管亮,第2ms第二個數(shù)碼管亮,這里需要用1ms時鐘去控制位選信號即哪個數(shù)碼管亮。每100ms數(shù)碼管顯示的十進(jìn)制數(shù)要+1,因此時鐘還要控制段選信號即選中的數(shù)碼管顯示什么值。中間信號有實(shí)例化后的輸出unit,...,h_tho,data_reg,cnt_1ms,flag_1ms,cnt_sel,sel_reg,data_disp。data_reg是數(shù)碼管帶顯示內(nèi)容寄存器,假設(shè)輸入要顯示的十進(jìn)制數(shù)是9999_9999,那么不考慮符號時8個數(shù)碼管顯示9999_9999。cnt_1ms時1ms計(jì)數(shù)器。flag_1ms是標(biāo)志信號,計(jì)滿時拉高,控制位選。cnt_sel是位選數(shù)碼管計(jì)數(shù)器,8個數(shù)碼管每1ms換一個亮,也就是每個數(shù)碼管8ms亮一次。cnt_sel從0-7計(jì)數(shù),相當(dāng)于給數(shù)碼管編碼。sel_reg是數(shù)碼管位選信號寄存器,選中點(diǎn)亮的數(shù)碼管后給他顯示的值。data_disp:當(dāng)前點(diǎn)亮數(shù)碼管顯示的值。
module seg_dynamic
(
input wire sys_clk , //系統(tǒng)時鐘,頻率50MHz
input wire sys_rst_n , //復(fù)位信號,低有效
input wire [26:0] data , //數(shù)碼管要顯示的值
input wire seg_en , //數(shù)碼管使能信號,高電平有效
output reg [7:0] sel , //數(shù)碼管位選信號
output reg [7:0] seg //數(shù)碼管段選信號
);
//parameter define
parameter CNT_MAX = 16'd49_999; //數(shù)碼管刷新時間計(jì)數(shù)最大值
//wire define
wire [3:0] unit ; //個位數(shù)
wire [3:0] ten ; //十位數(shù)
wire [3:0] hun ; //百位數(shù)
wire [3:0] tho ; //千位數(shù)
wire [3:0] t_tho ; //萬位數(shù)
wire [3:0] h_hun ; //十萬位數(shù)
wire [3:0] t_hun ;
wire [3:0] h_tho ;
//reg define
reg [31:0] data_reg ; //待顯示數(shù)據(jù)寄存器
reg [15:0] cnt_1ms ; //1ms計(jì)數(shù)器
reg flag_1ms ; //1ms標(biāo)志信號
reg [2:0] cnt_sel ; //數(shù)碼管位選計(jì)數(shù)器
reg [7:0] sel_reg ; //位選信號
reg [3:0] data_disp; //當(dāng)前數(shù)碼管顯示的數(shù)據(jù)
//data_reg:控制數(shù)碼管顯示數(shù)據(jù)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_reg <= 32'b0;
//不考慮小數(shù)點(diǎn),若顯示的數(shù)據(jù)是8位都非0,則8個數(shù)碼管全顯示
else if(h_tho)
data_reg <= {h_tho,t_hun,h_hun,t_tho,tho,hun,ten,unit};
//若顯示的數(shù)據(jù)7位非0,比如1234567不是顯示01234567,則7個數(shù)碼管亮
else if(t_hun)
data_reg <= {4'd10,t_hun,h_hun,t_tho,tho,hun,ten,unit};//4'd10我們定義為不顯示
//若顯示的數(shù)據(jù)6位非0,則6個數(shù)碼管亮
else if(h_hun)
data_reg <= {4'd10,4'd10,h_hun,t_tho,tho,hun,ten,unit};
//若顯示的數(shù)據(jù)5位非0,則5個數(shù)碼管亮
else if(t_tho)
data_reg <= {4'd10,4'd10,4'd10,t_tho,tho,hun,ten,unit};
//若顯示的數(shù)據(jù)4位非0,則4個數(shù)碼管亮
else if(tho)
data_reg <= {4'd10,4'd10,4'd10,4'd10,tho,hun,ten,unit};
//若顯示的數(shù)據(jù)3位非0,則3個數(shù)碼管亮
else if(hun)
data_reg <= {4'd10,4'd10,4'd10,4'd10,4'd10,hun,ten,unit};
//若顯示的數(shù)據(jù)2位非0,則2個數(shù)碼管亮
else if(ten)
data_reg <= {4'd10,4'd10,4'd10,4'd10,4'd10,4'd10,ten,unit};
//若上面都不滿足都只顯示一位數(shù)碼管
else
data_reg <= {4'd10,4'd10,4'd10,4'd10,4'd10,4'd10,4'd10,unit};
//cnt_1ms:1ms循環(huán)計(jì)數(shù)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_1ms <= 16'd0;
else if(cnt_1ms == CNT_MAX)
cnt_1ms <= 16'd0;
else
cnt_1ms <= cnt_1ms + 1'b1;
//flag_1ms:1ms標(biāo)志信號
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag_1ms <= 1'b0;
else if(cnt_1ms == CNT_MAX - 1'b1)
flag_1ms <= 1'b1;
else
flag_1ms <= 1'b0;
//cnt_sel:從0到7循環(huán)數(shù),用于選擇當(dāng)前顯示的數(shù)碼管
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_sel <= 3'd0;
else if((cnt_sel == 3'd7) && (flag_1ms == 1'b1))
cnt_sel <= 3'd0;
else if(flag_1ms == 1'b1)
cnt_sel <= cnt_sel + 1'b1;
else
cnt_sel <= cnt_sel;
//數(shù)碼管位選信號寄存器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sel_reg <= 8'b0000_0000;
else if((cnt_sel == 3'd0) && (flag_1ms == 1'b1))
sel_reg <= 8'b0000_0001;
else if(flag_1ms == 1'b1)
sel_reg <= sel_reg < < 1;
else
sel_reg <= sel_reg;
//控制數(shù)碼管的位選信號,使8個數(shù)碼管輪流顯示
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_disp <= 4'b0;
else if((seg_en == 1'b1) && (flag_1ms == 1'b1))
case(cnt_sel)
3'd0: data_disp <= data_reg[3:0] ; //給第1個數(shù)碼管賦個位值
3'd1: data_disp <= data_reg[7:4] ; //給第2個數(shù)碼管賦十位值
3'd2: data_disp <= data_reg[11:8] ; //給第3個數(shù)碼管賦百位值
3'd3: data_disp <= data_reg[15:12]; //給第4個數(shù)碼管賦千位值
3'd4: data_disp <= data_reg[19:16]; //給第5個數(shù)碼管賦萬位值
3'd5: data_disp <= data_reg[23:20]; //給第6個數(shù)碼管賦十萬位值
3'd6: data_disp <= data_reg[27:24]; //給第7個數(shù)碼管賦百萬位值
3'd7: data_disp <= data_reg[31:28]; //給第8個數(shù)碼管賦千萬位值
default:data_disp <= 4'b0;
endcase
else
data_disp <= data_disp;
//控制數(shù)碼管段選信號,顯示數(shù)字
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg <= 8'b1111_1111;
else
case(data_disp)
4'd0 : seg <= {1'b1,7'b100_0000}; //顯示數(shù)字0
4'd1 : seg <= {1'b1,7'b111_1001}; //顯示數(shù)字1
4'd2 : seg <= {1'b1,7'b010_0100}; //顯示數(shù)字2
4'd3 : seg <= {1'b1,7'b011_0000}; //顯示數(shù)字3
4'd4 : seg <= {1'b1,7'b001_1001}; //顯示數(shù)字4
4'd5 : seg <= {1'b1,7'b001_0010}; //顯示數(shù)字5
4'd6 : seg <= {1'b1,7'b000_0010}; //顯示數(shù)字6
4'd7 : seg <= {1'b1,7'b111_1000}; //顯示數(shù)字7
4'd8 : seg <= {1'b1,7'b000_0000}; //顯示數(shù)字8
4'd9 : seg <= {1'b1,7'b001_0000}; //顯示數(shù)字9
4'd10 : seg <= 8'b1111_1111 ; //不顯示任何字符
default:seg <= 8'b1100_0000;
endcase
//sel:數(shù)碼管位選信號賦值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sel <= 8'b0000_0000;
else
sel <= sel_reg;
bcd_8421 bcd_8421_inst
(
.sys_clk (sys_clk ), //系統(tǒng)時鐘,頻率50MHz
.sys_rst_n (sys_rst_n), //復(fù)位信號,低電平有效
.data (data ), //輸入需要轉(zhuǎn)換的數(shù)據(jù)
.unit (unit ), //個位BCD碼
.ten (ten ), //十位BCD碼
.hun (hun ), //百位BCD碼
.tho (tho ), //千位BCD碼
.t_tho (t_tho ), //萬位BCD碼
.h_hun (h_hun ), //十萬位BCD碼
.t_hun (t_hun ), //百萬位BCD碼
.h_tho (h_tho ) //千萬位BCD碼
);
endmodule
參數(shù)定義:1ms計(jì)數(shù)2500000個,最大計(jì)數(shù)值49_999。
data_reg:控制數(shù)碼管要顯示的數(shù)據(jù),復(fù)位有效時歸0,因?yàn)闆]有小數(shù)點(diǎn),我們考慮到有幾位就只讓幾個數(shù)碼管進(jìn)行顯示。不顯示的數(shù)碼管定義為4'd11
cnt_1ms:復(fù)位有效或計(jì)滿時歸0,其他情況+1
flag_1ms:1ms標(biāo)志位,復(fù)位有效時歸0,計(jì)滿數(shù)值-1時拉高,其他情況保持低電平
cnt_sel:數(shù)碼管編號,從0-7計(jì)數(shù),復(fù)位有效時歸0,計(jì)滿7個數(shù)且標(biāo)志位拉高時歸0,標(biāo)志位拉高時+1,其他情況保持不變
控制數(shù)碼管位選信號:復(fù)位有效時data_disp歸0,使能為高電平有效且標(biāo)志信號為高時,分情況討論,cnt_sel為0,第一個數(shù)碼管賦data_reg的低四位,第一個數(shù)碼管顯示個位,...,需要有default語句,data_disp賦0即可,其他情況,data_disp保持不變
控制數(shù)碼管段選信號:復(fù)位有效時seg所有位賦1表示每一段都不點(diǎn)亮,其他分情況討論,data_disp為0時數(shù)碼管顯示0,0對應(yīng)的段選碼上一節(jié)討論了,最高位是小數(shù)點(diǎn)不用都為1表示滅,低7位對應(yīng)abcdefg=100_0000,以此類推,加上default語句
sel:數(shù)碼管位選信號賦值,復(fù)位有效時歸0,其他情況將sel_reg賦值給
實(shí)例化BCD
4、74HC595控制模塊
直接用上一節(jié)的代碼,需要注意的是hc595_ctrl.v中第23行對data的賦值,把最右邊的數(shù)碼管作為個位比較符合我們的書寫習(xí)慣,所以位選信號的順序要改,原語句是assign data={sel,seg[0],seg[1],...,seg[7]};要改做assign data={sel[0],sel[1],...,sel[7],seg[0],seg[1],...,seg[7]};否則,數(shù)碼管最左邊是個位,不符合書寫習(xí)慣。
5、數(shù)碼管動態(tài)顯示模塊
該模塊主要是對數(shù)碼管動態(tài)顯示驅(qū)動模塊和74HC595控制模塊的實(shí)例化,以及對應(yīng)信號的連接
module seg_595_dynamic
(
input wire sys_clk , //系統(tǒng)時鐘,頻率50MHz
input wire sys_rst_n , //復(fù)位信號,低有效
input wire [26:0] data , //數(shù)碼管要顯示的值
input wire seg_en , //數(shù)碼管使能信號,高電平有效
output wire stcp , //輸出數(shù)據(jù)存儲寄時鐘
output wire shcp , //移位寄存器的時鐘輸入
output wire ds //串行數(shù)據(jù)輸入
);
//wire define
wire [7:0] sel; //數(shù)碼管位選信號
wire [7:0] seg; //數(shù)碼管段選信號
seg_dynamic seg_dynamic_inst
(
.sys_clk (sys_clk ), //系統(tǒng)時鐘,頻率50MHz
.sys_rst_n (sys_rst_n), //復(fù)位信號,低有效
.data (data ), //數(shù)碼管要顯示的值
.seg_en (seg_en ), //數(shù)碼管使能信號,高電平有效
.sel (sel ), //數(shù)碼管位選信號
.seg (seg ) //數(shù)碼管段選信號
);
hc595_ctrl hc595_ctrl_inst
(
.sys_clk (sys_clk ), //系統(tǒng)時鐘,頻率50MHz
.sys_rst_n (sys_rst_n), //復(fù)位信號,低有效
.sel (sel ), //數(shù)碼管位選信號
.seg (seg ), //數(shù)碼管段選信號
.en (1'b1),
.stcp (stcp ), //輸出數(shù)據(jù)存儲寄時鐘
.shcp (shcp ), //移位寄存器的時鐘輸入
.ds (ds ) //串行數(shù)據(jù)輸入
);
endmodule
兩個模塊的實(shí)例化
6、頂層模塊top_seg_595
頂層模塊主要是對各個子功能模塊的實(shí)例化,以及對應(yīng)信號的連接
module top_seg_595
(
input wire sys_clk , //系統(tǒng)時鐘,頻率50MHz
input wire sys_rst_n , //復(fù)位信號,低電平有效
output wire stcp , //輸出數(shù)據(jù)存儲寄時鐘
output wire shcp , //移位寄存器的時鐘輸入
output wire ds //串行數(shù)據(jù)輸入
);
//wire define
wire [26:0] data ; //數(shù)碼管要顯示的值
wire seg_en ;//數(shù)碼管使能信號,高電平有效
data_gen data_gen_inst
(
.sys_clk (sys_clk ), //系統(tǒng)時鐘,頻率50MHz
.sys_rst_n (sys_rst_n), //復(fù)位信號,低電平有效
.data (data ), //數(shù)碼管要顯示的值
.seg_en (seg_en) //數(shù)碼管使能信號,高電平有效
);
seg_595_dynamic seg_595_dynamic_inst
(
.sys_clk (sys_clk ), //系統(tǒng)時鐘,頻率50MHz
.sys_rst_n (sys_rst_n ), //復(fù)位信號,低有效
.data (data ), //數(shù)碼管要顯示的值
.seg_en (seg_en ), //數(shù)碼管使能信號,高電平有效
.stcp (stcp ), //輸出數(shù)據(jù)存儲寄時鐘
.shcp (shcp ), //移位寄存器的時鐘輸入
.ds (ds ) //串行數(shù)據(jù)輸入
);
endmodule
數(shù)據(jù)產(chǎn)生和動態(tài)顯示模塊的實(shí)例化
編寫testbench
`timescale 1ns/1ns
module tb_top_seg_595();
//wire define
wire stcp ; //輸出數(shù)據(jù)存儲寄時鐘
wire shcp ; //移位寄存器的時鐘輸入
wire ds ; //串行數(shù)據(jù)輸入
//reg define
reg sys_clk ;
reg sys_rst_n ;
//對sys_clk,sys_rst_n賦初始值
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#100
sys_rst_n <= 1'b1;
end
//clk:產(chǎn)生時鐘
always #10 sys_clk <= ~sys_clk;
//重新定義參數(shù)值,縮短仿真時間
defparam top_seg_595_inst.seg_595_dynamic_inst.seg_dynamic_inst.
CNT_MAX=19;
defparam top_seg_595_inst.data_gen_inst.CNT_MAX = 49;
top_seg_595 top_seg_595_inst
(
.sys_clk (sys_clk ), //系統(tǒng)時鐘,頻率50MHz
.sys_rst_n (sys_rst_n ), //復(fù)位信號,低電平有效
.stcp (stcp ), //輸出數(shù)據(jù)存儲寄時鐘
.shcp (shcp ), //移位寄存器的時鐘輸入
.ds (ds )//串行數(shù)據(jù)輸入
);
endmodule
testbench已經(jīng)很熟悉了。
對比波形
先看6個模塊的從屬關(guān)系,再分別檢查6個模塊的波形,比較容易debug。
數(shù)據(jù)產(chǎn)生模塊
后面幾個模塊不細(xì)列。
分配管腳
和上一節(jié)一樣
-
FPGA
+關(guān)注
關(guān)注
1630文章
21799瀏覽量
606194 -
發(fā)光二極管
+關(guān)注
關(guān)注
13文章
1205瀏覽量
66517 -
數(shù)碼管
+關(guān)注
關(guān)注
32文章
1887瀏覽量
91431 -
顯示模塊
+關(guān)注
關(guān)注
1文章
50瀏覽量
23604 -
動態(tài)顯示
+關(guān)注
關(guān)注
0文章
40瀏覽量
11728
發(fā)布評論請先 登錄
相關(guān)推薦
![](https://file1.elecfans.com/web2/M00/84/ED/wKgaomRmGQKAa0JPAAA1YJm4OhQ600.png)
#硬聲創(chuàng)作季 數(shù)字設(shè)計(jì)FPGA應(yīng)用:數(shù)碼管動態(tài)顯示1
![](https://file1.elecfans.com/web2/M00/84/ED/wKgaomRmGQKAa0JPAAA1YJm4OhQ600.png)
#硬聲創(chuàng)作季 數(shù)字設(shè)計(jì)FPGA應(yīng)用:數(shù)碼管動態(tài)顯示2
![](https://file1.elecfans.com/web2/M00/84/ED/wKgaomRmGQKAa0JPAAA1YJm4OhQ600.png)
#硬聲創(chuàng)作季 數(shù)字設(shè)計(jì)FPGA應(yīng)用:數(shù)碼管動態(tài)顯示3
這個fpga數(shù)碼管動態(tài)顯示程序錯誤嗎?動態(tài)掃描不出來
FPGA入門實(shí)現(xiàn)教程之數(shù)碼管動態(tài)顯示
數(shù)碼管動態(tài)顯示實(shí)驗(yàn)
基于FPGA的8段數(shù)碼管動態(tài)顯示IP核設(shè)計(jì)
![基于<b class='flag-5'>FPGA</b>的8段<b class='flag-5'>數(shù)碼管</b><b class='flag-5'>動態(tài)顯示</b>IP核設(shè)計(jì)](https://file1.elecfans.com//web2/M00/A5/75/wKgZomUMOIeAPsg5AABhwhMwh1M665.jpg)
數(shù)碼管(動態(tài)顯示)【C語言版】
采用FPGA DIY開發(fā)板實(shí)現(xiàn)數(shù)碼管動態(tài)顯示60計(jì)數(shù)
數(shù)字設(shè)計(jì)FPGA應(yīng)用:數(shù)碼管動態(tài)顯示實(shí)驗(yàn)
![數(shù)字設(shè)計(jì)<b class='flag-5'>FPGA</b>應(yīng)用:<b class='flag-5'>數(shù)碼管</b><b class='flag-5'>動態(tài)顯示</b>實(shí)驗(yàn)](https://file.elecfans.com/web1/M00/93/C0/o4YBAFztH4-ACc4pAAAqr7J4XBg140.jpg)
正點(diǎn)原子開拓者FPGA:數(shù)碼管動態(tài)顯示實(shí)驗(yàn)
![正點(diǎn)原子開拓者<b class='flag-5'>FPGA</b>:<b class='flag-5'>數(shù)碼管</b><b class='flag-5'>動態(tài)顯示</b>實(shí)驗(yàn)](https://file.elecfans.com/web1/M00/94/1E/pIYBAFztIHKABq39AAAj6J3PxJI843.jpg)
評論