【FPGA】基于 黑金AX301B开发板 的数字钟设计(12小时制,带PM位显示)

想深耕嵌入式?这个专辑值得收藏

MCU、FPGA、工控、传感器一站式学习,实战项目直接抄

目录

一、设计规格

二、设计划分

三、设计输入(代码)

四、引脚绑定

五、下载测试


一、设计规格

1. 功能特性

(1)12小时制(1-12)的计数功能,在12:59:59时置数回01:00:00,并翻转AM/PM信号;

(2)AM/PM显示功能,0(灭灯)表示AM,1(亮灯)表示PM;

(3)数字钟复位功能,当复位后显示为01:00:00,状态为AM;

(4)数码管显示功能,只显示数字,不显示标点。

2. 硬件平台

        该数字钟的实现平台是黑金(Alinx)的 Altera AX301B 开发板,如图1所示。该开发板采用的是Cyclone IV系列的芯片,具体型号为EP4CE6F17C8。AX301B搭载有源晶振,频率为50MHz。

图1  AX301B开发板

3. 数码管

        AX301B使用的是共阳极八段数码管,其段结构如图2所示。对于共阳极数码管,其为低电平有效(当某段控制数据为低电平(0)时,对应字段亮起;反之,当某段控制数据为高电平(1)时,对应字段不亮)。

图2  八段数码管的段结构

4. 按键

         AX301B拥有4个按键,分别为1个复位按键(RESET)和3个通用按键(KEY1~KEY3),其原理图如图3所示。可以看出,当按键松开时,为3.3V电源输入;而当按键按下时,导线接地。所以4个按键在松开状态下为高电平(1),在按压状态下为低电平(0)

图3  按键的原理图

5. LED灯

        AX301B拥有4个红色LED灯,其原理图如图4所示。可以看出,该结构为一个电阻和一个LED灯串联接地,当输出高电平时LED灯亮起,故4个LED灯为高电平有效

图4  LED灯的原理图

二、设计划分

1. 设计分析

        我们采用自顶向下的设计思路,将数字钟电路拆解成若干个小模块进行设计,然后再从顶层模块中进行例化实现上述功能。

(1)分钟和秒钟均为60进制,而4位二进制码是按16进制实现的,所以这里拆分成模10计数模块模6计数模块两个模块来设计;

(2)由于时钟位比较特别,置数时需同时参考个位片与十位片的值,所以时钟位统计进行设计。时钟位满足12进制,设计为模12计数模块

(3)AM/PM显示功能的设计也需要同时参考时钟个位片与十位片的值,故一同在模12计数模块中进行实现;

(4)复位功能在以上三个模块中均进行设计;

(5)数码管显示功能分为两部分:译码模块负责将上述模块输出的二进制码转换为对应的段控制码,以便能在数码管进行显示;数码管扫描显示模块负责顺序扫描每个数码管,并将段控制码输出到对应的数码管中。

        综上,设计思路是将数字钟拆分为了5个部分:模10计数模块模6计数模块模12计数模块译码模块数码管扫描显示模块

2. 模块设计细节

2.1  模10计数模块:充当个位片

        该模块具有异步复位、使能计数、进位输出功能,计数范围0-9,并在等于9时进位。

表1  模10计数模块的信号

信号名称方向宽度(bit)说明
clkin1

系统时钟,50MHz

rst_nin1

异步复位,低电平有效

enin1

计数使能

qout4

数据输出,范围0-9

coout1

进位输出,q等于9时置高

2.2  模6计数模块:充当十位片

        该模块具有异步复位、使能计数、进位输出功能,计数范围0-5,并在等于5时进位。

表2  模6计数模块的信号

信号名称方向宽度(bit)说明
clkin1系统时钟,50MHz
rst_nin1异步复位,低电平有效
enin1计数使能
qout4数据输出,范围0-5
coout1进位输出,q等于5时置高

2.3  模12计数模块:充当小时的个位片与十位片,并带有AM/PM转换功能

        该模块具有异步复位、同步置数、使能计数、进位输出功能。计数范围1-12,当等于12时复位为1,并对pm信号进行翻转。

表3  模12计数模块的信号

信号名称方向宽度(bit)说明
clkin1系统时钟,50MHz
rst_nin1异步复位,低电平有效
enin1计数使能
q1out4

个位数据输出,范围0-9,在q2q1等于12时置数回1

q2out4

十位数据输出,范围0-1,在q2q1等于12时置数回0

pmout1

AM/PM信号,0表示AM,1表示PM

2.4  译码模块

        该模块的功能是将二进制码转换为对应的数码管段控制信号。

表4  译码模块的信号

信号名称方向宽度(bit)说明

