2024年寒假练 -基于Lattice MXO2的小脚丫FPGA核心板 -具有启动、停止、递增和清除功能的秒表
该项目使用了Lattice MXO2的小脚丫FPGA核心板,实现了具有启动、停止、递增和清除功能的秒表的设计,它的主要功能为:通过小脚丫FPGA核心板上的2个数码管和轻触按键制作一个秒表,通过按键来控制秒表的功能,并在数码管上显示数值。使用七段显示器作为输出设备,在小脚丫FPGA核心板上创建一个2位数秒表。 秒表应从 0.0 秒计数到 9.9秒,然后翻转,计数值每0.1秒精确更新一次。 秒表使用四个按钮输入:开始、停止、增量和清除(重置)。 开始输入使秒表开始以10Hz时钟速率递增(即每0.1秒计数一次); 停止输入使计数器停止递增,但使数码管显示当前计数器值; 每次按下按钮时,增量输入都会导致显示值增加一次,无论按住增量按钮多长时间; 复位/清除输入强制计数器值为零。。
标签
FPGA
数字逻辑
zzkuner
更新2024-04-01
237

项目需求

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

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

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

需求分析

首先为了实现每0.1秒精确更新一次秒表,那么就需要一个模块 把12Mhz的时钟通过计数分频到10hz;

其次要让两位七段数码管正确显示,需要编写模块,可以通过传入数据直接显示对应的段码。

然后编写按键的模块代码,实现上升沿检测和消抖检测。

最后通过按键的键值,可以实现秒表的功能。

实现的方式

0.1秒精确计数

将12MHz的时钟分频到10Hz可以通过一个计数器实现。由于目标频率是10Hz,而源频率是12MHz,所以计数器需要计数1,200,000个周期(12MHz / 10Hz = 120,000,但因为每个上升沿都会触发一次,所以实际计数为240,000的一半,即1,200,000)。

这个模块使用了一个26位的寄存器counter来计数12MHz时钟的周期。当计数器达到1,199,999时,它会被重置,并且10Hz的输出时钟会被切换状态。由于输出时钟是从0到1再到0进行切换的,因此它的频率是输入时钟频率的1/1,200,000,即10Hz。

七段数码管显示

当驱动共阴七段数码管时,需要确保当对应的段需要点亮时,输出到该段的信号是高电平。Verilog代码可以通过简单的逻辑来实现这一点。以下是一个简单的Verilog模块,它接受一个4位BCD(二进制编码的十进制)输入,并产生一个7位输出,用于驱动共阴七段数码管显示对应的数字。

首先,需要定义七段数码管的段,通常这些段标记为A、B、C、D、E、F和G。共阴数码管要求当对应的段为高电平时,该段点亮。

在这个模块中,我使用了一个case语句来根据BCD输入选择正确的七段数码管显示编码。每个编码对应一个数字,且都是高电平有效(因为是共阴数码管)。

按键上升沿检测

每个时钟周期检查按钮信号是否从低电平变为高电平,并通过button_rising_edge信号报告结果。可以实现去抖动按钮输入,因为用户可以多次快速按下和释放按钮,而上升沿检测只会在按钮真正开始被按下的瞬间触发一次。

功能框图

代码及说明

0.1秒精确计数

module frequency_divider (
   input wire clk_12mhz, // 12MHz clock input
   output reg clk_out // Divided clock output (10Hz)
);
   reg [25:0] counter; // 26-bit counter

   always @(posedge clk_12mhz) begin
       if (counter == 1200000) // When the counter reaches 1200000 (equivalent to 10Hz)
           begin
               counter <= 0; // Reset the counter
               clk_out <= 1; // Toggle the output clock
           end
       else
           begin
               counter <= counter + 1; // Increment the counter
               clk_out <= 0; // Toggle the output clock
           end
   end
endmodule

代码说明

这段代码定义了一个名为frequency_divider的Verilog模块,用于将12MHz的输入时钟分频至10Hz的输出时钟。

输入与输出

  • clk_12mhz:输入信号,一个12MHz的时钟信号。
  • clk_out:输出信号,一个分频后的时钟信号,频率为10Hz。

内部变量

  • counter:一个26位的寄存器,用作计数器,以跟踪时钟周期的数量。

功能描述

  • clk_12mhz的上升沿发生时,always块会被触发。
  • 在每个上升沿,counter会递增。
  • 如果counter达到1,200,000(12MHz除以10Hz的结果),则counter会被重置为0,并且clk_out的值会被切换(toggle)。
  • 如果counter没有达到1,200,000,则counter继续递增,并且clk_out的值会被设置为0。

