FPGA 课程综合实验之倒计时
实验要求:
组合使用STEP MAX10 FPGA核心板和STEP BaseBoard扩展底板,编写程序,完成一个倒计时定时
器的设计。
功能要求:
- 使用扩展底板上相邻的4位数码管显示计时时间,显示数值单位为“秒”。(2分)
- 定时器最大定时时间为99秒,时间显示分辨力为1/100秒。(2分)
- 倒计时结束时,扩展底板上的蜂鸣器发出一组“滴答”声(先后发出2种频率的声音,各持续约0.5秒)作为提示。(2分)
- 时间设置步进间隔1秒,同时支持以下2种操作方式:
-
- 完全使用扩展底板上的旋转编码器进行操作:
-
-
- 旋转旋钮设定定时时间。(2分)
-
-
- -短按旋钮启动/暂停计时,长按清零。(2分)
- 完全使用扩展底板上的矩阵键盘进行操作:
-
- 直接按数字键输入设定定时时间。(2分)
-
- 分别设置启动/暂停按键和清零按键,实现相应功能。(2分)
- 分别设置启动/暂停按键和清零按键,实现相应功能。(2分)
根据手册与引脚图查阅与需要外设资源,我们可以进行引脚设置于分配
input clk, // 系统时钟 12MHz
input rst_n, // 系统复位 低有效
input encoder_a, // 旋转编码器EC11的A脚
input encoder_b, // 旋转编码器EC11的B脚
input encoder_sw, // 旋转编码器EC11的SW脚
input [3:0] col, // 矩阵按键的列接口
output [3:0] row, // 矩阵按键的行接口
output seg_rck, // 74HC595的RCK管脚
output seg_sck, // 74HC595的SCK管脚
output seg_din, // 74HC595的SER管脚
output beeper // 蜂鸣器
外设module编写
根据使用外设,我们可以编写外设程序
1.数码管显示(来自开源社区)
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Module: Segment_scan
//
// Author: Step
//
// Description: Display with Segment tube
//
// Web: www.stepfpga.com
//
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Version: |Mod. Date: |Changes Made:
// V1.0 |2015/11/11 |Initial ver
// --------------------------------------------------------------------
module Segment_scan
(
input clk, //系统时钟 12MHz
input rst_n, //系统复位 低有效
input [3:0] dat_1, //SEG1 显示的数据输入
input [3:0] dat_2, //SEG2 显示的数据输入
input [3:0] dat_3, //SEG3 显示的数据输入
input [3:0] dat_4, //SEG4 显示的数据输入
input [3:0] dat_5, //SEG5 显示的数据输入
input [3:0] dat_6, //SEG6 显示的数据输入
input [3:0] dat_7, //SEG7 显示的数据输入
input [3:0] dat_8, //SEG8 显示的数据输入
input [7:0] dat_en, //数码管数据位显示使能,[MSB~LSB]=[SEG1~SEG8]
input [7:0] dot_en, //数码管小数点位显示使能,[MSB~LSB]=[SEG1~SEG8]
output reg seg_rck, //74HC595的RCK管脚
output reg seg_sck, //74HC595的SCK管脚
output reg seg_din //74HC595的SER管脚
);
localparam CNT_40KHz = 300; //分频系数
localparam IDLE = 3'd0;
localparam MAIN = 3'd1;
localparam WRITE = 3'd2;
localparam LOW = 1'b0;
localparam HIGH = 1'b1;
//创建数码管的字库,字库数据依段码顺序有关
//这里字库数据[MSB~LSB]={G,F,E,D,C,B,A}
reg[6:0] seg [15:0];
always @(negedge rst_n) begin
seg[0] = 7'h3f; // 0
seg[1] = 7'h06; // 1
seg[2] = 7'h5b; // 2
seg[3] = 7'h4f; // 3
seg[4] = 7'h66; // 4
seg[5] = 7'h6d; // 5
seg[6] = 7'h7d; // 6
seg[7] = 7'h07; // 7
seg[8] = 7'h7f; // 8
seg[9] = 7'h6f; // 9
seg[10] = 7'h77; // A
seg[11] = 7'h7c; // b
seg[12] = 7'h39; // C
seg[13] = 7'h5e; // d
seg[14] = 7'h79; // E
seg[15] = 7'h71; // F
end
//计数器对系统时钟信号进行计数
reg [9:0] cnt = 1'b0;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) cnt <= 1'b0;
else if(cnt>=(CNT_40KHz-1)) cnt <= 1'b0;
else cnt <= cnt + 1'b1;
end
//根据计数器计数的周期产生分频的脉冲信号
reg clk_40khz = 1'b0;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) clk_40khz <= 1'b0;
else if(cnt<(CNT_40KHz>>1)) clk_40khz <= 1'b0;
else clk_40khz <= 1'b1;
end
//使用状态机完成数码管的扫描和74HC595时序的实现
reg [15:0] data;
reg [2:0] cnt_main;
reg [5:0] cnt_write;
reg [2:0] state = IDLE;
always@(posedge clk_40khz or negedge rst_n) begin
if(!rst_n) begin //复位状态下,各寄存器置初值
state <= IDLE;
cnt_main <= 3'd0; cnt_write <= 6'd0;
seg_din <= 1'b0; seg_sck <= LOW; seg_rck <= LOW;
end else begin
case(state)
IDLE:begin //IDLE作为第一个状态,相当于软复位
state <= MAIN;
cnt_main <= 3'd0; cnt_write <= 6'd0;
seg_din <= 1'b0; seg_sck <= LOW; seg_rck <= LOW;
end
MAIN:begin
cnt_main <= cnt_main + 1'b1;
state <= WRITE; //在配置完发给74HC595的数据同时跳转至WRITE状态,完成串行时序
case(cnt_main)
//对8位数码管逐位扫描
//data [15:8]为段选, [7:0]为位选
3'd0: data <= {{dot_en[7],seg[dat_1]},dat_en[7]?8'hfe:8'hff};
3'd1: data <= {{dot_en[6],seg[dat_2]},dat_en[6]?8'hfd:8'hff};
3'd2: data <= {{dot_en[5],seg[dat_3]},dat_en[5]?8'hfb:8'hff};
3'd3: data <= {{dot_en[4],seg[dat_4]},dat_en[4]?8'hf7:8'hff};
3'd4: data <= {{dot_en[3],seg[dat_5]},dat_en[3]?8'hef:8'hff};
3'd5: data <= {{dot_en[2],seg[dat_6]},dat_en[2]?8'hdf:8'hff};
3'd6: data <= {{dot_en[1],seg[dat_7]},dat_en[1]?8'hbf:8'hff};
3'd7: data <= {{dot_en[0],seg[dat_8]},dat_en[0]?8'h7f:8'hff};
default: data <= {8'h00,8'hff};
endcase
end
WRITE:begin
if(cnt_write >= 6'd33) cnt_write <= 1'b0;
else cnt_write <= cnt_write + 1'b1;
case(cnt_write)
//74HC595是串行转并行的芯片,3路输入可产生8路输出,而且可以级联使用
//74HC595的时序实现,参考74HC595的芯片手册
6'd0: begin seg_sck <= LOW; seg_din <= data[15]; end //SCK下降沿时SER更新数据
6'd1: begin seg_sck <= HIGH; end //SCK上升沿时SER数据稳定
6'd2: begin seg_sck <= LOW; seg_din <= data[14]; end
6'd3: begin seg_sck <= HIGH; end
6'd4: begin seg_sck <= LOW; seg_din <= data[13]; end
6'd5: begin seg_sck <= HIGH; end
6'd6: begin seg_sck <= LOW; seg_din <= data[12]; end
6'd7: begin seg_sck <= HIGH; end
6'd8: begin seg_sck <= LOW; seg_din <= data[11]; end
6'd9: begin seg_sck <= HIGH; end
6'd10: begin seg_sck <= LOW; seg_din <= data[10]; end
6'd11: begin seg_sck <= HIGH; end
6'd12: begin seg_sck <= LOW; seg_din <= data[9]; end
6'd13: begin seg_sck <= HIGH; end
6'd14: begin seg_sck <= LOW; seg_din <= data[8]; end
6'd15: begin seg_sck <= HIGH; end
6'd16: begin seg_sck <= LOW; seg_din <= data[7]; end
6'd17: begin seg_sck <= HIGH; end
6'd18: begin seg_sck <= LOW; seg_din <= data[6]; end
6'd19: begin seg_sck <= HIGH; end
6'd20: begin seg_sck <= LOW; seg_din <= data[5]; end
6'd21: begin seg_sck <= HIGH; end
6'd22: begin seg_sck <= LOW; seg_din <= data[4]; end
6'd23: begin seg_sck <= HIGH; end
6'd24: begin seg_sck <= LOW; seg_din <= data[3]; end
6'd25: begin seg_sck <= HIGH; end
6'd26: begin seg_sck <= LOW; seg_din <= data[2]; end
6'd27: begin seg_sck <= HIGH; end
6'd28: begin seg_sck <= LOW; seg_din <= data[1]; end
6'd29: begin seg_sck <= HIGH; end
6'd30: begin seg_sck <= LOW; seg_din <= data[0]; end
6'd31: begin seg_sck <= HIGH; end
6'd32: begin seg_rck <= HIGH; end //当16位数据传送完成后RCK拉高,输出生效
6'd33: begin seg_rck <= LOW; state <= MAIN; end
default: ;
endcase
end
default: state <= IDLE;
endcase
end
end
endmodule
2.编码器左右脉冲(来自开源社区)
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Module: Encoder
//
// Author: Step
//
// Description: Driver for rotary encoder
//
// Web: www.stepfapga.com
//
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Version: |Mod. Date: |Changes Made:
// V1.0 |2016/04/20 |Initial ver
// --------------------------------------------------------------------
module Encoder
(
input clk, // 系统时钟 12MHz
input rst_n, // 系统复位 低有效
input key_a, // 旋转编码器EC11的A脚
input key_b, // 旋转编码器EC11的B脚
output reg L_pulse, // 左旋脉冲输出
output reg R_pulse // 右旋脉冲输出
);
localparam NUM_250US = 3_000;
reg [12:0] cnt;
//count for clk_500us
always@(posedge clk or negedge rst_n) begin
if(!rst_n) cnt <= 0;
else if(cnt >= NUM_250US-1) cnt <= 1'b0;
else cnt <= cnt + 1'b1;
end
reg clk_500us;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) clk_500us <= 0;
else if(cnt == NUM_250US-1) clk_500us <= ~clk_500us;
else clk_500us <= clk_500us;
end
reg key_a_r,key_a_r1,key_a_r2;
//消除亚稳态
always@(posedge clk_500us) begin
key_a_r <= key_a;
key_a_r1 <= key_a_r;
key_a_r2 <= key_a_r1;
end
reg A_state;
//简单去抖动处理
always@(key_a_r1 or key_a_r2) begin
case({key_a_r1,key_a_r2})
2'b11: A_state <= 1'b1;
2'b00: A_state <= 1'b0;
default: A_state <= A_state;
endcase
end
reg key_b_r,key_b_r1,key_b_r2;
//消除亚稳态
always@(posedge clk_500us) begin
key_b_r <= key_b;
key_b_r1 <= key_b_r;
key_b_r2 <= key_b_r1;
end
reg B_state;
//简单去抖动处理
always@(key_b_r1 or key_b_r2) begin
case({key_b_r1,key_b_r2})
2'b11: B_state <= 1'b1;
2'b00: B_state <= 1'b0;
default: B_state <= B_state;
endcase
end
reg A_state_r,A_state_r1;
//对A_state信号进行边沿检测
always@(posedge clk) begin
A_state_r <= A_state;
A_state_r1 <= A_state_r;
end
wire A_pos = (!A_state_r1) && A_state_r;
wire A_neg = A_state_r1 && (!A_state_r);
//当A的上升沿伴随B的高电平或当A的下降沿伴随B的低电平 为向左旋转
always@(posedge clk or negedge rst_n) begin
if(!rst_n) L_pulse <= 1'b0;
else if((A_pos&&B_state)||(A_neg&&(!B_state))) L_pulse <= 1'b1;
else L_pulse <= 1'b0;
end
//当A的上升沿伴随B的低电平或当A的下降沿伴随B的高电平 为向右旋转
always@(posedge clk or negedge rst_n) begin
if(!rst_n) R_pulse <= 1'b0;
else if((A_pos&&(!B_state))||(A_neg&&B_state)) R_pulse <= 1'b1;
else R_pulse <= 1'b0;
end
endmodule
3.矩阵键盘获取(来自开源社区)
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Module: Encoder
//
// Author: Step
//
// Description: Driver for rotary encoder
//
// Web: www.stepfapga.com
//
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Version: |Mod. Date: |Changes Made:
// V1.0 |2016/04/20 |Initial ver
// --------------------------------------------------------------------
module Encoder
(
input clk, // 系统时钟 12MHz
input rst_n, // 系统复位 低有效
input key_a, // 旋转编码器EC11的A脚
input key_b, // 旋转编码器EC11的B脚
output reg L_pulse, // 左旋脉冲输出
output reg R_pulse // 右旋脉冲输出
);
localparam NUM_250US = 3_000;
reg [12:0] cnt;
//count for clk_500us
always@(posedge clk or negedge rst_n) begin
if(!rst_n) cnt <= 0;
else if(cnt >= NUM_250US-1) cnt <= 1'b0;
else cnt <= cnt + 1'b1;
end
reg clk_500us;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) clk_500us <= 0;
else if(cnt == NUM_250US-1) clk_500us <= ~clk_500us;
else clk_500us <= clk_500us;
end
reg key_a_r,key_a_r1,key_a_r2;
//消除亚稳态
always@(posedge clk_500us) begin
key_a_r <= key_a;
key_a_r1 <= key_a_r;
key_a_r2 <= key_a_r1;
end
reg A_state;
//简单去抖动处理
always@(key_a_r1 or key_a_r2) begin
case({key_a_r1,key_a_r2})
2'b11: A_state <= 1'b1;
2'b00: A_state <= 1'b0;
default: A_state <= A_state;
endcase
end
reg key_b_r,key_b_r1,key_b_r2;
//消除亚稳态
always@(posedge clk_500us) begin
key_b_r <= key_b;
key_b_r1 <= key_b_r;
key_b_r2 <= key_b_r1;
end
reg B_state;
//简单去抖动处理
always@(key_b_r1 or key_b_r2) begin
case({key_b_r1,key_b_r2})
2'b11: B_state <= 1'b1;
2'b00: B_state <= 1'b0;
default: B_state <= B_state;
endcase
end
reg A_state_r,A_state_r1;
//对A_state信号进行边沿检测
always@(posedge clk) begin
A_state_r <= A_state;
A_state_r1 <= A_state_r;
end
wire A_pos = (!A_state_r1) && A_state_r;
wire A_neg = A_state_r1 && (!A_state_r);
//当A的上升沿伴随B的高电平或当A的下降沿伴随B的低电平 为向左旋转
always@(posedge clk or negedge rst_n) begin
if(!rst_n) L_pulse <= 1'b0;
else if((A_pos&&B_state)||(A_neg&&(!B_state))) L_pulse <= 1'b1;
else L_pulse <= 1'b0;
end
//当A的上升沿伴随B的低电平或当A的下降沿伴随B的高电平 为向右旋转
always@(posedge clk or negedge rst_n) begin
if(!rst_n) R_pulse <= 1'b0;
else if((A_pos&&(!B_state))||(A_neg&&B_state)) R_pulse <= 1'b1;
else R_pulse <= 1'b0;
end
endmodule
4.PWM生成(来自开源社区)
用于蜂鸣器鸣响
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Module: PWM
//
// Author: Step
//
// Description: PWM
//
// Web: www.stepfpga.com
//
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Version: |Mod. Date: |Changes Made:
// V1.0 |2015/11/11 |Initial ver
// --------------------------------------------------------------------
module PWM #
(
parameter WIDTH = 32 //ensure that 2**WIDTH > cycle
)
(
input clk,
input rst_n,
input [WIDTH-1:0] cycle, //cycle > duty
input [WIDTH-1:0] duty, //duty < cycle
output reg pwm_out
);
reg [WIDTH-1:0] cnt;
//counter for cycle
always @(posedge clk or negedge rst_n)
if(!rst_n) cnt <= 1'b1;
else if(cnt >= cycle) cnt <= 1'b1;
else cnt <= cnt + 1'b1;
//pulse with duty
always @(posedge clk or negedge rst_n)
if(!rst_n) pwm_out <= 1'b1;
else if(cnt < duty) pwm_out <= 1'b1;
else pwm_out <= 1'b0;
endmodule
5.检测按键长按与短按
module key_detect (
input clk,
input rst,
input key,
output reg short_press,
output reg long_press
);
// 状态定义
localparam IDLE = 2'b00;
localparam PRESS = 2'b01;
localparam RELEASE = 2'b10;
// 状态寄存器和下一个状态逻辑
reg [1:0] state, next_state;
always @(posedge clk, negedge rst) begin
if (!rst) begin
state <= IDLE;
end else begin
state <= next_state;
end
end
// 下一个状态逻辑
always @(*) begin
case (state)
IDLE: begin
if (key == 1'b0) begin
next_state = PRESS;
end else begin
next_state = IDLE;
end
end
PRESS: begin
if (key == 1'b0) begin
next_state = PRESS;
end else begin
next_state = RELEASE;
end
end
RELEASE: begin
if (key == 1'b0) begin
next_state = IDLE;
end else begin
next_state = RELEASE;
end
end
default: next_state = IDLE;
endcase
end
// 长短按检测逻辑
reg [31:0] press_cnt;
always @(posedge clk or negedge rst) begin
if (!rst) begin
short_press <= 1'b0;
long_press <= 1'b0;
press_cnt <= 0;
end else begin
case (state)
IDLE: begin
short_press <= 1'b0;
long_press <= 1'b0;
press_cnt <= 0;
end
PRESS: begin
short_press <= 1'b0;
long_press <= 1'b0;
press_cnt <= press_cnt + 1;
end
RELEASE: begin
if (press_cnt >= 12_000_000) begin
short_press <= 1'b0;
long_press <= 1'b1;
end else if (press_cnt >= 12_000) begin
short_press <= 1'b1;
long_press <= 1'b0;
end else begin
short_press <= 1'b0;
long_press <= 1'b0;
end
press_cnt <= 0;
end
default: begin
short_press <= 1'b0;
long_press <= 1'b0;
press_cnt <= 0;
end
endcase
end
end
endmodule
以脉冲形式输出长短按信号,短按是指时间大于12_000个时钟周期(为了消抖),小于12_000_000个时钟周期的按键行为;长按是指时间大于12_000_000个时钟周期的按键行为。
主程序
现在我们的外设部分已经写完了,开始主体程序书写,首先考虑状态机
状态基
parameter Set_status = 5'b00000;
parameter Press_once = 5'b00001;
parameter Timing_status = 5'b00010;
parameter Ring_status_1 = 5'b00011;
parameter Ring_status_2 = 5'b00100;
parameter Clear_status = 5'b00101;
parameter Paused_status = 5'b00110;
状态转移条件
通过代码实现
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= Set_status;
end else begin
state <= state_next;
end
end
always @(*) begin
case(state)
Set_status: begin
if(key_pulse[9:0]) state_next <= Press_once;
else if(key_pulse[12]) state_next <= Timing_status;
else if(key_pulse[13]) state_next <= Clear_status;
else if(encoder_sw_pulse) state_next <= Timing_status;
else if(encoder_sw_long_press) state_next <= Clear_status;
else state_next <= Set_status;
end
Press_once: begin
if(key_pulse[12]) state_next <= Timing_status;
else if(key_pulse[13]) state_next <= Clear_status;
else if(encoder_sw_pulse) state_next <= Timing_status;
else if(encoder_sw_long_press) state_next <= Clear_status;
else if(key_pulse[9:0]) state_next <= Set_status;
else state_next <= Press_once;
end
Timing_status: begin
if(key_pulse[12]) state_next <= Paused_status;
else if(key_pulse[13]) state_next <= Clear_status;
else if(encoder_sw_pulse) state_next <= Paused_status;
else if(encoder_sw_long_press) state_next <= Clear_status;
else if(seg_data_8==0&&seg_data_7==0&&seg_data_6==0&&seg_data_5==0) state_next <= Ring_status_1;
else state_next <= Timing_status;
end
Ring_status_1: begin
if(beep_cnt==6_000_000) state_next <= Ring_status_2;
else state_next <= Ring_status_1;
end
Ring_status_2: begin
if(beep_cnt==12_000_000) state_next <= Set_status;
else state_next <= Ring_status_2;
end
Clear_status: begin
state_next <= Set_status;
end
Paused_status: begin
if(key_pulse[12]) state_next <= Timing_status;
else if(key_pulse[13]) state_next <= Clear_status;
else if(encoder_sw_pulse) state_next <= Timing_status;
else if(encoder_sw_long_press) state_next <= Clear_status;
else state_next <= Paused_status;
end
default: state_next <= Set_status;
endcase
end
我们注意到在转移条件中有beep_cnt,此变量要实现的功能是蜂鸣器响0.5s计时,在功能实现中累加。
功能实现
Set_status
我们要求实现按键设定时间与编码器实现时间增减,我们所有的输出都是脉冲的,所以我们只需要直接判断条件即可
//编码器增减
if(L_pulse)
begin
if(seg_data_8==4'd0)
begin
if(seg_data_7==4'd0)
begin
seg_data_7 <= 4'd0;
seg_data_8 <= 4'd0;
end
else
begin
seg_data_8 <= 4'd9;
seg_data_7 <= seg_data_7 - 1'b1;
end
end
else seg_data_8 <= seg_data_8 - 1'b1;
end
else if(R_pulse)
begin
if(seg_data_8==4'd9)
begin
if(seg_data_7==4'd9)
begin
seg_data_7 <= 4'd9;
seg_data_8 <= 4'd9;
end
else
begin
seg_data_8 <= 4'd0;
seg_data_7 <= seg_data_7 + 1'b1;
end
end
else seg_data_8 <= seg_data_8 + 1'b1;
end
//矩阵键盘时间设置
else if(key_pulse[9]) seg_data_7 <= 4'd0;
else if(key_pulse[0]) seg_data_7 <= 4'd1;
else if(key_pulse[1]) seg_data_7 <= 4'd2;
else if(key_pulse[2]) seg_data_7 <= 4'd3;
else if(key_pulse[3]) seg_data_7 <= 4'd4;
else if(key_pulse[4]) seg_data_7 <= 4'd5;
else if(key_pulse[5]) seg_data_7 <= 4'd6;
else if(key_pulse[6]) seg_data_7 <= 4'd7;
else if(key_pulse[7]) seg_data_7 <= 4'd8;
else if(key_pulse[8]) seg_data_7 <= 4'd9;
并且我们需要考虑数码管点亮使能问题
if(seg_data_7 == 4'd0)
begin
seg_en <= 8'b0000_0001;
seg_dot_en <= 8'h00;
end
else
begin
seg_en <= 8'b0000_0011;
seg_dot_en <= 8'h00;
end
Press_once
几乎与Set_status一致,不再进行赘述
Timing_status
在此状态中需要一个10ms的时钟信号,所以额外生成一份
//时钟
reg [7:0] s_counter = 0;
reg [7:0] counter_10ms = 0;
reg [21:0] counter_10ms_cnt = 0;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) begin
counter_10ms <= 0;
end
else if(counter_10ms_cnt == 12_000_0)
begin
counter_10ms <= 1;
end
else
begin
counter_10ms <= 0;
end
end
在功能实现中
counter_10ms_cnt<=counter_10ms_cnt+1;
beep_cnt <= 0;
if(counter_10ms)
begin
counter_10ms_cnt<=0;
if(seg_data_8==4'd0)
begin
if(seg_data_7==4'd0)
begin
if(seg_data_6==4'd0)
begin
if(seg_data_5==4'd0)
begin
end
else
begin
seg_data_8 <= 4'd9;
seg_data_7 <= 4'd9;
seg_data_6 <= 4'd9;
seg_data_5 <= seg_data_5 - 1'b1;
end
end
else
begin
seg_data_8 <= 4'd9;
seg_data_7 <= 4'd9;
seg_data_6 <= seg_data_6 - 1'b1;
end
end
else
begin
seg_data_8 <= 4'd9;
seg_data_7 <= seg_data_7 - 1'b1;
end
end
else
begin
seg_data_8 <= seg_data_8 - 1'b1;
end
end
seg_en <= 8'b0000_1111;
seg_dot_en <= 8'b100;
Ring_status_1与Ring_status_2
此处可和二唯一,由于初始思路问题,此处不再修改,仅此说明,此处需要用计数器记录响铃时间,所以产生一计数器,并且设置PWM频率
Ring_status_1: begin
beeper_cycle <= 16'd36408;
beeper_state <= 1'b1;
beep_cnt <= beep_cnt +1;
end
Ring_status_2: begin
beeper_cycle <= 16'd45872;
beeper_state <= 1'b1;
beep_cnt <= beep_cnt +1;
Clear_status
此状态只持续一个周期,清楚所有数据
Clear_status: begin
beeper_state <= 1'b0;
seg_data_1 <= 4'h0;
seg_data_2 <= 4'h0;
seg_data_3 <= 4'h0;
seg_data_4 <= 4'h0;
seg_data_5 <= 4'h0;
seg_data_6 <= 4'h0;
seg_data_7 <= 4'h0;
seg_data_8 <= 4'h0;
seg_en <= 8'b0000_0000;
seg_dot_en <= 8'h00;
beep_cnt <= 32'd0;
counter_10ms_cnt<=0;
end
Paused_status
此状态无需进行任何操作,等待即可文章来源:https://www.toymoban.com/news/detail-771114.html
至此,所有需要功能皆已实现,整体工程在附件中。
我用夸克网盘分享了「countdown.zip」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
链接:https://pan.quark.cn/s/2dc5273a9b01文章来源地址https://www.toymoban.com/news/detail-771114.html
到了这里,关于FPGA 课程综合实验——倒计时(简易计时器闹钟)基于STEP MAX10 FPGA的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!