【连载】 FPGA Verilog HDL 系列实例--------卡式电话计费器

痴心易碎 提交于 2019-12-22 06:32:23

【连载】 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 begin22     if ( rst== 1'b0 ) begin23         clkout <= 1'b0;24         count1 <= 17'b0; 25         end26     else begin27         if ( count1>=32'd25000000) begin28             clkout <= ~clkout ;29             count1 <=  32'd0; 30             end31         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             else if ( 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                                         end107                                     end108                                 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                                         end118                                     else dtime [7:4] <= dtime [7:4] +1'b1 ;119                                     end120                                 else begin 121                                     dtime[3:0] <= dtime [3:0] + 1'b1;122                                     warn <= 1'b0 ;123                                     reset_ena <= 1'b0 ;124                                     end125                                 end126                     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 begin133                                 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                                         end141                                     end142                                 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                                         end152                                     else dtime [7:4] <= dtime [7:4] +1'b1 ;153                                     end154                                 else     begin 155                                     dtime[3:0] <= dtime [3:0] + 1'b1;    156                                     reset_ena <= 1'b0 ; 157                                     warn <= 1'b0 ; 158                                     end159                                 end160                     endcase161             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         end168             169         end170     end171     172 always @ ( posedge clk_1Hz or negedge rst )       //当余额不足发出警报时,15S后自动切断通话信号173 174     begin 175         if ( rst == 1'b0 ) begin 176           temp <= 5'b0 ;      177          end178     else begin179         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             end185         if ( !card||!reset_ena ) begin 186             cut <= 1'b0 ;187             temp <= 1'b0 ;188             end189     end190 end191 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 <= #1 1'b1; 72         else if (cnt == period - 1)                    //设定的周期时间 73             begin  74             clkout <= #1 1'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         end104     3'b011 : 105         begin 106         DIG_r <= 8'b0000_1000;    107         A <= dispmoney[3:0];     108         end109     3'b100 : 110         begin 111         DIG_r <= 8'b0001_0000;    112         A <= dispmoney[7:4];     113         end114     3'b101 : 115         begin 116         DIG_r <= 8'b0010_0000;    117         A <= dispmoney[11:8];     118         end119     3'b110 : 120         begin 121         DIG_r <= 8'b0100_0000;    122         A <= num1[3:0];     123         end124     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 endcase135 end136 137 always @ ( A ) //译码138 begin 139     case (A )140             0: Y_r = 7'b0111111; // 0141             1: Y_r = 7'b0000110; // 1142             2: Y_r = 7'b1011011; // 2143             3: Y_r = 7'b1001111; // 3144             4: Y_r = 7'b1100110; // 4145             5: Y_r = 7'b1101101; // 5146             6: Y_r = 7'b1111101; // 6147             7: Y_r = 7'b0100111; // 7148             8: Y_r = 7'b1111111; // 8149             9: Y_r = 7'b1100111; // 9150             10: Y_r = 7'b1110111; // A151             11: Y_r = 7'b1111100; // b152             12: Y_r = 7'b0111001; // c153             13: Y_r = 7'b1011110; // d154             14: Y_r = 7'b1111001; // E155             15: Y_r = 7'b1110001; // F156             default: Y_r = 7'b0000000;157     endcase158 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灯和数码管的正确显示了。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!