基于lattice MXO2实现的简易秒表
项目需求
使用七段显示器作为输出设备,在小脚丫FPGA核心板上创建一个2位数秒表。 秒表应从 0.0 秒计数到 9.9秒,然后翻转,计数值每0.1秒精确更新一次。
秒表使用四个按钮输入:开始、停止、增量和清除(重置)。开始输入使秒表开始以10Hz时钟速率递增(即每0.1秒计数一次); 停止输入使计数器停止递增,但使数码管显示当前计数器值; 每次按下按钮时,增量输入都会导致显示值增加一次,无论按住增量按钮多长时间; 复位/清除输入强制计数器值为零。
需求分析
1.硬件资源分配:首先,需要确定小脚丫FPGA核心板上的可用资源,例如时钟模块、七段显示器控制器以及输入按钮接口等。确保核心板上有足够的资源来实现秒表功能。
2.时钟模块:使用FPGA上的时钟资源来生成一个10Hz的时钟信号,这将作为秒表的基准时钟。可以使用计数器或分频器来生成所需的时钟频率。
3输入按钮接口:连接3个按钮到FPGA核心板的输入引脚。需要编写相应的Verilog代码来检测按钮的按下和释放事件,并对其进行响应。
4计数器:实现一个可以递增的计数器模块,该计数器模块将根据基准时钟信号以0.1秒的间隔递增。当计数器达到9.9秒时,应该自动翻转为0.0秒。
5显示器控制器:可以编写一个七段显示器控制器模块,将计数器的值转换为七段显示器的输入信号。这个模块将根据计数器的值来控制七段显示器上的数字显示。(该模块包含在顶层模块内)
6顶层模块:编写一个顶层模块,将时钟模块、输入按钮接口、计数器、显示器控制器和状态机等模块连接在一起,并实现整个秒表的功能。
7仿真和调试:使用diamond仿真工具对设计进行仿真和调试,确保它按照预期工作。模拟按钮的按下和释放事件,观察七段显示器的输出是否正确。
8下载到FPGA核心板:将最终的设计综合、布局和生成比特流文件,然后将其下载到小脚丫FPGA核心板上进行验证和测试。
实现方式(代码放在代码部分)
1. 时钟模块:通过Verilog编写一个divide模块实现对核心板上晶振产生的12mhz时钟信号进行分频,通过设置两个计数器(上升沿计数,下降沿计数)来实现占空比为50%,频率为10hz的信号分频,作为秒表的基准时钟,该模块有两个参数,分频倍数n,及其位宽width。这里设置两个计数器以实现当n不为偶数时,该模块依旧可以正常实现分频功能。
2. 按键消抖模块:通过使用寄存器变量存储前一个时钟周期和当前时钟周期的按键状态,并使用计数器实现延时,从而实现按键消抖的功能。
3. 计数器:设置两个计数器cnt_s/cnt_ds,分别进行秒和分秒的计数,
在顶层模块定义计数器进位规则,以及配置数码管显示驱动。
4. 顶层模块:接入消抖及分频模块,并规定计数器进位规则,以及配置数码管显示驱动。
功能框图
代码
以下是顶层模块的代码展示
module timer(clk, rest, hold, num_1, num_2, led, add,start);
input clk, hold, rest,start;
input add;
output [8:0] num_1, num_2;
output led;
wire hold_pl;
wire clk1;
reg [6:0] seg [9:0];
reg [3:0] cnt_s, cnt_ds;
reg hold_flag;
reg finish;
reg add_trigger; // 新增的触发信号
reg reset_hold; // 新增复位保持标志
initial
begin
seg[0] = 9'h3f;
seg[1] = 9'h06;
seg[2] = 9'h5b;
seg[3] = 9'h4f;
seg[4] = 9'h66;
seg[5] = 9'h6d;
seg[6] = 9'h7d;
seg[7] = 9'h07;
seg[8] = 9'h7f;
seg[9] = 9'h6f;
end
key_delay ho
(
.clk(clk),
.rst(rest),
.key(hold),
.key_pulse(hold_pl)
);
divide #(.width(32), .n(1200000)) u1
(
.clk(clk),
.clkout(clk1),
.res(rest)
);
always @(posedge hold_pl)
if (!rest) hold_flag <= 0;
else hold_flag <= ~hold_flag; // 暂停实现模块
always @(*)
if (!rest)
finish <= 0;
else if (cnt_s == 4'd9 && cnt_ds == 4'd9)
finish <= 1;
else finish <= 0; // 计时完成标志模块
always @(posedge clk1 or negedge rest)
begin
if (!rest)
begin
cnt_s <= 0;
cnt_ds <= 0;
reset_hold <= 1; // 复位时激活停止计数标志
end
else if (reset_hold) // 如果处于复位保持状态
begin
if (!start) reset_hold <= 0;// 保持计数器不变,或者根据特定的用户操作来清除reset_hold标志
// 这部分可以根据具体需求添加,例如一个按钮触发清零start
end
else if (hold_flag == 1)
begin
if (!add_trigger && add) // 检查触发信号和add键状态
begin
add_trigger <= 1;
if (cnt_ds == 4'd9)
begin
cnt_s <= cnt_s + 1;
cnt_ds <= 0;
end
else
begin
cnt_ds <= cnt_ds + 1;
end
end
else if (!add)
begin
add_trigger <= 0;
end
end
else if (cnt_s == 4'd9 && cnt_ds == 4'd9)
begin
cnt_s <= 0;
cnt_ds <= 0;
end // 计数完成
else if (cnt_ds == 4'd10)
begin
cnt_s <= cnt_s + 1;
cnt_ds <= 0;
end // 进位模块
else
cnt_ds <= cnt_ds + 1;
end // 计数器模块
assign led = add;
assign num_1 = {2'b01, seg[cnt_s]};
assign num_2 = {2'b00, seg[cnt_ds]};
endmodule
代码分为主要的三个模块:顶层模块;分频器时钟模块;按键消抖模块。其作用在实现方式内有进行介绍,也使用gpt对其进行了部分修改及英文注释。实现了要求的基本功能并且提高可读性。这里介绍一下顶层模块中计数器的进位规则:
如果rest信号为低电平(表示复位状态),那么计数器会被重置为零。cnt_s和cnt_ds计数器都会被赋值为0。复位标志位被挂起,若按下启动键即start为0,标志位清零开始计数
如果hold_flag信号为高电平(表示计数器处于暂停状态),那么进入以下判断:
如果add_trigger触发信号为低电平且add信号为高电平,表示增加操作的触发条件满足。在此情况下,会进行如下操作:
add_trigger触发信号被设置为高电平。
如果cnt_ds计数器的值为9,表示个位数需要进位,那么执行以下操作:
cnt_s十位数计数器加1。
cnt_ds个位数计数器归零。
否则,如果cnt_ds计数器的值小于9,那么执行以下操作:
cnt_ds个位数计数器加1。
否则,如果add信号为低电平,表示增加操作结束,那么执行以下操作:
add_trigger触发信号被设置为低电平。
否则,如果cnt_s计数器的值为9且cnt_ds计数器的值为9,表示计数器计数完成,那么执行以下操作:
cnt_s十位数计数器归零。
cnt_ds个位数计数器归零。
否则,如果cnt_ds计数器的值为10,表示个位数需要进位,那么执行以下操作:
cnt_s十位数计数器加1。
cnt_ds个位数计数器归零。
否则,如果以上条件都不满足,表示计数器正常计数,那么执行以下操作:
cnt_ds个位数计数器加1。
管脚分配
资源占用说明
Design Summary:
Number of registers: 65 out of 4635 (1%)
PFU registers: 65 out of 4320 (2%)
PIO registers: 0 out of 315 (0%)
Number of SLICEs: 74 out of 2160 (3%)
SLICEs as Logic/ROM: 74 out of 2160 (3%)
SLICEs as RAM: 0 out of 1620 (0%)
SLICEs as Carry: 40 out of 2160 (2%)
Number of LUT4s: 147 out of 4320 (3%)
Number used as logic LUTs: 67
Number used as distributed RAM: 0
Number used as ripple logic: 80
Number used as shift registers: 0
Number of PIO sites used: 23 + 4(JTAG) out of 105 (26%)
Number of block RAMs: 0 out of 10 (0%)
Number of GSRs: 1 out of 1 (100%)
EFB used : No
JTAG used : No
Readback used : No
Oscillator used : No
Startup used : No
POR : On
Bandgap : On
Number of Power Controller: 0 out of 1 (0%)
Number of Dynamic Bank Controller (BCINRD): 0 out of 6 (0%)
Number of Dynamic Bank Controller (BCLVDSO): 0 out of 1 (0%)
Number of DCCA: 0 out of 8 (0%)
Number of DCMA: 0 out of 2 (0%)
Number of PLLs: 0 out of 2 (0%)
Number of DQSDLLs: 0 out of 2 (0%)
Number of CLKDIVC: 0 out of 4 (0%)
Number of ECLKSYNCA: 0 out of 4 (0%)
Number of ECLKBRIDGECS: 0 out of 2 (0%)