具有启动、停止、递增和清除功能的秒表
一、项目需求
在本次在硬禾科技2024寒假在家一起练活动中,我选择了平台1-基于Lattice MXO2的小脚丫FPGA核心板 - Type C接口中的任务1,具有启动、停止、递增和清除功能的秒表。该任务要求通过小脚丫FPGA核心板上的2个数码管和轻触按键制作一个秒表,通过按键来控制秒表的功能,并在数码管上显示数值。使用七段显示器作为输出设备,在小脚丫FPGA核心板上创建一个2位数秒表。 秒表应从 0.0 秒计数到 9.9秒,然后翻转,计数值每0.1秒精确更新一次。秒表使用四个按钮输入:开始、停止、增量和清除(重置)。 开始输入使秒表开始以10Hz时钟速率递增(即每0.1秒计数一次); 停止输入使计数器停止递增,但使数码管显示当前计数器值; 每次按下按钮时,增量输入都会导致显示值增加一次,无论按住增量按钮多长时间; 复位/清除输入强制计数器值为零。
二、需求分析
小脚丫FPGA核心板上有两个七段数码管,两个RGB三色灯,8个单色LED灯,4个拨动开关,4个轻触按键。我们可以让4个轻触按键分别作为开始、停止、增量和清除键,而两个七段数码管显示时间。可以在按下按键时改变相应的设置,在时钟上升沿时计数,时间到0.1秒时根据相应设置改变数码管要显示的数字,并将这个数字和七段数码管哪一段亮对应起来。
三、实现的方式
实现可以利用ChatGPT编写一个初步的代码,修改其中的错误和本项目要求的具体操作,然后利用平台为我们提供的stepfpga平台运行代码,查看在fpga上的效果,并用同样的方式完成仿真文件的编写,查看仿真结果。
四、功能框图
五、代码说明
首先设置相关变量,有时钟信号和用于记录0.1秒时间的键,4个要求的按键,显示的数码管的数值和控制值,以及启动标志和增量标志。
module miaobiao(
input clock, //时钟
input start, //启动键
input pause, //停止键
input increase, //增量键
input reset, //复位键
output reg [8:0] seg_led_1, //显示整数秒数的数码管
output reg [8:0] seg_led_2 //显示小数秒数的数码管
);
reg [23:0] counter= 24'd0; //时钟计数
reg start_flag = 1'b0; //启动标志
reg increase_flag = 1'b0; //增量标志
reg [3:0] seg_data_1 = 4'd0; //整数秒数值
reg [3:0] seg_data_2 = 4'd0; //小数秒数值
然后当按下启动键后启动标志设为1,按下停止键后设为0:
always @(negedge start or negedge pause) begin //当按下启动键或停止键后设置启动标志
if (start == 1'b0) begin
start_flag <= 1'b1;
end else begin
start_flag <= 1'b0;
end
end
然后若按下复位键则数码管值和计数值置0,若按下增量键则增量标志置1,然后考虑启动标志,若为1则说明需要开始计数,所以开始计数,当时钟信号上升沿触发1200000次后就过了0.1秒,需要改变数码管的显示,改变时先增加小数的值增加1,若小数为9时进位,整数值加1,若整数值也为9后小数整数值全部变回0。若启动标志为0则考虑增量标志,若增量标志为1,则用同样的方法改变数码管对应的值,两种情况下每改变一次数字就将增量标志置0,以避免增量操作重复触发。
always @(posedge clock or negedge reset or negedge increase) begin
if (reset == 1'b0) begin //若按下复位键则复位
counter <= 24'd0;
seg_data_1 <= 4'd0;
seg_data_2 <= 4'd0;
end else begin
if (increase == 1'b0) begin //若按下增量键则令增量标志为1
increase_flag <= 1'b1;
end else begin //时钟上升沿
if (start_flag == 1'b1) begin //若启动标志为1则开始计数
increase_flag <= 1'b0; //令增量键按一次只触发一次
if (counter == 24'd1200000) begin //0.1秒钟改变一次计数
counter <= 24'd0;
seg_data_2 <= seg_data_2 + 4'd1; // 统计小数位数
if (seg_data_2 == 4'd9) begin
seg_data_2 <= 4'd0;
seg_data_1 <= seg_data_1 + 4'd1; // 统计整数位数
if (seg_data_1 == 4'd9) begin
seg_data_2 <= 4'd0; // 归零
seg_data_1 <= 4'd0;
end
end
end else begin
counter <= counter + 24'd1;
end
end else begin //启动标志为0时考虑是否有增量
if (increase_flag == 1'b1) begin
increase_flag <= 1'b0;
seg_data_2 <= seg_data_2 + 4'd1; // 统计个位数
if (seg_data_2 == 4'd9) begin
seg_data_2 <= 4'd0;
seg_data_1 <= seg_data_1 + 4'd1; // 统计十位数
if (seg_data_1 == 4'd9) begin
seg_data_2 <= 4'd0; // 归零
seg_data_1 <= 4'd0;
end
end
end
end
end
end
end
最后让两个七段数码管显示对应的数字,两个数码管有区别的是显示整数的数码管需点亮小数点,而小数的则不点亮。
always @(*) begin //让两块七段数码管显示对应的数字
case (seg_data_1)
4'd0: seg_led_1 = 9'hbf; //显示整数秒数的数码管且点亮小数点
4'd1: seg_led_1 = 9'h86;
4'd2: seg_led_1 = 9'hdb;
4'd3: seg_led_1 = 9'hcf;
4'd4: seg_led_1 = 9'he6;
4'd5: seg_led_1 = 9'hed;
4'd6: seg_led_1 = 9'hfd;
4'd7: seg_led_1 = 9'h87;
4'd8: seg_led_1 = 9'hff;
4'd9: seg_led_1 = 9'hef;
endcase
end
always @(*) begin
case (seg_data_2)
4'd0: seg_led_2 = 9'h3f; //显示小数秒数的数码管且不点亮小数点
4'd1: seg_led_2 = 9'h06;
4'd2: seg_led_2 = 9'h5b;
4'd3: seg_led_2 = 9'h4f;
4'd4: seg_led_2 = 9'h66;
4'd5: seg_led_2 = 9'h6d;
4'd6: seg_led_2 = 9'h7d;
4'd7: seg_led_2 = 9'h07;
4'd8: seg_led_2 = 9'h7f;
4'd9: seg_led_2 = 9'h6f;
endcase
end
endmodule
在编写代码的过程中我利用了ChatGPT辅助我的编写,ChatGPT让我快速了解了verilog语言的编写方式且明白了该秒表项目如何实现,但是ChatGPT所编写的代码仍有一些错误,比如:
output wire [6:0] seg,
output reg dp
ChatGPT只编写了一个数码管的显示,且小数点单独作为1个变量,我将其改为两个数码管,且小数点的显示也并入到数码管的显示中。
又比如:
if (counter >= 250_000) begin // 每0.1秒计数一次
counter <= 0;
ones <= ones + 1;
if (ones == 10) begin // 个位数满10进位
ones <= 0;
tens <= tens + 1;
if (tens == 10) begin // 十位数满10清零
tens <= 0;
end
end
end
ChatGPT并不是9进位而是10进位,10进位的方式符合此前我们学过的其它编程语言的逻辑,但在仿真过程中我发现这些的数值可能并不是执行完一行代码后就发生改变,而是执行完整个模块的代码后再改变,所以进为时并不是先变为10再进位,而是需要进位时这个值是9,所以进位。
又比如ChatGPT的代码没有让增量按键只触发一次,而是每次时钟上升沿时,若增量键处于按下的状态时都能方生改变,因此我引入了增量标志,每次数值发生改变后就让增量标志置0。
在仿真文件的编写中令每过一段时间就分别按下开始,停止,增量,复位键
且为了方便仿真显示,我原本代码中的0.1秒改变一次数值变为时钟沿上升10次就改变
initial
begin
clock = 1'b0; //初始化时钟为低电平
start = 1'b1; //初始化启动键为高电平
pause = 1'b1; //初始化停止键为高电平
increase = 1'b1; //初始化增量键为高电平
reset = 1'b1; //初始化复位键为高电平
repeat (10) begin
#1 clock = ~clock;
end
#1 start = 1'b0; //过一段时间后按下启动键
clock = ~clock;
#1 start = 1'b1;
clock = ~clock;
repeat (3000) begin
#1 clock = ~clock;
end
#1 pause = 1'b0; //过一段时间后按下停止键
clock = ~clock;
#1 pause = 1'b1;
clock = ~clock;
repeat (100) begin
#1 clock = ~clock;
end
#1 increase = 1'b0; //过一段时间后按下增量键
clock = ~clock;
#1 increase = 1'b1;
clock = ~clock;
repeat (10) begin
#1 clock = ~clock;
end
#1 reset = 1'b0; //过一段时间后按下复位键
clock = ~clock;
#1 reset = 1'b1;
clock = ~clock;
$finish;
end
ChatGPT的仿真代码中也有一些错误,如:
//按下停止键
#5 pause = 1'b0;
按下相应的键后它没有恢复该键原本的值,且此时时钟停止了变化。
六、仿真波形图
可以看到开始时显示0.0,按下启动键后启动标志置1,couter开始计数
counter计数到10的时候数码管小数值变为1,且之后变为2、3……且对应的对数码管的控制值也发生改变
数码管小数值为9后小数变为0,整数变为1
数码管数值达到9.9秒后又变回0.0秒
按下停止键后couter停止计数,数码管数值也不再发生变化
按下增量键后数码管数值增加了0.1秒,按下复位键后数码管数值归0
七、FPGA资源利用说明