一. 项目需求
- 通过小脚丫FPGA核心板上的2个数码管和轻触按键制作一个秒表,通过按键来控制秒表的功能,并在数码管上显示数值。
- 使用七段显示器作为输出设备,在小脚丫FPGA核心板上创建一个2位数秒表。 秒表应从 0.0 秒计数到 9.9秒,然后翻转,计数值每0.1秒精确更新一次。
- 秒表使用四个按钮输入:开始、停止、增量和清除(重置)。 开始输入使秒表开始以10Hz时钟速率递增(即每0.1秒计数一次); 停止输入使计数器停止递增,但使数码管显示当前计数器值; 每次按下按钮时,增量输入都会导致显示值增加一次,无论按住增量按钮多长时间; 复位/清除输入强制计数器值为零。
二. 需求分析
- 目标:
设计一个具有启动、停止、递增和清除功能的秒表,使用小脚丫FPGA核心板上的2个数码管和轻触按键。
- 功能需求:
秒表应从 0.0 秒计数到 9.9秒,然后翻转,计数值每0.1秒精确更新一次。
秒表使用四个按钮输入:开始、停止、增量和清除(重置)。
开始输入使秒表开始以10Hz时钟速率递增(即每0.1秒计数一次);
停止输入使计数器停止递增,但使数码管显示当前计数器值;
每次按下按钮时,增量输入都会导致显示值增加一次,无论按住增量按钮多长时间;
复位/清除输入强制计数器值为零。
- 设计约束:
使用小脚丫FPGA核心板作为硬件平台,使用Verilog HDL作为编程语言。
使用七段显示器作为输出设备,在小脚丫FPGA核心板上创建一个2位数秒表。
使用轻触按键作为输入设备,分别连接到小脚丫FPGA核心板上的四个引脚。
使用一个12MHz的时钟信号作为秒表的时基,通过分频器产生10Hz的时钟信号。
使用一个4位的二进制计数器作为秒表的核心,通过译码器将其转换为七段显示器的控制信号。
使用一个状态机作为秒表的控制逻辑,根据输入信号的变化切换不同的状态。
- 验收标准:
秒表能够正确地显示计数值,从 0.0 秒到 9.9秒,然后翻转,每0.1秒更新一次。
秒表能够响应四个按钮的输入,实现启动、停止、递增和清除的功能。
秒表的设计符合功能需求和设计约束,没有逻辑错误或硬件故障。
三. 实现的方式
- 通过分频器产生10Hz的时钟信号,用于驱动秒表的计数器。分频器的分频比是1200000,即每120000个时钟周期,就会产生一个10Hz的时钟脉冲。
- 定义一个4位的二进制计数器作为秒表的核心,每接收到一个10Hz的时钟脉冲,就递增一次,从 0 到 99,然后翻转。计数器的输出作为译码器的输入,将其转换为七段显示器的控制信号,用于在数码管上显示计数值。
- 定义一个状态机作为秒表的控制逻辑,有四个状态:停止、运行、增量和清除。状态机的输入是四个按钮信号,状态机的输出是计数器的使能信号和清零信号。状态机的初始状态是停止,根据输入信号的变化切换不同的状态,实现秒表的功能。
- 将所有的模块连接起来,完成秒表的设计。在小脚丫FPGA核心板上进行仿真和测试,验证秒表的正确性和稳定性。
四. 硬件介绍
- 使用了USB Type C接口提供板上+5V供电、FPGA的配置,并新增了UART通信的功能,因此无需再通过其它端口与PC进行数据通信。
- 支持U盘模式(连接到上位机的USB端口,上位机自动弹出StepFPGA的U盘盘符)的下载,任何操作系统的电脑 -Windows、Mac OS以及Linux(包括树莓派)都可以在不安装任何驱动程序的情况下,直接将生成的jed配置文件发送到StepFPGA盘中即可完成编程。
- 为配合这款小脚丫FPGA的使用,我们特别升级了Web IDE系统,用户不必再下载安装Diamond软件,即可在任何一款电脑上通过浏览器进行FPGA的编程和编译。图形化的界面使得操作非常直观、便捷。
五. 功能框图
六. 代码及说明
- 实现按键消抖,一般按键按下时会产生低于 20ms 的高频脉冲信号抖动,为消除按键抖动,提高按键检测的可靠性,FPGA程序设计每20ms检测一次按键的状态,当检测到有效下降沿,说明有按键按下,每20ms检测一次按键的状态。
if(cnt==18'd239999)begin // check the button status every 20ms
cnt <= 18'd0;
start_rst <= start;
start_rst_pre <= start_rst;
stop_rst <= stop;
stop_rst_pre <= stop_rst;
inc_rst <= inc;
inc_rst_pre <= inc_rst;
reset_rst <= reset;
reset_rst_pre <= reset_rst;
end
else begin
cnt <= cnt + 18'd1;
end
- 产生10Hz的时钟信号,更新状态机,并利用四位二进制计数器开始计数。
当reset_edge为1时,重置,将计数器counter,ones和tenths都重置为0,状态机state更新为11。
当start_edge为1时,开始计数,计数器counter计数到1199999时为0.1秒。状态机state更新为01。
当inc_edge为1时,增量,此时tenths加1,若tenths为9,则ones加1,tenths置零。状态机state更新为10。
当stop_edge为1时,停止计数,状态机state更新为00。
// if reset is pressed, force counter, ones and tenths to zero, state to reset
if (reset_edge) begin
counter <= 21'd0;
ones <= 4'b0;
tenths <= 4'b0;
state <= 2'b11;
end
// otherwise, update counter, ones, tenths and state according to inputs and state
else begin
// if state is stop
if (state == 2'b00) begin
// if start is pressed, change state to run
if (start_edge) begin
state <= 2'b01;
end
// if increment is pressed, increase ones by one, wrap around if exceed max, carry over to tenths if needed
else if (inc_edge) begin
// first check tenths
if (tenths == MAX_DIGIT) begin
tenths <= 4'b0;
// then check ones
if (ones == MAX_DIGIT) begin
ones <= 4'b0;
end
else begin
ones <= ones + 4'b1;
end
end
else begin
tenths <= tenths + 4'b1;
end
state <= 2'b10;
end
end
// if state is run
else if (state == 2'b01) begin
// if stop is pressed, change state to stop
if (stop_edge) begin
state <= 2'b00;
end
// if counter reaches max, reset counter and increase ones by one, wrap around if exceed max, carry over to tenths if needed
else if (counter == MAX_COUNT) begin
counter <= 21'd0;
// first check tenths
if (tenths == MAX_DIGIT) begin
tenths <= 4'b0;
// then check ones
if (ones == MAX_DIGIT) begin
ones <= 4'b0;
end
else begin
ones <= ones + 4'b1;
end
end
else begin
tenths <= tenths + 4'b1;
end
end
// otherwise, increment counter by one
else begin
counter <= counter + 21'd1;
end
end
// if state is increment
else if (state == 2'b10) begin
// if increment is released, change state to stop
if (~inc_edge) begin
state <= 2'b00;
end
end
// if state is reset
else if (state == 2'b11) begin
// if reset is released, change state to stop
if (~reset_edge) begin
state <= 2'b00;
end
end
end
- 通过译码器转换为七段数码管控制信号。
// output 7-segment display codes according to ones and tenths values
case (ones)
4'b0000: digit1 <= 9'b010111111; // 0
4'b0001: digit1 <= 9'b010000110; // 1
4'b0010: digit1 <= 9'b011011011; // 2
4'b0011: digit1 <= 9'b011001111; // 3
4'b0100: digit1 <= 9'b011100110; // 4
4'b0101: digit1 <= 9'b011101101; // 5
4'b0110: digit1 <= 9'b011111101; // 6
4'b0111: digit1 <= 9'b010000111; // 7
4'b1000: digit1 <= 9'b011111111; // 8
4'b1001: digit1 <= 9'b011101111; // 9
default: digit1 <= 9'b000000000; // blank
endcase
case (tenths)
4'b0000: digit2 <= 9'b000111111; // 0
4'b0001: digit2 <= 9'b000000110; // 1
4'b0010: digit2 <= 9'b001011011; // 2
4'b0011: digit2 <= 9'b001001111; // 3
4'b0100: digit2 <= 9'b001100110; // 4
4'b0101: digit2 <= 9'b001101101; // 5
4'b0110: digit2 <= 9'b001111101; // 6
4'b0111: digit2 <= 9'b000000111; // 7
4'b1000: digit2 <= 9'b001111111; // 8
4'b1001: digit2 <= 9'b001101111; // 9
default: digit2 <= 9'b000000000; // blank
endcase
end
七. 仿真波形和功能展示
- 仿真结果说明
按键消抖和状态机更新:观察到当经过按键消抖后检测到start按键按下时,状态机state更新为01(运行),开始计数,之后依次按下停止,增量,重置,状态机由01(运行),依次更新为00(停止),10(增量),11(重置),00(停止),说明状态机模块运行正常。
开始计数:状态机为01(运行)时,开始计数,tenths(十分位)开始计数,观察到计数期间,tenths(十分位)由0逐渐增加到8,说明开始计数模块正常。
停止计数:状态机由01(运行)更新为00(停止)时,观察到tenths(十分位)到8后停止计数,可以看到数字8的持续时间明显比前几位数字持续时间长,说明停止计数模块正常。
增量:状态机由00(停止)更新为10(增量),观察到tenths(十分位)由8增加为9,说明增量模块正常。
重置:状态机由00(停止)更新为11(重置)后,观察到tenths(十分位)由9变为0,说明重置模块正常。
- 开始计数模块
点击开始按钮,状态机为01(运行)时,开始计数,tenths(十分位)开始计数,观察到计数期间,数码管十分位和个位逐渐增加,说明开始计数模块正常。
- 停止计数模块
点击停止按钮,状态机由01(运行)更新为00(停止)时,观察到计数期间,数码管十分位和个位停止增加,说明停止计数模块正常。
- 增量模块
点击停止按钮,状态机由00(停止)更新为10(增量),观察到计数期间,数码管由停止计数时的9.2增量到9.3,说明增量模块正常。
- 重置模块
点击重置按钮,状态机由00(停止)更新为11(重置)后,观察到数码管重置为0.0,说明重置模块正常。
八. 使用GPT说明和FPGA的资源利用说明
- GPT说明
以下展示导出后的部分聊天内容,具体的内容见附件。
- FPGA的资源利用说明
部分资源利用说明:
Number of registers: 这是 FPGA 中用于存储数据的触发器的数量。触发器可以用来实现状态机、计数器、寄存器等功能。设计使用了 72 个触发器,占总数的 2%。
PFU registers: 这是 FPGA 中的 Programmable Functional Unit (PFU) 触发器的数量。PFU 是 FPGA 的基本逻辑单元,每个 PFU 包含一个 4 输入的查找表 (LUT4) 和一个触发器。设计使用了 72 个 PFU 触发器,占总数的 2%。
PIO registers: 这是 FPGA 中的 Programmable Input/Output (PIO) 触发器的数量。PIO 是 FPGA 的输入输出单元,每个 PIO 包含一个触发器和一个三态缓冲器。设计没有使用 PIO 触发器,占总数的 0%。
Number of SLICEs: 这是 FPGA 中的 SLICE 的数量。SLICE 是 FPGA 的逻辑划分单元,每个 SLICE 包含两个 PFU 和一些额外的逻辑资源。设计使用了 61 个 SLICE,占总数的 3%。
SLICEs as Logic/ROM: 这是 FPGA 中的 SLICE 作为逻辑或只读存储器 (ROM) 使用的数量。逻辑是指用 LUT4 实现的组合逻辑功能,如逻辑门、多路复用器、算术运算器等。ROM 是指用 LUT4 实现的存储功能,如查找表、状态表等。设计使用了 61 个 SLICE 作为逻辑或 ROM,占总数的 3%。
SLICEs as RAM: 这是 FPGA 中的 SLICE 作为随机存取存储器 (RAM) 使用的数量。RAM 是指用 LUT4 和触发器实现的存储功能,如寄存器文件、缓冲区、队列等。设计没有使用 SLICE 作为 RAM,占总数的 0%。
SLICEs as Carry: 这是 FPGA 中的 SLICE 作为进位链使用的数量。进位链是指用 LUT4 和触发器实现的进位传递功能,如加法器、比较器、计数器等。设计使用了 21 个 SLICE 作为进位链,占总数的 1%。
Number of LUT4s: 这是 FPGA 中的 LUT4 的数量。LUT4 是 FPGA 的基本逻辑单元,可以实现任意的 4 输入的逻辑函数。设计使用了 117 个 LUT4,占总数的 3%。
Number used as logic LUTs: 这是 FPGA 中的 LUT4 作为逻辑使用的数量。设计使用了 75 个 LUT4 作为逻辑,占总数的 1.7%。
Number used as distributed RAM: 这是 FPGA 中的 LUT4 作为分布式 RAM 使用的数量。分布式 RAM 是指用 LUT4 实现的小容量的 RAM,通常用于存储少量的数据或控制信号。设计没有使用 LUT4 作为分布式 RAM,占总数的 0%。
Number used as ripple logic: 这是 FPGA 中的 LUT4 作为波纹逻辑使用的数量。波纹逻辑是指用 LUT4 实现的无进位的逻辑功能,如异或、奇偶校验、比特反转等。设计使用了 42 个 LUT4 作为波纹逻辑,占总数的 1%。
Number used as shift registers: 这是 FPGA 中的 LUT4 作为移位寄存器使用的数量。移位寄存器是指用 LUT4 和触发器实现的串行数据传输功能,如串行通信、循环冗余校验、线性反馈移位寄存器等。设计没有使用 LUT4 作为移位寄存器,占总数的 0%。
Number of PIO sites used: 这是 FPGA 中的 PIO 站点使用的数量。PIO 站点是指 FPGA 的输入输出引脚,可以配置为不同的电气特性和功能。设计使用了 23 个 PIO 站点,加上 4 个 JTAG 站点,共 27 个,占总数的 26%。
九. 主要难题及解决方法、
- 主要难题:本次代码使用gpt生成,生成的代码错误较多,且很难符合全部要求。
- 解决方法:多次尝试不同提问方式,反复训练。
十. 未来的计划或建议
- 在FPGA学习的基础上,我计划进一步提升自己的硬件设计和开发能力。
- 在与ai合作的基础上,我们也要善用ai来提高自己的工作效率。