【FPGA——Cyclone Ⅳ學習筆記】六.數碼管動態掃描顯示(下)(EP4CE6F17C8)

上篇的代碼源於正點原子的的例程,但是經過對比,我還是更喜歡黑金版本的思路,因爲邏輯更加清晰。
實驗效果:與上篇相同,計時顯示。個位爲ms,十位爲s…
頂層結構圖:
在這裏插入圖片描述

1.seg_decoder.v

此模塊是數碼管位的解碼模塊將數據轉換爲數碼管的段選碼輸出給後續的掃描模塊。對應是頂層結構圖中右側的六個,因爲有六個位,所以每個位都對應一個此模塊。

module seg_decoder
(
	input[3:0]      bin_data,     // 數碼管一個位的數據
	output reg[6:0] seg_data      // 數碼管的段碼
);

always@(*)
begin
	case(bin_data)	//數字判斷(0~f)
		4'd0:seg_data <= 7'b100_0000;
		4'd1:seg_data <= 7'b111_1001;
		4'd2:seg_data <= 7'b010_0100;
		4'd3:seg_data <= 7'b011_0000;
		4'd4:seg_data <= 7'b001_1001;
		4'd5:seg_data <= 7'b001_0010;
		4'd6:seg_data <= 7'b000_0010;
		4'd7:seg_data <= 7'b111_1000;
		4'd8:seg_data <= 7'b000_0000;
		4'd9:seg_data <= 7'b001_0000;
		4'ha:seg_data <= 7'b000_1000;
		4'hb:seg_data <= 7'b000_0011;
		4'hc:seg_data <= 7'b100_0110;
		4'hd:seg_data <= 7'b010_0001;
		4'he:seg_data <= 7'b000_0110;
		4'hf:seg_data <= 7'b000_1110;
		default:seg_data <= 7'b111_1111;
	endcase
end
endmodule

2.seg_scan.v

此爲數碼管的掃描模塊,原理與之前相同,快速掃描六個位,利用視覺暫留現象形成動態。

module seg_scan
(
	input           clk,		  //系統時鐘
	input           rst_n,		  //復位信號
	output reg[5:0] seg_sel,      //數碼管位選輸出
	output reg[7:0] seg_data,     //當前顯示位的段選碼輸出
	input[7:0]      seg_data_0,	  //個位的段選碼,由上面的解碼器模塊得到
	input[7:0]      seg_data_1,	  //十位的段選碼
	input[7:0]      seg_data_2,	  //百位的段選碼
	input[7:0]      seg_data_3,	  //千位的段選碼
	input[7:0]      seg_data_4,	  //萬位位的段選碼
	input[7:0]      seg_data_5	  //十萬位的段選碼
);

parameter SCAN_FREQ = 200;     //掃描頻率,此處的掃描頻率是指6個位全部掃描一遍的頻率,200Hz->5ms
parameter CLK_FREQ = 50_000_000; //時鐘頻率

parameter SCAN_COUNT = CLK_FREQ /(SCAN_FREQ * 6) - 1;	

reg[31:0] scan_timer;  //動態掃描計數器
reg[3:0]  scan_sel;    //位選計數器

