FPGA 課程綜合實驗之倒計時
實驗要求:
組合使用STEP MAX10 FPGA核心板和STEP BaseBoard擴展底板,編寫程序,完成一個倒計時定時
器的設計。
功能要求:
- 使用擴展底板上相鄰的4位數(shù)碼管顯示計時時間,顯示數(shù)值單位為“秒”。(2分)
- 定時器最大定時時間為99秒,時間顯示分辨力為1/100秒。(2分)
- 倒計時結束時,擴展底板上的蜂鳴器發(fā)出一組“滴答”聲(先后發(fā)出2種頻率的聲音,各持續(xù)約0.5秒)作為提示。(2分)
- 時間設置步進間隔1秒,同時支持以下2種操作方式:
-
- 完全使用擴展底板上的旋轉編碼器進行操作:
-
-
- 旋轉旋鈕設定定時時間。(2分)
-
-
- -短按旋鈕啟動/暫停計時,長按清零。(2分)
- 完全使用擴展底板上的矩陣鍵盤進行操作:
-
- 直接按數(shù)字鍵輸入設定定時時間。(2分)
-
- 分別設置啟動/暫停按鍵和清零按鍵,實現(xiàn)相應功能。(2分)
- 分別設置啟動/暫停按鍵和清零按鍵,實現(xiàn)相應功能。(2分)
根據手冊與引腳圖查閱與需要外設資源,我們可以進行引腳設置于分配
input clk, // 系統(tǒng)時鐘 12MHz
input rst_n, // 系統(tǒng)復位 低有效
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.數(shù)碼管顯示(來自開源社區(qū))
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> 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, //系統(tǒng)時鐘 12MHz
input rst_n, //系統(tǒng)復位 低有效
input [3:0] dat_1, //SEG1 顯示的數(shù)據輸入
input [3:0] dat_2, //SEG2 顯示的數(shù)據輸入
input [3:0] dat_3, //SEG3 顯示的數(shù)據輸入
input [3:0] dat_4, //SEG4 顯示的數(shù)據輸入
input [3:0] dat_5, //SEG5 顯示的數(shù)據輸入
input [3:0] dat_6, //SEG6 顯示的數(shù)據輸入
input [3:0] dat_7, //SEG7 顯示的數(shù)據輸入
input [3:0] dat_8, //SEG8 顯示的數(shù)據輸入
input [7:0] dat_en, //數(shù)碼管數(shù)據位顯示使能,[MSB~LSB]=[SEG1~SEG8]
input [7:0] dot_en, //數(shù)碼管小數(shù)點位顯示使能,[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; //分頻系數(shù)
localparam IDLE = 3'd0;
localparam MAIN = 3'd1;
localparam WRITE = 3'd2;
localparam LOW = 1'b0;
localparam HIGH = 1'b1;
//創(chuàng)建數(shù)碼管的字庫,字庫數(shù)據依段碼順序有關
//這里字庫數(shù)據[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
//計數(shù)器對系統(tǒng)時鐘信號進行計數(shù)
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
//根據計數(shù)器計數(shù)的周期產生分頻的脈沖信號
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
//使用狀態(tài)機完成數(shù)碼管的掃描和74HC595時序的實現(xiàn)
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 //復位狀態(tài)下,各寄存器置初值
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作為第一個狀態(tài),相當于軟復位
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; //在配置完發(fā)給74HC595的數(shù)據同時跳轉至WRITE狀態(tài),完成串行時序
case(cnt_main)
//對8位數(shù)碼管逐位掃描
//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路輸出,而且可以級聯(lián)使用
//74HC595的時序實現(xiàn),參考74HC595的芯片手冊
6'd0: begin seg_sck <= LOW; seg_din <= data[15]; end //SCK下降沿時SER更新數(shù)據
6'd1: begin seg_sck <= HIGH; end //SCK上升沿時SER數(shù)據穩(wěn)定
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位數(shù)據傳送完成后RCK拉高,輸出生效
6'd33: begin seg_rck <= LOW; state <= MAIN; end
default: ;
endcase
end
default: state <= IDLE;
endcase
end
end
endmodule
2.編碼器左右脈沖(來自開源社區(qū))
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> 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, // 系統(tǒng)時鐘 12MHz
input rst_n, // 系統(tǒng)復位 低有效
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;
//消除亞穩(wěn)態(tài)
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;
//消除亞穩(wěn)態(tài)
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.矩陣鍵盤獲取(來自開源社區(qū))
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> 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, // 系統(tǒng)時鐘 12MHz
input rst_n, // 系統(tǒng)復位 低有效
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;
//消除亞穩(wěn)態(tài)
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;
//消除亞穩(wěn)態(tài)
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生成(來自開源社區(qū))
用于蜂鳴器鳴響
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> 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
);
// 狀態(tài)定義
localparam IDLE = 2'b00;
localparam PRESS = 2'b01;
localparam RELEASE = 2'b10;
// 狀態(tài)寄存器和下一個狀態(tài)邏輯
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
// 下一個狀態(tài)邏輯
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個時鐘周期的按鍵行為。
主程序
現(xiàn)在我們的外設部分已經寫完了,開始主體程序書寫,首先考慮狀態(tài)機
狀態(tài)基
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;
狀態(tài)轉移條件
通過代碼實現(xiàn)
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,此變量要實現(xiàn)的功能是蜂鳴器響0.5s計時,在功能實現(xiàn)中累加。
功能實現(xiàn)
Set_status
我們要求實現(xiàn)按鍵設定時間與編碼器實現(xiàn)時間增減,我們所有的輸出都是脈沖的,所以我們只需要直接判斷條件即可
//編碼器增減
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;
并且我們需要考慮數(shù)碼管點亮使能問題
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
在此狀態(tài)中需要一個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
在功能實現(xiàn)中
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
此處可和二唯一,由于初始思路問題,此處不再修改,僅此說明,此處需要用計數(shù)器記錄響鈴時間,所以產生一計數(shù)器,并且設置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
此狀態(tài)只持續(xù)一個周期,清楚所有數(shù)據
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
此狀態(tài)無需進行任何操作,等待即可文章來源:http://www.zghlxwxcb.cn/news/detail-771114.html
至此,所有需要功能皆已實現(xiàn),整體工程在附件中。
我用夸克網盤分享了「countdown.zip」,點擊鏈接即可保存。打開「夸克APP」,無需下載在線播放視頻,暢享原畫5倍速,支持電視投屏。
鏈接:https://pan.quark.cn/s/2dc5273a9b01文章來源地址http://www.zghlxwxcb.cn/news/detail-771114.html
到了這里,關于FPGA 課程綜合實驗——倒計時(簡易計時器鬧鐘)基于STEP MAX10 FPGA的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!