⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 account2.v

📁 卡式计费电话电路,用verilogHDL编写,主要完成模拟真实电话的功能
💻 V
字号:
/*--------卡式电话计费器----------
 本实验假定通话时间disptime最长为59分钟,卡内余额dispmoney最大数额为5元*/
//信号定义
//clk:			时钟信号,频率为1Hz
//card:			卡是否插入,高电平有效
//state:		电话接通信号,高电平有效
//decide:		电话局反馈回来的信号,代表话务种类,“01”表示市话,“10”表示长话,“11”表示特话。
//set_money_low:设置卡中钱的低位  money的低位按一下+1 在0-9变化
//set_money_high:设置卡中钱的高位 money的高位按一下+1 在0-9变化	    	
//disptime:		显示本次通话的时长,其单位为分钟,这里假设能显示的最大时间为59分钟。
//dispmoney:	显示卡内余额,其单位为角,这里假设能显示的最大数额为5元,即50角。
//write,read:	当write信号下降沿到来时写卡;当话卡插入,read信号变高读卡。
//warn:			余额过少时的告警信号。当打市话时,余额少于3角,打长话时,余额少于6角,即会产生告警信号。
//cut:			当告警时间过长(>15s)时自动切断通话信号。

//state_out:    电话接通信号
//decide_out:   话务种类,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;          // 中间变量,用于计费(卡内余额),以t1m为时钟信号!
  reg[7:0] dtime;          // 中间变量,用于通话计时,以t1m为时钟信号!
  reg t1m;                 // 中间变量——分时钟,写卡的时间
  //reg set,reset_ena;       // set为“0”时置money初值;reset_ena为“0”时复位cut信号
  reg reset_ena;
  reg cut_decide;
  integer num1,temp;       // num1——对通话时间计数;temp——用于计告警时间  
  integer num2;            //num2-对decide按钮的时间计时,在num2=15 即1.5秒后设置decide
  reg currentState,nextstate;
  
  assign dispmoney = card_reg? money:0;//只要电话卡一插入,则显示卡内余额;否则不显示卡内余额
  assign disptime = dtime;
  assign read = card_reg? 1:0;         //只要电话卡一插入,则产生读卡信号(高电平);否则读卡信号为"0"。
  assign state_out=state_reg;
  assign decide_out=decide_reg;

  //1、锁存card信号,将输入信号锁存到相应寄存器中
  //当按一次card,插入卡,在按一次拔出
  always@(card or currentState)
   begin
      //当按一次表示插入卡,在按一次表示拔出
	  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信号,由于需要至多按两个按钮来产生decide信号,所以必须在案两个按钮时具有一定的时间间隔
	 //设定为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];
		   //计数
		   if (num2==4)
		      begin
		        decide_reg<={decide1,decide0};
				num2<=0;
			  end
		   else
		      begin
		         num2<=num2+1;
		      end
		  end
	 end
   //3、锁存state 当插入卡后判断通话的类型,在市话并且money>3时才允许按接通信号
   //否则产生cut信号;在长话并且money>6时才允许按接通信号,否则产生cut信号;在
   //特话时则可以按接通信号
   always@ (posedge clk)
    begin
       if (card_reg)
         begin
           //市话           
           if (decide_reg==2'b01)
         	 begin
         	    if (money<3)
        	        begin
         	          //如果没有warn信号说明是在开始的时候钱数就不够
 					  if (!warn)
 						begin
						 state_reg<=0;
         	             cut_decide<=1;
                        end
					   
					  if (cut)              //在卡拔出,产生了cut信号,则置接通信号为无效
					     state_reg<=0;
         	       end
         	    else
         	       begin
                      //产生了接通信号
                      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.产生分时钟
  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计数
          else num1<=0;
          t1m<=0; 
        end
    end
 


  //----- 5.下面的always模块完成电话计费和通话计时功能
  always @(negedge clk)
    begin
     //设置卡的钱数
      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为计数器的时钟信号)
          case (decide_reg)
          2'b01:begin          //(1)若话务为市话 
              //① 若卡上余额>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;
                       
 			 if (money<3)		  //② 若卡上余额<3角,则告警   
                begin
			      warn<=1;write<=0;
                end
              else
                begin                        
			       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;end
	              end
          	        
          	     end      
	      2'b10:begin     //(2)若话务为长话
	 	           	      // ①若卡上余额>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 (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                     // 若卡拔出或线路未接通,则对一些信号进行复位
        begin dtime<=0;warn<=0;write<=0;end	 	   
    end

  //----- 6.下面的always模块在告警时间过长时切断通话
  always @(posedge clk)
    begin
      if(warn) temp<=temp+1;           // 若有告警信号,则temp开始加1计数
      else temp<=0;                    // 否则temp清零
      if(temp==15||cut_decide)        // 若计到15s 或者开始时就money不足
        begin cut<=1;temp<=0;end       // 则切断通话
      if(!card_reg)            // 若卡已拔出,则复位cut信号
        begin cut<=0;temp<=0;end
    end
endmodule	 
                
     

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -