2024年寒假练 - 基于Lattice MXO2的小脚丫FPGA核心板制作具有启动、停止、递增和清除功能的秒表
该项目使用了WebIDE平台、Verilog HDL语言,实现了秒表的设计,它的主要功能为:启动和停止计时,递增和复位。
标签
FPGA
小脚丫
核心板
Verilog HDL
USB Type C
WebIDE
Glass
更新2024-03-29
华北电力大学
418

1.项目需求

通过小脚丫FPGA核心板上的2个数码管和轻触按键制作一个秒表,通过按键来控制秒表的功能,并在数码管上显示数值。

使用七段显示器作为输出设备,在小脚丫FPGA核心板上创建一个2位数秒表。 秒表应从 0.0 秒计数到 9.9秒,然后翻转,计数值每0.1秒精确更新一次。

秒表使用四个按钮输入:开始、停止、增量和清除(重置)。 开始输入使秒表开始以10Hz时钟速率递增(即每0.1秒计数一次); 停止输入使计数器停止递增,但使数码管显示当前计数器值; 每次按下按钮时,增量输入都会导致显示值增加一次,无论按住增量按钮多长时间; 复位/清除输入强制计数器值为零。


2.需求分析

2.1时钟频率

image.png

根据原理图,确认CLK时钟信号输入脚以及信号频率12MHz。而我们的秒表递增的速率为10Hz(即每0.1s计数一次),我们设置一个寄存器变量cnt进行计数,通过cnt的赋值,来实现10Hz的频率。

2.2数码管


image.png

由原理图可知,核心板上的两个数码管均为共阴极数码管,每个数码管共有9位输入信号,分别是DIG、DP、A、B、C、D、E、F、G。我们可以根据要显示的内容,如0~9,提前设置位宽为9,深度为10的寄存器变量。要注意的是,两个数码管的配合,以及小数点的使用。

2.3按键

image.png

四个按键,先分析原理图,按键输入默认高电平,按下按键输入低电平。

然后分析功能:开始按键,按下开始计数,且再次按下,计数状态不变,增量按键不影响常规计数状态,只有按下停止或者复位按键,才改变常规的计数的状态;停止按键,按下停止计数,数码管状态不变,再次按下增量键显示数字递增0.1,按下开始键继续计时,按下复位键,复位;增量按键,按下时,在其他三个按键的状态下,都能够递增0.1s,再根据题目要求,无论按多久,按下一次只递增一次;复位按键,按下数字清零,按下开始按键,会再次计数,按下增量键,递增0.1s。

分析功能,有助于后续对按键标志位的形式以及切换状态的条件判断的书写。


3.实现方式

3.1时钟频率

已知时钟频率为12MHz,秒表频率为10Hz,设置一个reg变量(cnt),通过对时钟信号的上升沿检测,当按键条件允许计数时,对cnt加1。由此可知,当cnt变量达到1_200_000 - 1时,此时经过0.1s(),然后更新数码管显示。


3.2数码管

提前设置好十个reg变量,存储数码管显示0~9时,信号脚的信号数组。这里我是设置了一个深度为2的reg变量(num)存储数码管显示的数字,一个十位,一个个位,然后模拟十进制两位数的进位。


3.3按键

根据按键的功能,及按键触发功能的不同,设置了两个reg变量存储按键状态。首先是key_flag存储开始、停止、复位按键状态,这些键按下之后切换状态,如果重复按下则保持不变。然后是key_3_flag存储增量按钮的状态,当增量按钮按下时,产生一个时钟周期的高电平脉冲,除非松开再次按下,否则不再产生新的高电平脉冲。此外,还增加了一个按键消抖的功能。


4.功能框图

image.png


5.代码及说明

5.1输入信号、输出信号
input wire sys_clk,                       // System clock input
input wire key_1, // Input for key 1
input wire key_2, // Input for key 2
input wire key_3, // Input for key 3
input wire key_4, // Input for key 4

output wire [8:0] seg_led_1, // Output for segment LED 1
output wire [8:0] seg_led_2 // Output for segment LED 2

时钟信号,sys_clk;四个按键,key_1,key_2,key_3,key_4;数码管的信号,用组合逻辑,assign语句赋值,所以是wire类型,seg_led_1,seg_led_2。


5.2数码管0~9信号
reg [8:0] seg [9:0];                          // Array to store segment data for each digit

