2024年寒假练 - 基于Lattice MXO2的小脚丫FPGA核心板 实现秒表
该项目使用了Lattice MXO2的小脚丫FPGA核心板,实现了秒表的设计,它的主要功能为:启动、停止、复位、递增功能。
标签
FPGA
USB
参加活动
Astesia
更新2024-04-17
北京理工大学
49

2024年寒假练 - 基于小脚丫FPGA实现秒表

一、任务要求

(一)、任务名称

具有启动、停止、递增和清除功能的秒表


(二)、任务宗旨

  • 结合数字电路书本知识,深刻理解数字逻辑的功能实现及设计流程
  • 培养工程化设计理念、规范化的设计流程及解决未知问题的能力
  • 探索使用行业新工具在项目研发中存在的问题和解决方法


(三)、任务内容

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


二、需求分析

(一)、任务目标

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

 

(二)、实现方法

  • WebIDE环境下进行Verilog代码编程、综合、仿真、生成JED代码并下载到FPGA中进行验证;
  • 通过GPT等大模型来生成,进行验证、修改后整合在一起实现所需的功能


(三)、前置知识

FPGA:了解FPGA的基本概念和工作原理,包括可编程逻辑块(PLBs)、可编程连接(Interconnects)等。

Verilog:这是常用于FPGA设计的硬件描述语言(HDL)。需要了解如何使用它来描述数字电路和逻辑功能。

数字电路设计:理解数字电路的基础知识,比如逻辑门、寄存器、计数器等。秒表可以被视为一个计时器,需要理解如何设计这样的逻辑电路。

数码管原理:了解数码管的工作原理,包括共阳极和共阴极数码管的区别,以及如何驱动它们显示不同的数字。

按键输入:学习如何读取和处理来自按键的输入信号,比如检测按键的按下和松开。

状态机设计:秒表通常可以使用状态机来实现。需要了解状态机的概念,并且知道如何在Verilog中实现状态机。


三、功能框图

四、代码分析

(一)、分频器divider

/*-------------------------------------*/
// Module name : divide
// Author : STEP
// Description : 任意整数分频
// Web : www.stepfpga.com
/*-------------------------------------*/
module divide #
(
parameter WIDTH = 24, //计数器的位数,计数的最大值为 2**(WIDTH-1)
parameter N = 12_000_000 //分频系数,确保 N<2**(WIDTH-1)
)
(
input clk,
input rst,
output clkout
);
reg [WIDTH-1:0] cnt_p,cnt_n; //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器
reg clk_p,clk_n; //clk_p为上升沿触发时分频时钟,clk_n为下降沿触发时分频时钟

/**********上升沿触发部分**************************************/
//上升沿触发时计数器的控制
always @(posedge clk or negedge rst) begin
if(!rst)
cnt_p <= 1'b0;
else if(cnt_p == (N-1))
cnt_p <= 1'b0;
else
cnt_p <= cnt_p + 1'b1;
end
//上升沿触发的分频时钟输出
always @(posedge clk or negedge rst)
begin
if(!rst)
clk_p <= 1'b0;
else if(cnt_p < (N>>1))
clk_p <= 1'b0;
else
clk_p <= 1'b1;
end
/*****************下降沿触发部分**************************************/
//下降沿触发时计数器的控制
always @(negedge clk or negedge rst)
begin
if(!rst)
cnt_n <= 1'b0;
else if(cnt_n == (N-1))
cnt_n <= 1'b0;
else
cnt_n <= cnt_n + 1'b1;
end
//下降沿触发的分频时钟输出,和clk_p相差半个clk时钟
always @(negedge clk or negedge rst)
begin
if(!rst)
clk_n <= 1'b0;
else if(cnt_n < (N>>1))
clk_n <= 1'b0;
else
clk_n <= 1'b1; //得到的分频时钟正周期比负周期多一个clk时钟
end
/*************************************************************************/
wire clk1 = clk; //当N=1时,直接输出clk
wire clk2 = clk_p; //当N为偶数也就是N的最低位为0,N[0]=0,输出clk_p
wire clk3 = clk_p & clk_n; //当N为奇数也就是N最低位为1,N[0]=1,输出clk_p&clk_n。

assign clkout = (N==1)? clk1:(N[0]? clk3:clk2);
endmodule

在WEBIDE中,有现成的模块可以调用。该模块的功能为将FPGA自身的12MHz频率转化为其他频率,方便我们下一步使用。在本例中,需要转化为10Hz,故parameter N应为1200000,在逻辑综合模块实例化时覆写此参数。


(二)、显示控制模块display

module display(input1, input2, output1, output2);
input [3:0] input1;
input [3:0] input2;
output [8:0] output1;
output [8:0] output2;
//数组,用于转换输入与输出
reg [8:0] array1 [9:0];
reg [8:0] array2 [9:0];

initial
begin
//左边LED显示,且小数点常亮
array1[0] = 9'hbf;
array1[1] = 9'h86;
array1[2] = 9'hdb;
array1[3] = 9'hcf;
array1[4] = 9'he6;
array1[5] = 9'hed;
array1[6] = 9'hfd;
array1[7] = 9'h87;
array1[8] = 9'hff;
array1[9] = 9'hef;

