?? account2.v
字號:
/*--------卡式電話計費(fèi)器----------
本實驗假定通話時間disptime最長為59分鐘,卡內(nèi)余額dispmoney最大數(shù)額為5元*/
//信號定義
//clk: 時鐘信號,頻率為1Hz
//card: 卡是否插入,高電平有效
//state: 電話接通信號,高電平有效
//decide: 電話局反饋回來的信號,代表話務(wù)種類,“01”表示市話,“10”表示長話,“11”表示特話。
//set_money_low:設(shè)置卡中錢的低位 money的低位按一下+1 在0-9變化
//set_money_high:設(shè)置卡中錢的高位 money的高位按一下+1 在0-9變化
//disptime: 顯示本次通話的時長,其單位為分鐘,這里假設(shè)能顯示的最大時間為59分鐘。
//dispmoney: 顯示卡內(nèi)余額,其單位為角,這里假設(shè)能顯示的最大數(shù)額為5元,即50角。
//write,read: 當(dāng)write信號下降沿到來時寫卡;當(dāng)話卡插入,read信號變高讀卡。
//warn: 余額過少時的告警信號。當(dāng)打市話時,余額少于3角,打長話時,余額少于6角,即會產(chǎn)生告警信號。
//cut: 當(dāng)告警時間過長(>15s)時自動切斷通話信號。
//state_out: 電話接通信號
//decide_out: 話務(wù)種類,01-市話,10-長途,11-特話
//+num1和temp的輸出信號
module account2(clk,card,state,decide,set_money_low,set_money_high,
disptime,dispmoney,write,read,warn,cut,state_out,decide_out);
input clk,card,state;
input[1:0] decide;
input set_money_low;
input set_money_high;
output[7:0] disptime;
output[7:0] dispmoney;
output write,read,warn,cut,state_out;
output[1:0] decide_out;
reg card_reg,state_reg,set_reg;
reg [1:0] decide_reg;
//按下decide的各個按鈕時分別鎖存至decide1,decide0
reg decide1,decide0;
reg write,warn,cut;
reg[7:0] money; // 中間變量,用于計費(fèi)(卡內(nèi)余額),以t1m為時鐘信號!
reg[7:0] dtime; // 中間變量,用于通話計時,以t1m為時鐘信號!
reg t1m; // 中間變量——分時鐘,寫卡的時間
//reg set,reset_ena; // set為“0”時置money初值;reset_ena為“0”時復(fù)位cut信號
reg reset_ena;
reg cut_decide;
integer num1,temp; // num1——對通話時間計數(shù);temp——用于計告警時間
integer num2; //num2-對decide按鈕的時間計時,在num2=15 即1.5秒后設(shè)置decide
reg currentState,nextstate;
assign dispmoney = card_reg? money:0;//只要電話卡一插入,則顯示卡內(nèi)余額;否則不顯示卡內(nèi)余額
assign disptime = dtime;
assign read = card_reg? 1:0; //只要電話卡一插入,則產(chǎn)生讀卡信號(高電平);否則讀卡信號為"0"。
assign state_out=state_reg;
assign decide_out=decide_reg;
//1、鎖存card信號,將輸入信號鎖存到相應(yīng)寄存器中
//當(dāng)按一次card,插入卡,在按一次拔出
always@(card or currentState)
begin
//當(dāng)按一次表示插入卡,在按一次表示拔出
if (currentState)
card_reg=1;
else
card_reg=0;
nextstate=0;
if (!currentState)
if (card)
nextstate=1;
else
nextstate=currentState;
if (currentState)
if (card)
nextstate=0;
else
nextstate=currentState;
end
always@(posedge clk)
begin
currentState<=nextstate;
end
//2、鎖存decide信號,由于需要至多按兩個按鈕來產(chǎn)生decide信號,所以必須在案兩個按鈕時具有一定的時間間隔
//設(shè)定為4秒
//在拔除卡時為0
always@(posedge clk)
begin
if (~card_reg)
begin
decide_reg<=0;
num2<=0;
decide1<=0;
decide0<=0;
end
else
begin
if (decide[0])
decide0<=decide[0];
if (decide[1])
decide1<=decide[1];
//計數(shù)
if (num2==4)
begin
decide_reg<={decide1,decide0};
num2<=0;
end
else
begin
num2<=num2+1;
end
end
end
//3、鎖存state 當(dāng)插入卡后判斷通話的類型,在市話并且money>3時才允許按接通信號
//否則產(chǎn)生cut信號;在長話并且money>6時才允許按接通信號,否則產(chǎn)生cut信號;在
//特話時則可以按接通信號
always@ (posedge clk)
begin
if (card_reg)
begin
//市話
if (decide_reg==2'b01)
begin
if (money<3)
begin
//如果沒有warn信號說明是在開始的時候錢數(shù)就不夠
if (!warn)
begin
state_reg<=0;
cut_decide<=1;
end
if (cut) //在卡拔出,產(chǎn)生了cut信號,則置接通信號為無效
state_reg<=0;
end
else
begin
//產(chǎn)生了接通信號
if (state)
state_reg<=1;
end
end
//長話
else if (decide_reg==2'b10)
begin
if (money<6)
begin
if (!warn)
begin
cut_decide<=1;
state_reg<=0;
end
if (cut)
state_reg<=0;
end
else
begin
if (state)
state_reg<=1;
end
end
//特話
else if (decide_reg==2'b11)
begin
if (state)
state_reg<=1;
end
end
else
begin
state_reg<=0;
cut_decide<=0;
end
end
// ----- 4.產(chǎn)生分時鐘
always @(posedge clk)
begin
if(num1==59) begin num1<=0; t1m<=1; end // 若計到59s,則num1清零,t1m=1
else
begin
if(state_reg) num1<=num1+1; // 若接通線路,則num1開始加1計數(shù)
else num1<=0;
t1m<=0;
end
end
//----- 5.下面的always模塊完成電話計費(fèi)和通話計時功能
always @(negedge clk)
begin
//設(shè)置卡的錢數(shù)
if (set_money_low)
begin
if (money[3:0]==9)
money[3:0]=4'h0;
else
money[3:0]=money[3:0]+4'h1;
end
if (set_money_high)
begin
if (money[7:4]==9)
money[7:4]=4'h0;
else
money[7:4]=money[7:4]+1;
end
if(card_reg && state_reg) // 若卡已插入且線路已接通
if(t1m) // 若通話時間夠1分鐘(以t1m為計數(shù)器的時鐘信號)
case (decide_reg)
2'b01:begin //(1)若話務(wù)為市話
//① 若卡上余額>3角,則對市話計費(fèi)
if(money[3:0]<4'b0011) // 若余額個位<3角
begin
money[3:0]=money[3:0]+7; // 減3相當(dāng)于加7(借位)
money[7:4]=money[7:4]-1; // 十位減1
end
else money[3:0]=money[3:0]-3;
if (money<3) //② 若卡上余額<3角,則告警
begin
warn<=1;write<=0;
end
else
begin
write<=1; //③ 準(zhǔn)備寫卡
//④ 對市話通話計時
if(dtime[3:0]==9)
begin
dtime[3:0]<=0;
if(dtime[7:4]==5) // 最大可計時59分鐘
dtime[7:4]<=0;
else dtime[7:4]<=dtime[7:4]+1;
end
else
begin dtime[3:0]<=dtime[3:0]+1;warn<=0;end
end
end
2'b10:begin //(2)若話務(wù)為長話
// ①若卡上余額>6角,則對長話計費(fèi)
if(money[3:0]<6) // 若余額個位<6角
begin
money[3:0]=money[3:0]+4;// 減6相當(dāng)于加4(借位)
money[7:4]=money[7:4]-1;
end
else money[3:0]=money[3:0]-6;
if (money<6) // ②若卡上余額<6角,則告警
begin
warn<=1;
write<=0;
end
else
begin
//③ 對長話通話計時
if(dtime[3:0]==9)
begin
dtime[3:0]<=0;
if(dtime[7:4]==5)
begin dtime[7:4]<=0;end
else dtime[7:4]<=dtime[7:4]+1;
end
else dtime[3:0]<=dtime[3:0]+1;
write<=1;warn<=0; //④寫卡
end
end
endcase
else write<=0; // 若t1m=0,則不寫卡
else // 若卡拔出或線路未接通,則對一些信號進(jìn)行復(fù)位
begin dtime<=0;warn<=0;write<=0;end
end
//----- 6.下面的always模塊在告警時間過長時切斷通話
always @(posedge clk)
begin
if(warn) temp<=temp+1; // 若有告警信號,則temp開始加1計數(shù)
else temp<=0; // 否則temp清零
if(temp==15||cut_decide) // 若計到15s 或者開始時就money不足
begin cut<=1;temp<=0;end // 則切斷通話
if(!card_reg) // 若卡已拔出,則復(fù)位cut信號
begin cut<=0;temp<=0;end
end
endmodule
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -