一、项目创建
1.创建工程
点击File->New Project Wizard...或者直接在页面处点击
在第一行选择文件存放地点,第二行为项目名称,第三行为顶级设计实体名称
(下面的步骤可以暂时不做直接点Finish,因为是先写代码先把它跑出来暂时不用开发板)
一直Next直到下图,在框出的地方输入开发板芯片型号并选择
这里选择 ModelSim-Altera 进行仿真(不需要仿真可以不选)
然后继续点Next,直到完成
2.创建文件
选择File,点击New创建文件
选择框出的选项
然后关联了VSCode后会自动跳转到VSCode
二、功能实现
1.在DE2-115开发板上用Verilog编程实现一个分秒计数器,并具备按键暂停、按键消抖功能
代码:
module top(
input CLOCK_50, // 50MHz时钟(PIN_Y2)
input KEY0, // 复位按钮(PIN_M23)
input KEY1, // 暂停按钮(PIN_M21)
output [6:0] HEX0, // 秒个位(PIN_G18等)
output [6:0] HEX1, // 秒十位(PIN_M24等)
output [6:0] HEX2, // 分个位(PIN_K22等)
output [6:0] HEX3 // 分十位(PIN_K21等)
);
// 内部信号声明
wire reset = ~KEY0; // 低电平有效复位
wire clk_1hz; // 1Hz时钟
wire carry_sec;
wire key_stable; // 消抖后的按键信号
reg pause_state = 0; // 暂停状态寄存器
reg key_stable_d; // 用于边沿检测的延迟寄存器
wire [3:0] sec_ones; // 秒个位
wire [3:0] sec_tens; // 秒十位
wire [3:0] min_ones; // 分个位
wire [3:0] min_tens; // 分十位
// 消抖后的暂停信号
debounce pause_debouncer(
.clk(CLOCK_50),
.button(~KEY1), // KEY1低电平有效
.out(key_stable)
);
// 边沿检测逻辑(上升沿)
always @(posedge CLOCK_50) begin
key_stable_d <= key_stable;
end
wire key_rise = key_stable & ~key_stable_d;
// 状态翻转逻辑(每次按键翻转pause_state)
always @(posedge CLOCK_50 or posedge reset) begin
if (reset) begin
pause_state <= 0;
end else if (key_rise) begin
pause_state <= ~pause_state; // 按键按下时翻转状态
end
end
// 时钟分频模块实例化
clk_divider clk_div(
.clk(CLOCK_50),
.reset(reset),
.pause(pause_state), // 暂停控制
.clk_1hz(clk_1hz)
);
// 秒计数器模块实例化(添加enable端口)
second_counter sec_cnt(
.clk(clk_1hz),
.reset(reset),
.enable(~pause), // 暂停时停止计数
.sec_ones(sec_ones),
.sec_tens(sec_tens),
.carry_sec(carry_sec)
);
// 分钟计数器模块实例化
minute_counter min_cnt(
.clk(clk_1hz),
.reset(reset),
.inc(carry_sec),
.min_ones(min_ones),
.min_tens(min_tens)
);
// 七段译码器实例化
seg7_decoder seg_sec0(.bcd(sec_ones), .seg(HEX0)); // 秒个位
seg7_decoder seg_sec1(.bcd(sec_tens), .seg(HEX1)); // 秒十位
seg7_decoder seg_min0(.bcd(min_ones), .seg(HEX2)); // 分个位
seg7_decoder seg_min1(.bcd(min_tens), .seg(HEX3)); // 分十位
endmodule
// 时钟分频模块(带暂停控制)
module clk_divider(
input clk,
input reset,
input pause,
output reg clk_1hz
);
reg [25:0] counter;
always @(posedge clk or posedge reset) begin
if (reset) begin
counter <= 0;
clk_1hz <= 0;
end
else if (!pause) begin // 暂停时停止分频
if (counter == 26'd24_999_999) begin
counter <= 0;
clk_1hz <= ~clk_1hz;
end
else begin
counter <= counter + 1;
end
end
end
endmodule
// 改进的按键消抖模块(20ms消抖)
module debounce(
input clk,
input button,
output reg out
);
reg [19:0] counter;
reg [2:0] button_sync; // 三级同步器
always @(posedge clk) begin
// 同步器链
button_sync <= {button_sync[1:0], button};
// 消抖逻辑
if (button_sync[2] != out) begin
counter <= counter + 1;
if (&counter) begin // 计满20ms(50MHz时钟)
out <= button_sync[2];
counter <= 0;
end
end
else begin
counter <= 0;
end
end
endmodule
// 带使能端的秒计数器
module second_counter(
input clk,
input reset,
input enable, // 使能信号
output reg [3:0] sec_ones,
output reg [3:0] sec_tens,
output carry_sec // 改为组合逻辑输出
);
// 组合逻辑判断是否到达59秒
assign carry_sec = (sec_ones == 9) && (sec_tens == 5);
always @(posedge clk or posedge reset) begin
if (reset) begin
sec_ones <= 0;
sec_tens <= 0;
end
else if (enable) begin
if (sec_ones == 9) begin
sec_ones <= 0;
if (sec_tens == 5)
sec_tens <= 0;
else
sec_tens <= sec_tens + 1;
end
else begin
sec_ones <= sec_ones + 1;
end
end
end
endmodule
// 分钟计数器(保持不变)
module minute_counter(
input clk,
input reset,
input inc,
output reg [3:0] min_ones,
output reg [3:0] min_tens
);
always @(posedge clk or posedge reset) begin
if (reset) begin
min_ones <= 0;
min_tens <= 0;
end
else if (inc) begin
if (min_ones == 9) begin
min_ones <= 0;
if (min_tens == 5)
min_tens <= 0;
else
min_tens <= min_tens + 1;
end
else begin
min_ones <= min_ones + 1;
end
end
end
endmodule
// 七段译码器(保持不变)
module seg7_decoder(
input [3:0] bcd,
output reg [6:0] seg
);
always @(*) begin
case (bcd)
4'd0 : seg = 7'b1000000; // 0
4'd1 : seg = 7'b1111001; // 1
4'd2 : seg = 7'b0100100; // 2
4'd3 : seg = 7'b0110000; // 3
4'd4 : seg = 7'b0011001; // 4
4'd5 : seg = 7'b0010010; // 5
4'd6 : seg = 7'b0000010; // 6
4'd7 : seg = 7'b1111000; // 7
4'd8 : seg = 7'b0000000; // 8
4'd9 : seg = 7'b0010000; // 9
default : seg = 7'b1111111; // 灭
endcase
end
endmodule
代码写好后一定要保存(每次更改也要保存不然运行的不是你更改后的代码),文件名默认为Verilog1,点击另存为,文件名为top(后缀.v,文件名和你的顶层实体名一样)
然后回到Quartus点击编译(此处单纯进行代码编译,检查代码是否错误,整体运行时间较久)点击1或者2处均可,编译成功无报错后点击3处或者在菜单栏点击Assignments->Pin Planner配置引脚
引脚配置如下图所示,配置好后退出就行
然后对整个程序进行运行,点击框出的按钮或者点击Processing->Start Compilation
运行成功无报错后进行烧录(板子提前插好电源线和烧录程序的线),点击下图框选的两处均可进行烧录
第一次烧录可先点击Hardware Setup...,然后在Currently...处选择接入的USB线(第一次做的或许会找不到,可能是因为没有安装驱动,打开设备管理器,可以看到Altera USB-Blaster,图标下方有个黄色三角形警告,点击它选择下载驱动就行)
注意1,2处的选择,默认一般是这样,然后就可以点击Start,进度条为100%就成功了
最终效果:
计时器
2.状态机思想实现的分秒计数器
代码:
module top(
input CLOCK_50, // 50MHz时钟(PIN_Y2)
input KEY0, // 复位按钮(PIN_M23)
input KEY1, // 暂停按钮(PIN_M21)
output [6:0] HEX0, // 秒个位(PIN_G18等)
output [6:0] HEX1, // 秒十位(PIN_M24等)
output [6:0] HEX2, // 分个位(PIN_K22等)
output [6:0] HEX3 // 分十位(PIN_K21等)
);
// 状态定义
localparam RUN = 1'b0;
localparam PAUSE = 1'b1;
// 内部信号声明
wire reset = ~KEY0; // 低电平有效复位
wire clk_1hz; // 1Hz时钟
wire carry_sec;
wire key_stable; // 消抖后的按键信号
reg key_stable_d; // 用于边沿检测的延迟寄存器
// 计数器输出信号定义
wire [3:0] sec_ones;
wire [3:0] sec_tens;
wire [3:0] min_ones;
wire [3:0] min_tens;
// 状态寄存器
reg current_state;
reg next_state;
// 消抖后的暂停信号
debounce pause_debouncer(
.clk(CLOCK_50),
.button(~KEY1), // KEY1低电平有效
.out(key_stable)
);
// 边沿检测逻辑(上升沿)
always @(posedge CLOCK_50) begin
key_stable_d <= key_stable;
end
wire key_rise = key_stable & ~key_stable_d;
// 状态转移逻辑
always @(*) begin
case (current_state)
RUN: next_state = key_rise ? PAUSE : RUN;
PAUSE: next_state = key_rise ? RUN : PAUSE;
default: next_state = RUN;
endcase
end
// 状态翻转逻辑(每次按键翻转pause_state)
always @(posedge CLOCK_50 or posedge reset) begin
if (reset) current_state <= RUN;
else current_state <= next_state;
end
// 输出控制信号
wire pause = (current_state == PAUSE);
// 时钟分频模块实例化
clk_divider clk_div(
.clk(CLOCK_50),
.reset(reset),
.pause(pause),
.clk_1hz(clk_1hz)
);
// 秒计数器模块实例化
second_counter sec_cnt(
.clk(clk_1hz),
.reset(reset),
.enable(~pause), // 暂停时停止计数
.sec_ones(sec_ones),
.sec_tens(sec_tens),
.carry_sec(carry_sec)
);
// 分钟计数器模块实例化
minute_counter min_cnt(
.clk(clk_1hz),
.reset(reset),
.inc(carry_sec),
.min_ones(min_ones),
.min_tens(min_tens)
);
// 七段译码器实例化
seg7_decoder seg_sec0(.bcd(sec_ones), .seg(HEX0)); // 秒个位
seg7_decoder seg_sec1(.bcd(sec_tens), .seg(HEX1)); // 秒十位
seg7_decoder seg_min0(.bcd(min_ones), .seg(HEX2)); // 分个位
seg7_decoder seg_min1(.bcd(min_tens), .seg(HEX3)); // 分十位
endmodule
// 时钟分频模块(带暂停控制)
module clk_divider(
input clk,
input reset,
input pause,
output reg clk_1hz
);
reg [25:0] counter;
always @(posedge clk or posedge reset) begin
if (reset) begin
counter <= 0;
clk_1hz <= 0;
end
else if (!pause) begin // 暂停时停止分频
if (counter == 26'd24_999_999) begin
counter <= 0;
clk_1hz <= ~clk_1hz;
end
else begin
counter <= counter + 1;
end
end
end
endmodule
// 按键消抖模块(20ms消抖)
module debounce(
input clk,
input button,
output reg out
);
reg [19:0] counter;
reg [2:0] button_sync; // 三级同步器
always @(posedge clk) begin
// 同步器链
button_sync <= {button_sync[1:0], button};
// 消抖逻辑
if (button_sync[2] != out) begin
counter <= counter + 1;
if (&counter) begin // 计满20ms(50MHz时钟)
out <= button_sync[2];
counter <= 0;
end
end
else begin
counter <= 0;
end
end
endmodule
// 带使能端的秒计数器
module second_counter(
input clk,
input reset,
input enable, // 使能信号
output reg [3:0] sec_ones,
output reg [3:0] sec_tens,
output carry_sec // 改为组合逻辑输出
);
// 组合逻辑判断是否到达59秒
assign carry_sec = (sec_ones == 9) && (sec_tens == 5);
always @(posedge clk or posedge reset) begin
if (reset) begin
sec_ones <= 0;
sec_tens <= 0;
end
else if (enable) begin
if (sec_ones == 9) begin
sec_ones <= 0;
if (sec_tens == 5)
sec_tens <= 0;
else
sec_tens <= sec_tens + 1;
end
else begin
sec_ones <= sec_ones + 1;
end
end
end
endmodule
// 分钟计数器
module minute_counter(
input clk,
input reset,
input inc,
output reg [3:0] min_ones,
output reg [3:0] min_tens
);
always @(posedge clk or posedge reset) begin
if (reset) begin
min_ones <= 0;
min_tens <= 0;
end
else if (inc) begin
if (min_ones == 9) begin
min_ones <= 0;
if (min_tens == 5)
min_tens <= 0;
else
min_tens <= min_tens + 1;
end
else begin
min_ones <= min_ones + 1;
end
end
end
endmodule
// 七段译码器
module seg7_decoder(
input [3:0] bcd,
output reg [6:0] seg
);
always @(*) begin
case (bcd)
4'd0 : seg = 7'b1000000; // 0
4'd1 : seg = 7'b1111001; // 1
4'd2 : seg = 7'b0100100; // 2
4'd3 : seg = 7'b0110000; // 3
4'd4 : seg = 7'b0011001; // 4
4'd5 : seg = 7'b0010010; // 5
4'd6 : seg = 7'b0000010; // 6
4'd7 : seg = 7'b1111000; // 7
4'd8 : seg = 7'b0000000; // 8
4'd9 : seg = 7'b0010000; // 9
default : seg = 7'b1111111; // 灭
endcase
end
endmodule
其他步骤都是一样的,在开发板上的效果也同上。
三、总结
本次实验在DE2-115开发板上实现了一个分秒计数器,且有按键暂停、按键消抖的功能,还用状态机思想实现了一次,代码是用DeepSeek辅助写的,自己暂时还写不出来,先把功能实现后再逐步分析正确的代码更有助于我的学习,文章有什么问题与不足还请多多指正。