bin_data

in4

二进制数据,范围0-9

seg_data

out8

共阳极数码管的段控制数据,共8段

表5  各数字和字符对应的段控制数据

字符段控制码(1gfe_dcba)
0

1100_0000

1

1111_1001

2

1010_0100

3

1011_0000

4

1001_1001

5

1001_0010

6

1000_0010

7

1111_1000

8

1000_0000

9

1001_0000

a

1000_1000

b

1000_0011

c

1100_0110

d

1010_0001

e

1000_0110

f

1000_1110

2.5  数码管扫描显示模块

        该模块的功能是将多位数码管的段控制信号分别输出。

表6  数码管扫描显示模块的参数

参考名称类型说明

CLK_FRE

parameter

系统时钟频率,50MHz

SCAN_FRE

parameter

单个数码管的扫描频率

SCAN_CNT

parameter

单次扫描的计数值

表7  数码管扫描显示模块的信号

信号名称方向宽度(bit)说明

clk

in1

系统时钟,50MHz

rst_n

in1

异步复位,低电平有效

data_0

in8

1位数码管的段控制信号,低电平亮

data_1

in8

2位数码管的段控制信号,低电平亮

data_2

in8

3位数码管的段控制信号,低电平亮

data_3

in8

4位数码管的段控制信号,低电平亮

data_4

in8

5位数码管的段控制信号,低电平亮

data_5

in8

6位数码管的段控制信号,低电平亮

seg_sel

out6

数码管选择信号,低电平有效

seg_data

out8

数码管段控制信号,低电平亮

2.6  顶层模块

        该模块的功能是例化前5个模块,以实现12小时制数字钟的功能。

表8  顶层模块的信号

信号名称方向宽度(bit)说明
clkin1

系统时钟,50MHz

rst_nin1

异步复位,低电平有效

seg_sel

out6

数码管选择信号,低电平有效

seg_data

out8

数码管段控制信号,低电平亮

三、设计输入(代码)

1. 模10计数模块