// Initial block to initialize segment data and digit values
initial
begin
seg[0] = 9'h3f; // 7-segment display for digit 0
seg[1] = 9'h06; // 7-segment display for digit 1
seg[2] = 9'h5b; // 7-segment display for digit 2
seg[3] = 9'h4f; // 7-segment display for digit 3
seg[4] = 9'h66; // 7-segment display for digit 4
seg[5] = 9'h6d; // 7-segment display for digit 5
seg[6] = 9'h7d; // 7-segment display for digit 6
seg[7] = 9'h07; // 7-segment display for digit 7
seg[8] = 9'h7f; // 7-segment display for digit 8
seg[9] = 9'h6f; // 7-segment display for digit 9
num[0] = 4'd0; // Initialize the first digit value to 0
num[1] = 4'd0; // Initialize the second digit value to 0
end

因为数码管有9个信号脚,0~9有十个数字,所以设置一个位宽为9,深度为10的reg变量,seg。根据原理图(详见2.2),用initial语句,将seg变量提前赋值。


5.3按键消抖
reg [3:0] key_flag = 3'd4;                    // Flag for key state
reg key_3_flag; // Flag for key 3 state

parameter CNT_20MS_MAX = 18'd239_999
reg [17:0] cnt_20ms; // Counter for 20ms intervals

// Always block to handle 20ms intervals and update key flags
always @(posedge sys_clk)
if((key_1 == 1'b1) && (key_2 == 1'b1) && (key_3 == 1'b1) && (key_4 == 1'b1))
cnt_20ms <= 18'd0;
else if(cnt_20ms == CNT_20MS_MAX)
cnt_20ms <= CNT_20MS_MAX;
else
cnt_20ms <= cnt_20ms + 18'd1;

