2024年寒假练 - 基于Lattice MXO2的小脚丫FPGA核心板制作一个秒表
该项目使用了Diamond软件、WebIDE平台、Verilog语言,实现了一个Lattice MXO2的小脚丫FPGA核心板的设计,它的主要功能为:通过小脚丫FPGA核心板上的2个数码管和轻触按键制作一个秒表,通过按键来控制秒表的功能,并在数码管上显示数值。。
标签
FPGA
2024寒假练
谢庥泉
更新2024-04-24
西南科技大学
112

一、项目需求

  • 使用七段显示器作为输出设备,在小脚丫FPGA核心板上创建一个2位数秒表。 秒表应从 0.0 秒计数到 9.9秒,然后翻转,计数值每0.1秒精确更新一次。
  • 秒表使用四个按钮输入:开始、停止、增量和清除(重置)。 开始输入使秒表开始以10Hz时钟速率递增(即每0.1秒计数一次); 停止输入使计数器停止递增,但使数码管显示当前计数器值; 每次按下按钮时,增量输入都会导致显示值增加一次,无论按住增量按钮多长时间; 复位/清除输入强制计数器值为零。

二、需求分析

功能描述:

  • 计数功能: 秒表应能够从0.0秒开始计数,以10Hz的速率递增,即每0.1秒更新一次。
  • 显示功能: 使用七段数码管显示当前的秒表计数值,范围从0.0到9.9秒。
  • 按钮控制: 使用四个按钮进行控制:开始、停止、增量和清除(重置)。
  • 开始功能: 按下开始按钮后,秒表开始递增,以10Hz的速率更新。
  • 停止功能: 按下停止按钮后,秒表停止递增,但仍然显示当前计数值。
  • 增量功能: 按下增量按钮时,秒表计数值增加一次,无论按钮按下多长时间。
  • 清除功能: 按下清除按钮时,秒表计数值被强制重置为零。

按钮输入处理:

  • 开始/停止切换: 开始按钮和停止按钮之间应该有一个切换功能,即按下开始后,停止按钮有效,按下停止后,开始按钮有效。
  • 增量操作: 按住增量按钮应该导致计数值持续增加,不受按钮按下的时间影响。
  • 清除功能: 清除按钮按下后,计数器值应立即重置为零。

显示要求:

  • 数码管显示: 使用两位七段数码管显示秒表的计数值。
  • 范围: 计数值范围应从0.0到9.9秒,然后重新开始。
  • 更新频率: 每0.1秒更新一次数码管显示。

硬件要求:

  • FPGA核心板: 小脚丫FPGA核心板应支持时钟模块和数字输入模块。
  • 按钮接口: 需要与FPGA核心板上的按钮接口进行连接。
  • 数码管接口: 需要与FPGA核心板上的七段数码管接口进行连接。

时序和同步:

  • 时序要求:12Mhz和10Hz

三、实现方式

  1. 设计时钟模块:
    • 创建一个时钟模块,产生10Hz的时钟信号用于秒表计数。
    • 确保时钟模块的稳定性和精度。
  2. 设计计数模块:
    • 创建一个计数模块,用于处理秒表的计数逻辑。
    • 包括开始、停止、增量和清除功能。
  3. 设计显示模块:
    • 创建一个显示模块,将计数模块的输出显示在两位七段数码管上。
    • 确保更新频率为每0.1秒一次。
  4. 按钮输入处理:
    • 创建一个按钮输入处理模块,根据按钮信号触发相应的计数模块操作。
    • 考虑使用状态机或类似的结构以处理按钮的不同状态。
  5. 管脚配置:
    • 在WebIDE中完成管脚的配置。
    • 制定布局规划,确保信号传输的稳定性和时序要求得到满足。
  6. 仿真测试:
    • 使用仿真工具Diamond验证设计的功能和正确性。
    • 确保计数、显示和按钮输入处理的逻辑都按预期工作。
  7. 下载到FPGA核心板:
    • 将综合后的设计下载到FPGA核心板中。
    • 连接硬件并验证实际性能。
  8. 调试和优化:
    • 在实际硬件上进行调试,确保所有功能按照预期工作。
    • 进行性能优化。
  9. 文档记录:
    • 编写详细的文档,包括设计说明、硬件连接图、代码注释等。
    • 记录所有硬件和软件配置,以备将来参考和维护。

