Verilog HDL 之 卡式电话计费器
我们每天都在和手机打交道,更熟悉了打电话的各项业务,那么怎么通过Verilog HDL 硬件描述语言简单的控制电话的计时计费呢,下面我们就来看看是如何实现的。先介绍下卡式电话计费器的要求。
一、实验要求及原理
(1) 计费器在话卡插入后,能将卡中的币值读出并显示出来;在通话过程中,根据话务种类计话费并将话费从卡值中扣除,卡值余额每分钟更新一次;计时与计费数据均以十进制形式显示出来。
(2)话务分为3类:市话、长话和特话,其中市话按每分钟3角钱计费,长话按每分钟6角钱计费,特话不收费。当卡上余额不足时产生告警信号,当告警达到一定时间则切断当前通话。
二、实验平台
Quartus II 7.2 集成开发环境、SOPC-MBoard板、ByteBlaster II 下载电缆
三、实验实现
1、设计思路
此系统由三个模块组成,一是时钟分频模块,负责产生1Hz的时间;二是卡式电话计费主体,负责计时计费,余额不足时,产生警报后自动切断通话信号;三是顶层模块,负责数码管的显示。
2、在设计文件中输入Verilog代码。
(1)时钟分频
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)卡式电话计费主体
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)顶层显示
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灯和数码管的正确显示了。