用FPGA設(shè)計(jì)一個(gè)數(shù)字鬧鐘應(yīng)該說(shuō)是一個(gè)比較綜合的小系統(tǒng)门躯,包含了按鍵声旺、數(shù)碼
管、狀態(tài)機(jī)等內(nèi)容席楚,本文主要是講述三鍵輸入的數(shù)字鬧鐘總體的設(shè)計(jì),整個(gè)作品和小時(shí)候兩三塊一個(gè)的電子手表十分類(lèi)似
功能描述
1 用四個(gè)數(shù)碼管正常顯示時(shí)税稼、分高低位烦秩,實(shí)現(xiàn)正常顯示時(shí)間。
2 具備調(diào)分調(diào)時(shí)功能
3 鬧鐘功能
功能并不復(fù)雜郎仆,我們現(xiàn)在來(lái)分析一下需要哪些模塊闻镶。
首先是時(shí)鐘功能,正常顯示時(shí)間肯定是必須的丸升,為實(shí)現(xiàn)這一可以設(shè)計(jì)一個(gè)60進(jìn)制計(jì)數(shù)器和一個(gè)24進(jìn)制計(jì)數(shù)器铆农,當(dāng)然也可以根據(jù)邏輯直接書(shū)寫(xiě)出來(lái),但無(wú)論是什么辦法狡耻,這肯定需要一個(gè)模塊來(lái)實(shí)現(xiàn)它墩剖。
第二就是調(diào)分調(diào)時(shí)了,說(shuō)白了就是置數(shù)夷狰,要置數(shù)岭皂,那么就必須有一個(gè)區(qū)域去控制數(shù)據(jù),也需要一個(gè)地方存儲(chǔ)數(shù)據(jù)沼头,然后將置數(shù)的數(shù)據(jù)傳給時(shí)鐘爷绘,所以它應(yīng)該與鍵盤(pán)的聯(lián)系,內(nèi)部有存儲(chǔ)器进倍。
第三是鬧鐘土至,鬧鐘不難想,比較器猾昆,我設(shè)定鬧鐘時(shí)間陶因,然后與時(shí)鐘的時(shí)間比較,如果兩者相同垂蜗,輸出鬧鐘信號(hào)楷扬,就是如此解幽。
最后的便是顯示電路,主要是數(shù)碼管的顯示原理烘苹,驅(qū)動(dòng)數(shù)碼管顯示時(shí)間躲株。
就是這幾樣部分,貌似這么一說(shuō)镣衡,確實(shí)沒(méi)有什么東西徘溢,一個(gè)系統(tǒng)就是需要輸入和輸出相互協(xié)調(diào)好,這里面的邏輯必須是相互對(duì)應(yīng)的捆探,不出矛盾然爆,個(gè)人認(rèn)為,這是設(shè)計(jì)的難度所在黍图。
整體設(shè)計(jì)圖
模塊講解
鍵盤(pán)模塊(key)
輸入 | 功能說(shuō)明 | 輸出 | 功能說(shuō)明 |
---|---|---|---|
add_in | 加 | c_add | 時(shí)鐘加 |
aub_in | 減 | c_sub | 時(shí)鐘減 |
model_in | 模式控制端 | a_hour | 調(diào)鬧鐘小時(shí) |
clk | 時(shí)鐘 | a_minute | 調(diào)鬧鐘分鐘 |
rst_n | 復(fù)位 | cnt_control | 計(jì)數(shù)器開(kāi)關(guān) |
Display_Model | 顯示控制 | ||
Time_model | 調(diào)時(shí)鐘轉(zhuǎn)換信號(hào) |
細(xì)節(jié)講解
model:模式的選擇寄存器
整個(gè)鬧鐘系統(tǒng)我設(shè)置為五個(gè)模式曾雕,所以model需要是三位的[2:0]
00:時(shí)鐘正常走時(shí)
01:時(shí)鐘調(diào)分模式,該模式下時(shí)鐘的計(jì)數(shù)器停止助被,時(shí)鐘是不走的剖张,同時(shí)顯示模式也會(huì)轉(zhuǎn)到調(diào)時(shí)鐘模式。
10:時(shí)鐘調(diào)時(shí)模式揩环,與調(diào)分模式類(lèi)似搔弄。
11:鬧鐘調(diào)分設(shè)置模式,此時(shí)時(shí)鐘走時(shí)丰滑,顯示模式為鬧鐘模式顾犹。
100:鬧鐘調(diào)時(shí)模式,與調(diào)分時(shí)類(lèi)似褒墨。
cnt_control:計(jì)數(shù)器開(kāi)關(guān)
正常走時(shí)和調(diào)鬧鐘模式下炫刷,計(jì)數(shù)器開(kāi),cnt_control = 0;
當(dāng)進(jìn)入調(diào)分和調(diào)時(shí)模式郁妈,計(jì)數(shù)器關(guān)閉浑玛,cnt_control = 1。
Time_Model:調(diào)時(shí)鐘轉(zhuǎn)換信號(hào)
這個(gè)是連接時(shí)鐘模塊(clock)的噩咪,是調(diào)分模式和調(diào)時(shí)模式的切換信號(hào)顾彰。
Display_Model:顯示控制
正常走時(shí),進(jìn)入調(diào)分和調(diào)時(shí)模式時(shí)胃碾,停止走時(shí)涨享,整個(gè)過(guò)程我設(shè)置為同一種顯示模式;
鬧鐘模式下书在,顯示模式轉(zhuǎn)換灰伟;
所以一共是兩種模式拆又,一根線(xiàn)足以儒旬。
代碼展示
module key(
input clk,
input rst_n,
input add_in,//增加按鈕
input sub_in,//減去按鈕
input model_in,//模式選擇
output reg Display_Model,
//時(shí)鐘與鬧鐘顯示選擇栏账,0 代表時(shí)鐘,1代表鬧鐘
output reg cnt_control, //控制定時(shí)器
output reg [2:0]Time_model,
output reg c_add, //控制時(shí)鐘 加
output reg c_sub, //控制時(shí)鐘 減
output reg a_add, //控制鬧鐘 加
output reg a_sub //控制鬧鐘 減
);
/************************************/
parameter T40MS = 20'd40_000;
parameter T1S = 30'd1_000_000;
/************************************/
/// add_in 按鍵 /////
reg add;
reg [19:0]cnt_a;
reg [1:0]a;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt_a <= 0;
a <= 0;
add <= 1;
end
else
begin
case(a)
0:begin
if(cnt_a < T40MS)
// 按下時(shí)間大于40MS 認(rèn)為有效
begin
if(!add_in)
cnt_a = cnt_a+1'b1;
else
cnt_a = 0;
end
else //counter> 40MS 栈源,說(shuō)明確實(shí)按鍵是按下了
begin
add = 0;
// 給沖擊信號(hào) 挡爵,0~1 是上升沿
a = 1;
//確定按鍵按下,轉(zhuǎn)到狀態(tài) 1
cnt_a = 0; //計(jì)數(shù)器清零
end
end
1:begin
add = 1; //產(chǎn)生尖脈沖
if(cnt_a < T40MS)
// 按下時(shí)間大于40MS 松開(kāi)有效
begin
if(add_in)
cnt_a = cnt_a+1'b1;
else
cnt_a = 0;
end
else
begin
a = 0;
// 若松開(kāi)甚垦,回到狀態(tài) 0 茶鹃,等待下次按鍵到來(lái)
cnt_a = 0;
end
end
default : a = 1;
endcase
end
end
//////////////////////////////////////////////////////////
/// sub_in 按鍵 ///
reg sub;
reg [19:0]cnt_s;
reg [1:0]s;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt_s <= 0;
s <= 0;
sub <= 1;
end
else
begin
case(s)
0:begin
if(cnt_s < T40MS)
// 按下時(shí)間大于40MS 認(rèn)為有效
begin
if(!sub_in)
cnt_s = cnt_s+1'b1;
else
cnt_s = 0;
end
else //counter> 40MS ,說(shuō)明確實(shí)按鍵是按下了
begin
sub = 0;
// 給沖擊信號(hào) 艰亮,0~1 是上升沿
s = 1;
//確定按鍵按下闭翩,轉(zhuǎn)到狀態(tài) 1
cnt_s = 0; //計(jì)數(shù)器清零
end
end
1:begin
sub = 1; //產(chǎn)生尖脈沖
if(cnt_s < T40MS)
// 按下時(shí)間大于40MS 松開(kāi)有效
begin
if(sub_in)
cnt_s = cnt_s+1'b1;
else
cnt_s = 0;
end
else
begin
s = 0;
// 若松開(kāi),回到狀態(tài) 0 迄埃,等待下次按鍵到來(lái)
cnt_s = 0;
end
end
default : s = 1;
endcase
end
end
////////////////////////////////////////////////////////////
/// model_in 按鍵 ///
reg model;
reg [19:0]cnt_m;
reg [1:0]m;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt_m <= 0;
m <= 0;
model <= 1;
end
else
begin
case(m)
0:begin
if(cnt_m < T40MS)
// 按下時(shí)間大于40MS 認(rèn)為有效
begin
if(!model_in)
cnt_m = cnt_m+1'b1;
else
cnt_m = 0;
end
else //counter> 40MS 疗韵,說(shuō)明確實(shí)按鍵是按下了
begin
model = 0;
// 給沖擊信號(hào) ,0~1 是上升沿
m = 1;
//確定按鍵按下侄非,轉(zhuǎn)到狀態(tài) 1
cnt_m = 0; //計(jì)數(shù)器清零
end
end
1:begin
model = 1; //產(chǎn)生尖脈沖
if(cnt_m < T40MS)
// 按下時(shí)間大于40MS 松開(kāi)有效
begin
if(model_in)
cnt_m = cnt_m+1'b1;
else
cnt_m = 0;
end
else
begin
m = 0;
// 若松開(kāi)蕉汪,回到狀態(tài) 0 ,等待下次按鍵到來(lái)
cnt_m = 0;
end
end
default : m = 1;
endcase
end
end
////////////////////////////////////////////////////////////
/************************************************/
reg [2:0]type;
//00:時(shí)鐘正常跑模式
//01:時(shí)鐘調(diào)分模式,在該模式時(shí)間計(jì)數(shù)器停止計(jì)數(shù)
//10: 時(shí)鐘調(diào)時(shí)模式逞怨,在該模式時(shí)間計(jì)數(shù)器停止計(jì)數(shù)
//11:鬧鐘調(diào)分模式者疤,在該模式時(shí)間計(jì)數(shù)器正常計(jì)數(shù)
//100:鬧鐘調(diào)時(shí)模式,在該模式時(shí)間計(jì)數(shù)器正常計(jì)數(shù)
/************************************************/
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
Display_Model <= 1'b0;
a_add <= 1'b0;
a_sub <= 1'b0;
c_add <= 1'b0;
c_sub <= 1'b0;
Time_model <= 3'b000;
type <= 3'b000;
cnt_control <= 1'b1;//啟動(dòng)計(jì)數(shù)
end
else
begin
if(!model)
begin
if(type == 3'b100)
type = 3'b000;
else
begin
type = type + 1'b1;
end
end
case(type)
//時(shí)鐘正常開(kāi)始跑
3'b000:
begin
Time_model <= 3'b000;
cnt_control <= 1'b1;//啟動(dòng)計(jì)數(shù)
Display_Model <= 1'b0;
a_add <= 1'b0;
a_sub <= 1'b0;
c_add <= 1'b0;
c_sub <= 1'b0;
end
//調(diào)分模式
3'b001:
begin
cnt_control <= 1'b0; //關(guān)閉計(jì)數(shù)
Time_model <= 3'b001;
Display_Model <= 1'b0;
if(!add)//加
begin
c_add <=1'b1 ;
end
else
begin
c_add <= 1'b0;
end
if(!sub)//減
begin
c_sub <= 1'b1;
end
else
begin
c_sub <= 1'b0;
end
end
//調(diào)時(shí)模式
3'b010:
begin
cnt_control <= 1'b0;//關(guān)閉計(jì)數(shù)
Time_model <= 2'b010;
Display_Model <= 1'b0;
if(!add)//加
begin
c_add <=1'b1 ;
end
else
begin
c_add <= 1'b0;
end
if(!sub)//減
begin
c_sub <= 1'b1;
end
else
begin
c_sub <= 1'b0;
end
end
//調(diào)分模式
3'b011:
begin
cnt_control <= 1'b1; //kaijishu
Time_model <= 3'b011;
Display_Model <= 1'b1;
if(!add)//加
begin
a_add <=1'b1 ;
end
else
begin
a_add <= 1'b0;
end
if(!sub)//減
begin
a_sub <= 1'b1;
end
else
begin
a_sub <= 1'b0;
end
end
//調(diào)時(shí)模式
3'b100:
begin
cnt_control <= 1'b1;//關(guān)閉計(jì)數(shù)
Time_model <= 3'b100;
Display_Model <= 1'b1;
if(!add)//加
begin
a_add <=1'b1 ;
end
else
begin
a_add <= 1'b0;
end
if(!sub)//減
begin
a_sub <= 1'b1;
end
else
begin
a_sub <= 1'b0;
end
end
default:type <= 3'b000;
endcase
end
endmodule
</div>
時(shí)鐘模塊(clock)
輸入 | 功能說(shuō)明 | 輸出 | 功能說(shuō)明 |
---|---|---|---|
c_add | 加 | hour_h | 小時(shí)高位 |
c_sub | 減 | hour_l | 小時(shí)低位 |
Time_model | 模式控制端 | minute_h | 分鐘高位 |
cot_control | 計(jì)數(shù)器開(kāi)關(guān) | minute_l | 分鐘低位 |
clk | 時(shí)鐘 | ||
rst_n | 復(fù)位 |
細(xì)節(jié)講解
時(shí)鐘模塊的輸入都是來(lái)自鍵盤(pán)模塊叠赦,所以輸入不多說(shuō)了驹马,提一點(diǎn),我的板子上的輸入的時(shí)鐘(clk)除秀,用的是50MHz晶振,而時(shí)鐘是1Hz,也就是一秒走一下窥翩,所以?xún)?nèi)部必須分頻,代碼里注意看一下鳞仙,我為了方便調(diào)試寇蚊,分頻并不是分頻到1Hz,如果你有需要用到棍好,修改里面的參數(shù)就好仗岸。
模塊輸出
模塊的輸出就是時(shí)鐘的數(shù)據(jù),是傳給顯示模塊去驅(qū)動(dòng)數(shù)碼管顯示的借笙。
小時(shí)高位扒怖,0~2,三種情況业稼,兩根線(xiàn)[1:0]
小時(shí)低位盗痒,0~0,十種情況,四根線(xiàn)[3:0]
分鐘高位俯邓,0~5骡楼,六種情況,三根線(xiàn)[2:0]
分鐘低位稽鞭,0~9鸟整,十種情況,四根線(xiàn)[3:0]
代碼展示
module clock(
input clk,
input rst_n,
input cnt_control, //控制定時(shí)器 ,1啟動(dòng) 朦蕴,0停止
input c_add, //控制 加
input c_sub, //控制 減
input [2:0]Time_model,
output [1:0]hour_h, //小時(shí) 十位
output [3:0]hour_l, //小時(shí) 個(gè)位
output [2:0]minute_h, //分鐘 十位
output [3:0]minute_l //分鐘 個(gè)位
);
parameter S= 100000000;
parameter M=60;
/*********************************************************/
//1S計(jì)數(shù)器
reg [31:0] cnt1s;
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt1s <= 15'd0;
else if((cnt1s == S) || (!cnt_control))
cnt1s <= 15'd0;
else if(cnt_control)
cnt1s <= cnt1s + 1'b1;
/*********************************************************/
///////////////////////////////////////////////////////////
// 功能控制 //
//////////////////////////////////////////////////////////
reg [1:0]flag;//用來(lái)標(biāo)志reg1是否到了2篮条,到了2,reg2只能加到4
reg [1:0] reg1;//時(shí)的第一位:0~2
reg [3:0] reg2;
//時(shí)的第二位:當(dāng)?shù)谝晃粸?和1時(shí),可以是0~9,當(dāng)?shù)谝晃粸?時(shí)吩抓,只能是0~9,
reg [2:0] reg3;//分的第一位:只能是0~5
reg [3:0] reg4;//分的第二位:是0~9
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
reg1 <= 2'd0; //小時(shí) 高位
reg2 <= 4'd0; //小時(shí) 低位
reg3 <= 3'd0; //分鐘 高位
reg4 <= 4'd0; //分鐘 低位
flag <= 2'd0;
end
else
case(Time_model)
//時(shí)鐘正常開(kāi)始跑
3'b000:
begin
if(cnt1s == S) //一分鐘到了
begin
reg4 <= reg4 + 1'b1;
if(reg4 == 4'd9)
begin
reg4 <= 4'd0;
reg3 <= reg3 + 1'b1;
if(reg3 == 3'd5)
begin
reg3 <= 3'd0;
if(reg1 == 2'd2)
begin
reg2 <= reg2 + 1'b1;
if(reg2 == 4'd3)
begin
reg2 <= 4'd0;
reg1 <= 2'd0;
end
end
else
begin
reg2 <= reg2 + 1'b1;
if(reg2 == 4'd9)
begin
reg2 <= 4'd0;
reg1 <= reg1 + 1'b1;
end
end
end
end
end
end
//調(diào)分模式
3'b001:
begin
if(c_add)//加
begin
reg4 <= reg4 + 1'b1;
if(reg4 == 4'd9)
begin
reg4 <= 4'd0;
reg3 <= reg3 + 1'b1;
if(reg3 > 3'd5)
reg3 <= 3'd0;
end
end
else if(c_sub)//減
begin
reg4 <= reg4 - 1'b1;
if(reg4 == 4'd0)
begin
reg4 <= 4'd9;
reg3 <= reg3 - 3'd1;
if(reg3 == 3'd0)
reg3 <= 3'd5;
end
end
end
//調(diào)時(shí)模式
3'b010:
begin
if(c_add)//加
begin
if(flag == 2'd2)
begin
reg2 <= reg2 + 1'b1;
if(reg2 >= 4'd3)
begin
reg2 <= 4'd0;
reg1 <= 2'd0;
flag <= 2'd0;
end
end
else
begin
reg2 <= reg2 + 1'b1;
if(reg2 == 4'd9)
begin
flag <= flag + 1'b1;
reg2 <= 4'd0;
reg1 <= reg1 + 1'b1;
end
end
end
else if(c_sub)//減
begin
if(flag == 2'd0)
begin
reg2 <= reg2 - 1'b1;
if(reg2 == 4'd0)
begin
reg2 <= 4'd3;
reg1 <= 2'd2;
flag <= 2'd2;
end
end
else
begin
reg2 <= reg2 - 1'b1;
if(reg2 == 4'd0)
begin
flag <= flag - 1'b1;
reg1 <= reg1 - 1'b1;
reg2 <= 4'd9;
end
end
end
end
endcase
end
/************************************************/
assign hour_h = reg1;
assign hour_l = reg2;
assign minute_h = reg3;
assign minute_l = reg4;
/************************************************/
endmodule
鬧鐘模塊(alarm)
輸入 | 功能說(shuō)明 | 輸出 | 功能說(shuō)明 |
---|---|---|---|
a_hour | 鬧鐘小時(shí)控制 | a_hour_h | 鬧鐘小時(shí)高位 |
a_minute | 鬧鐘分鐘控制 | a_hour_l | 鬧鐘小時(shí)低位 |
clk | 時(shí)鐘 | a_minute_h | 鬧鐘分鐘高位 |
rst_n | 復(fù)位 | a_minute_l | 鬧鐘分鐘低位 |
細(xì)節(jié)講解
鬧鐘模塊與時(shí)鐘模塊的其實(shí)沒(méi)什么區(qū)別涉茧,就是在調(diào)鬧鐘時(shí),時(shí)鐘正常運(yùn)行疹娶,時(shí)鐘調(diào)分降瞳,調(diào)時(shí)都會(huì)停止運(yùn)行,也就是計(jì)數(shù)器不計(jì)數(shù)蚓胸,其他的區(qū)別不大挣饥。
代碼展示
<button class="testButton" onclick="document.all.child3.style.display=(document.all.child3.style.display =='none')?'':'none'">點(diǎn)擊顯\隱代碼</button>
<div id="child3" style="display:">
module alarm(
input clk,
input rst_n,
input c_add, //控制 加
input c_sub, //控制 減
input [2:0]Time_model,
output [1:0]a_hour_h, //鬧鐘小時(shí) 十位
output [3:0]a_hour_l, //鬧鐘小時(shí) 個(gè)位
output [2:0]a_minute_h, //鬧鐘分鐘 十位
output [3:0]a_minute_l //鬧鐘分鐘 個(gè)位
);
//////////////////////////////////////////////////////////
// 功能控制 //
////////////////////////////////////////////////////////
reg [1:0]flag;//用來(lái)標(biāo)志reg1是否到了2,到了2,reg2只能加到4
reg [1:0] reg1;//時(shí)的第一位:0~2
reg [3:0] reg2;
//時(shí)的第二位:當(dāng)?shù)谝晃粸?和1時(shí)沛膳,可以是0~9,當(dāng)?shù)谝晃粸?時(shí)扔枫,只能是0~9,
reg [2:0] reg3;//分的第一位:只能是0~5
reg [3:0] reg4;//分的第二位:是0~9
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
reg1 <= 2'd0; //鬧鐘小時(shí) 高位
reg2 <= 4'd0; //鬧鐘小時(shí) 低位
reg3 <= 3'd0; //鬧鐘分鐘 高位
reg4 <= 4'd0; //鬧鐘分鐘 低位
flag <= 2'd0;
end
else
case(Time_model)
//鬧鐘調(diào)分模式
3'b011:
begin
if(c_add)//加
begin
reg4 <= reg4 + 1'b1;
if(reg4 == 4'd9)
begin
reg4 <= 4'd0;
reg3 <= reg3 + 1'b1;
if(reg3 > 3'd4)
reg3 <= 3'd0;
end
end
else if(c_sub)//減
begin
reg4 <= reg4 - 1'b1;
if(reg4 == 4'd0)
begin
reg4 <= 4'd9;
reg3 <= reg3 - 3'd1;
if(reg3 == 3'd0)
reg3 <= 3'd5;
end
end
end
//鬧鐘調(diào)時(shí)模式
3'b100:
begin
if(c_add)//加
begin
if(flag == 2'd2)
begin
reg2 <= reg2 + 1'b1;
if(reg2 >= 4'd3)
begin
reg2 <= 4'd0;
reg1 <= 2'd0;
flag <= 2'd0;
end
end
else
begin
reg2 <= reg2 + 1'b1;
if(reg2 == 4'd9)
begin
flag <= flag + 1'b1;
reg2 <= 4'd0;
reg1 <= reg1 + 1'b1;
end
end
end
else if(c_sub)//減
begin
if(flag == 2'd0)
begin
reg2 <= reg2 - 1'b1;
if(reg2 == 4'd0)
begin
reg2 <= 4'd3;
reg1 <= 2'd2;
flag <= 2'd2;
end
end
else
begin
reg2 <= reg2 - 1'b1;
if(reg2 == 4'd0)
begin
flag <= flag - 1'b1;
reg1 <= reg1 - 1'b1;
reg2 <= 4'd9;
end
end
end
end
endcase
end
/************************************************/
assign a_hour_h = reg1;
assign a_hour_l = reg2;
assign a_minute_h = reg3;
assign a_minute_l = reg4;
/************************************************/
endmodule
顯示模塊(display)
輸入 | 功能說(shuō)明 | 輸出 | 功能說(shuō)明 |
---|---|---|---|
a_hour_h | 鬧鐘小時(shí)高位 | data | 段選信號(hào) |
a_hour_l | 鬧鐘小時(shí)低位 | select_wei | 位選信號(hào) |
a_minute_h | 鬧鐘分鐘高位 | beep | 蜂鳴器 |
a_minute_l | 鬧鐘分鐘低位 | ||
hour_h | 時(shí)鐘小時(shí)高位 | ||
hour_l | 時(shí)鐘小時(shí)低位 | ||
minute_h | 時(shí)鐘分鐘高位 | ||
minute_l | 時(shí)鐘分鐘低位 | ||
Display_Model | 顯示模式控制 | ||
clk | 時(shí)鐘 | ||
rst_n | 復(fù)位 |
顯示模塊的輸入有三種類(lèi)型:
- 鬧鐘的數(shù)據(jù)
- 時(shí)鐘的數(shù)據(jù)
- 顯示模式控制信號(hào)
輸出也只有三個(gè)
- data是八段數(shù)碼管的段選信號(hào),由于我沒(méi)用小數(shù)點(diǎn)锹安,所以七根線(xiàn)
- select_wei數(shù)碼管位選短荐,四個(gè)數(shù)碼管,四根線(xiàn)
- beep鏈接蜂鳴器的叹哭,一根線(xiàn)忍宋。
細(xì)節(jié)講解
顯示模塊里用到的主要是數(shù)碼管動(dòng)態(tài)掃描的知識(shí),掃描頻率如何設(shè)置风罩,這些問(wèn)題糠排,查一下數(shù)碼管的是如何顯示就知道了,抓住段選和位選超升,還有動(dòng)態(tài)掃描的原理入宦,然后分清楚你使用的數(shù)碼管是共陰還是共陽(yáng),這個(gè)顯示模塊就很好理解了室琢。
代碼展示
module display(
input clk,
input rst_n,
//時(shí)鐘模式 雙段選數(shù)據(jù)
input [1:0] hour_h,
input [3:0] hour_l,
input [2:0] minute_h,
input [3:0] minute_l,
//鬧鐘模式 段選數(shù)據(jù)
input [1:0] a_hour_h,
input [3:0] a_hour_l,
input [2:0] a_minute_h,
input [3:0] a_minute_l,
input Display_Model,//0:時(shí)鐘模式乾闰,1:秒表模式
output [6:0] data,//數(shù)碼管段選
output reg[3:0] select_wei, //數(shù)碼管位選
output reg alarm_out
);
/***********************************/
parameter
SEG_0 = 7'h7e,//c0,
SEG_1 = 7'h30,//f9,
SEG_2 = 7'h6d,//a4,
SEG_3 = 7'h79,//b0,
SEG_4 = 7'h33,//99,
SEG_5 = 7'h5b,//92,
SEG_6 = 7'h5f,//82,
SEG_7 = 7'h70,//F8,
SEG_8 = 7'h7f,//80,
SEG_9 = 7'h7b;//90,
/***********************************/
//時(shí)鐘數(shù)據(jù)編碼
/***********************************/
wire [6:0]c_data1;
wire [6:0]c_data2;
wire [6:0]c_data3;
wire [6:0]c_data4;
//數(shù)碼管一要顯示的列表數(shù)據(jù)(0~2)
reg [6:0] data1_temp;
always @(posedge clk or negedge rst_n)
if(!rst_n)
data1_temp <= SEG_0;
else
case(hour_h)
2'd0: data1_temp <= SEG_0;
2'd1: data1_temp <= SEG_1;
2'd2: data1_temp <= SEG_2;
default: data1_temp <= SEG_0;
endcase
/***********************************/
//數(shù)碼管二要顯示的列表數(shù)據(jù)(0~9)
reg [6:0] data2_temp;
always @(posedge clk or negedge rst_n)
if(!rst_n)
data2_temp <= SEG_0;
else
case(hour_l)
4'd0: data2_temp <= SEG_0;
4'd1: data2_temp <= SEG_1;
4'd2: data2_temp <= SEG_2;
4'd3: data2_temp <= SEG_3;
4'd4: data2_temp <= SEG_4;
4'd5: data2_temp <= SEG_5;
4'd6: data2_temp <= SEG_6;
4'd7: data2_temp <= SEG_7;
4'd8: data2_temp <= SEG_8;
4'd9: data2_temp <= SEG_9;
default: data2_temp <= SEG_0;
endcase
/***********************************/
//數(shù)碼管三要顯示的列表數(shù)據(jù) (0~5)
reg [6:0] data3_temp;
always @(posedge clk or negedge rst_n)
if(!rst_n)
data3_temp <= SEG_0;
else
case(minute_h)
3'd0: data3_temp <= SEG_0;
3'd1: data3_temp <= SEG_1;
3'd2: data3_temp <= SEG_2;
3'd3: data3_temp <= SEG_3;
3'd4: data3_temp <= SEG_4;
3'd5: data3_temp <= SEG_5;
default: data3_temp <= SEG_0;
endcase
/***********************************/
//數(shù)碼管四要顯示的列表數(shù)據(jù)(1~9)
reg [6:0] data4_temp;
always @(posedge clk or negedge rst_n)
if(!rst_n)
data4_temp <= SEG_0;
else
case(minute_l)
4'd0: data4_temp <= SEG_0;
4'd1: data4_temp <= SEG_1;
4'd2: data4_temp <= SEG_2;
4'd3: data4_temp <= SEG_3;
4'd4: data4_temp <= SEG_4;
4'd5: data4_temp <= SEG_5;
4'd6: data4_temp <= SEG_6;
4'd7: data4_temp <= SEG_7;
4'd8: data4_temp <= SEG_8;
4'd9: data4_temp <= SEG_9;
default: data4_temp <= SEG_0;
endcase
/*****************************************/
assign c_data1 = data1_temp;
assign c_data2 = data2_temp;
assign c_data3 = data3_temp;
assign c_data4 = data4_temp;
/*****************************************/
/***********************************/
//鬧鐘數(shù)據(jù)編碼
/***********************************/
wire [6:0]a_data1;
wire [6:0]a_data2;
wire [6:0]a_data3;
wire [6:0]a_data4;
//數(shù)碼管一要顯示的列表數(shù)據(jù)(0~5)
reg [6:0] a_data1_temp;
always @(posedge clk or negedge rst_n)
if(!rst_n)
a_data1_temp <= SEG_0;
else
case(a_hour_h)
3'd0: a_data1_temp <= SEG_0;
3'd1: a_data1_temp <= SEG_1;
3'd2: a_data1_temp <= SEG_2;
3'd3: a_data1_temp <= SEG_3;
3'd4: a_data1_temp <= SEG_4;
3'd5: a_data1_temp <= SEG_5;
default: a_data1_temp <= SEG_0;
endcase
/***********************************/
//數(shù)碼管二要顯示的列表數(shù)據(jù)(0~9)
reg [6:0] a_data2_temp;
always @(posedge clk or negedge rst_n)
if(!rst_n)
a_data2_temp <= SEG_0;
else
case(a_hour_l)
4'd0: a_data2_temp <= SEG_0;
4'd1: a_data2_temp <= SEG_1;
4'd2: a_data2_temp <= SEG_2;
4'd3: a_data2_temp <= SEG_3;
4'd4: a_data2_temp <= SEG_4;
4'd5: a_data2_temp <= SEG_5;
4'd6: a_data2_temp <= SEG_6;
4'd7: a_data2_temp <= SEG_7;
4'd8: a_data2_temp <= SEG_8;
4'd9: a_data2_temp <= SEG_9;
default: a_data2_temp <= SEG_0;
endcase
/*****************************************/
//數(shù)碼管三要顯示的列表數(shù)據(jù)(0~9)
reg [6:0] a_data3_temp;
always @(posedge clk or negedge rst_n)
if(!rst_n)
a_data3_temp <= SEG_0;
else
case(a_minute_h)
4'd0: a_data3_temp <= SEG_0;
4'd1: a_data3_temp <= SEG_1;
4'd2: a_data3_temp <= SEG_2;
4'd3: a_data3_temp <= SEG_3;
4'd4: a_data3_temp <= SEG_4;
4'd5: a_data3_temp <= SEG_5;
4'd6: a_data3_temp <= SEG_6;
4'd7: a_data3_temp <= SEG_7;
4'd8: a_data3_temp <= SEG_8;
4'd9: a_data3_temp <= SEG_9;
default: a_data3_temp <= SEG_0;
endcase
/***********************************/
//數(shù)碼管四要顯示的列表數(shù)據(jù)(0~9)
reg [6:0] a_data4_temp;
always @(posedge clk or negedge rst_n)
if(!rst_n)
a_data4_temp <= SEG_0;
else
case(a_minute_l)
4'd0: a_data4_temp <= SEG_0;
4'd1: a_data4_temp <= SEG_1;
4'd2: a_data4_temp <= SEG_2;
4'd3: a_data4_temp <= SEG_3;
4'd4: a_data4_temp <= SEG_4;
4'd5: a_data4_temp <= SEG_5;
4'd6: a_data4_temp <= SEG_6;
4'd7: a_data4_temp <= SEG_7;
4'd8: a_data4_temp <= SEG_8;
4'd9: a_data4_temp <= SEG_9;
default: a_data4_temp <= SEG_0;
endcase
/*******************************************************/
assign a_data1 = a_data1_temp;
assign a_data2 = a_data2_temp;
assign a_data3 = a_data3_temp;
assign a_data4 = a_data4_temp;
/***************************************************/
/******************************************/
parameter shuaxin = 17'h1ffff;
// 數(shù)碼管掃描頻率
reg [19:0] cnt;
reg [1:0] num;//每隔5MS,num加1
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
select_wei <= 4'd8; // 1000
cnt <= 18'd0;
num <= 2'd0;
end
else if(cnt == shuaxin)
begin
num <= num + 1'b1;
cnt <= 18'd0;
if(select_wei == 4'd1) //0001
select_wei <= 4'd8;
else
select_wei <= {1'b0,select_wei[3:1]}; //右移
end
else
cnt <= cnt + 1'b1;
/******************************************/
//通過(guò)Display_Model來(lái)確定是要送秒表數(shù)據(jù)還是鬧鐘的數(shù)據(jù)
reg [7:0] data_temp;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
data_temp <= 7'h7e;
else if(cnt == shuaxin)
case(num)
2'd0: data_temp <= Display_Model ? a_data1:c_data1;//給第一個(gè)數(shù)碼管送數(shù)據(jù)
2'd1: data_temp <= Display_Model ? a_data2:c_data2;//給第二個(gè)數(shù)碼管送數(shù)據(jù)
2'd2: data_temp <= Display_Model ? a_data3:c_data3;//給第二個(gè)數(shù)碼管送數(shù)據(jù)
2'd3: data_temp <= Display_Model ? a_data4:c_data4;//給第二個(gè)數(shù)碼管送數(shù)據(jù)
endcase
end
assign data = data_temp;
/******************************************/
////// 比較器模塊 //////
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
alarm_out <= 0 ;
else if(a_data1 == c_data1 && a_data2 == c_data2 && a_data3 == c_data3 && a_data4 == c_data4)
alarm_out <=1;
else
alarm_out<=0;
end
endmodule
</div>
top層
主要是鏈接盈滴,直接上代碼吧涯肩。
代碼展示
module top(
input clk,
input rst_n,
input add_in,
input sub_in,
input model_in,
output [6:0] data,//數(shù)碼管段選數(shù)據(jù)
output [3:0] select_wei, //數(shù)碼管位選
output alarm_out
);
wire [1:0] hour_h;
wire [3:0] hour_l;
wire [2:0] minute_h;
wire [3:0] minute_l;
wire [1:0] a_hour_h;
wire [3:0] a_hour_l;
wire [2:0] a_minute_h;
wire [3:0] a_minute_l;
wire Display_Model;
wire [2:0]Time_model;
wire c_add;
wire c_sub;
wire a_add;
wire a_sub;
wire cnt_control; //控制定時(shí)器
//
key U1(
//top的input
.clk(clk),
.rst_n(rst_n),
.add_in(add_in),
.sub_in(sub_in),
.model_in(model_in),
//連clock的線(xiàn)
.cnt_control(cnt_control),
.c_add(c_add),
.c_sub(c_sub),
.Time_model(Time_model),
//連alarm的線(xiàn)
.a_add(a_add),
.a_sub(a_sub),
//連display的線(xiàn)
.Display_Model(Display_Model)
);
clock U2(
//input
.clk(clk),
.rst_n(rst_n),
//從key來(lái)的線(xiàn)
.c_add(c_add),
.c_sub(c_sub),
.cnt_control(cnt_control),
.Time_model(Time_model),
//output
//連display的線(xiàn)
.hour_h(hour_h),
.hour_l(hour_l),
.minute_h(minute_h),
.minute_l(minute_l)
);
alarm U3(
//input
.clk(clk),
.rst_n(rst_n),
//從key來(lái)的線(xiàn)
.c_add(a_add),
.c_sub(a_sub),
.Time_model(Time_model),
//output
//連display的線(xiàn)
.a_hour_h(a_hour_h),
.a_hour_l(a_hour_l),
.a_minute_h(a_minute_h),
.a_minute_l(a_minute_l)
);
display U4(
//input
.clk(clk),
.rst_n(rst_n),
//從clock 來(lái)的線(xiàn)
.hour_h(hour_h),
.hour_l(hour_l),
.minute_h(minute_h),
.minute_l(minute_l),
//從alarm 來(lái)的線(xiàn)
.a_hour_h(a_hour_h),
.a_hour_l(a_hour_l),
.a_minute_h(a_minute_h),
.a_minute_l(a_minute_l),
//從key 來(lái)的線(xiàn)
.Display_Model(Display_Model),
//output
.data(data),
.select_wei(select_wei),
.alarm_out(alarm_out)
);
endmodule
細(xì)節(jié)講解
top層的作用是連接各個(gè)模塊,列出系統(tǒng)的輸入輸出,然后分清楚中間節(jié)點(diǎn)病苗,如果之前沒(méi)有寫(xiě)過(guò)top層疗垛,可以先從試著寫(xiě)個(gè)小系統(tǒng),比如:全加器(調(diào)用半加器實(shí)現(xiàn))铅乡,如果你已經(jīng)是老司機(jī)继谚,相信已經(jīng)駕輕就熟了烈菌,不多說(shuō)了阵幸。其實(shí),我這個(gè)例化寫(xiě)得有點(diǎn)煩了芽世,例化如果非要分寫(xiě)法可以分為兩種挚赊,我這是比較煩的,不過(guò)我也不改了济瓢,╭(╯^╰)╮
寫(xiě)在后面的話(huà)
數(shù)字鐘就講訴到這里荠割,整個(gè)系統(tǒng)不難理解,只是模塊之間的聯(lián)系必須弄清楚旺矾,我的觀(guān)點(diǎn)是:把需要的模塊列出來(lái)蔑鹦,分析模塊之間的聯(lián)系,再具體看各個(gè)模塊的內(nèi)容箕宙,單個(gè)驗(yàn)證嚎朽,自頂向下設(shè)計(jì),主要還是多琢磨吧柬帕,有耐心就好哟忍。
關(guān)于文章,如果有任何問(wèn)題都可以在評(píng)論區(qū)和我交流陷寝,如果有錯(cuò)誤锅很,歡迎斧正,謝謝了~~