開發(fā)板:此款開發(fā)板使用的是 ALTERA 公司的 Cyclone IV 系列 FPGA,型號為 EP4CE6F17C8, 256 個引腳的 FBGA 封裝。
?題目:在EDA開發(fā)板上實現(xiàn)電子時鐘功能
要求:實現(xiàn)電子時鐘程序編寫,實現(xiàn)在7段數(shù)碼管顯示時、分、秒,使用4x4矩陣按鍵模擬調節(jié)時鐘指令輸入按鍵,并實現(xiàn)整點報時功能。按鍵功能包括但不限以下功能:選擇(時分秒選擇按鍵、可以一一對應,也可以只用1個按鍵)、復位、+(時分秒加)、-(時分秒減)。
程序設計步驟:
1、七段數(shù)碼管顯示
1 |
2. |
4 |
6. |
5 |
7 |
圖1 ?開機顯示畫面,其中.為時分秒的間隔
2、 數(shù)據輸入:在圖1所示的狀態(tài)下,用4x4矩陣按鍵來進行時分秒的調節(jié)。
3、整點報時:到整點時,自動播放一段音樂。
?4、一鍵復原:完成時間調節(jié)后,按“復原”按鍵,七段數(shù)碼管顯示最初的狀態(tài),回到圖1所示狀態(tài)。
以上既是該電子時鐘的設計要求。
功能設計部分,分為以下7個模塊。
EDA_clock | 頂層模塊文件 | 將各個模塊進行整合 |
clk1hz | 時鐘頻率 | 將50MHz晶振頻率轉化為1秒鐘的頻率,1Hz=1s |
cnt24 | 24計數(shù)器 | 時鐘中 “時”的計數(shù),并判斷 |
cnt60 | 60計數(shù)器 | 時鐘中“分”、“秒”的計數(shù),并判斷個位十位實時狀態(tài) |
key4x4_clock | 4x4矩陣鍵盤 | 矩陣鍵盤功能設置 |
seg_dynamic | 七段數(shù)碼管 | 接收當前計數(shù)器值 |
buzzer | 蜂鳴器控制 | 當整點時播放音樂3秒鐘 |
對于以下各個代碼塊有較為詳細的標注,請自行對照理解,有疑惑的可以評論區(qū),看到回復
1. EDA_clock.v
創(chuàng)建工程后,該模塊為頂層文件
代碼如下:
/**
* @copyright: 2782978674@qq.com
* @author: xietiancheng
* @date: 2023.6.4
*
**/
?module EDA_clock(
input wire sys_clk,
input wire rst_n,
input wire [3:0] key_in_y, // 輸入矩陣鍵盤的列信號(KEY0~KEY3)
output wire [3:0] key_out_x, // 輸出矩陣鍵盤的行信號(KEY4~KEY7)
output wire [5:0] sel , //數(shù)碼管位選信號
output wire [7:0] seg , //數(shù)碼管段選信號
output wire buzzer
);
wire clk_1hz;
wire count_s;
wire count_m;
wire [6:0] Sec; //秒
wire [6:0] Sec_out; //秒輸出
wire [6:0] Min; //分
wire [6:0] Min_out; //分輸出
wire [6:0] Hour; //時
wire [6:0] Hour_out; //時輸出
wire [4:0] Sec1; //秒的個位
wire [4:0] Sec2; //秒的十位
wire [4:0] Min1; //分的個位
wire [4:0] Min2; //分的十位
wire [4:0] Hour1; //時的個位
wire [4:0] Hour2; //時的十位
wire en_s; //秒的使能信號
wire en_m; //分的使能信號
wire en_h; //時的使能信號
wire time_en;//當設置時間時,設置使能信號,當有效時時間停止,進行時鐘各位賦值。
// assign en_s=1'b1;
assign en_m=count_s && en_s;
assign en_h= (Min_out == 7'd59 && Sec_out == 7'd58)?1:0;
//1hz代表一秒鐘,時鐘頻率設置
clk1hz
#(
.N (26'd25_000_000 ) //代表
)
clk1hz_inst
(
.clk(sys_clk),
.rst_n(rst_n),
.clk_out(clk_1hz)
);
/*********秒和分使用使能信號en_s和en_m來控制*********/
//秒的代碼
cnt60 cnt60_inst1(
.clk(clk_1hz),
.rst_n(rst_n),
.en(en_s),
.time_en(time_en),
.cnt0(Sec),
.cnt_out(Sec_out),
.cnt1(Sec1), //秒的個位
.cnt2(Sec2), //秒的十位
.flag(count_s) //秒的使能信號
);
//分的代碼
cnt60 cnt60_inst2(
.clk(clk_1hz),
.rst_n(rst_n),
.en(en_m),
.time_en(time_en),
.cnt0(Min),
.cnt_out(Min_out),
.cnt1(Min1), //分的個位
.cnt2(Min2), //分的十位
.flag(count_m)
);
//時間的設置
cnt24 cnt24_inst(
.clk(clk_1hz),
.rst_n(rst_n),
.en(en_h),
.time_en(time_en),
.cnt0(Hour),
.cnt_out(Hour_out),
.cnt1(Hour1),
.cnt2(Hour2)
);
//數(shù)碼管控制顯示模塊
seg_dynamic seg_dynamic_inst
(
.clk(sys_clk),
.rst_n(rst_n),
.Sec1(Sec1), //秒的個位
.Sec2(Sec2), //秒的十位
.Min1(Min1), //分的個位
.Min2(Min2), //分的十位
.Hour1(Hour1), //時的個位
.Hour2(Hour2), //時的十位
.sel (sel), //數(shù)碼管位選信號
.seg(seg) //數(shù)碼管段選信號
);
//矩陣鍵盤設置調節(jié)時間
key4x4_clock key4x4_clock_inst(
.clk(sys_clk) ,
.rst_n(rst_n) ,
.Sec_out (Sec_out) ,
.Min_out (Min_out) ,
.Hour_out (Hour_out) ,
.key_in_y(key_in_y) , // 輸入矩陣鍵盤的列信號(KEY0~KEY3)
.key_out_x(key_out_x) , // 輸出矩陣鍵盤的行信號(KEY4~KEY7)
.Sec(Sec) , //秒修改
.Min(Min) , //分修改
.Hour(Hour) , //時修改
.en(en_s) , //時鐘是否運行的使能信號
.time_en(time_en)
);
buzzer buzzer_inst(
.clk (sys_clk),
.rst_n (rst_n ),
.Sec_out(Sec_out),
.Min_out(Min_out),
.buzzer (buzzer)
);
endmodule
/**********************************************************
quartusII綜合報錯(Error (10028): Can't resolve multiple constant drivers for net "txd_cnt[3]")
出現(xiàn)這個錯誤的原因在于,在不同的always邏輯塊中,對同一個reg變量進行了賦值。
在多個alwasy邏輯塊同時并行工作的時候,會出現(xiàn)沖突。解決的辦法就是,對于一個變量,只在一個always塊中,進行賦值。
***********************************************************/
2.?clk1hz.v
將50MHz轉化為1Hz的頻率,可通過parameter參數(shù)N進行更改轉化為其他頻率
代碼如下:
module clk1hz
#(parameter N = 26'd25_000_000)
(
input clk,
input rst_n,
output reg clk_out
);
reg [32:0] tmp;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) begin
tmp <= 0;
clk_out<=0;
end
else if (tmp == N-1)
begin
clk_out<= ~clk_out;
tmp <= 0;
end
else
begin
tmp <= tmp+1;
clk_out <=clk_out;
end
end
endmodule
3.?cnt24.v
代碼如下:
module cnt24
// #(parameter CNT = 5'd0)
(
input wire clk ,
input wire rst_n ,
input wire en ,
input wire time_en ,
input wire [6:0] cnt0,
output reg [6:0] cnt_out, //控制cnt的傳入傳出
output reg [4:0] cnt1,
output reg [4:0] cnt2
);
reg [6:0] cnt;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) begin
cnt<=cnt0;
cnt1<=cnt%10;
cnt2<=cnt/10;
cnt_out<=cnt;
end
else
begin
if(en==1)
begin
if(cnt<23)
begin
cnt<=cnt+1;
cnt1<=cnt%10;
cnt2<=cnt/10;
cnt_out<=cnt;
end
else begin
cnt<=0;
cnt1<=cnt%10;
cnt2<=cnt/10;
cnt_out<=cnt;
end
end
else if(time_en==1'b1)begin
cnt <=cnt0;
cnt1<=cnt%10;
cnt2<=cnt/10;
cnt_out<=cnt;
end
else begin //if(en_m==0 &&en == 0)begin
cnt<=cnt;
cnt1<=cnt%10;
cnt2<=cnt/10;
cnt_out<=cnt;
end
end
end
endmodule
/*
if(cnt1<10)
begin
cnt1 <= cnt1+1;
end
else
begin
cnt1<= 0;
cnt2<=cnt2+1;
end
*/
4.?cnt60.v
代碼如下:
module cnt60
(
input wire clk,
input wire rst_n,
input wire en,
input wire time_en, //修改時鐘值的使能信號
input wire [6:0] cnt0, //控制cnt的傳入傳出
output reg [6:0] cnt_out, //控制cnt的傳入傳出
output reg [4:0] cnt1,
output reg [4:0] cnt2,
output reg flag
);
reg [6:0] cnt; //時鐘始終變化著運行著的值
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt<=cnt0;
//控制個位和十位的變化
cnt1<=cnt%10;
cnt2<=cnt/10;
cnt_out<=cnt;
end
else
begin
if(en==1)
begin
if(cnt<59)
begin
cnt <=cnt +1;
//控制個位和十位的變化
cnt1<=cnt%10;
cnt2<=cnt/10;
cnt_out<=cnt;
end
else begin
cnt <= 0;
cnt1<=cnt%10;
cnt2<=cnt/10;
cnt_out<=cnt;
end
end
else if(time_en==1'b1)begin
cnt <=cnt0 ;
cnt1<=cnt%10;
cnt2<=cnt/10;
cnt_out<=cnt;
end
else begin
cnt <=cnt;
cnt1<=cnt%10;
cnt2<=cnt/10;
cnt_out<=cnt;
end
end
end
//當cnt到達58時flag的變化
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
flag<=0;
else if(cnt <58)
flag <=0;
else if(cnt == 58)
flag <= 1;
else flag <= 0;
end
endmodule
5.?key4x4_clock.v
代碼如下:
`timescale 1ns / 1ps //精度 可不用
module key4x4_clock(
input wire clk,
input wire rst_n,
input wire [6:0] Sec_out,
input wire [6:0] Min_out,
input wire [6:0] Hour_out,
input wire [3:0] key_in_y, // 輸入矩陣鍵盤的列信號(KEY0~KEY3)
output reg [3:0] key_out_x, // 輸出矩陣鍵盤的行信號(KEY4~KEY7)
output reg [6:0] Sec, //秒修改
output reg [6:0] Min, //分修改
output reg [6:0] Hour, //時修改
output reg en , //時鐘是否運行的使能信號
output reg time_en //時鐘是否運行的使能信號
);
//寄存器定義
reg [19:0] count;
reg [1:0] count1; //時鐘修改的時候,在修改時它的值等于當前已經變化后的值,count1作為該修改值的使能信號
//==============================================
// 輸出矩陣鍵盤的行信號,20ms 掃描矩陣鍵盤一次,采樣頻率小于按鍵毛刺頻率,相當于濾除掉了高頻毛刺信號。
//==============================================
always @(posedge clk or negedge rst_n) //檢測時鐘的上升沿和復位的下降沿
begin
if(!rst_n) begin //復位信號低有效
count <= 20'd0; //計數(shù)器清 0
key_out_x <= 4'b1111;
end
else begin
if(count == 20'd0) //0ms 掃描第一行矩陣鍵盤
begin
key_out_x <= 4'b1110; //開始掃描第一行矩陣鍵盤,第一行輸出0
count <= count + 20'b1; //計數(shù)器加1
end
else if(count == 20'd249_999) //5ms 掃描第二行矩陣鍵盤,5ms 計數(shù)(50M/200-1=249_999)
begin
key_out_x <= 4'b1101; //開始掃描第二行矩陣鍵盤,第二行輸出 0
count <= count + 20'b1; //計數(shù)器加 1
end
else if(count ==20'd499_999) //10ms掃描第三行矩陣鍵盤 ,10ms計數(shù)(50M/100-1=499_999)
begin
key_out_x <= 4'b1011; //掃描第三行矩陣鍵盤,第三行輸出0
count <= count + 20'b1; //計數(shù)器加1
end
else if(count ==20'd749_999) //15ms掃描第四行矩陣鍵盤 ,15ms 計 數(shù)(50M/67.7-1=749_999)
begin
key_out_x <= 4'b0111; //掃描第四行矩陣鍵盤,第四行輸出0
count <= count + 20'b1; //計數(shù)器加 1
end
else if(count ==20'd999_999) //20ms 計數(shù)(50M/50-1=999_999)
begin
count <= 0; //計數(shù)器為 0
end
else
count <= count + 20'b1; //計數(shù)器加 1
end
end
//====================================================
// 采樣列的按鍵信號
//====================================================
reg [3:0] key_h1_scan; //第一行按鍵掃描值 KEY
reg [3:0] key_h1_scan_r; //第一行按鍵掃描值寄存器 KEY
reg [3:0] key_h2_scan; //第二行按鍵掃描值 KEY
reg [3:0] key_h2_scan_r; //第二行按鍵掃描值寄存器 KEY
reg [3:0] key_h3_scan; //第三行按鍵掃描值 KEY
reg [3:0] key_h3_scan_r; //第三行按鍵掃描值寄存器 KEY
reg [3:0] key_h4_scan; //第四行按鍵掃描值 KEY
reg [3:0] key_h4_scan_r; //第四行按鍵掃描值寄存器 KEY
always @(posedge clk)
begin
if(!rst_n) begin //復位信號低有效
key_h1_scan <= 4'b1111;
key_h2_scan <= 4'b1111;
key_h3_scan <= 4'b1111;
key_h4_scan <= 4'b1111;
end
else begin
if(count == 20'd124_999) //2.5ms 掃描第一行矩陣鍵盤值
key_h1_scan<=key_in_y; //掃描第一行的矩陣鍵盤值
else if(count == 20'd374_999) //7.5ms 掃描第二行矩陣鍵盤值
key_h2_scan<=key_in_y; //掃描第二行的矩陣鍵盤值
else if(count == 20'd624_999) //12.5ms 掃描第三行矩陣鍵盤值
key_h3_scan<=key_in_y; //掃描第三行的矩陣鍵盤值
else if(count == 20'd874_999) //17.5ms 掃描第四行矩陣鍵盤值
key_h4_scan<=key_in_y; //掃描第四行的矩陣鍵盤值
end
end
//====================================================
// 按鍵信號鎖存一個時鐘節(jié)拍
//====================================================
always @(posedge clk)
begin
key_h1_scan_r <= key_h1_scan;
key_h2_scan_r <= key_h2_scan;
key_h3_scan_r <= key_h3_scan;
key_h4_scan_r <= key_h4_scan;
end
wire [3:0] flag_h1_key = key_h1_scan_r[3:0] & (~key_h1_scan[3:0]); //當檢測到按鍵有下降沿變化時,代表該按鍵被按下,按鍵有效
wire [3:0] flag_h2_key = key_h2_scan_r[3:0] & (~key_h2_scan[3:0]); //當檢測到按鍵有下降沿變化時,代表該按鍵被按下,按鍵有效
wire [3:0] flag_h3_key = key_h3_scan_r[3:0] & (~key_h3_scan[3:0]); //當檢測到按鍵有下降沿變化時,代表該按鍵被按下,按鍵有效
wire [3:0] flag_h4_key = key_h4_scan_r[3:0] & (~key_h4_scan[3:0]); //當檢測到按鍵有下降沿變化時,代表該按鍵被按下,按鍵有效
/* 狀態(tài)參數(shù)的定義 --- 可以使用獨熱碼 */
parameter IDLE = 5'b00001, //初始狀態(tài)(也是終態(tài)) 使能信號正常,可以初次進行時鐘正常運行
ONE = 5'b00010, //設置秒的個十位
TWO = 5'b00100, //設置分
THREE = 5'b01000, //設置時
SETTING = 5'b10000; //時間設置鍵 使能信號失效
/**************按鍵排列******************
K1設置鍵 K2設置秒 K3設置分 K4設置時
K5確認鍵
K9時間加 K10時間減
*****************************************/
reg [4:0] state ; //狀態(tài)跳變
//狀態(tài)跳轉
always@ (posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
state <=IDLE;
else
case(state)
IDLE: if(flag_h1_key[0]==1'b1)
state <= SETTING;
else
state <= IDLE;
SETTING:if(flag_h1_key[1]==1'b1)
state <= ONE;
else if(flag_h1_key[2]==1'b1)
state <= TWO;
else if(flag_h1_key[3]==1'b1)
state <= THREE;
else if(flag_h2_key[0]==1'b1)
state <= IDLE;
else
state <= SETTING;
ONE: if(flag_h1_key[2])
state <= TWO;
else if(flag_h1_key[3]==1'b1)
state <= THREE;
else if(flag_h2_key[0]==1'b1)
state <= IDLE;
else
state <= ONE;
TWO: if(flag_h1_key[1])
state <= ONE;
else if(flag_h1_key[3]==1'b1)
state <= THREE;
else if(flag_h2_key[0]==1'b1)
state <= IDLE;
else
state <= TWO;
THREE: if(flag_h1_key[1]==1'b1)
state <= ONE;
else if(flag_h1_key[2]==1'b1)
state <= TWO;
else if(flag_h2_key[0]==1'b1)
state <= IDLE;
else
state <= THREE;
default:state <=IDLE;
endcase
end
/* 描述狀態(tài)IDLE和SETTING的輸出 */
always@(posedge clk or negedge rst_n)
begin
if(rst_n==1'b0)begin
en <= 1'b0;
time_en <= 1'b0;
count1 <=1'b0;
end
else if(state <= IDLE) begin //相當于確認按鍵,按下以后使能信號有效,時鐘繼續(xù)運行
en <= 1'b1;
time_en <= 1'b0;
end
else if(state <= SETTING)begin
en <= 1'b0;
time_en <= 1'b1;
count1 <= 1'b1;
end
else if(flag_h2_key[0]==1'b1)
count1 <= 1'b0;
else begin
en <= en;
end
end
/* 描述ONE狀態(tài)的輸出 */
always@(posedge clk or negedge rst_n)
begin
if(rst_n==1'b0)begin
Sec <= 7'd57;
end
else if(state==SETTING && count1 ==1'b0)begin
Sec <= Sec_out;
end
else if (state == ONE && flag_h3_key[0] == 1'b1 && Sec < 59)
Sec <=Sec + 1'b1;
else if (state == ONE && flag_h3_key[1] == 1'b1 && Sec >0)
Sec <=Sec - 1'b1;
else if(state == ONE && flag_h3_key[0] == 1'b1 && Sec == 7'd59)
Sec<= 7'd0;
else if(state == ONE && flag_h3_key[1] == 1'b1 && Sec == 7'd0)
Sec<=7'd59;
else
Sec <=Sec;
end
/* 描述TWO狀態(tài)的輸出 */
always@(posedge clk or negedge rst_n)
begin
if(rst_n==1'b0)begin
Min <= 7'd46;
end
else if(state==SETTING && count1 ==1'b0)begin
Min <= Min_out;
end
else if (state == TWO && flag_h3_key[0] == 1'b1 && Min < 59)
Min <= Min + 1'b1;
else if (state == TWO && flag_h3_key[1] == 1'b1 && Min >0)
Min <= Min - 1'b1;
else if(state == TWO && flag_h3_key[0] == 1'b1 && Min == 7'd59)
Min<= 7'd0;
else if(state == TWO && flag_h3_key[1] == 1'b1 && Min == 7'd0)
Min<=7'd59;
else
Min <= Min;
end
/* 描述THREE狀態(tài)的輸出 */
always@(posedge clk or negedge rst_n)
begin
if(rst_n==1'b0)begin
Hour<= 7'd12;
end
else if(state==SETTING && count1 ==1'b0)begin
Hour <= Hour_out;
end
else if (state == THREE && flag_h3_key[0] == 1'b1 && Hour < 7'd23)
Hour <=Hour + 1'b1;
else if (state == THREE && flag_h3_key[1] == 1'b1 && Hour > 7'd0)
Hour <=Hour - 1'b1;
else if(state == THREE && flag_h3_key[0] == 1'b1 && Hour == 7'd23)
Hour<= 7'd0;
else if(state == THREE && flag_h3_key[1] == 1'b1 && Hour == 7'd0)
Hour<=7'd23;
else
Hour <=Hour;
end
endmodule
6.?seg_dynamic.v
代碼如下:
module seg_dynamic
(
input wire clk,
input wire rst_n,
input wire [4:0] Sec1, //秒的個位
input wire [4:0] Sec2, //秒的十位
input wire [4:0] Min1, //分的個位
input wire [4:0] Min2, //分的十位
input wire [4:0] Hour1, //時的個位
input wire [4:0] Hour2, //時的十位
output reg [5:0] sel , //數(shù)碼管位選信號
output reg [7:0] seg //數(shù)碼管段選信號
);
//十六進制數(shù)顯示編碼
parameter
SEG_0 = 8'b1100_0000,
SEG_1 = 8'b1111_1001,
SEG_2 = 8'b1010_0100,
SEG_3 = 8'b1011_0000,
SEG_4 = 8'b1001_1001,
SEG_5 = 8'b1001_0010,
SEG_6 = 8'b1000_0010,
SEG_7 = 8'b1111_1000,
SEG_8 = 8'b1000_0000,
SEG_9 = 8'b1001_0000,
SEG_A = 8'b1000_1000, SEG_B = 8'b1000_0011,
SEG_C = 8'b1100_0110, SEG_D = 8'b1010_0001,
SEG_E = 8'b1000_0110, SEG_F = 8'b1000_1110;
parameter IDLE = 8'b1111_1111; //不顯示狀態(tài)
//reg define
reg [23:0] data_reg ; //待顯示數(shù)據寄存器
reg [15:0] cnt_1ms ; //1ms計數(shù)器
reg flag_1ms ; //1ms標志信號
reg [2:0] cnt_sel ; //數(shù)碼管位選計數(shù)器
reg [5:0] sel_reg ; //位選信號
reg [3:0] data_disp ; //當前數(shù)碼管顯示的數(shù)據
parameter CNT_MAX = 16'd49_999; //數(shù)碼管刷新時間計數(shù)最大值
reg [7:0] led_SG ; //秒的個位
reg [7:0] led_SS ; //秒的十位
reg [7:0] led_MG ; //分的個位
reg [7:0] led_MS ; //分的十位
reg [7:0] led_HG ; //時的個位
reg [7:0] led_HS ; //時的十位
/****************************************************
*****************數(shù)碼管段選信號**********************
******************************************************/
//七段數(shù)碼管顯示秒的個位
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
led_SG<=IDLE;
else begin
case(Sec1)
0: led_SG<=SEG_0;
1: led_SG<=SEG_1;
2: led_SG<=SEG_2;
3: led_SG<=SEG_3;
4: led_SG<=SEG_4;
5: led_SG<=SEG_5;
6: led_SG<=SEG_6;
7: led_SG<=SEG_7;
8: led_SG<=SEG_8;
9: led_SG<=SEG_9;
default led_SG<=IDLE;
endcase
end
end
//七段數(shù)碼管顯示秒的十位
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
led_SS<=IDLE;
else begin
case(Sec2)
0: led_SS<=SEG_0;
1: led_SS<=SEG_1;
2: led_SS<=SEG_2;
3: led_SS<=SEG_3;
4: led_SS<=SEG_4;
5: led_SS<=SEG_5;
6: led_SS<=SEG_6;
7: led_SS<=SEG_7;
8: led_SS<=SEG_8;
9: led_SS<=SEG_9;
default led_SS<=IDLE;
endcase
end
end
//七段數(shù)碼管顯示分的個位
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
led_MG<=IDLE;
else begin
case(Min1)
0: led_MG<=8'b0100_0000;
1: led_MG<=8'b0111_1001;
2: led_MG<=8'b0010_0100;
3: led_MG<=8'b0011_0000;
4: led_MG<=8'b0001_1001;
5: led_MG<=8'b0001_0010;
6: led_MG<=8'b0000_0010;
7: led_MG<=8'b0111_1000;
8: led_MG<=8'b0000_0000;
9: led_MG<=8'b0001_0000;
default led_MG<=8'b0111_1111;
endcase
end
end
//七段數(shù)碼管顯示分的十位
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
led_MS<=IDLE;
else begin
case(Min2)
0: led_MS<=SEG_0;
1: led_MS<=SEG_1;
2: led_MS<=SEG_2;
3: led_MS<=SEG_3;
4: led_MS<=SEG_4;
5: led_MS<=SEG_5;
6: led_MS<=SEG_6;
7: led_MS<=SEG_7;
8: led_MS<=SEG_8;
9: led_MS<=SEG_9;
default led_MS<=IDLE;
endcase
end
end
//七段數(shù)碼管顯示時的個位
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
led_HG <= IDLE;
else begin
case(Hour1)
0: led_HG <= 8'b0100_0000;
1: led_HG <= 8'b0111_1001;
2: led_HG <= 8'b0010_0100;
3: led_HG <= 8'b0011_0000;
4: led_HG <= 8'b0001_1001;
5: led_HG <= 8'b0001_0010;
6: led_HG <= 8'b0000_0010;
7: led_HG <= 8'b0111_1000;
8: led_HG <= 8'b0000_0000;
9: led_HG <= 8'b0001_0000;
default led_HG <= 8'b0111_1111;
endcase
end
end
//七段數(shù)碼管顯示時的十位
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
led_HS<=IDLE;
else begin
case(Hour2)
0: led_HS<=SEG_0;
1: led_HS<=SEG_1;
2: led_HS<=SEG_2;
3: led_HS<=SEG_3;
// 4: led_HS<=SEG_4;
// 5: led_HS<=SEG_5;
// 6: led_HS<=SEG_6;
// 7: led_HS<=SEG_7;
// 8: led_HS<=SEG_8;
// 9: led_HS<=SEG_9;
default led_HS<=IDLE;
endcase
end
end
/****************************************************
*****************數(shù)碼管位選信號**********************
******************************************************/
//cnt_1ms:1ms循環(huán)計數(shù)
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
cnt_1ms <= 16'd0;
else if(cnt_1ms == CNT_MAX)
cnt_1ms <= 16'd0;
else
cnt_1ms <= cnt_1ms + 1'b1;
//flag_1ms:1ms標志信號
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
flag_1ms <= 1'b0;
else if(cnt_1ms == CNT_MAX - 1'b1)
flag_1ms <= 1'b1;
else
flag_1ms <= 1'b0;
//cnt_sel:從0到5循環(huán)數(shù),用于選擇當前顯示的數(shù)碼管
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
cnt_sel <= 3'd0;
else if((cnt_sel == 3'd5) && (flag_1ms == 1'b1))
cnt_sel <= 3'd0;
else if(flag_1ms == 1'b1)
cnt_sel <= cnt_sel + 1'b1;
else
cnt_sel <= cnt_sel;
//數(shù)碼管位選信號寄存器
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
sel_reg <= 6'b000_000;
else if((cnt_sel == 3'd0) && (flag_1ms == 1'b1))
sel_reg <= 6'b000_001;
else if(flag_1ms == 1'b1)
sel_reg <= sel_reg << 1;
else
sel_reg <= sel_reg;
//控制數(shù)碼管的位選信號,使六個數(shù)碼管輪流顯示
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
seg <= 8'hff;
else if( flag_1ms == 1'b1)
case(cnt_sel)
3'd0: seg <= led_HS; //給第6個數(shù)碼管賦十萬位值
3'd1: seg <= led_HG; //給第5個數(shù)碼管賦萬位值
3'd2: seg <= led_MS; //給第4個數(shù)碼管賦千位值
3'd3: seg <= led_MG ; //給第3個數(shù)碼管賦百位值
3'd4: seg <= led_SS ; //給第2個數(shù)碼管賦十位值
3'd5: seg <= led_SG ; //給第1個數(shù)碼管賦個位值
default:seg <= 8'hff;
endcase
else
seg <= seg;
//sel:數(shù)碼管位選信號賦值
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
sel <= 6'b111_111;
else
sel <= ~sel_reg;
endmodule
7.?buzzer.v
buzzer==0響否則=1不響,歌曲放了兩首,都能使用,自行選擇,但意義不大。
代碼如下:
?
module buzzer(
input wire clk , //系統(tǒng)時鐘50MHz
input wire rst_n ,
input wire [6:0] Sec_out ,
input wire [6:0] Min_out ,
// input wire Min1 ,
// input wire Min2 ,
output reg buzzer //蜂鳴器輸出端
);
// assign buzzer =( Sec_out==1'b0 && Min_out==1'b0 )?0:1; //只響一秒鐘
/**********--------------森林狂想曲-----------------************************/
//模塊名稱song
reg beep_r; //寄存器
reg[7:0] state; //樂譜狀態(tài)機
reg[16:0]count,count_end;
reg[23:0]count1;
//樂譜參數(shù):D=F/2K (D:參數(shù),F:時鐘頻率,K:音高頻率)
parameter L_3 = 17'd75850, //低音3
L_5 = 17'd63776, //低音5
L_6 = 17'd56818, //低音6
L_7 = 17'd50618, //低音7
M_1 = 17'd47774, //中音1
M_2 = 17'd42568, //中音2
M_3 = 17'd37919, //中音3
M_5 = 17'd31888, //中音5
M_6 = 17'd28409, //中音6
H_1 = 17'd23889; //高音1
parameter TIME = 12000000; //控制每一個音的長短(250ms)
// assign buzzer = beep_r; //輸出音樂
//★★★以下兩個時序邏輯模塊較為重點關注
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)begin
buzzer <= 1'b1;
end
else if(Min_out==1'b0 && Sec_out<=7'd3) //整點報時并3s后停止
buzzer <= beep_r;
else
buzzer <=1'b1;
end
always@(posedge clk) begin
count <= count + 1'b1; //計數(shù)器加1
if(count == count_end) begin
count <= 17'h0; //計數(shù)器清零
beep_r <= !beep_r; //輸出取反
end
end
//曲譜 產生分頻的系數(shù)并描述出曲譜
always @(posedge clk) begin
if(count1 < TIME) //一個節(jié)拍250mS
count1 = count1 + 1'b1;
else begin
count1 = 24'd0;
if(state == 8'd63)
state = 8'd0;
else
state = state + 1'b1;
case(state)
8'd0:count_end = L_6;
8'd1:count_end=M_1;
8'd2:count_end=M_3;
8'D3:count_end=M_5;
8'D4,8'D5:count_end=M_3;
8'D6:count_end=M_3;
8'D7:count_end=M_2;
8'D8,8'D9:count_end=M_3;
8'D10:count_end=M_3;
8'D11:count_end=M_2;
8'D12,8'D13:count_end=M_3;
8'D14:count_end=L_6;
8'D15:count_end=L_7;
8'D16:count_end=M_1;
8'D17:count_end=M_3;
8'D18:count_end=M_2;
8'D19:count_end=M_1;
8'D20,8'D21:count_end=L_6;
8'D22,8'D23:count_end=L_5;
8'D24,8'D25,8'D26,8'D27,8'D28,8'D29,8'D30,8'D31:count_end=L_3;
8'd32:count_end = L_6;
8'd33:count_end=M_1;
8'd34:count_end=M_3;
8'D35:count_end=M_5;
8'D36,8'D37:count_end=M_3;
8'D38:count_end=M_3;
8'D39:count_end=M_2;
8'D40,8'D41:count_end=M_3;
8'D42:count_end=M_3;
8'D43:count_end=M_2;
8'D44,8'D45:count_end=M_3;
8'D46:count_end=L_6;
8'D47:count_end=L_7;
8'D48:count_end=M_1;
8'D49:count_end=M_3;
8'D50:count_end=M_2;
8'D51:count_end=M_1;
8'D52,8'D53:count_end=L_6;
8'D54,8'D55:count_end=L_5;
8'D56,8'D57,8'D58,8'D59,8'D60,8'D61:count_end=L_6;
8'D62:count_end=L_6;
8'D63:count_end=L_7;
default: count_end = 16'h0;
endcase
end
end
/************************************************************************
-------------------------兩只老虎----------------------------------------
//中間信號定義
reg [16:0] cnt0 ; //產生PWM的計數(shù)器
wire add_cnt0;
wire end_cnt0;
reg [7:0] cnt1 ; //每個音符持續(xù)時間的計數(shù)器
wire add_cnt1;
wire end_cnt1;
reg [5:0] cnt2 ; //《兩只老虎》共32個音節(jié)
wire add_cnt2;
wire end_cnt2;
reg [16:0] pre_set ; //存放每個音節(jié)的頻率在系統(tǒng)中的時鐘個數(shù)
//每個音符對應的系統(tǒng)周期計數(shù),中音
localparam M1=95602, //音符1do
M2=85178, //音符rui
M3=75872, //音符mi
M4=71633, //音符fa
M5=63775, //音符so
M6=56818, //音符la
M7=50607; //音符xi
//每個音符對應的系統(tǒng)周期計數(shù),低音音符so,頻率392
//周期是1/392s,換算成ns是2551020ns,每個
//系統(tǒng)時鐘周期是20ns,所以上述是2551020/20個系統(tǒng)周期個數(shù)127,551
localparam D5=127551; //音符so,低音
//每個音節(jié)的頻率在系統(tǒng)時鐘周期下對應的系統(tǒng)周期個數(shù)
//--------------------------------------------
//比如:音符1的頻率是523HZ,它的周期是1/523s,換算成ns是1912045ns,每個
//系統(tǒng)時鐘周期是20ns,所以上述是1912045/20個系統(tǒng)周期個數(shù),即cnt0的計數(shù)
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt0<=0;
end
else if(add_cnt0)begin
if(end_cnt0)
cnt0<=0;
else
cnt0<=cnt0+1;
end
end
assign add_cnt0=1'b1;
assign end_cnt0=add_cnt0 && cnt0==pre_set-1;
// assign buzzer=(cnt0>=(pre_set/2) && Min_out==1'b0)?1:0; //每個音符的占空比為50%
//每個音符持續(xù)一段時間
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)begin
buzzer <= 1'b1;
end
else if(cnt0>=(pre_set/2) && Min_out==1'b0 && Sec_out<=7'd3)
buzzer <= 1'b0;
else
buzzer <=1'b1;
end
//每個音符持續(xù)一段時間
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt1<=0;
end
else if(add_cnt1)begin
if(end_cnt1)
cnt1<=0;
else
cnt1<=cnt1+1;
end
end
assign add_cnt1=end_cnt0;
assign end_cnt1=add_cnt1 && cnt1==150-1;
//計32個音符(兩只老虎共32音節(jié))
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt2<=0;
end
else if(add_cnt2)begin
if(end_cnt2)
cnt2<=0;
else
cnt2<=cnt2+1;
end
end
assign add_cnt2=end_cnt1;
assign end_cnt2=add_cnt2 && cnt2==32-1;
//存放歌曲的簡譜
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)begin
pre_set<=0;
end
else begin
case(cnt2)
0:pre_set<=M1;
1:pre_set<=M2;
2:pre_set<=M3;
3:pre_set<=M1;
4:pre_set<=M1;
5:pre_set<=M2;
6:pre_set<=M3;
7:pre_set<=M1;
8:pre_set<=M3;
9:pre_set<=M4;
10:pre_set<=M5;
11:pre_set<=M3;
12:pre_set<=M4;
13:pre_set<=M5;
14:pre_set<=M5;
15:pre_set<=M6;
16:pre_set<=M5;
17:pre_set<=M4;
18:pre_set<=M3;
19:pre_set<=M1;
20:pre_set<=M5;
21:pre_set<=M6;
22:pre_set<=M5;
23:pre_set<=M4;
24:pre_set<=M3;
25:pre_set<=M1;
26:pre_set<=M2;
27:pre_set<=D5;
28:pre_set<=M1;
29:pre_set<=M2;
30:pre_set<=D5;
31:pre_set<=M1;
default:pre_set<=0;
endcase
end
end
*/
endmodule
?
? ? ? ? 對于以上各個模塊內,進行了非常清晰的層次化設計,大部分都有了較為詳細的標注,并通過了基礎測試驗證。從頂層文件開始,對照各個參數(shù)寄存器等依次往下進行理解比較,最后得出自己的設計結果。
對于各個引腳配置如下:
? ? ? ?對于引腳的配置,可直接將如下配置直接復制到EDA_clock.qsf文件中,然后進行綜合即可直接配置完成。
set_location_assignment PIN_E1 -to sys_clk
set_location_assignment PIN_N13 -to rst_n
set_location_assignment PIN_R14 -to seg[0]
set_location_assignment PIN_N9 -to sel[0]
set_location_assignment PIN_P9 -to sel[1]
set_location_assignment PIN_M10 -to sel[2]
set_location_assignment PIN_N11 -to sel[3]
set_location_assignment PIN_P11 -to sel[4]
set_location_assignment PIN_M11 -to sel[5]
set_location_assignment PIN_N16 -to seg[1]
set_location_assignment PIN_P16 -to seg[2]
set_location_assignment PIN_T15 -to seg[3]
set_location_assignment PIN_P15 -to seg[4]
set_location_assignment PIN_N12 -to seg[5]
set_location_assignment PIN_N15 -to seg[6]
set_location_assignment PIN_R16 -to seg[7]
set_location_assignment PIN_B5 -to key_in_y[3]
set_location_assignment PIN_A4 -to key_in_y[2]
set_location_assignment PIN_B4 -to key_in_y[1]
set_location_assignment PIN_A3 -to key_in_y[0]
set_location_assignment PIN_B3 -to key_out_x[3]
set_location_assignment PIN_A2 -to key_out_x[2]
set_location_assignment PIN_B1 -to key_out_x[1]
set_location_assignment PIN_C2 -to key_out_x[0]
set_location_assignment PIN_C11 -to buzzer
運行成功:文章來源:http://www.zghlxwxcb.cn/news/detail-761852.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-761852.html
到了這里,關于基于FPGA的電子時鐘設計與實現(xiàn) (在EDA開發(fā)板上實現(xiàn)電子時鐘功能)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!