設計規劃
8個數碼管顯示從十進制0開始計數,每0.1s加1,一直加到十進制數9999_9999,然后回到0重新計數。
理論基礎
上一節介紹了靜態顯示,每個數碼管顯示的數字是一樣的,但是實際生活中遠遠不能滿足需求。因此我們要學習顯示不同字符的數碼管驅動方式-動態驅動。靜態驅動的原理是位選信號為1111_1111,即8個數碼管同時選中,再用段選信號讓數碼管顯示理想數值,那么8個數碼管的字符就一樣。那么如果我們每次只選中一個數碼管,再利用段選信號讓它顯示理想數值,就可以顯示不同數值了。由于視覺暫留以及數碼管的余暉效應 即使數碼管不是同時點亮,我們在視覺效果上看到的也是同時點亮。(視覺暫留:視覺影像不會立即消失,動畫就是利用這個原理,當一秒內幀數達到24就會感覺比較流暢。余暉效應:停止供電發光二極管亮度會維持一段時間。)實驗證明,掃描間隔為1ms,即一秒點亮1000次,不會有閃爍感。那么我們只需要第1ms點亮第一個數碼管,第2ms點亮第二個數碼管…
BCD碼:2-10進制碼,將1位十進制數和4位二進制數對應的碼。8421碼比較常見,第0位權重為1,第1位權重為2,第三位權重為4,第4位權重為8,0對應0000,1對應0001,...,9對應1001。那么例如一個二進制數10010,對應十進制是18,對應BCD碼是0001_1000。
編寫代碼
通過系統框圖可以看出,分為6個模塊:數據生成模塊,二進制轉BCD模塊,數碼管動態顯示驅動模塊,74HC595模塊,數碼管動態顯示模塊,頂層模塊。
1、數據生成模塊data_gen
應該具有輸入:時鐘和復位,輸出:數據data和使能seg_en。中間信號有100ms計數器cnt_100ms,標志位cnt_flag。
module data_gen
#(
parameter CNT_MAX = 23'd4999_999, //100ms計數值
parameter DATA_MAX= 27'd9999_9999 //顯示的最大值
)
(
input wire sys_clk , //系統時鐘,頻率50MHz
input wire sys_rst_n , //復位信號,低電平有效
output reg [26:0] data , //數碼管要顯示的值
output reg seg_en //數碼管使能信號,高電平有效
);
//reg define
reg [22:0] cnt_100ms ; // 100ms計數器
reg cnt_flag ; //100ms標志信號
//cnt_100ms:用50MHz時鐘從0到4999_999計數即為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產生一個標志信號
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;
//數碼管顯示的數據: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;
//數碼管使能信號給高即可
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
參數定義:首先確定計數和顯示的最大值,計數100ms,用50MHz的時鐘需要從0記到4999_999,顯示的最大值是999_999,前者是23位,后者是27位。
cnt_100ms:復位有效和記滿時歸零,其他情況+1
cnt_flag:復位有效時歸0,計滿時拉高,其他情況都是保持低電平
data:復位有效時歸0,數據達到最大值且標志位拉高時+1(數據要在999_999保持0.1ms,如果計滿就+1就只能維持一個時鐘周期,這就是flag的意義),其他情況保持
seg_en:復位有效時歸0,其他情況都是高電平有效。
2、BCD模塊bcd_8421
輸入是時鐘、復位和數據data,data是2進制數,要先轉換成10進制,再將10進制的每一位轉換成BCD碼,才能使每一個數碼管顯示對應的字符。我們看二進制碼如何變為BCD碼。輸出是8個數碼管對應8位,每位轉換BCD碼是4位。輸出是:個位,十位,百位,千位,萬位,十萬位,百萬位,千萬位。中間信號是移位判斷計數器cnt_shift,移位判斷數據寄存器data_shift,移位判斷標志信號shift_flag。
以十進制數234為例,二進制是1110_1010,BCD碼應該是0010_0011_1000,那么先進行補0操作,輸入的二進制碼不足12位,在高位補0。再將二進制碼的最高位作為BCD的最低位進行移位,并判斷每一個BCD碼其對應的十進制數是否大于4,如果大于4就對BCD碼做加3操作,若小于等于4就讓其值保持不變。然后繼續移位,每次移位后都要進行判斷。
module bcd_8421(
input wire sys_clk , //系統時鐘,頻率50MHz
input wire sys_rst_n , //復位信號,低電平有效
input wire [26:0] data , //輸入需要轉換的數據
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 ; //移位判斷計數器
reg [58:0] data_shift ; //移位判斷數據寄存器
reg shift_flag ; //移位判斷標志信號
//cnt_shift:從0到28循環計數
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:計數器為0時賦初值,計數器為1~27時進行移位判斷操作
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:移位判斷標志信號,用于控制移位判斷的先后順序
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
shift_flag <= 1'b0;
else
shift_flag <= ~shift_flag;
//當計數器等于28時,移位判斷操作完成,對各個位數的BCD碼進行賦值
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:移位判斷計數器,data有27位,一共要判斷27次,cnt_shift位數為5位,從0開始計數到28,其中1-27是移位判斷操作。復位有效時歸0,計滿且flag為高點平(移位結束)時歸0,flag為高點平(每次移位結束)都+1,其他情況保持不變
data_shift:移位判斷數據寄存器,移位數據放在高位,data數據放在低位,輸出數據一共要32位,data有27位,一共需要59位。計數器cnt_shift為0時賦初值,計數器為1-27時移位判斷。復位有效時歸0,計數器為0時賦初值,高32位為0,后27位是data初值。當計數器不到27且flag為低電平(還沒開始判斷時),就要開始判斷移位了,具體是:判斷data_shift[30:27]是否大于4(0-26是data,27-30是移位數據的低4位),大于4則將[30:27]+3,不滿足就保持原值。...判斷data_shift[58:55]是否大于4,大于4則+3,不滿足保持原值,判斷結束后,data_shift左移一位,其他情況維持不變
shift_flag:隨著時鐘周期高低變化的移位判斷標志信號,復位有效時歸0,其他情況取反,即一個時鐘周期內為低電平表示判斷,下一個時鐘周期內為高點平表示移位
輸出:復位有效時,個位-千萬位的輸出都為0。由于data有27位,要判斷移位27次,計數器計數到27時結束最后一次判斷移位,計數到28時進行輸出的賦值。個位的4位BCD碼是移位數據的低四位data_shift[31:27],千萬位的4位BCD碼是移位數據的高4位data_shift[58:55]
3、數碼管動態顯示驅動模塊seg_dynamic
我們由上一節知道數碼管是由位選和段選信號進行選擇和控制的,那么這個模塊里要將輸入的data轉換成對應的段選位選信號。因此,輸入為時鐘、復位、data、seg_en,輸出為sel,seg。因為第1ms第一個數碼管亮,第2ms第二個數碼管亮,這里需要用1ms時鐘去控制位選信號即哪個數碼管亮。每100ms數碼管顯示的十進制數要+1,因此時鐘還要控制段選信號即選中的數碼管顯示什么值。中間信號有實例化后的輸出unit,...,h_tho,data_reg,cnt_1ms,flag_1ms,cnt_sel,sel_reg,data_disp。data_reg是數碼管帶顯示內容寄存器,假設輸入要顯示的十進制數是9999_9999,那么不考慮符號時8個數碼管顯示9999_9999。cnt_1ms時1ms計數器。flag_1ms是標志信號,計滿時拉高,控制位選。cnt_sel是位選數碼管計數器,8個數碼管每1ms換一個亮,也就是每個數碼管8ms亮一次。cnt_sel從0-7計數,相當于給數碼管編碼。sel_reg是數碼管位選信號寄存器,選中點亮的數碼管后給他顯示的值。data_disp:當前點亮數碼管顯示的值。
module seg_dynamic
(
input wire sys_clk , //系統時鐘,頻率50MHz
input wire sys_rst_n , //復位信號,低有效
input wire [26:0] data , //數碼管要顯示的值
input wire seg_en , //數碼管使能信號,高電平有效
output reg [7:0] sel , //數碼管位選信號
output reg [7:0] seg //數碼管段選信號
);
//parameter define
parameter CNT_MAX = 16'd49_999; //數碼管刷新時間計數最大值
//wire define
wire [3:0] unit ; //個位數
wire [3:0] ten ; //十位數
wire [3:0] hun ; //百位數
wire [3:0] tho ; //千位數
wire [3:0] t_tho ; //萬位數
wire [3:0] h_hun ; //十萬位數
wire [3:0] t_hun ;
wire [3:0] h_tho ;
//reg define
reg [31:0] data_reg ; //待顯示數據寄存器
reg [15:0] cnt_1ms ; //1ms計數器
reg flag_1ms ; //1ms標志信號
reg [2:0] cnt_sel ; //數碼管位選計數器
reg [7:0] sel_reg ; //位選信號
reg [3:0] data_disp; //當前數碼管顯示的數據
//data_reg:控制數碼管顯示數據
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_reg <= 32'b0;
//不考慮小數點,若顯示的數據是8位都非0,則8個數碼管全顯示
else if(h_tho)
data_reg <= {h_tho,t_hun,h_hun,t_tho,tho,hun,ten,unit};
//若顯示的數據7位非0,比如1234567不是顯示01234567,則7個數碼管亮
else if(t_hun)
data_reg <= {4'd10,t_hun,h_hun,t_tho,tho,hun,ten,unit};//4'd10我們定義為不顯示
//若顯示的數據6位非0,則6個數碼管亮
else if(h_hun)
data_reg <= {4'd10,4'd10,h_hun,t_tho,tho,hun,ten,unit};
//若顯示的數據5位非0,則5個數碼管亮
else if(t_tho)
data_reg <= {4'd10,4'd10,4'd10,t_tho,tho,hun,ten,unit};
//若顯示的數據4位非0,則4個數碼管亮
else if(tho)
data_reg <= {4'd10,4'd10,4'd10,4'd10,tho,hun,ten,unit};
//若顯示的數據3位非0,則3個數碼管亮
else if(hun)
data_reg <= {4'd10,4'd10,4'd10,4'd10,4'd10,hun,ten,unit};
//若顯示的數據2位非0,則2個數碼管亮
else if(ten)
data_reg <= {4'd10,4'd10,4'd10,4'd10,4'd10,4'd10,ten,unit};
//若上面都不滿足都只顯示一位數碼管
else
data_reg <= {4'd10,4'd10,4'd10,4'd10,4'd10,4'd10,4'd10,unit};
//cnt_1ms:1ms循環計數
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標志信號
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循環數,用于選擇當前顯示的數碼管
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;
//數碼管位選信號寄存器
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;
//控制數碼管的位選信號,使8個數碼管輪流顯示
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個數碼管賦個位值
3'd1: data_disp <= data_reg[7:4] ; //給第2個數碼管賦十位值
3'd2: data_disp <= data_reg[11:8] ; //給第3個數碼管賦百位值
3'd3: data_disp <= data_reg[15:12]; //給第4個數碼管賦千位值
3'd4: data_disp <= data_reg[19:16]; //給第5個數碼管賦萬位值
3'd5: data_disp <= data_reg[23:20]; //給第6個數碼管賦十萬位值
3'd6: data_disp <= data_reg[27:24]; //給第7個數碼管賦百萬位值
3'd7: data_disp <= data_reg[31:28]; //給第8個數碼管賦千萬位值
default:data_disp <= 4'b0;
endcase
else
data_disp <= data_disp;
//控制數碼管段選信號,顯示數字
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}; //顯示數字0
4'd1 : seg <= {1'b1,7'b111_1001}; //顯示數字1
4'd2 : seg <= {1'b1,7'b010_0100}; //顯示數字2
4'd3 : seg <= {1'b1,7'b011_0000}; //顯示數字3
4'd4 : seg <= {1'b1,7'b001_1001}; //顯示數字4
4'd5 : seg <= {1'b1,7'b001_0010}; //顯示數字5
4'd6 : seg <= {1'b1,7'b000_0010}; //顯示數字6
4'd7 : seg <= {1'b1,7'b111_1000}; //顯示數字7
4'd8 : seg <= {1'b1,7'b000_0000}; //顯示數字8
4'd9 : seg <= {1'b1,7'b001_0000}; //顯示數字9
4'd10 : seg <= 8'b1111_1111 ; //不顯示任何字符
default:seg <= 8'b1100_0000;
endcase
//sel:數碼管位選信號賦值
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 ), //系統時鐘,頻率50MHz
.sys_rst_n (sys_rst_n), //復位信號,低電平有效
.data (data ), //輸入需要轉換的數據
.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
參數定義:1ms計數2500000個,最大計數值49_999。
data_reg:控制數碼管要顯示的數據,復位有效時歸0,因為沒有小數點,我們考慮到有幾位就只讓幾個數碼管進行顯示。不顯示的數碼管定義為4'd11
cnt_1ms:復位有效或計滿時歸0,其他情況+1
flag_1ms:1ms標志位,復位有效時歸0,計滿數值-1時拉高,其他情況保持低電平
cnt_sel:數碼管編號,從0-7計數,復位有效時歸0,計滿7個數且標志位拉高時歸0,標志位拉高時+1,其他情況保持不變
控制數碼管位選信號:復位有效時data_disp歸0,使能為高電平有效且標志信號為高時,分情況討論,cnt_sel為0,第一個數碼管賦data_reg的低四位,第一個數碼管顯示個位,...,需要有default語句,data_disp賦0即可,其他情況,data_disp保持不變
控制數碼管段選信號:復位有效時seg所有位賦1表示每一段都不點亮,其他分情況討論,data_disp為0時數碼管顯示0,0對應的段選碼上一節討論了,最高位是小數點不用都為1表示滅,低7位對應abcdefg=100_0000,以此類推,加上default語句
sel:數碼管位選信號賦值,復位有效時歸0,其他情況將sel_reg賦值給
實例化BCD
4、74HC595控制模塊
直接用上一節的代碼,需要注意的是hc595_ctrl.v中第23行對data的賦值,把最右邊的數碼管作為個位比較符合我們的書寫習慣,所以位選信號的順序要改,原語句是assign data={sel,seg[0],seg[1],...,seg[7]};要改做assign data={sel[0],sel[1],...,sel[7],seg[0],seg[1],...,seg[7]};否則,數碼管最左邊是個位,不符合書寫習慣。
5、數碼管動態顯示模塊
該模塊主要是對數碼管動態顯示驅動模塊和74HC595控制模塊的實例化,以及對應信號的連接
module seg_595_dynamic
(
input wire sys_clk , //系統時鐘,頻率50MHz
input wire sys_rst_n , //復位信號,低有效
input wire [26:0] data , //數碼管要顯示的值
input wire seg_en , //數碼管使能信號,高電平有效
output wire stcp , //輸出數據存儲寄時鐘
output wire shcp , //移位寄存器的時鐘輸入
output wire ds //串行數據輸入
);
//wire define
wire [7:0] sel; //數碼管位選信號
wire [7:0] seg; //數碼管段選信號
seg_dynamic seg_dynamic_inst
(
.sys_clk (sys_clk ), //系統時鐘,頻率50MHz
.sys_rst_n (sys_rst_n), //復位信號,低有效
.data (data ), //數碼管要顯示的值
.seg_en (seg_en ), //數碼管使能信號,高電平有效
.sel (sel ), //數碼管位選信號
.seg (seg ) //數碼管段選信號
);
hc595_ctrl hc595_ctrl_inst
(
.sys_clk (sys_clk ), //系統時鐘,頻率50MHz
.sys_rst_n (sys_rst_n), //復位信號,低有效
.sel (sel ), //數碼管位選信號
.seg (seg ), //數碼管段選信號
.en (1'b1),
.stcp (stcp ), //輸出數據存儲寄時鐘
.shcp (shcp ), //移位寄存器的時鐘輸入
.ds (ds ) //串行數據輸入
);
endmodule
兩個模塊的實例化
6、頂層模塊top_seg_595
頂層模塊主要是對各個子功能模塊的實例化,以及對應信號的連接
module top_seg_595
(
input wire sys_clk , //系統時鐘,頻率50MHz
input wire sys_rst_n , //復位信號,低電平有效
output wire stcp , //輸出數據存儲寄時鐘
output wire shcp , //移位寄存器的時鐘輸入
output wire ds //串行數據輸入
);
//wire define
wire [26:0] data ; //數碼管要顯示的值
wire seg_en ;//數碼管使能信號,高電平有效
data_gen data_gen_inst
(
.sys_clk (sys_clk ), //系統時鐘,頻率50MHz
.sys_rst_n (sys_rst_n), //復位信號,低電平有效
.data (data ), //數碼管要顯示的值
.seg_en (seg_en) //數碼管使能信號,高電平有效
);
seg_595_dynamic seg_595_dynamic_inst
(
.sys_clk (sys_clk ), //系統時鐘,頻率50MHz
.sys_rst_n (sys_rst_n ), //復位信號,低有效
.data (data ), //數碼管要顯示的值
.seg_en (seg_en ), //數碼管使能信號,高電平有效
.stcp (stcp ), //輸出數據存儲寄時鐘
.shcp (shcp ), //移位寄存器的時鐘輸入
.ds (ds ) //串行數據輸入
);
endmodule
數據產生和動態顯示模塊的實例化
編寫testbench
`timescale 1ns/1ns
module tb_top_seg_595();
//wire define
wire stcp ; //輸出數據存儲寄時鐘
wire shcp ; //移位寄存器的時鐘輸入
wire ds ; //串行數據輸入
//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:產生時鐘
always #10 sys_clk <= ~sys_clk;
//重新定義參數值,縮短仿真時間
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 ), //系統時鐘,頻率50MHz
.sys_rst_n (sys_rst_n ), //復位信號,低電平有效
.stcp (stcp ), //輸出數據存儲寄時鐘
.shcp (shcp ), //移位寄存器的時鐘輸入
.ds (ds )//串行數據輸入
);
endmodule
testbench已經很熟悉了。
對比波形
先看6個模塊的從屬關系,再分別檢查6個模塊的波形,比較容易debug。
數據產生模塊
后面幾個模塊不細列。
分配管腳
和上一節一樣
-
FPGA
+關注
關注
1630文章
21798瀏覽量
606065 -
發光二極管
+關注
關注
13文章
1205瀏覽量
66513 -
數碼管
+關注
關注
32文章
1887瀏覽量
91410 -
顯示模塊
+關注
關注
1文章
50瀏覽量
23602 -
動態顯示
+關注
關注
0文章
40瀏覽量
11726
發布評論請先 登錄
相關推薦
評論