always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
	begin
		scan_timer <= 32'd0;
		scan_sel <= 4'd0;
	end
	else if(scan_timer >= SCAN_COUNT)	//按位進行掃描顯示
	begin
		scan_timer <= 32'd0;
		if(scan_sel == 4'd5)
			scan_sel <= 4'd0;
		else
			scan_sel <= scan_sel + 4'd1;	//每計到1個週期位選數加1,用來顯示下一個位
	end
	else
		begin
			scan_timer <= scan_timer + 32'd1;
		end
end

always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
	begin
		seg_sel <= 6'b111111;
		seg_data <= 8'hff;
	end
	else
	begin
		case(scan_sel)
			//個位數碼管顯示
			4'd0:
			begin
				seg_sel <= 6'b11_1110;	// 最低位爲0,即個位顯示
				seg_data <= seg_data_0;	// 個位的段選碼
			end
			//十位數碼管顯示
			4'd1:
			begin
				seg_sel <= 6'b11_1101;
				seg_data <= seg_data_1;
			end
			//...
			4'd2:
			begin
				seg_sel <= 6'b11_1011;
				seg_data <= seg_data_2;
			end
			4'd3:
			begin
				seg_sel <= 6'b11_0111;
				seg_data <= seg_data_3;
			end
			4'd4:
			begin
				seg_sel <= 6'b10_1111;
				seg_data <= seg_data_4;
			end
			4'd5:
			begin
				seg_sel <= 6'b01_1111;
				seg_data <= seg_data_5;
			end
			default:
			begin
				seg_sel <= 6'b11_1111;
				seg_data <= 8'hff;
			end
		endcase
	end
end

endmodule

3.count_m10.v

10進制的計數模塊。此模塊的使用是實例化多個此模塊,然後將一個模塊的輸出t與下一個模塊輸入en相連,從而將多個此模塊串聯在一起。具體可看主模塊。

module count_m10
(
	input          clk,
	input          rst_n,
	input          en,    // 此計數器使能信號,可看作前一個的進位信號
	input          clr,   // 同步復位  
	output reg[3:0]data,  // 計數器輸出值
	output reg     t      // 給出下一個計數器的使能信號,可看作向下一個發出進位信號
);

always@(posedge clk or negedge rst_n) 
begin
    if(rst_n==0)
    begin
        data <= 4'd0;
        t <= 1'd0;
    end
    else if(clr)
    begin
        data <= 4'd0;
        t <= 1'd0;      
    end
    else if(en)	//如果使能,則開始計數
    begin
        if(data==4'd9)	
        begin
            t<= 1'b1;    //計到9後產生進位信號
            data <= 4'd0;//計數器復位
        end
        else
        begin
            t <= 1'b0;
            data <= data + 4'd1;
        end
    end
    else
        t <= 1'b0;
end

endmodule

4.seg_test.v

主模塊

module seg_test
(
	input      clk,
	input      rst_n,
	output[5:0]seg_sel,		// 位選輸出
	output[7:0]seg_data		// 段選輸出
);
					 
reg[31:0] timer_cnt;		// 計數器
reg en_1hz;                 // 

//最底層計數器語句,每1ms給出一個信號
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        en_1hz <= 1'b0;
        timer_cnt <= 32'd0;
    end
    else if(timer_cnt >= 32'd4_999_999)	//1ms
    begin
        en_1hz <= 1'b1;
        timer_cnt <= 32'd0;
    end
    else
    begin
        en_1hz <= 1'b0;
        timer_cnt <= timer_cnt + 32'd1; 
    end
end

//實例化6個10進制計數器模塊並串聯,形成6位10進制計數器
wire[3:0] count0;
wire t0;
count_m10 count10_m0
(
    .clk    (clk),
    .rst_n  (rst_n),
    .en     (en_1hz),	
    .clr    (1'b0),
    .data   (count0),
    .t      (t0)
 );
 
wire[3:0] count1;
wire t1;
count_m10 count10_m1
(
     .clk    (clk),
     .rst_n  (rst_n),
     .en     (t0),
     .clr    (1'b0),
     .data   (count1),
     .t      (t1)
);

wire[3:0] count2;
wire t2;
count_m10 count10_m2
(
    .clk   (clk),
    .rst_n (rst_n),
    .en    (t1),
    .clr   (1'b0),
    .data  (count2),
    .t     (t2)
);

wire[3:0] count3;
wire t3;
count_m10 count10_m3
(
    .clk   (clk),
    .rst_n (rst_n),
    .en    (t2),
    .clr   (1'b0),
    .data  (count3),
    .t     (t3)
);

wire[3:0] count4;
wire t4;
count_m10 count10_m4
(
    .clk   (clk),
    .rst_n (rst_n),
    .en    (t3),
    .clr   (1'b0),
    .data  (count4),
    .t     (t4)
);

wire[3:0] count5;
wire t5;
count_m10 count10_m5
(
    .clk   (clk),
    .rst_n (rst_n),
    .en    (t4),
    .clr   (1'b0),
    .data  (count5),
    .t     (t5)
);

//實例化6個位的解碼模塊
wire[6:0] seg_data_0;
seg_decoder seg_decoder_m0
(
    .bin_data  (count5),
    .seg_data  (seg_data_0)
);

wire[6:0] seg_data_1;
seg_decoder seg_decoder_m1
(
    .bin_data  (count4),
    .seg_data  (seg_data_1)
);

wire[6:0] seg_data_2;
seg_decoder seg_decoder_m2
(
    .bin_data  (count3),
    .seg_data  (seg_data_2)
);

wire[6:0] seg_data_3;
seg_decoder seg_decoder_m3
(
    .bin_data  (count2),
    .seg_data  (seg_data_3)
);

wire[6:0] seg_data_4;
seg_decoder seg_decoder_m4
(
    .bin_data  (count1),
    .seg_data  (seg_data_4)
);

wire[6:0] seg_data_5;
seg_decoder seg_decoder_m5(
    .bin_data  (count0),
    .seg_data  (seg_data_5)
);

//實例化動態掃描模塊
seg_scan seg_scan_m0
(
    .clk        (clk),
    .rst_n      (rst_n),
    .seg_sel    (seg_sel),
    .seg_data   (seg_data),
    .seg_data_0 ({1'b1,seg_data_0}),  //小數點段控制,低電平有效
    .seg_data_1 ({1'b1,seg_data_1}), 
    .seg_data_2 ({1'b1,seg_data_2}),
    .seg_data_3 ({1'b1,seg_data_3}),
    .seg_data_4 ({1'b1,seg_data_4}),
    .seg_data_5 ({1'b1,seg_data_5})
);
endmodule 

以上代碼的邏輯思路十分清晰使用起來也十分簡單。如果後續模塊過多,還可以把解碼器模塊和掃描模塊進行二次封裝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章