📄 account1.v
字号:
/*--------卡式电话计费器----------
本实验假定通话时间disptime最长为59分钟,卡内余额dispmoney最大数额为5元*/
//信号定义
//clk: 时钟信号,频率为1Hz
//card: 卡是否插入,高电平有效
//state: 电话接通信号,高电平有效
//decide: 电话局反馈回来的信号,代表话务种类,“01”表示市话,“10”表示长话,“11”表示特话。
//disptime: 显示本次通话的时长,其单位为分钟,这里假设能显示的最大时间为59分钟。
//dispmoney: 显示卡内余额,其单位为角,这里假设能显示的最大数额为5元,即50角。
//write,read: 当write信号下降沿到来时写卡;当话卡插入,read信号变高读卡。
//warn: 余额过少时的告警信号。当打市话时,余额少于3角,打长话时,余额少于6角,即会产生告警信号。
//cut: 当告警时间过长(>15s)时自动切断通话信号。
//+num1和temp的输出信号
module account1(clk,card,state,decide,disptime,dispmoney,write,read,warn,cut,t1m,
num10,temp1,money,set,reset_ena);
input clk,card,state;
input[1:0] decide;
output[7:0] disptime;
output[7:0] dispmoney;
output write,read,warn,cut,t1m;
output[31:0] num10,temp1;
output[7:0] money;
output set,reset_ena;
reg write,warn,cut;
reg[7:0] money; // 中间变量,用于计费(卡内余额),以t1m为时钟信号!
reg[7:0] dtime; // 中间变量,用于通话计时,以t1m为时钟信号!
reg t1m; // 中间变量——分时钟,写卡的时间
reg set,reset_ena; // set为“0”时置money初值;reset_ena为“0”时复位cut信号
integer num1,temp; // num1——对通话时间计数;temp——用于计告警时间
assign num10=num1;
assign temp1=temp;
assign dispmoney = card? money:0;//只要电话卡一插入,则显示卡内余额;否则不显示卡内余额
assign disptime = dtime;
assign read = card? 1:0; //只要电话卡一插入,则产生读卡信号(高电平);否则读卡信号为"0"。
// ----- 1.产生分时钟
always @(posedge clk)
begin
if(num1==59) begin num1<=0; t1m<=1; end // 若计到59s,则num1清零,t1m=1
else
begin
if(state) num1<=num1+1; // 若接通线路,则num1开始加1计数
else num1<=0;
t1m<=0;
end
end
//----- 2.下面的always模块完成电话计费和通话计时功能
always @(negedge clk)
begin
if(!set) // 置卡中金额初值为50角
begin set<=1;money<=12'd50;end
if(card && state) // 若卡已插入且线路已接通
if(t1m) // 若通话时间够1分钟(以t1m为计数器的时钟信号)
case (decide)
2'b01:begin //(1)若话务为市话
if(money<3) //① 若卡上余额<3角,则告警
begin warn<=1;write<=0;reset_ena<=1;end
else
begin //② 若卡上余额>3角,则对市话计费
if(money[3:0]<4'b0011) // 若余额个位<3角
begin
money[3:0]<=money[3:0]+7; // 减3相当于加7(借位)
money[7:4]<=money[7:4]-1; // 十位减1
end
else money[3:0]<=money[3:0]-3;
write<=1; //③ 准备写卡
//④ 对市话通话计时
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;reset_ena<=0;end
end
end
2'b10:begin //(2)若话务为长话
if(money<6) //① 若卡上余额<6角,则告警
begin warn<=1;write<=0;reset_ena<=1;end
else
begin //② 若卡上余额>6角,则对长话计费
if(money[3:0]<6) // 若余额个位<6角
begin
money[3:0]<=money[3:0]+4;// 减6相当于加4(借位)
money[7:4]<=money[7:4]-1;
end
else money[3:0]<=money[3:0]-6;
//③ 对长话通话计时
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;reset_ena<=0;warn<=0; //④写卡
end
end
endcase
else write<=0; // 若t1m=0,则不写卡
else // 若卡拔出或线路未接通,则对一些信号进行复位
begin dtime<=0;warn<=0;write<=0;reset_ena<=0;end
end
//----- 3.下面的always模块在告警时间过长时切断通话
always @(posedge clk)
begin
if(warn) temp<=temp+1; // 若有告警信号,则temp开始加1计数
else temp<=0; // 否则temp清零
if(temp==15) // 若计到15s
begin cut<=1;temp<=0;end // 则切断通话
if(!card||!reset_ena) // 若卡已拔出,则复位cut信号
begin cut<=0;temp<=0;end
end
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -