【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 

以上代码的逻辑思路十分清晰使用起来也十分简单。如果后续模块过多,还可以把解码器模块和扫描模块进行二次封装。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

默默无闻小菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值