1.项目需求:
制作一个具有启动、停止、递增和清除功能的秒表;
具体功能如下——
通过小脚丫FPGA核心板上的2个数码管和轻触按键制作一个秒表,通过按键来控制秒表的功能,并在数码管上显示数值。
使用七段显示器作为输出设备,在小脚丫FPGA核心板上创建一个2位数秒表。
秒表应从 0.0 秒计数到 9.9秒,然后翻转,计数值每0.1秒精确更新一次。
秒表使用四个按钮输入:开始、停止、增量和清除(重置)。
开始输入:使秒表开始以10Hz时钟速率递增(即每0.1秒计数一次);
停止输入:使计数器停止递增,但使数码管显示当前计数器值;
增量输入:每次按下按钮时,都会导致显示值增加一次,无论按住增量按钮多长时间;
复位/清除输入:强制计数器值为零。
2.需求分析:
制作一个秒表,用2位数码管显示——
①秒表正常计数:正常从0.0到9.9,计数0.1s更新一次;(需要“时钟分频”)
②当有按键输入:
开始输入:秒表开始计数;
停止输入:秒表停止计数,数码管显示当前数值;
增量输入:秒表显示值增加一次,无论按住增量按钮多长时间;(需要“负边沿检测”)
重置输入:秒表初始至0.0。
③经过分析我们知道,秒表有两种状态:计数状态(state=1),不计数状态(state=0)。
当处于“计数状态”时:计数器进入“计数过程”——
一般情况下,整数位不变、小数位增加1;
若小数位满9则变为0,且若当整数位也同时为9,则整数位、小数位均变为0;(9.9->0.0实现了翻转的效果)
当处于“不计数状态”时:计数器整数位不变、小数位也不变;
④而按键输入对于计数状态的影响:
开始输入:进入“计数状态”;
停止输入:进入“不计数状态”;
重置输入:进入“不计数状态”,且小数位、整数位均变为0;
增量输入:当进入“不计数状态”后,有增量输入,计数器完成一次“计数过程”。
⑤数码管显示:
cnt_1(个数位),cnt_2(整数位)范围:0-9(需要4位2进制);
数码管需能够显示0-9之间的十个数字(即数组seg_1[9:0]与数组seg_2[9:0]),并对其进行初始化(数码管1需显示小数点位dp);
当输入 cnt_1 和 cnt_2 改变时,相应的七段数码管LED灯就会显示对应的数字。
3.实现的方式:
一、项目模块:
总共三个模块Counter、clk_divider_10hz和edge_detector,其功能分别为
计数器(顶层文件,主要模块,模块内实例化了时钟分频器和边沿检测器)
时钟分频(将输入时钟信号分频为10hz的时钟信号,用于实现计数器每0.1s更新一次)
和负边沿检测(检测输入信号 key 的负边沿,用于实现无论按住增量按键多长时间,秒表显示值增加一次)
二、实现逻辑:
输入:时钟(clk)、开始(start)、停止(stop)、增量(inc)、重置(rst)
输出:两个数码管(seg_led_1、seg_led_2)
寄存器:cnt_1(小数位),cnt_2(整数位)
①模块声明:
module Counter (
input wire clk, rst, start, stop, inc, // Input signals: clock, reset, start, stop, increment
output reg [8:0] seg_led_1, // Output for 7-segment display 1
output reg [8:0] seg_led_2 // Output for 7-segment display 2
);
②内部信号说明:
reg state; // State variable: 1 for counting state, 0 for non-counting state
reg [3:0] cnt_1; // Counter 1
reg [3:0] cnt_2; // Counter 2
wire clk_10hz; // Clock divided by 10Hz
wire inc_negedge; // Negative edge of increment signal
③初始化seg:
// Initial values for 7-segment display patterns
initial begin
seg_1[0] = 9'hbf;
seg_1[1] = 9'h86;
// ...
seg_2[8] = 9'h7f;
seg_2[9] = 9'h6f;
end
④时钟分频器和边沿检测器实例化:
// Clock divider for 10Hz output
clk_divider U1 (
.clk(clk),
.rst(rst),
.clkout(clk_10hz)
);
// Edge detector for increment signal
edge_detector U2 (
.clk(clk_10hz),
.rst(rst),
.key(inc),
.neg_edge(inc_negedge)
);
⑤状态控制逻辑:
// State machine: counting or non-counting state
always @(posedge clk_10hz or negedge rst) begin
if (!rst)
state <= 1'b0; // Non-counting state
else if (!start && stop)
state <= 1'b1; // Counting state
else if (start && !stop)
state <= 1'b0; // Non-counting state
else
state <= state;
end
⑥计数逻辑:
// Counter logic
always @(posedge clk_10hz or negedge rst) begin
// 计数
if (!rst) begin
cnt_1 <= 4'd0;
cnt_2 <= 4'd0;
end else begin
// ...
end
end
⑦seg_led输出逻辑:
// Assigning 7-segment display outputs
always @ (posedge clk_10hz) begin
seg_led_1 <= seg_1[cnt_2];
seg_led_2 <= seg_2[cnt_1];
end
4.功能框图:
如下图所示:
5.代码(内嵌到报告中)及说明:
module Counter (
input wire clk, rst, start, stop, inc, // Input signals: clock, reset, start, stop, increment
output reg [8:0] seg_led_1, // Output for 7-segment display 1
output reg [8:0] seg_led_2 // Output for 7-segment display 2
);
reg state; // State variable: 1 for counting state, 0 for non-counting state
reg [3:0] cnt_1; // Counter 1
reg [3:0] cnt_2; // Counter 2
wire clk_10hz; // Clock divided by 10Hz
wire inc_negedge; // Negative edge of increment signal
// Initial values for 7-segment display patterns
initial begin
seg_1[0] = 9'hbf;
seg_1[1] = 9'h86;
seg_1[2] = 9'hdb;
seg_1[3] = 9'hcf;
seg_1[4] = 9'he6;
seg_1[5] = 9'hed;
seg_1[6] = 9'hfd;
seg_1[7] = 9'h87;
seg_1[8] = 9'hff;
seg_1[9] = 9'hef;
seg_2[0] = 9'h3f;
seg_2[1] = 9'h06;
seg_2[2] = 9'h5b;
seg_2[3] = 9'h4f;
seg_2[4] = 9'h66;
seg_2[5] = 9'h6d;
seg_2[6] = 9'h7d;
seg_2[7] = 9'h07;
seg_2[8] = 9'h7f;
seg_2[9] = 9'h6f;
end
// Clock divider for 10Hz output
clk_divider U1 (
.clk(clk),
.rst(rst),
.clkout(clk_10hz)
);
// Edge detector for increment signal
edge_detector U2 (
.clk(clk_10hz),
.rst(rst),
.key(inc),
.neg_edge(inc_negedge)
);
// State machine: counting or non-counting state
always @(posedge clk_10hz or negedge rst) begin
if (!rst)
state <= 1'b0; // Non-counting state
else if (!start && stop)
state <= 1'b1; // Counting state
else if (start && !stop)
state <= 1'b0; // Non-counting state
else
state <= state;
end
// Counter logic
always @(posedge clk_10hz or negedge rst) begin
if (!rst) begin
cnt_1 <= 4'd0;
cnt_2 <= 4'd0;
end
else begin
if (state == 1) begin
if (cnt_1 == 4'd9) begin
cnt_1 <= 4'd0;
if (cnt_2 == 4'd9)
cnt_2 <= 4'd0;
else
cnt_2 <= cnt_2 + 1'b1;
end
else begin
cnt_1 <= cnt_1 + 1'b1;
cnt_2 <= cnt_2;
end
end
else if (inc_negedge && state == 0) begin
if (cnt_1 == 4'd9) begin
cnt_1 <= 4'd0;
if (cnt_2 == 4'd9)
cnt_2 <= 4'd0;
else
cnt_2 <= cnt_2 + 1'b1;
end
else begin
cnt_1 <= cnt_1 + 1'b1;
cnt_2 <= cnt_2;
end
end
else begin
cnt_1 <= cnt_1;
cnt_2 <= cnt_2;
end
end
end
// Assigning 7-segment display outputs
always @ (posedge clk_10hz) begin
seg_led_1 <= seg_1[cnt_2];
seg_led_2 <= seg_2[cnt_1];
end
endmodule
module edge_detector (
input clk, // Clock input
input rst, // Reset input
input key, // Key input for edge detection
output neg_edge // Output indicating negative edge detection
);
reg [1:0] D; // Delay register to capture key changes
always @(posedge clk or negedge rst) begin
if (!rst) begin
D <= 2'b11; // Reset delay register when reset is active
end
else begin
D <= {D[0], key}; // Shift in new key value at every clock cycle
end
end
assign neg_edge = D[1] & ~D[0]; // Output negative edge detection
endmodule
module clk_divider (
input wire clk, // Input clock signal
input wire rst, // Reset signal
output wire clkout // Output divided clock signal
);
reg [24:0] cnt; // Counter for dividing the clock frequency
reg clk_10hz; // Output signal representing a 10 Hz clock
// Counter increment logic
always @(posedge clk or negedge rst) begin
if (!rst)
cnt <= 25'd0; // Reset the counter to zero
else if (cnt == 1_200_000 - 1) // Check if counter reaches desired value
cnt <= 25'd0; // Reset the counter
else
cnt <= cnt + 1'b1; // Increment the counter
end
// Generating a 10 Hz clock signal
always @(posedge clk or negedge rst) begin
if (!rst)
clk_10hz <= 1'b0; // Reset the 10 Hz clock signal
else if (cnt >= 600_000 - 1) // Check if counter reaches half the desired value
clk_10hz <= 1'b1; // Set the 10 Hz clock signal
else
clk_10hz <= 1'b0; // Keep the 10 Hz clock signal low
end
// Assign the 10 Hz clock signal to the output
assign clkout = clk_10hz;
endmodule
6.仿真波形图:
(无)
7.FPGA的资源利用说明:
Design Summary:
Number of registers: 52 out of 4635 (1%)
PFU registers: 52 out of 4320 (1%)
PIO registers: 0 out of 315 (0%)
Number of SLICEs: 39 out of 2160 (2%)
SLICEs as Logic/ROM: 39 out of 2160 (2%)
SLICEs as RAM: 0 out of 1620 (0%)
SLICEs as Carry: 13 out of 2160 (1%)
Number of LUT4s: 76 out of 4320 (2%)
Number used as logic LUTs: 50
Number used as distributed RAM: 0
Number used as ripple logic: 26
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%)
Notes:-
1. Total number of LUT4s = (Number of logic LUT4s) + 2*(Number of distributed RAMs) + 2*(Number of ripple logic)
2. Number of logic LUT4s does not include count of distributed RAM and ripple logic.
Number of clocks: 2
Net clk_10hz: 15 loads, 15 rising, 0 falling (Driver: U1/clk_10hz_15 )
Net clk_c: 14 loads, 14 rising, 0 falling (Driver: PIO clk )
Number of Clock Enables: 2
Net clk_10hz_enable_8: 2 loads, 2 LSLICEs
Net clk_10hz_enable_7: 2 loads, 2 LSLICEs
Number of LSRs: 7
Net cnt_1_0: 1 loads, 1 LSLICEs
Net clk_10hz_enable_8: 2 loads, 2 LSLICEs
Net n398: 2 loads, 2 LSLICEs
Net cnt_2_3: 1 loads, 1 LSLICEs
Net rst_c: 1 loads, 1 LSLICEs
Net cnt_2_0: 1 loads, 1 LSLICEs
Net U1/n390: 13 loads, 13 LSLICEs
Number of nets driven by tri-state buffers: 0
Top 10 highest fanout non-clock nets:
Net cnt_2_1: 15 loads
Net cnt_2_2: 14 loads
Net U1/n390: 13 loads
Net cnt_1_0: 12 loads
Net cnt_2_0: 12 loads
Net cnt_1_1: 11 loads
Net cnt_1_2: 10 loads
Net cnt_2_3: 10 loads
Net cnt_1_3: 9 loads
Net clk_10hz_enable_8: 5 loads
Number of warnings: 0
Number of errors: 0
8.演示视频(3-5分钟,可以将GPT生成的代码做个备份,在演示视频中以便介绍):
项目功能演示详见项目介绍视频。
9.代码附件(上传到电子森林):
代码源文件详情见代码附件。
10.Chat GPT使用情况的介绍与总结:
在此项目开发中,自己使用Chat GPT主要完成的任务有
①代码的生成(更重要的是为学习者提供宝贵的实现思路参考)
然后不断地对ChatGPT提出合适的修订信息,ChatGPT会给予代码的订正;
②代码逻辑的阅读,以及生成相应的注释。
以edge_detecot模块为例,向其提供Verilog代码,ChatGPT会对代码进行阅读并且给出较为详细的解释,结果如下图所示——
再以clk_divider时钟模块为例,向ChatGPT提供Verilog代码并提出了对代码进行英文注释的要求,结果如下图所示——
总的来说,通过这段时间使用ChatGPT尝试对完成小脚丫FPGA核心板任务的学习,自己对于ChatGPT的在项目中的使用已经有了初步的认知。