FPGA Verilog HDL 系列实例--------卡式电话计费器

Verilog HDL 之 卡式电话计费器

  我们每天都在和手机打交道,更熟悉了打电话的各项业务,那么怎么通过Verilog HDL 硬件描述语言简单的控制电话的计时计费呢,下面我们就来看看是如何实现的。先介绍下卡式电话计费器的要求。

一、实验要求及原理

(1) 计费器在话卡插入后,能将卡中的币值读出并显示出来;在通话过程中,根据话务种类计话费并将话费从卡值中扣除,卡值余额每分钟更新一次;计时与计费数据均以十进制形式显示出来。

(2)话务分为3类:市话、长话和特话,其中市话按每分钟3角钱计费,长话按每分钟6角钱计费,特话不收费。当卡上余额不足时产生告警信号,当告警达到一定时间则切断当前通话。

二、实验平台

  Quartus II 7.2 集成开发环境、SOPC-MBoard板、ByteBlaster II 下载电缆

三、实验实现

1、设计思路

  此系统由三个模块组成,一是时钟分频模块,负责产生1Hz的时间;二是卡式电话计费主体,负责计时计费,余额不足时,产生警报后自动切断通话信号;三是顶层模块,负责数码管的显示。

2、在设计文件中输入Verilog代码。

(1)时钟分频