四、功能框图

五、代码

顶层文件

Counter.v

module Counter(
input wire clk, // Clock input
input wire rst, // Reset input
input wire start, // Start control input
input wire stop, // Stop control input
input wire incr, // Increment control input

output [8:0] seg_out_1, // Seven-segment output 1
output [8:0] seg_out_2 // Seven-segment output 2
);

reg flag; // Flag for counting enable/disable
reg [3:0] num2; // Second digit of the count value
reg [3:0] num1; // First digit of the count value
wire clkin; // Clock input for internal logic
wire incr0; // Delayed increment signal

Freq_Div Freq_Div( // Frequency Divider instance
.clk(clk), // Input clock
.rst_n(rst), // Active-low reset
.clkout(clkin) // Output clock for internal logic
);

test u1( // Test module instance
.clk(clkin), // Input clock
.rst_n(rst), // Active-low reset
.data(incr), // Increment control input
.neg_edge(incr0) // Delayed increment signal
);

always @(posedge clkin or negedge rst)
begin
if (!rst)
flag <= 1'b0;
else
if (!start && stop)
flag <= 1'b1;
else if (start && !stop)
flag <= 1'b0;
else
flag <= flag;
end

always @(posedge clkin or negedge rst)
begin
if (!rst)
begin
num1 <= 4'd0;
num2 <= 4'd0;
end
else
begin
if (flag == 1)
begin
if (num1 == 4'd9)
begin
num1 <= 4'd0;
if (num2 == 4'd9)
num2 <= 4'd0;
else
num2 <= num2 + 1'b1;
end
else
begin
num1 <= num1 + 1'b1;
num2 <= num2;
end
end
else if (incr0 && flag == 0)
begin
if (num1 == 4'd9)
begin
num1 <= 4'd0;
if (num2 == 4'd9)
num2 <= 4'd0;
else
num2 <= num2 + 1'b1;
end
else
begin
num1 <= num1 + 1'b1;
num2 <= num2;
end
end
else
begin
num1 <= num1;
num2 <= num2;
end
end
end

LED1 LED1( // Seven-segment LED module instance
.seg_data_1(num2), // Input data for segment 1
.seg_data_2(num1), // Input data for segment 2
.seg_led_1(seg_out_1), // Output for segment 1
.seg_led_2(seg_out_2) // Output for segment 2
);

endmodule

分频器模块

Freq_Div.v

module Freq_Div(
input wire clk, // Clock input
input wire rst_n, // Active-low reset input
output wire clkout // Output clock at 10 Hz
);

reg [24:0] cnt; // Counter for frequency division
reg clk_10Hz; // 10 Hz clock signal

always @(posedge clk or negedge rst_n)
begin
if (!rst_n)
cnt <= 25'd0;
else
if (cnt == 1_200_000 - 1)
cnt <= 25'd0;
else
cnt <= cnt + 1'b1;
end

always @(posedge clk or negedge rst_n)
begin
if (!rst_n)
clk_10Hz <= 1'b0;
else
if (cnt >= 600_000 - 1)
clk_10Hz <= 1'b1;
else
clk_10Hz <= 1'b0;
end

assign clkout = clk_10Hz; // Assign 10 Hz clock signal to output
endmodule

LED数码管显示模块

Segement.v

module LED1 (
input [3:0] seg_data_1,
input [3:0] seg_data_2,
output [8:0] seg_led_1,
output [8:0] seg_led_2
);
reg [8:0] seg_2 [9:0];
reg [8:0] seg_1 [9:0];

initial
begin
seg_1[0] = 9'hbf; // Display digit 0 on 7-segment display
seg_1[1] = 9'h86; // Display digit 1 on 7-segment display
seg_1[2] = 9'hdb; // Display digit 2 on 7-segment display
seg_1[3] = 9'hcf; // Display digit 3 on 7-segment display
seg_1[4] = 9'he6; // Display digit 4 on 7-segment display
seg_1[5] = 9'hed; // Display digit 5 on 7-segment display
seg_1[6] = 9'hfd; // Display digit 6 on 7-segment display
seg_1[7] = 9'h87; // Display digit 7 on 7-segment display
seg_1[8] = 9'hff; // Display digit 8 on 7-segment display
seg_1[9] = 9'hef; // Display digit 9 on 7-segment display

seg_2[0] = 9'h3f; // Display digit 0 on 7-segment display
seg_2[1] = 9'h06; // Display digit 1 on 7-segment display
seg_2[2] = 9'h5b; // Display digit 2 on 7-segment display
seg_2[3] = 9'h4f; // Display digit 3 on 7-segment display
seg_2[4] = 9'h66; // Display digit 4 on 7-segment display
seg_2[5] = 9'h6d; // Display digit 5 on 7-segment display
seg_2[6] = 9'h7d; // Display digit 6 on 7-segment display
seg_2[7] = 9'h07; // Display digit 7 on 7-segment display
seg_2[8] = 9'h7f; // Display digit 8 on 7-segment display
seg_2[9] = 9'h6f; // Display digit 9 on 7-segment display
end

assign seg_led_1 = seg_1[seg_data_1];
assign seg_led_2 = seg_2[seg_data_2];
endmodule

按键下降沿检测模块

test.v

module test(
input clk,
input rst_n,
input data,
output neg_edge // Output for falling edge detection
);

reg [1:0] D; // 2-bit register for storing previous and current data

always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
D <= 2'b11; // Initialize to 11 when reset
end
else begin
D <= {D[0], data}; // Shift in new data, D[1] represents the previous state, D[0] represents the current state (new data)
end
end

// Combinational logic for edge detection
assign neg_edge = D[1] & ~D[0]; // Output is high when there is a falling edge

endmodule

六、仿真波形图

对顶层文件(Counter.v)模块进行仿真:

对分频器模块(Freq_Div.v)进行仿真:

对数码管显示模块(Segement.v)进行仿真:

对按键下降沿检测模块(test.v)进行仿真:

七、FPGA的资源利用说明

八、遇到的主要难题及解决方法

主要难题:

一开始在WebIDE上采用顶层文件(Top Module)控制数码管模块、按键下降沿检测模块、状态机模块和分频器模块(如图所示),发现状态机模块的输出管脚不能正确地将数据传到数码管模块的输入管脚,烧录后数码管一直维持在0.0s

解决方法:

放弃状态机的逻辑,使用简单的always块和条件语句编写计时逻辑,将Counter.v作为顶层文件,直接在Counter.v中编写计时器的逻辑代码并通过例化数码管模块输出,烧录后发现数码管正常显示

PS:在此项目中,我向chatGPT讨教了一下分频器的语法和用法问题

九、未来的计划或建议

首先要感谢电子森林平台,本次寒假练给我提供了一个入门FPGA的平台和机会,不仅仅让我学习了硬件描述语言(Verilog)的基本知识和逻辑设计的原理,同时也使我对数电逻辑的功能实现及设计流程有了深刻的理解,培养了我的工程化设计理念、规范化的设计流程及解决未知问题的能力,同时也使我具有了探索使用行业新工具在项目研发中存在的问题和解决方法的素养

此外,与行业新工具的接触让我意识到技术进步的速度之快,因此持续学习和不断更新对新工具的适应能力变得至关重要,在未来的学习中,我会学着尝试深入了解现代FPGA技术的发展趋势,例如高级综合(HLS)的应用、异构计算架构等。

最重要的是,这段经历不仅仅是对技术能力的提升,也是对我自身能力的锻炼,通过参与本次活动,我深刻体会到在数字电路设计中,每一个细节都可能对系统的功能和性能产生重大影响,通过规范化的设计流程,我学会了如何从概念到实现,从仿真验证到综合布局布线,全面掌握项目开发的各个环节。

最后,本次活动是我第一次接触FPGA这种设计,给了我很大的触动,也激起了我的兴趣,我会继续夯实我的数电模电知识基础,向更深的FPGA领域进行探索。

附件下载
archive (2).zip
ClockDivider.v
Counter.v
Segement1.v
test.v
团队介绍
个人
团队成员
谢庥泉
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号