工作原理

由于clk_12mhz的频率是12MHz,这意味着每秒钟有12,000,000个上升沿。通过将计数器设置为1,200,000,我们可以确保每秒钟clk_out切换10次,从而生成一个10Hz的时钟信号。

总结

这个模块是一个简单的频率分频器,它接受一个12MHz的输入时钟,并输出一个10Hz的时钟信号。它使用了一个26位的计数器来跟踪输入时钟的周期,并在计数达到1,200,000时切换输出时钟的状态。这种分频器在数字电路设计中很常见,用于生成不同频率的时钟信号,以满足系统中不同组件的需求。


大模型生成截图:

七段数码管显示

module LED (  
   seg_data_1,  // 4-bit input for segment data for the first LED  
   seg_data_2,  // 4-bit input for segment data for the second LED  
   clk_12mhz,   // 12 MHz clock input  
   seg_led_1,   // 8-bit output for the segments of the first LED  
   seg_led_2,   // 8-bit output for the segments of the second LED  
   seg_dig      // 2-bit output indicating which LED is active (0 for LED 1, 1 for LED 2)  
);  
 
   input  [3:0] seg_data_1;  // 4-bit input for the first LED's segment data  
   input  [3:0] seg_data_2;  // 4-bit input for the second LED's segment data  
   input  clk_12mhz;         // Clock signal at 12 MHz  
   output reg[7:0] seg_led_1; // 8-bit output for controlling the segments of the first LED  
   output reg[7:0] seg_led_2; // 8-bit output for controlling the segments of the second LED  
   output [1:0] seg_dig;     // 2-bit output indicating the active LED (0 for LED 1, 1 for LED 2)  
 
   always @(posedge clk_12mhz) begin  
       // Decode the seg_data_1 to control the segments of the first LED  
       case(seg_data_1)  
           4'b0000: seg_led_1 <= 8'b1011_1111;  // Display 0 on the first LED  
           4'b0001: seg_led_1 <= 8'b1000_0110;  // Display 1 on the first LED  
           4'b0010: seg_led_1 <= 8'b1101_1011;  // Display 2 on the first LED  
           4'b0011: seg_led_1 <= 8'b1100_1111;  // Display 3 on the first LED  
           4'b0100: seg_led_1 <= 8'b1110_0110;  // Display 4 on the first LED  
           4'b0101: seg_led_1 <= 8'b1110_1101;  // Display 5 on the first LED  
           4'b0110: seg_led_1 <= 8'b1111_1101;  // Display 6 on the first LED  
           4'b0111: seg_led_1 <= 8'b1000_0111;  // Display 7 on the first LED  
           4'b1000: seg_led_1 <= 8'b1111_1111;  // Display 8 on the first LED  
           4'b1001: seg_led_1 <= 8'b1110_1111;  // Display 9 on the first LED  
           default: seg_led_1 <= 8'b1000_0000;  // Display blank or an invalid number on the first LED  
       endcase  
       // Decode the seg_data_2 to control the segments of the second LED  
       case(seg_data_2)  
           4'b0000: seg_led_2 <= 8'b0011_1111;  // Display 0 on the second LED  
           4'b0001: seg_led_2 <= 8'b0000_0110;  // Display 1 on the second LED  
           4'b0010: seg_led_2 <= 8'b0101_1011;  // Display 2 on the second LED  
           4'b0011: seg_led_2 <= 8'b0100_1111;  // Display 3 on the second LED  

           4'b0100 : seg_led_2 <= 8'b0110_0110;// Display 4 on the second LED
           4'b0101: seg_led_2 <= 8'b0110_1101; // Display 5 on the second LED
           4'b0110: seg_led_2 <= 8'b0111_1101; // Display 6 on the second LED
           4'b0111: seg_led_2 <= 8'b0000_0111; // Display 7 on the second LED
           4'b1000: seg_led_2 <= 8'b0111_1111; // Display 8 on the second LED
           4'b1001: seg_led_2 <= 8'b0110_1111; // Display 9 on the second LED
           default: seg_led_2 <= 8'b0000_0000; // Display blank or an invalid number on the second LED
       endcase
   end
endmodule

代码说明

这段Verilog模块,用于控制两个7段数码管LED的显示。该模块根据输入的4位二进制数字来显示相应的数字。