module counter_10 (
	// input
	input				clk, 	// 系统时钟,50MHz
	input				rst_n, 	// 系统复位,低电平有效
	input				en,		// 使能信号
	// output
	output	reg	[3:0]	q, 		// 数据输出
	output	reg			co		// 进位输出
);
	always @(posedge clk, negedge rst_n) begin
		if (rst_n == 1'b0) begin
            co    <= 1'b0;
			q     <= 4'd8;    // 8用作测试,默认复位应设为0
		end else if (en == 1'b1) begin
			if (q == 4'd9) begin
                co    <= 1'b1;
				q     <= 4'd0;
			end else begin
                co    <= 1'b0;
				q     <= q + 4'd1;
			end
		end else begin
			co    <= 1'b0;
		end
	end
endmodule

2. 模6计数模块

module counter_6 (
	// input
	input				clk,	// 系统时钟,50MHz
	input 				rst_n,	// 系统复位,低电平有效
	input				en,		// 使能信号
	// output
	output	reg	[3:0]	q,		// 数据输出
	output	reg			co		// 进位输出
);
	always @(posedge clk, negedge rst_n) begin
		if (rst_n == 1'b0) begin
            co    <= 1'b0;
			q     <= 4'd5;    // 5用作测试,默认复位应设为0
		end else if (en == 1'b1) begin
			if (q == 4'd5) begin
				co    <= 1'b1;
                q 	  <= 4'd0;
			end else begin
				co    <= 1'b0;
                q     <= q + 4'd1;
			end
		end else begin
			co    <= 1'b0;
		end
	end
endmodule

3. 模12计数模块

module counter_12 (
	// input
	input 				clk, 	// 系统时钟,50MHz
	input 				rst_n, 	// 系统复位,低电平有效
	input				en,		// 使能信号
	// output
	output	reg	[3:0]	q1, 	// 时钟 个位输出
	output	reg [3:0]	q2, 	// 时钟 十位输出
	output	reg			pm		// AM/PM信号,0:AM,1:PM
);
	// reg
	reg co_hho;    // 时钟个位 进位输出
	
	// 时钟个位片
	always @(posedge clk, negedge rst_n) begin
		if (rst_n == 1'b0) begin
			co_hho	<= 1'b0;
			q1 		<= 4'd2;    // 2用作测试,默认复位应设为1
		end else if (en == 1'b1) begin
			if ( q2 == 4'd1 && q1 == 4'd2 ) begin    // 置数
				co_hho	<= 1'b0;
				q1 		<= 4'd1;
			end else if (q1 == 4'd9) begin
				co_hho	<= 1'b1;
				q1 		<= 4'd0;
			end else begin
				co_hho	<= 1'b0;
				q1 		<= q1 + 4'd1;
			end
		end else begin
			co_hho	<= 1'b0;
		end
	end
	
	// 时钟十位片
	always @(posedge clk, negedge rst_n) begin
		if (rst_n == 1'b0) begin
			q2 <= 4'd1;        // 1用作测试,默认复位应设为0
		end else if (en == 1'b1) begin
			if ( q2 == 4'd1 && q1 == 4'd2 ) begin    // 置数
				q2 <= 4'd0;
			end
		end else if (co_hho == 1'b1) begin
			q2 <= q2 + 4'd1;
		end
	end
	
	// AM/PM信号
	always @(posedge clk, negedge rst_n) begin
		if (rst_n == 1'b0) begin
			pm <= 1'b0;
		end else if (en == 1'b1) begin
			if ( q2 == 4'd1 && q1 == 4'd2 ) begin
				pm <= ~pm;
			end
		end
	end
endmodule

4. 译码模块

module seg_decoder (
	// input
	input		[3:0]	bin_data, 	// 二进制数据
	// output
	output	reg	[7:0]	seg_data	// 段控制数据
);
	always @(*) begin
		case (bin_data)
			4'h0: 	seg_data = 8'b1100_0000;	// 0
			4'h1: 	seg_data = 8'b1111_1001;	// 1
			4'h2: 	seg_data = 8'b1010_0100;	// 2
			4'h3: 	seg_data = 8'b1011_0000;	// 3
			4'h4: 	seg_data = 8'b1001_1001;	// 4
			4'h5: 	seg_data = 8'b1001_0010;	// 5
			4'h6: 	seg_data = 8'b1000_0010;	// 6
			4'h7: 	seg_data = 8'b1111_1000;	// 7
			4'h8: 	seg_data = 8'b1000_0000;	// 8
			4'h9: 	seg_data = 8'b1001_0000;	// 9
			4'ha: 	seg_data = 8'b1000_1000;
			4'hb: 	seg_data = 8'b1000_0011;
			4'hc: 	seg_data = 8'b1100_0110;
			4'hd: 	seg_data = 8'b1010_0001;
			4'he: 	seg_data = 8'b1000_0110;
			4'hf: 	seg_data = 8'b1000_1110;
			default:    seg_data = 8'hff;		// 关闭
		endcase
	end
endmodule

5. 数码管扫描显示模块

module seg_scan 
#(
	// parameter
	parameter CLK_FRE 	= 50_000_000,                     // 系统时钟频率
	parameter SCAN_FRE	= 200,                            // 单个数码管的扫描频率
	parameter SCAN_CNT	= CLK_FRE / (SCAN_FRE * 6) - 1    // 扫描计数值
)
(
	// input
	input 				clk,		// 系统时钟,50MHz
	input 				rst_n, 		// 系统复位,低电平有效
    // 6个数码管的段控制数据
	input		[7:0]	data_0,
	input		[7:0]	data_1,
	input		[7:0]	data_2,
	input		[7:0]	data_3,
	input		[7:0]	data_4,
	input		[7:0]	data_5,
	// output
	output	reg	[5:0]	seg_sel, 	// 数码管选择信号
	output	reg	[7:0]	seg_data	// 段控制数据
);
	// reg
	reg	[31:0]	time_cnt;		// 周期计数器
	reg	[3:0]	scan_sel;		// 数码管选择标志
	
	// 设置 scan_sel
	always @(posedge clk, negedge rst_n) begin
		if (rst_n == 1'b0) begin
			time_cnt	<= 32'd0;
			scan_sel	<= 4'd0;
		end else if (time_cnt == SCAN_CNT) begin
			time_cnt <= 32'd0;
			if (scan_sel == 4'd5) begin
				scan_sel	<= 4'd0;
			end else begin
				scan_sel	<= scan_sel + 4'd1;
			end
		end else begin
			time_cnt    <= time_cnt + 32'd1;
		end
	end
	
	// 数码管扫描显示
	always @(posedge clk, negedge rst_n) begin
		if (rst_n == 1'b0) begin
			seg_sel	    <= 6'h3f;
			seg_data    <= 8'hff;
		end else begin
			case (scan_sel)     // 根据scan_sel的值来选择显示对应的数码管
				4'd0: begin		
					seg_sel	    <= 6'b011_111;		// 右1管
					seg_data	<= data_0;
				end
				4'd1: begin
					seg_sel	    <= 6'b101_111;		// 右2管
					seg_data	<= data_1;
				end
				4'd2: begin
					seg_sel	    <= 6'b110_111;		// 右3管
					seg_data	<= data_2;
				end
				4'd3: begin
					seg_sel	    <= 6'b111_011;		// 右4管
					seg_data	<= data_3;
				end
				4'd4: begin
					seg_sel	    <= 6'b111_101;		// 右5管
					seg_data	<= data_4;
				end
				4'd5: begin
					seg_sel	    <= 6'b111_110;		// 右6管
					seg_data	<= data_5;
				end
				default: begin
					seg_sel	    <= 6'h3f;
					seg_data	<= 8'hff;
				end
			endcase
		end
	end
endmodule

6. 顶层模块

module digital_clock (
	// input
	input			clk,		// 系统时钟,50MHz
	input 			rst_n, 		// 系统复位,低电平有效
	// output
	output	[5:0]	seg_sel,	// 数码管选择信号
	output	[7:0]	seg_data,	// 段控制数据
	output			pm			// AM/PM信号,0:AM,1:PM
);
	// -------------------- Variables -------------------------------
	// reg
	reg			en_1hz;       // 1Hz使能信号
	reg	[31:0]	timer_cnt;    // 周期计数器
	

	// -------------------- Code ------------------------------------
	// 设置 en_1hz
	always @(posedge clk, negedge rst_n) begin
		if (rst_n == 1'b0) begin
			en_1hz 		<= 1'b0;
			timer_cnt	<= 32'd0;
		end else if (timer_cnt == 32'd49_999_999) begin
			en_1hz 		<= 1'b1;
			timer_cnt	<= 32'd0;
		end else begin
			en_1hz 		<= 1'b0;
			timer_cnt	<= timer_cnt + 32'd1;
		end
	end
	

	// -------------------- Instantiate -----------------------------
	// (1) 数字钟:
	// 二进制数据信号
	wire	[3:0]	b_hht;		// hh ten digit
	wire	[3:0]	b_hho;		// hh one digit
	wire	[3:0]	b_mmt;		// mm ten digit
	wire	[3:0]	b_mmo;		// mm one digit
	wire	[3:0]	b_sst;		// ss ten digit
	wire	[3:0]	b_sso;		// ss one digit
	
	// 进位信号
	wire			co_mmt;
	wire			co_mmo;
	wire			co_sst;
	wire			co_sso;
	
	counter_12 M4 ( .clk(clk), .rst_n(rst_n), .en(co_mmt), .q1(b_hho), .q2(b_hht), .pm(pm) );
	counter_6  M3 ( .clk(clk), .rst_n(rst_n), .en(co_mmo), .q(b_mmt),  .co(co_mmt) );
	counter_10 M2 ( .clk(clk), .rst_n(rst_n), .en(co_sst), .q(b_mmo),  .co(co_mmo) );
	counter_6  M1 ( .clk(clk), .rst_n(rst_n), .en(co_sso), .q(b_sst),  .co(co_sst) );
	counter_10 M0 ( .clk(clk), .rst_n(rst_n), .en(en_1hz), .q(b_sso),  .co(co_sso) );
	

	// (2) 译码器:
	// 段控制数据
	wire	[7:0] s_hht;
	wire	[7:0] s_hho;
	wire	[7:0] s_mmt;
	wire	[7:0] s_mmo;
	wire	[7:0] s_sst;
	wire	[7:0] s_sso;
	
	seg_decoder M10	( .bin_data(b_hht), .seg_data(s_hht) );
	seg_decoder M9  ( .bin_data(b_hho), .seg_data(s_hho) );
	seg_decoder M8  ( .bin_data(b_mmt), .seg_data(s_mmt) );
	seg_decoder M7  ( .bin_data(b_mmo), .seg_data(s_mmo) );
	seg_decoder M6  ( .bin_data(b_sst), .seg_data(s_sst) );
	seg_decoder M5  ( .bin_data(b_sso), .seg_data(s_sso) );
	

	// (3) 数码管扫描显示:
	seg_scan M11 (
		.clk		(clk		), 
		.rst_n		(rst_n		),
		
		.data_5		(s_hht		),
		.data_4		(s_hho		),
		.data_3		(s_mmt		),
		.data_2		(s_mmo		),
		.data_1		(s_sst		),
		.data_0		(s_sso		),
		
		.seg_sel	(seg_sel	), 
		.seg_data	(seg_data	)
	);
endmodule

四、引脚绑定

五、下载测试

        数字钟从12:58:58开始进行测试,此时LED1为熄灭状态,表示当前为AM。

        进行到12:59:59,当下一个1Hz使能触发时,数字钟置数回01:00:00,此时LED1为亮起状态,表示当前为PM。

想深耕嵌入式?这个专辑值得收藏

MCU、FPGA、工控、传感器一站式学习,实战项目直接抄

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值