zoukankan      html  css  js  c++  java
  • 【连载】 FPGA Verilog HDL 系列实例卡式电话计费器

    【连载】 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 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 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 <= #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 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灯和数码管的正确显示了。

  • 相关阅读:
    冷门JS技巧
    JavaScript小技巧整理篇(非常全)
    JS实现标签页切换效果
    MySQL主从配置详解
    mysql主从复制(超简单)
    1.4isAlive()方法
    1.3currentThread()方法
    1.2.4注意Sysyem.out.println与i--
    1.2.3实例变量与线程安全
    1.2.2实现Runnable接口
  • 原文地址:https://www.cnblogs.com/kongtiao/p/2143163.html
Copyright © 2011-2022 走看看