//右边LED显示,且小数点长灭
array2[0] = 9'h3f; // 0
array2[1] = 9'h06; // 1
array2[2] = 9'h5b; // 2
array2[3] = 9'h4f; // 3
array2[4] = 9'h66; // 4
array2[5] = 9'h6d; // 5
array2[6] = 9'h7d; // 6
array2[7] = 9'h07; // 7
array2[8] = 9'h7f; // 8
array2[9] = 9'h6f; // 9
end

//查表
assign output1 = array1[input1];
assign output2 = array2[input2];

endmodule

该模块的设计思路为:设计两个逻辑表(需要两个是因为实际需求,个位LED小数点需要常亮,而十分位LED小数点需要常灭,造成了两个LED逻辑表不同),传入需要显示的数字(十进制),输出控制信号(二进制)。


(三)、逻辑模块stopwatch

module stopwatch(clk, start, stop, reset, increase, output_led1, output_led2);
input clk, start, stop, reset, increase;
output [8:0] output_led1;
output [8:0] output_led2;
reg [3:0] data1;
reg [3:0] data2;
reg run_status;
reg increase_flag;

initial
begin
data1 = 4'd0;
data2 = 4'd0;
run_status = 0;
increase_flag = 0;
end

//显示模块实例化
display display_instance(
.input1(data1),
.input2(data2),
.output1(output_led1),
.output2(output_led2)
);

//分频模块实例化,分出10Hz的频
wire clk_100ms;
divide #(
.WIDTH(24),
.N(1200000))u0(
.clk(clk),
.rst(reset),
.clkout(clk_100ms));

always @(posedge clk_100ms or negedge reset)
begin
if(reset == 0)
begin
run_status <= 1'd0;
data1 <= 4'd0;
data2 <= 4'd0;
increase_flag <= 0;
end
else
begin
if(stop == 0 && run_status == 1)
begin
run_status <= 1'd0;
end

if(start == 0 && run_status == 0)
begin
run_status <= 1'd1;
end

//增量逻辑
if(!increase && run_status == 0)
begin
if(increase_flag != 1)
begin
increase_flag <= 1;
//十分位0-8时,仅十分位递增1
if(data2 != 4'd9)
begin
data2 <= data2 + 4'd1;
end

//十分位为9时
else
begin
if(data1 == 4'd9)
begin
data2 <= 4'd0;
data1 <= 4'd0;
end
else
begin
data2 <= 4'd0;
data1 <= data1 + 4'd1;
end
end
end
end

//当increase没有被持续按下时,刷新flag
else
begin
increase_flag <= 0;
end

//标准走时逻辑
if(run_status == 1)
begin
//十分位为9时的特殊情况
if(data2 == 4'd9)
begin
//到达9.9后,循环秒表
if(data1 == 4'd9)
begin
data2 <= 4'd0;
data1 <= 4'd0;
end
//十分位为9且个位不为9时,十分位变0,个位+1
else
begin
data2 <= 4'd0;
data1 <= data1 + 4'd1;
end
end
//其他情况,仅十分位递增1
else
begin
data2 <= data2 + 4'd1;
end
end
end
end

endmodule

该模块接受来自用户的按键输入,并将分频器和显示模块实例化,根据项目的要求实现逻辑。


五、FPGA的资源利用说明

Design Summary:
Number of registers: 35 out of 4635 (1%)
PFU registers: 35 out of 4320 (1%)
PIO registers: 0 out of 315 (0%)
Number of SLICEs: 37 out of 2160 (2%)
SLICEs as Logic/ROM: 37 out of 2160 (2%)
SLICEs as RAM: 0 out of 1620 (0%)
SLICEs as Carry: 13 out of 2160 (1%)
Number of LUT4s: 74 out of 4320 (2%)
Number used as logic LUTs: 48
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%)


六、遇到的问题及解决方案

(一)、阻塞赋值与非阻塞赋值

在项目中,需要认真考虑使用阻塞与非阻塞赋值中的哪一种,否则有可能导致程序逻辑错误

解决方案:

阻塞赋值使用单个等号(=)来进行赋值操作。当执行阻塞赋值时,Verilog 将按照顺序执行,每次只执行一个阻塞赋值,然后继续执行下一个语句。这意味着在阻塞赋值的语句执行完毕之前,后续的语句将会被阻塞。

非阻塞赋值使用双等号(<=)来进行赋值操作。它们允许在一个时钟周期内同时进行多个赋值,而不受执行顺序的影响。非阻塞赋值在时序逻辑中经常用于描述寄存器的行为,因为它们可以模拟时钟的行为,所有赋值操作在一个时钟周期内同时生效。


(二)、数据长度不匹配造成溢出或不足

在编写程序传递参数或变量时,长度不匹配会造成程序报错或板卡运行异常

解决方案:

参数传递时仔细核对传入与传出的位数是否匹配。


(三)、特殊功能实现

在本次项目中,需要实现一个特殊功能:当长按增量键时,秒表只能增长0.1,不能持续增长。

解决方案:

使用一个变量用来记录上个周期增量键是否被按下,如果按下则这周期增量键再被激活时不进入增量逻辑循环。若不是则刷新该变量。

附件下载
FPGA_ver3.0.rar
团队介绍
单人参加:何贝格,北京理工大学
团队成员
Astesia
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号