always @(posedge sys_clk)
if(cnt_20ms == (CNT_20MS_MAX - 18'd1))
if(key_1 == 1'b0) // Key 1: Start
key_flag <= 3'd1;
else if(key_2 == 1'b0) // Key 2: Stop
key_flag <= 3'd2;
else if(key_3 == 1'b0) // Key 3: Increment
begin
key_3_flag <= 1'b1;
if(key_flag == 3'd4)
key_flag <= 3'd2;
else
key_flag <= key_flag;
end
else if(key_4 == 1'b0) // Key 4: Reset
key_flag <= 3'd4;
else
begin
key_flag <= key_flag;
key_3_flag <= 1'b0;
end
else
begin
key_flag <= key_flag;
key_3_flag <= 1'b0;
end

第一个时序逻辑,首先利用计数器原理,设置CNT_20MS_MAX参数和cnt_20ms的reg变量,作为20ms按键消抖的标志,在时钟信号的上升沿,判断,当按键未按下时,将cnt_20ms赋值为0;当cnt_20ms到达20ms计数值时,cnt_20ms值保持不变;除此之外(也就是按键按下时),cnt_20ms变量递增。

第二个时序逻辑,当cnt_20ms值为CNT_20MS_MAX - 1时,判断是否有按键按下,此时,相应的按键标志都会被触发,但因为是非阻塞赋值,所以在cnt_20ms为

CNT_20MS_MAX时,也就是按键按下20ms时,按键标志才会被真正使用。

在第二个时序逻辑中,根据对按键功能的分析(见2.3和3.3),当开始、停止、复位按键按下时,key_flag进行更新,若不再按下时,不进行更新(将自己的值赋给自己),所以key_flag可以简单理解为秒表的状态。当增量按键按下时,key_3_flag会产生一个时钟周期的高电平脉冲,然后恢复低电平,相当于一次触发事件,而由于我们按键标志更新的条件为cnt_20ms == (CNT_20MS_MAX - 1),所以一次有效的按键按下,只会更新一次按键标志。并且增量按键按下时,对不同状态做了不同处理,当状态为复位状态时,调整为停止状态,否则会一直进行复位操作。除此之位,都将key_3_flag保持低电平,key_flag值保持不变。


5.4按键+数码管数字
reg [20:0] cnt = 21'd0;                        // Counter for system clock ticks
reg [3:0] num [1:0]; // Array to store current digit values

parameter CNT_100MS_MAX = 21'd1_199_999, // Maximum count for 0.1 second

// Always block to handle counting based on system clock ticks
always @(posedge sys_clk)
if((cnt == CNT_100MS_MAX) || (key_flag == 3'd4))
cnt <= 21'd0;
else if(key_flag == 3'd1)
cnt <= cnt + 21'd1;
else
cnt <= cnt;

// Always block to update digit values based on key presses
always @(posedge sys_clk)
if(((cnt == CNT_100MS_MAX) || (key_3_flag == 1'b1)) && (num[1] != 9))
begin
num[1] <= num[1] + 4'd1;
num[0] <= num[0];
end
else if(((cnt == CNT_100MS_MAX) || (key_3_flag == 1'b1)) && (num[1] == 9) && (num[0] != 9))
begin
num[1] <= 4'd0;
num[0] <= num[0] + 4'd1;
end
else if((((cnt == CNT_100MS_MAX) || (key_3_flag == 1'b1)) && (num[1] == 9) && (num[0] == 9)) || (key_flag == 3'd4))
begin
num[1] <= 4'd0;
num[0] <= 4'd0;
end
else
begin
num[1] <= num[1];
num[0] <= num[0];
end

第一个时序逻辑,同样利用计数器原理,设置CNT_100MS_MAX参数和cnt的reg变量,给秒表提供10Hz(0.1s)的频率。开始、复位、停止,三个状态之间只能相互打断,而之前的设置,当增量按键按下后,会将复位状态变为停止状态,所以我们如下设置:当cnt计数到最大值(即经过0.1s时)或者复位状态时,cnt清0;当开始按键按下后时,cnt保持递增状态。除此之外,cnt都保持不变。

第二个时序逻辑,首先介绍一下深度为2的reg变量num,num[0]存储个位数字,num[1]存储一位小数数字。是key_3_flag产生作用的情况,因为key_3_flag只产生一个时钟周期的高电平信号,所以第二个时序逻辑中的数字变化只会变化一次。当cnt计数达到最大值或者增量按键按下时,num[1]会加1,并且配合进位规则(小数位为9时,个位+1;两数为99时,两数更新为00)。其中当复位按键按下时,两数也会更新为00。除此之外,均不更新两数数值。


5.5数码管信号
// Assign statements to drive segment LED outputs with the corresponding digit values
assign seg_led_1 = seg[num[0]] + POINT;
assign seg_led_2 = seg[num[1]];

parameter POINT = 9'h80, // Decimal point value for the display

应用组合逻辑,更新变量类型为wire的两个代表数码管信号的变量seg_led_1、seg_led_2,其中由于秒表的特点,第一个数码管的小数点需要保持显示,所以加上一个POINT参数,代表拉高小数点(DP)引脚电平。


6.仿真波形图

这里由于WebIDE仿真只有1600ns的界面,我就采用ModelSim仿真。

6.1按键消抖和开始功能

image.png


6.2循环计数

image.png


6.3增量功能

image.png


6.4停止和复位功能

image.png


7.FPGA的资源利用说明

资源占用.png


8.演示视频



附件下载
implement.jed
该jed文件可直接烧录到小脚丫FPGQ核心板
clock.v
项目.v顶层设计文件
clock_tb.v
项目.v仿真文件
团队介绍
华北电力大学 电气与电子信息工程学院 电子信息工程 王亚楠
团队成员
Glass
和自己相比,有进步吗?
评论
0 / 100
查看更多
猜你喜欢
2024年寒假练 - 基于Lattice MXO2的小脚丫FPGA核心板制作具有启动、停止、递增和清除功能的秒表该项目使用了Lattice MXO2的小脚丫FPGA核心板,实现了具有启动、停止、递增和清除功能的秒表的设计,它的主要功能为:使用七段显示器作为输出设备,在小脚丫FPGA核心板上创建一个2位数秒表。 秒表应从 0.0 秒计数到 9.9秒,然后翻转,计数值每0.1秒精确更新一次。。
Ling_da_jin
175
2024年寒假练 - 基于Lattice MXO2的小脚丫FPGA核心板制作具有启动、停止、递增和清除功能的秒表该项目使用了基于Lattice MXO2的小脚丫FPGA核心板,实现了具有启动、停止、递增和清除功能的秒表的设计,它的主要功能为:使用七段显示器作为输出设备,在小脚丫FPGA核心板上创建一个2位数秒表。 秒表应从 0.0 秒计数到 9.9秒,然后翻转,计数值每0.1秒精确更新一次。 秒表使用四个按钮输入:开始、停止、增量和清除(重置)。 开始输入使秒表开始以10Hz时钟速率递增(即每0.1秒计数一次); 停止输入使计数器停止递增,但使数码管显示当前计数器值; 每次按下按钮时,增量输入都会导致显示值增加一次,无论按住增量按钮多长时间; 复位/清除输入强制计数器值为零。。
电小麦
317
2024寒假练——基于Lattice MXO2的小脚丫FPGA核心板制作具有启动、停止、递增和清除功能的秒表该项目使用了Lattice MXO2的小脚丫FPGA核心板,基于stepfpga网页版编译器,实现了具有启动、停止、递增和清除功能的秒表的设计,它的主要功能为:创建一个2位数码管秒表 ,秒表从 0.0 秒计数到 9.9秒,然后翻转,计数值每0.1秒精确更新一次,通过按键可以控制开始、停止,递增和清零。。
MSCu
311
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号