输入与输出

  • seg_data_1seg_data_2:两个4位宽的输入信号,分别表示要在两个LED上显示的数字。这些数字应该是0到9之间的整数。
  • clk_12mhz:一个12MHz的时钟信号,用于同步地更新LED显示。
  • seg_led_1seg_led_2:两个8位宽的输出信号,用于控制两个LED的各个段是否点亮。
  • seg_dig:一个2位宽的输出信号,表示当前激活的LED。2'b00 表示第一个LED激活,2'b01 表示第二个LED激活。

功能描述

模块内部使用case语句根据seg_data_1seg_data_2 的值来选择相应的8位编码来点亮LED的相应段。这些编码是7段LED显示器的标准编码,用于显示0到9的数字。

例如,如果seg_data_14'b0000,则seg_led_1的输出将是8'b1000_0000,这将点亮7段LED显示器的第一个段,从而显示数字0。

如果输入的值不在0到9的范围内,default 语句将确保LED显示空白或不显示有效的数字。

时钟同步

由于输入和输出都与时钟clk_12mhz同步,因此LED的显示将在每个时钟周期更新,产生连续且稳定的显示。

总结

这个模块是一个简单的7段LED显示器控制器,它接受两个数字作为输入,并使用一个12MHz的时钟来更新两个LED的显示。它使用标准的7段LED编码来点亮相应的段,以显示输入的数字。如果输入无效,它将显示空白或不显示有效的数字。


大模型生成截图:

按键上升沿检测

module ButtonEdgeDetection (
   input wire clk, // clock signal
   input wire button, // Key signal
   output reg button_rising_edge // Rising edge detection result
);
   reg button_last_state; // Key status of the previous cycle

   always @(posedge clk) begin
       // Detect rising edge
       if (button && !button_last_state)
           button_rising_edge <= 1'b1;
       else
           button_rising_edge <= 1'b0;

       // Record the current key status
       button_last_state <= button;
   end
endmodule

代码说明

这个Verilog代码实现了一个简单的上升沿检测器,用于检测一个按钮信号button从低电平(0)变为高电平(1)的瞬间。下面是代码实现的原理:

寄存器声明

  • button_last_state:这是一个寄存器,用于存储按钮在上一个时钟周期的状态。在Verilog中,reg类型用于声明可以保持其值的变量,即使它们不在赋值语句的左侧。

时钟边沿检测

  • always @(posedge clk):这是一个始终块,它会在clk(时钟)信号的上升沿(从0到1的跳变)时被触发。在这个块内部执行的代码会在每个时钟周期执行一次。

上升沿检测逻辑

  • if (button && !button_last_state):这个条件检查当前按钮状态是否为高电平(button为1),并且上一个状态是否为低电平(button_last_state为0)。只有当这两个条件都满足时,即按钮从低电平跳变为高电平,才认为检测到了上升沿。
  • button_rising_edge <= 1'b1;:如果检测到了上升沿,则将输出button_rising_edge设置为1。1'b1是一个1位二进制字面量,表示值为1。
  • else:如果没有检测到上升沿,
  • button_rising_edge <= 1'b0;:则将输出button_rising_edge设置为0。这表示当前没有检测到上升沿。

状态更新

  • button_last_state <= button;:无论是否检测到上升沿,都需要更新button_last_state以存储当前按钮的状态。这样,在下一个时钟周期,我们可以比较新的button状态和button_last_state以检测另一个上升沿。

输出

  • button_rising_edge:这是一个输出信号,它会在每次检测到按钮的上升沿时变为1,并在其他时间保持为0。

大模型生成截图:

仿真波形图

0.1秒精确计数仿真测试

七段数码管显示仿真测试

按键上升沿检测仿真测试

FPGA的资源利用说明

image.png

Design Summary:
Number of registers: 58 out of 4635 (1%)
PFU registers: 58 out of 4320 (1%)
PIO registers: 0 out of 315 (0%)
Number of SLICEs: 51 out of 2160 (2%)
SLICEs as Logic/ROM: 51 out of 2160 (2%)
SLICEs as RAM: 0 out of 1620 (0%)
SLICEs as Carry: 14 out of 2160 (1%)
Number of LUT4s: 102 out of 4320 (2%)
Number used as logic LUTs: 74
Number used as distributed RAM: 0
Number used as ripple logic: 28
Number used as shift registers: 0
Number of PIO sites used: 31 + 4(JTAG) out of 105 (33%)
Number of block RAMs: 0 out of 10 (0%)
Number of GSRs: 0 out of 1 (0%)
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%)
附件下载
archive.zip
WebIDE下载的工程
团队介绍
个人
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号