View Code
 1 //--------------------------------------------------------------------------------------------------
 2 // Title       : clkgen
 3 // Author      : wangliang
 4 // Generated   : 2011.08.17
 5 //-------------------------------------------------------------------------------------------------
 6 `timescale 1 ns /1 ps
 7 
 8 module clkgen ( rst ,clkout ,clk );
 9 
10 input rst ;
11 wire rst ;
12 input clk ;
13 wire clk ; 
14 
15 output clkout ;
16 reg clkout ;
17       
18 reg     [31:0]    count1;
19 
20 always @ ( posedge clk or negedge rst)   
21 begin
22 if ( rst==1'b0 ) begin
23         clkout <=1'b0;
24         count1 <=17'b0; 
25         end
26 else begin
27 if ( count1>=32'd25000000) begin
28             clkout <=~clkout ;
29             count1 <=32'd0; 
30             end
31 else     count1 <= count1 +1'b1;
32         end 
33 end      
34   
35 endmodule

  产生1Hz的时间,供给主体部分的计时。

(2)卡式电话计费主体

View Code
  1 //--------------------------------------------------------------------------------------------------
  2 // Title       : phone_account
  3 // Author      : wangliang
  4 // Generated   : 2011.08.17
  5 //-------------------------------------------------------------------------------------------------
  6 `timescale 1 ns /1 ps
  7 
  8 module phone_account ( num1,state ,warn ,dispmoney ,rst ,clk ,card ,write ,cut ,read ,decide ,disptime );
  9 
 10 input      state ;
 11 wire       state ;
 12 input          rst ;
 13 wire           rst ;
 14 input           card ;
 15 wire            card ;
 16 input           clk ;
 17 wire            clk ;
 18 input   [1:0]   decide ;
 19 wire    [1:0]   decide ;
 20 
 21 output          warn ;
 22 reg             warn ;
 23 output  [11:0]    dispmoney ;
 24 wire    [11:0]    dispmoney ;
 25 output            write ;
 26 reg               write ;
 27 output            cut ;
 28 reg               cut ;
 29 output            read ;
 30 wire               read ;
 31 output  [11:0]    disptime ;
 32 wire    [11:0]    disptime ;
 33 output     [7:0]        num1 ;
 34 
 35 reg     [7:0]    num1 ;
 36 reg              t1m ;            //整分钟标志      
 37 reg              set ;            
 38 reg    [11:0]    money ;    
 39 reg              reset_ena ;      
 40 reg    [11:0]    dtime ;      
 41 wire             clk_1Hz ;  
 42 reg     [4:0]    temp ;          
 43 
 44 clkgen clkgen (
 45         .rst ( rst ),
 46         .clk ( clk ),
 47         .clkout ( clk_1Hz )
 48 
 49         );
 50 
 51 always @ ( posedge clk_1Hz or negedge rst )
 52     begin
 53 if ( rst ==1'b0 ) begin 
 54             num1 <=1'b0 ;
 55             t1m <=1'b0 ;
 56         end
 57 else begin
 58 if ( num1 >=8'h59 ) begin 
 59                 num1 <=8'b0 ;
 60                 t1m <=1'b1 ;    
 61             end
 62 else begin     
 63 if ( num1[3:0] >=4'b1001)
 64                 begin 
 65                     num1[3:0] <=4'b0 ;
 66                     num1[7:4] <= num1[7:4] +1'b1 ;       
 67                 end
 68 elseif ( card & state )            //当卡拿下来或者不打电话时,不计时
 69                     num1 <= num1 +1'b1 ;
 70 else 
 71                 num1 <=1'b0 ;
 72             t1m <=1'b0 ;
 73             end
 74         end
 75     end
 76  
 77 always @( posedge clk_1Hz or negedge rst )
 78     begin 
 79 if ( rst ==1'b0 ) begin 
 80             money <=12'b0 ;      
 81             dtime    <=12'b0 ;  
 82 set<=1'b0 ;
 83             end
 84 else begin 
 85 if ( !set )    begin 
 86             money <=12'h500 ;                //初始值50元
 87 set<=1'b1;
 88             end
 89 if ( card & state )    
 90 if ( t1m )
 91 case ( { state , decide } )
 92 3'b101 :                             //市话
 93 if ( money <=11'd3 )begin  
 94                                 warn <=1'b1 ;
 95                                 write <=1'b0 ;
 96                                 reset_ena<=1'b1 ;
 97                                 end       
 98 else begin                   
 99 if ( money [3:0] <4'b0011)    begin         //计费
100                                     money [3:0] <= money[3:0] +12'd7 ;
101 if ( money [7:4] !=0 )
102                                         money [7:4] <= money [7:4] -1'b1;
103 else begin 
104                                         money [7:4] <=12'd9 ;
105                                         money [10:8] <= money [10:8] -1'b1;
106                                         end
107                                     end
108 else 
109                                     money [3:0] <= money [3:0]-3 ;     
110                                 write <=1'b1 ;
111                                 
112 if ( dtime [3:0] >=4'd9 ) begin          //计时
113                                     dtime [3:0]    <=4'b0 ;
114 if ( dtime[7:4]>=4'd9) begin 
115                                         dtime [7:4] <=4'b0 ;
116                                         dtime [11:8] <=dtime [11:8] +1'b1 ;
117                                         end
118 else dtime [7:4] <= dtime [7:4] +1'b1 ;
119                                     end
120 else begin 
121                                     dtime[3:0] <= dtime [3:0] +1'b1;
122                                     warn <=1'b0 ;
123                                     reset_ena <=1'b0 ;
124                                     end
125                                 end
126 3'b110 :                             //长途
127 if ( money <=12'd6 )begin                 
128                                 warn <=1'b1 ;
129                                 write <=1'b0 ;
130                                 reset_ena<=1'b1 ;
131                                 end       
132 else begin
133 if ( money [3:0] <4'b0110)    begin         //计费
134                                     money [3:0] <= money[3:0] +4 ;
135 if ( money [7:4] !=0 )
136                                         money [7:4] <= money [7:4] -1'b1;
137 else begin 
138                                         money [7:4] <=12'd9 ;
139                                         money [11:8] <= money [11:8] -1'b1;
140                                         end
141                                     end
142 else 
143                                     money [3:0] <= money [3:0]-6 ;     
144                                 write <=1'b1 ; 
145                                 
146 if ( dtime[3:0] >=4'd9)    begin         //计时
147                                     dtime [3:0]    <=4'b0 ;
148 if ( dtime[7:4]>=4'd9) begin 
149                                         dtime [7:4] <=4'b0 ;
150                                         dtime [11:8] <=dtime [11:8] +1'b1 ;
151                                         end
152 else dtime [7:4] <= dtime [7:4] +1'b1 ;
153                                     end
154 else     begin 
155                                     dtime[3:0] <= dtime [3:0] +1'b1;    
156                                     reset_ena <=1'b0 ; 
157                                     warn <=1'b0 ; 
158                                     end
159                                 end
160                     endcase
161 else write <=1'b0;
162 else begin 
163             dtime <=1'b0 ;
164             warn <=1'b0 ;
165             write <=1'b0 ;
166             reset_ena <=1'b0 ;
167         end
168             
169         end
170     end
171     
172 always @ ( posedge clk_1Hz or negedge rst )       //当余额不足发出警报时,15S后自动切断通话信号
173 
174     begin 
175 if ( rst ==1'b0 ) begin 
176           temp <=5'b0 ;      
177          end
178 else begin
179 if (warn)    temp <= temp +1'b1 ;
180 else         temp <=1'b0 ;  
181 if ( temp >=5'd15 )
182             begin cut <=1'b1 ;
183                 temp <=1'b0 ;
184             end
185 if ( !card||!reset_ena ) begin 
186             cut <=1'b0 ;
187             temp <=1'b0 ;
188             end
189     end
190 end
191 
192 assign dispmoney = card? money :0 ;
193 assign disptime = dtime ;
194 assign read = card?1: 0 ;
195     
196 endmodule

  从代码中可以看出,卡式电话计费主体是由4部分组成。

  第44行~第49行:调用时钟分频模块,得到1Hz时钟;

  第51行~第75行:秒针计时,当卡拿出来或者挂掉电话时,不计时,金钱初始值是50元,慢慢打吧。:-D

  第77行~第170行:市话、长途的计分钟和计费,特话不收费;

  第172行~第190行:当余额不足发出警报时,15S后自动切断通话信号。


(3)顶层显示

View Code
  1 //--------------------------------------------------------------------------------------------------
  2 // Title       : top
  3 // Author      : wangliang
  4 // Generated   : 2011.08.17
  5 //-------------------------------------------------------------------------------------------------
  6 `timescale 1 ns /1 ps
  7 
  8 module top ( state ,warn ,rst ,clk ,card ,write ,cut ,read ,decide ,seven_seg );
  9 
 10 input state ;
 11 wire state ;
 12 input rst ;
 13 wire rst ;
 14 input card ;
 15 wire card ;
 16 input clk ;
 17 wire clk ;
 18 input [1:0] decide ;
 19 wire [1:0] decide ;
 20 
 21 output warn ;
 22 wire warn ;
 23 output write ;
 24 wire write ;
 25 output cut ;
 26 wire cut ;
 27 output read ;
 28 wire read ;
 29 output [15:0] seven_seg ;
 30 wire [15:0] seven_seg ;
 31 wire [7:0]    num1 ;
 32 
 33 wire     [11:0]    disptime ;
 34 wire     [11:0]    dispmoney ;
 35 
 36 phone_account phone_account ( 
 37 . state ( state )  ,
 38 .warn( warn )  ,
 39 .dispmoney( dispmoney ) ,
 40 .rst( rst )  ,
 41 .clk( clk )  ,
 42 .card( card )  ,
 43 .write( write )  ,
 44 .cut( cut )  ,
 45 .read( read )  ,
 46 .decide( decide )  ,
 47 .disptime( disptime ), 
 48 .num1(num1));
 49 
 50 /*********************8数码管译码部分*************/
 51 
 52 reg clkout ;
 53 reg [31:0]cnt;  
 54 reg [2:0]scan_cnt ;     
 55 reg [3:0]A ;
 56 parameter  period=100000;
 57 reg [6:0] Y_r;
 58 reg [7:0] DIG_r ;
 59 
 60 assign seven_seg[7:0] = {1'b1,(~Y_r[6:0])};
 61 assign seven_seg[15:8] =~DIG_r;
 62 
 63 
 64 always @( posedge clk or negedge rst)          //分频50Hz
 65 begin 
 66 if (!rst)    cnt <=0 ;
 67 else  
 68         begin  
 69         cnt<= cnt+1;
 70 if (cnt    == (period >>1) -1)               //设定周期时间的一半
 71             clkout <= #11'b1;
 72 elseif (cnt == period -1)                    //设定的周期时间
 73             begin 
 74             clkout <= #11'b0;
 75             cnt <= #1'b0;      
 76             end
 77         end
 78 end
 79 
 80 always @(posedge clkout or negedge rst)          
 81 begin 
 82 if (!rst)    scan_cnt <=0 ;
 83 else          scan_cnt <= scan_cnt +1;       
 84 end
 85     
 86 always @( scan_cnt)         //数码管选择
 87 begin 
 88 case ( scan_cnt )    
 89 3'b000 : 
 90         begin 
 91         DIG_r <=8'b0000_0001;    
 92         A <= disptime[3:0];     
 93         end    
 94 3'b001 : 
 95         begin 
 96         DIG_r <=8'b0000_0010;    
 97         A <= disptime[7:4];     
 98         end
 99 3'b010 : 
100         begin 
101         DIG_r <=8'b0000_0100;    
102         A <= disptime[11:8];     
103         end
104 3'b011 : 
105         begin 
106         DIG_r <=8'b0000_1000;    
107         A <= dispmoney[3:0];     
108         end
109 3'b100 : 
110         begin 
111         DIG_r <=8'b0001_0000;    
112         A <= dispmoney[7:4];     
113         end
114 3'b101 : 
115         begin 
116         DIG_r <=8'b0010_0000;    
117         A <= dispmoney[11:8];     
118         end
119 3'b110 : 
120         begin 
121         DIG_r <=8'b0100_0000;    
122         A <= num1[3:0];     
123         end
124 3'b111 : 
125         begin 
126         DIG_r <=8'b1000_0000;    
127         A <= num1[7:4];     
128         end      
129 default :  
130         begin 
131         DIG_r <=8'b0000_0000;    
132         A <=0;     
133         end     
134 endcase
135 end
136 
137 always @ ( A ) //译码
138 begin 
139 case (A )
140 0: Y_r =7'b0111111; // 0
141 1: Y_r =7'b0000110; // 1
142 2: Y_r =7'b1011011; // 2
143 3: Y_r =7'b1001111; // 3
144 4: Y_r =7'b1100110; // 4
145 5: Y_r =7'b1101101; // 5
146 6: Y_r =7'b1111101; // 6
147 7: Y_r =7'b0100111; // 7
148 8: Y_r =7'b1111111; // 8
149 9: Y_r =7'b1100111; // 9
150 10: Y_r =7'b1110111; // A
151 11: Y_r =7'b1111100; // b
152 12: Y_r =7'b0111001; // c
153 13: Y_r =7'b1011110; // d
154 14: Y_r =7'b1111001; // E
155 15: Y_r =7'b1110001; // F
156 default: Y_r =7'b0000000;
157     endcase
158 end        
159     
160 endmodule

第86行~第135行:选择数码管的位置,共有8个数码管,最前面2位是显示秒针计时,中间3位是显示余额,后3位显示拨打了多少分钟;

第137行~第158行:数码管显示的数值。

3、由设计文件生成的.bsf文件,其外接接口如下图所示。  

4、引脚分配

  我们只需要对最后的一个图进行引脚分配,state接按键,表示接通还是挂断;rst接复位信号;clk接时钟信号;card接按键,表示卡是否插入;decide[1..0]接按键,表示拨打的是什么电话,市话?长途?特话?warn、write、cut、read都接LED灯,seven_seg接数码管。

5、实验结果

  

  拨动按键就能看到LED灯和数码管的正确显示了。

你可能感兴趣的:(FPGA学习)