基于FPGA的出租车计费器的设计

1  概述

EDA(Electronic Design Automation)即电子设计自动化,是电子设计技术的核心,它的系统级高层次电子设计方法,对整个系统进行方案设计和功能划分,无须通过门级原理图描述电路,而是针对设计目标进行功能描述。
FPGA 是现场可编程门阵列的简称。它结合了微电子技术、电路技术和EDA技术,使设计者可以集中精力进行所需逻辑功能的设计,缩短设计周期,提高设计质量。FPGA的开发系统包括软件和硬件两个部分,开发系统软件指专用的编程语言和相应的汇编程序或编译程序。开发系统硬件部分包括计算机和编程器。编程器是对FPGA进行写入和擦除的专用装置,能够供写入或擦除操作所需要的电源电压和控制信号,并通过串行接口从计算机接收编程数据,最终写进FPGA之中。
基于FPGA的计费器系统利用Verilog HDL语言,采用模块化程序设计,自顶向下、由粗到细、逐步求精的方法,将基于FPGA的计费器系统的整体逐步分解各个模块。它不需要专门的硬件,只通过软件编程即可实现计费器系统的逻辑功能、电路结构和连接形式。Verilog HDL语言类似C语言,可读性强、更易理解,这种语言几乎覆盖了以往各种硬件描述语言的功能,在编程的过程中一般采用自顶向下的电路设计过程。
本设计利用Verilog HDL语言,在QuartusⅡ13.0软件中将出租车计费器基本结构分成6个模块对其进行程序汇编。将各块程序生成的.v文件组合在一起,生成数字钟源代码的.bdf 图形文件,最后下载到CycloneⅡ系列芯片EP20C8Q208C8N中,验证试验结果。
 

1.1 设计要求1.1.1 设计任务

设计并制作一台出租车计费器。
 

1.1.2 性能指标要求

① 用EDA实训仪的I/O设备和PLD芯片实现出租车计费器的设计。
② 出租车起步开始计程和计费,计程系统按实际公里数计程,计费系统首先显示起步价(如7.0),车行驶2km以内,只收起步价7元。
③ 出租车行驶超过2km后,按每公里1.6元在7.0元的基础上增加。
④ 出租车行驶超过10km后(或超过20元路费),每公里加收50%的车费,即车费变为每公里2.4元。
⑤ 出租车达到目的地后,(用一个按钮)计程和计费数据清零,为下一次计费开始。
 

1.2 总体设计基本原理及框图1.2.1 基本原理

该出租车计费器的基本原理方框图如图1所示,由时钟模块、控制模块、计程模块、音乐模块、LCD显示模块、计费模块6部分组成。该计费系统通过分频模块将20MHz的时钟信号通过分频器变成1Hz的时钟信号和50Hz的显示输出信号。该出租车计费的标准是起步价是6元,2公里之内费用不变,当超过2公里时,每行驶1公里,费用加收50%元;由peo信号来控制有人或者没人,高电平有人,低电平显示空车,出租车计费显示模块显示相应的费用和行驶的里程。当res为低电平时,计费系统复位。该计费系统的显示费用是0~999.9元
 

1.2.2 总体框图

基于FPGA的出租车计费器的设计
图1  总体框图
 
 

2 系统软件设计分析

整个系统由6个模块组成:
 

2.1时钟模块

时钟模块,提供实时时间,并可以通过按键调节分钟和小时并由其qs、qm、qh分别输出秒、分、时,clk20m输入20Mhz,clrn清零,fj和hj为调分和调时。用于区分白天与夜间计费,白天时间6:00~00:00、夜间时间00:00~6:00,由两个60进制计数器和一个24进制计数器组成,生成一个元件符号。
基于FPGA的出租车计费器的设计
图2-1    时钟模块元件符号图
 
60进制计数器程序:
  1. module cont60(clk,clrn,q,cout,j);
  2.                             input j,clrn,clk;
  3.                             output reg [7:0] q;
  4.                             output reg cout;
  5.                                           always @(  posedge clk^j or posedge clrn  )
  6.                                                         begin
  7.                                                         if(clrn) q=0;
  8.                                                         else
  9.                                                         begin
  10.                                                                                     q = q+1; if(q[3:0] >= 10)
  11.                                                                                     begin q[3:0] = 0;q[7:4] = q[7:4]+1;
  12.                                                                                          if(q[7:4] >= 6) q[7:4] = 0;
  13.                                                                                     end            
  14.                                                                                     if( q == 'h00 ) cout = 1;else  cout = 0;
  15.                                                         end
  16.                                           end
  17.               endmodule
  18. 24进制计数器程序:
  19. module cont24(clk,clrn,q,cout,j);
  20.                  input j,clk,clrn;
  21.                             output reg [7:0] q;
  22.                  output reg cout;
  23.                                           [email protected](  posedge clk^j or posedge clrn  )
  24.                                                         begin
  25.                                                         if(clrn)begin q=0;cout = 0;end
  26.                                                         else
  27.                                                         begin
  28.                                                                       q = q+1; if(q[3:0] >= 10)
  29.                                                                       begin q[3:0] = 0; q[7:4] = q[7:4]+1;            
  30.                                                                       end            
  31.                                                                       if( q >= 'h24 )
  32.                                                                       begin q = 0; cout = 1; end
  33.                                                                       else  cout = 0; end               
  34. end               
  35. endmodule
基于FPGA的出租车计费器的设计
图2-2   时钟仿真图
 

2.2控制模块

控制模块是用于控制车速的模块clk输入20Mhz,res清零作用,key_up是加速、key_down是减速,对应速度有0km/h、20km/h、40km/h——260km/h、280km/h、300km/h共15个速度调节来产生不同的频率由clk_speed输出,20km/h即11.1m每秒,所以20km/h要产生一秒为11100个上升沿,20Mhz/(2*11100),而gear输出不同的档位,通过对20MHz分频来产生不同的频率对应不同的速度,1秒内10000个上升沿表示1秒行驶了1m,改变频率即改变了1秒内上升沿的个数,就改变了速度。
基于FPGA的出租车计费器的设计
图2-3    按键控制模块元件符号图
 
控制模块程序:
  1. module key(clk,
  2.           key_up,
  3.                                           gear,
  4.                                           res,
  5.                                           key_down,
  6.                                           clk_speed,
  7.                                           people);
  8. input res,people;
  9. input key_up,clk,key_down;
  10. output reg clk_speed;
  11. reg [29:0] clk_sp_reg;
  12. output reg[3:0]gear;
  13. reg [29:0]up_c,down_c,n;
  14. initial begin
  15. gear='b1000;up_c=0;down_c=0;n=0;
  16. clk_sp_reg=0;
  17. end
  18. [email protected]( posedge clk or posedge res)//加速减速控制
  19. begin
  20.   if(res) begin  down_c=0;up_c=0;end
  21.   else if(!people)begin  up_c=0;  down_c =0;   end else
  22.   begin
  23.                                           if(key_up)
  24.                                                         begin
  25.                                                                       up_c=up_c+1'b1;
  26.                                                         end
  27.                                                         else
  28.                                                         begin
  29.                                                                       up_c=0;
  30.                                                         end
  31.                                           if(key_down)
  32.                                                         begin
  33.                                                                       down_c=down_c+1'b1;
  34.                                                         end
  35.                                                         else
  36.                                                         begin
  37.                                                                       down_c=0;
  38.                                                         end
  39.   end
  40. end
  41. always @(posedge clk or posedge res)//速度对应的分频数,
  42. begin
  43.     if(res) begin  gear=0;  end
  44.               else if(!people)begin  gear=0; clk_sp_reg=0;  end else
  45.               begin
  46.                   if(key_up ^ key_down )
  47.                             begin
  48.                                 if(key_up==1)
  49.                                 begin
  50.                                              if(up_c==5 && gear<='b1110)//200000)
  51.                                                         gear=gear+1;
  52.                                                         if(gear>='b1111)
  53.                                                         gear='b1111;
  54.                                           end
  55.                                           if(key_down==1)
  56.                                 begin
  57.                                              if(down_c==5)//200000)
  58.                                                         if(gear=='b0)
  59.                                                         gear='b0;else gear=gear-1;
  60.                                           end
  61.        end            
  62.         case (gear)
  63.                                           0 :  ;                                                                                                                              //速度为0
  64.                                           1       :       clk_sp_reg=909;
  65.                                           2       :       clk_sp_reg=454;
  66.                                           3       :       clk_sp_reg=303;
  67.                                           4       :       clk_sp_reg=227;
  68.                                           5       :       clk_sp_reg=181;
  69.                                           6       :       clk_sp_reg=151;
  70.                                           7       :       clk_sp_reg=129;
  71.                                           8       :       clk_sp_reg=113;
  72.                                           9       :       clk_sp_reg=101;
  73.                                           10      :       clk_sp_reg=90;
  74.                                           11      :       clk_sp_reg=82;
  75.                                           12      :       clk_sp_reg=75;
  76.                                           13      :       clk_sp_reg=69;
  77.                                           14      :       clk_sp_reg=64;
  78.                                           15      :       clk_sp_reg=60;
  79.           endcase
  80.               end
  81. end
  82. always @( posedge  clk  or  posedge res) //把20MHz分频,产生相对应速度的频率
  83. begin
  84.                                           if(res)begin n<=0;clk_speed<=0;end
  85.                                           else  if(!people)begin  n<=0;clk_speed<=0;  end else
  86.                                           begin
  87.                                                         if (n>=clk_sp_reg && gear!=0)            
  88.                                                         begin n<=0;clk_speed<=~clk_speed; end
  89.                                              else
  90.                                                         begin              n<=n+1; clk_speed<=clk_speed;end
  91.                                           end
  92. end  
  93. endmodule
基于FPGA的出租车计费器的设计
图2-4                            控制模块仿真图


2.3计程模块

计程模块由五个100进制的计数器组成,clk输入控制模块分频出来的频率,然后在计程模块进行计数,只显示qshiwan到qshiyi的计程其中qshiwan[7:4]是百米计程,这样能使计费精确到分以下,所以计程用1000个上升沿记为1米,
基于FPGA的出租车计费器的设计
图2-5                            计程模块元件符号图
 
计程模块程序:
  1. module counter0_99(clk,clr,q,cout,people);
  2.                             input clk,clr,people;
  3.                             output reg [7:0] q;
  4.                             output reg cout;
  5.                             reg one='b1;
  6.                             initial q='h99;
  7.                                           [email protected](  posedge clk or posedge clr or  negedge people )
  8.                                                         begin
  9.                                                         if(clr ) q=0;
  10.                                                         else
  11.                                                         begin    if(!people) q=0;
  12.                                                                     else
  13.                                                                                                                 begin
  14.                                                                                                                 q = q+1;
  15.                                                                                                                 if(q[3:0] >= 10)
  16.                                                                                                                 begin
  17.                                                                                                                               q[3:0] = 0;
  18.                                                                                                                               q[7:4] = q[7:4]+one;
  19.                                                                                                                               if(q[7:4] >= 10)
  20.                                                                                                                               q[7:4] = 0;
  21.                                                                                                                 end            
  22.                                                                                                                 if( q == 0 )
  23.                                                                                                                 cout = 1;
  24.                                                                                                                 else
  25.                                                                                                                 cout = 0;
  26.                                                                                                                 end                end                                          end              endmodule
基于FPGA的出租车计费器的设计
图2-6                            计程模块仿真图
 

2.4音乐模块

音乐模块的clk是时钟输入,people是有人和没人的状态标志,beep外接蜂鸣器,并设定了两个音乐《送别》和《起风了》,作为乘客上车下车时播放的音乐,播放音乐的原理是通过改变频率来改变音高,改变延时时间来确定一小节拍的时间是240ms,通过分频产生。
//音高与频率的对应关系
//| | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
//|低音 |261.6Hz |293.7Hz |329.6Hz |349.2Hz | 392Hz | 440Hz |493.9Hz |
//|中音 |523.3Hz |587.3Hz |659.3Hz |698.5Hz | 784Hz | 880Hz |987.8Hz |
//|高音 |1045.5Hz|1174.7Hz|1318.5Hz|1396.9Hz| 1568Hz | 1760Hz |1975.5Hz|
//乐谱参数:D=F/2K (D:参数,F:时钟频率,K:音高频率)
基于FPGA的出租车计费器的设计
图2-7                            音乐模块元件符号图
音乐模块程序:
  1. module music( clk,people,  beep);
  2. input clk,people;
  3. output reg  beep;
  4. reg flag ,flag1;
  5. reg[7:0] state,state1; //乐谱状态机
  6. reg[16:0]count,count_end;
  7. reg[23:0]count1,count2;  //乐谱参数:D=F/2K (D:参数,F:时钟频率,K:音高频率)
  8. parameter   S_0=8'd20000000,   
  9.             L_1 = 17'd38226, M_1 = 17'd19109, H_1 = 17'd09564, //音1
  10.                                                         L_2 = 17'd34048, M_2 = 17'd17027, H_2 = 17'd08512, //音2
  11.                                                         L_3 = 17'd30339, M_3 = 17'd15167, H_3 = 17'd07584, //音3
  12.                                                         L_4 = 17'd28636, M_4 = 17'd14316, H_4 = 17'd07158, //音4
  13.                                                         L_5 = 17'd25510, M_5 = 17'd13368, H_5 = 17'd06377, //音5
  14.                                                         L_6 = 17'd22727, M_6 = 17'd11363, H_6 = 17'd05681, //音6
  15.                                                         L_7 = 17'd20247, M_7 = 17'd10123, H_7 = 17'd05062; //音7
  16. parameter TIME = 2400000; //控制每一个音的长短(480ms)
  17. parameter TIME1 = 4800000; //控制每一个音的长短(240ms)
  18.                                                         always @(posedge clk)
  19.                                                         begin
  20.                                                         if(people==0)
  21.                                                         begin
  22.                                                               flag=1; state1 =0;count2=0;
  23.                                                              if(flag1==1)
  24.                                                               begin
  25.                                                                                         count = count + 1'b1; //计数器加1
  26.                                                                                         if(count == count_end && count_end!=S_0)
  27.                                                                                                   begin count = 17'h0; //计数器清零
  28.                                                                                                                     beep = !beep;end  //输出取反                  
  29.                                                                                                   if(count1 < TIME) count1 = count1 + 1'b1;
  30.                                                                                                   //一个节拍240mS  data=F/2/ms   T=2*N*Tc        
  31.                                                                                                   else  begin  count1 = 24'd0;
  32.                                                                                                                   if(state == 8'd127)
  33.                                                                                                                   begin flag = 0;state=8'd0;  end
  34.                                                                                                                   else  state = state + 1'b1;
  35.                                                                                                                   case(state)
  36.                                                                                                                   8'd0,8'd1,8'd2,8'd3: count_end = M_5;//低音"3",4个节拍
  37.                                                                                                                   8'd4,8'd5: count_end = M_3;//低音"5",持续2个节拍
  38.                                                                                                                   8'd6,8'd7: count_end = M_5;//低音"6",持续2个节拍
  39.                                                                                                                   8'd8,8'd9,8'd10,8'd11,
  40.                                                                                                                   8'd12,8'd13,8'd14,8'd15: count_end = H_1;//高音"1",8拍
  41.                                                                                                                   8'd16,8'd17,8'd18,8'd19: count_end = M_6;//中音"6",4拍
  42.                                                                                                                   8'd20,8'd21,8'd22,8'd23: count_end = H_1;//高音"1",4拍
  43.                                                                                                                   8'd24,8'd25,8'd26,8'd27,
  44.                                                                                                                   8'd28,8'd29,8'd30,8'd31,
  45.                                                                                                                   8'd32,8'd33,8'd34,8'd35: count_end = M_5;//中音"5",8拍
  46.                                                                                                                   8'd36,8'd37: flag1=0;//count_end = M_1;//低音"5",2拍
  47.                                                                                                                   endcase
  48.                                                                                                                               end
  49.                                                                                                   end
  50.                                                                       end
  51.                                                                       else
  52.                                                                       if(people==1)
  53.                                                                       begin
  54.                                                               flag1=1; state =0;count1=0;
  55.                                                               if(flag==1)
  56.                                                               begin
  57.                                                                                         count = count + 1'b1; //计数器加1
  58.                                                                                         if(count == count_end)
  59.                                                                                                   begin count = 17'h0; //计数器清零
  60.                                                                                                                 beep = !beep;end  //输出取反                  
  61.                                                                                                   if(count2 < TIME1) count2 = count2 + 1'b1;
  62.                                                                                                   //一个节拍240mS  data=F/2/ms   T=2*N*Tc        
  63.                                                                                                   else  begin  count2 = 24'd0;
  64.                                                                                                                   if(state1 == 8'd229)
  65.                                                                                                                   begin flag = 0;state1=8'd0;  end
  66.                                                                                                                   else  state1 = state1 + 1'b1;
  67.                                                                                                                   case(state1)
  68.                                                                                                                               8'd0,8'd1 : count_end = M_1;
  69.                                                                                                                               8'd2,8'd3 : count_end = M_2;
  70.                                                                                                                               8'd4,8'd5 : count_end = M_3;
  71.                                                                                                                               8'd6,8'd7 : count_end = M_1;//
  72.                                                                                                                               8'd8,8'd9 : count_end = M_6;
  73.                                                                                                                               8'd10 : count_end = M_5;
  74.                                                                                                                               8'd11 : count_end = M_6;
  75.                                                                                                                               8'd12 : count_end = M_6;
  76.                                                                                                                               8'd13,8'd14 : flag=0;//count_end = S_0;
  77.                                                                                                                   endcase
  78.                                                                                                                               end
  79.                                                                                                   end
  80.                                                                       end              
  81.                                           end
  82. endmodul

复制代码

 

2.5 LCD显示模块

显示模块是使用LCD1602液晶屏,其中clk是时钟,people是有人和没人的状态为rstn是清零,in_data是档位输入,q0到q4是公里数输入,qs、qm、qh是时钟输入,cost_lcd_in是费用输入,显示界面可以显示时间、行驶路程、速度、费用,由于程序数据转换太多,这里只给出一部分程序,后面的程序在附录。
LCD1602主要技术参数:显示容量:16×2个字符、芯片工作电压:4.5—5.5V、工作电流:2.0mA(5.0V)、模块最佳工作电压:5.0V、字符尺寸:2.95×4.35(W×H)mm。
基于FPGA的出租车计费器的设计
图2-8                            LCD1602模型图

 

编号
符号
引脚说明
编号
符号
引脚说明
1
VSS
电源地
9
D2
数据
2
VDD
电源正极
10
D3
数据
3
VL
液晶显示偏压
11
D4
数据
4
RS
数据/命令选择
12
D5
数据
5
R/W
读/写选择
13
D6
数据
6
E
使能信号
14
D7
数据
7
D0
数据
15
BLA
背光源正极
8
D1
数据
16
BLK
背光源负极

 

表1                            引脚接口说明表

 

序号
指令
RS
R/W
D7
D6
D5
D4
D3
D2
D1
D0
1
清显示
0
0
0
0
0
0
0
0
0
1
2
光标返回
0
0
0
0
0
0
0
0
1
*
3
置输入模式
0
0
0
0
0
0
0
1
I/D
S
4
显示开/关控制
0
0
0
0
0
0
1
D
C
B
5
光标或字符移位
0
0
0
0
0
1
S/C
R/L
*
*
6
置功能
0
0
0
0
1
DL
N
F
*
*
7
置字符发生存贮器地址
0
0
0
1
字符发生存贮器地址
8
置数据存贮器地址
0
0
1
显示数据存贮器地址
9
读忙标志或地址
0
1
BF
计数器地址
10
写数到CGRAM或DDRAM)
1
0
要写的数据内容
11
从CGRAM或DDRAM读数
1
1
读出的数据内容

 

表2                            控制指令表
 
1602液晶模块的读写操作,屏幕和光标的操作都是通过指令编程来实现的。(说明1为高电平,0为低电平)
指令1:清显示,指令码01H,光标复位到地址00H位置
指令2:光标复位,光标返回到地址00H
指令3:光标和显示位置设置I/D,光标移动方向,高电平右移,低电平左移,S:屏幕上所有文字是否左移或右移,高电平表示有效,低电平表示无效。
指令4:显示开关控制。D:控制整体的显示开与关,高电平表示开显示,低电平表示关显示。C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位 S/C :高电平时显示移动的文字,低电平时移动光标
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时为双行显示,F:低电平时显示5X7的点阵字符,高电平时显示5X10的显示字符。
指令7:字符发生器RAM地址设置。
指令8:DDRAM地址设置。
指令9:读忙信号和光标地址 BF:忙标志位,高电平表示忙,此时模块不能接收命令或数据,如果为低电平表示不忙。
基于FPGA的出租车计费器的设计
图2-9                            LCD显示模块元件符号图
LCD显示模块程序:
  1. module lcd1602(sys_clk    ,
  2.       sys_rstn   ,     
  3.                             lcd_rs     ,   
  4.                             lcd_rw     ,   
  5.                             lcd_en     ,
  6.                             lcd_data   ,  
  7.                  in_data,
  8.       q0,q1,q2,q3,q4,qs,qm,qh,people,
  9.                             cost_lcd_in
  10.               ); //输入输出信号定义
  11.                             input               [31:0]              cost_lcd_in;
  12.                             input  [7:0]  q0,q1,q2,q3,q4,qs,qm,qh;
  13.                             input  sys_clk    ;//系统时钟输入
  14.                             input    people,      sys_rstn   ;//系统复位信号,低电平有效
  15.                             input   [3:0] in_data;
  16.                             output         lcd_rs     ;//lcd的寄存器选择输出信号
  17.                             output         lcd_rw     ;//lcd的读、写操作选择输出信号
  18.                             output         lcd_en     ;//lcd使能信号
  19.                             output  [7:0]  lcd_data   ;//lcd的数据总线(不进行读操作,故为输出)
  20.                             reg            lcd_rs     ;
  21.                             reg            clk_div    ;
  22.                             reg [7:0]  q1h,q1l,q2h,q2l,q3h,q3l,q4l;
  23.                             reg [7:0]              sp_reg1,sp_reg2,sp_reg3;
  24.                             reg [7:0]              qsl,qsh,qml,qmh,qhl,qhh;
  25.                             reg [7:0] in_data_reg;
  26.                             reg [7:0]              cost_reg0,cost_reg1,cost_reg2,cost_reg3;
  27.                             reg     [17:0] delay_cnt  ;
  28.                             reg     [7:0]  lcd_data   ;
  29.                             reg     [4:0]  char_cnt   ;
  30.                             reg     [7:0]  data_disp  ;
  31.                             reg     [9:0]  state      ;
  32.                             parameter   
  33.                             idle                                                                         = 10'b000000000, //初始状态,下一个状态为CLEAR   
  34.                             clear                                                                        = 10'b000000001,  //清屏   
  35.                             set_function                                           = 10'b000000010,
  36.                             switch_mode                                           = 10'b000000100,
  37.                             set_mode                                              = 10'b000001000,
  38.                             shift                                                            = 10'b000010000,
  39.                             //光标、画面位移设置:光标向左平移一个字符位
  40.                             set_ddram1                                             = 10'b000100000,
  41.                             //设置DDRAM的地址:第一行起始为0x00(注意输出时DB7一定要为1)     
  42.                             set_ddram2                                             = 10'b001000000,  //设置DDRAM的地址:第二行为0x40                            write_ram1                                             = 10'b010000000,  //数据写入DDRAM相应的地址   
  43.                             write_ram2                                            = 10'b100000000;  //数据写入DDRAM相应的地址
  44.                             assign lcd_rw = 1'b0;      //没有读操作,R/W信号始终为低电平
  45.                             assign lcd_en = clk_div; //E信号出现高电平以及下降沿的时刻与LCD时钟相同              [email protected](posedge sys_clk or posedge sys_rstn) /////分频
  46.               begin   if(sys_rstn)   begin    delay_cnt<=18'd0;    clk_div<=1'b0;
  47.               end  else if(delay_cnt==18'd200000)
  48.               begin
  49.               delay_cnt<=18'd0;    clk_div<=~clk_div;   end  else
  50.               begin    delay_cnt<=delay_cnt+1'b1;    clk_div<=clk_div;
  51.               end end
  52.               [email protected](posedge clk_div or posedge sys_rstn) //State Machine
  53.               begin  if(sys_rstn)
  54.               begin    state   <= idle;    lcd_data <= 8'b0;    char_cnt <= 5'd0;      
  55.               lcd_rs<=1'b0;//地址\数据
  56.    end  else   begin
  57.               case(state)
  58.               idle: begin      //初始状态     
  59.                          state <= clear;      lcd_data <= 8'b0;     end
  60.               clear: begin      //清屏   
  61.                                                         state <= set_function;   
  62.                                                         lcd_rs<=1'b0;   
  63.                                                         lcd_data <= 8'b00000001;     
  64.                                                         end  
  65.               set_function:      //功能设置(38H):8位数据接口/2行显示/5*8点阵字符  
  66.                                                                       begin      state <= switch_mode;      lcd_rs<=1'b0;
  67.                                                                       lcd_data <= 8'b00111000;         end  
  68.               switch_mode:       //显示开关控制(0CH):开显示,光标和闪烁关闭   
  69.                                                                       begin      state <= set_mode;      lcd_rs<=1'b0;   
  70.                                                                       lcd_data <= 8'b00001110;     end  
  71.               set_mode:begin   //输入方式设置(06H):数据读写操作后,地址自动加一/画面不动
  72.                            state <= shift;       lcd_rs<=1'b0;   
  73.                                                                       lcd_data <= 8'b00000110;     end
  74.               shift: begin      //光标、画面位移设置(10H):光标向左平移一个字符位
  75.                                                                       //(光标显示是关闭的,所以实际上设置是看不出效果的)  
  76.            state <= set_ddram1;      lcd_rs<=1'b0;   
  77.                                             lcd_data <= 8'b0001_0000;        end   
  78. set_ddram1: //设置DDRAM的地址:第一行起始为00H(注意输出时DB7一定要为1)     
  79.           begin      state <= write_ram1;   
  80.                                                                                     lcd_rs<=1'b0;      lcd_data <= 8'b1000_0000;//Line1
  81.                                           end
  82. set_ddram2:       //设置DDRAM的地址:第二行为40H(DB7一定要为1)
  83.                                                                       begin      state <= write_ram2;   
  84.                                                                       lcd_rs<=1'b0;      lcd_data <= 8'b1100_0000;//Line2   
  85.                                                                       end  
  86. write_ram1:        
  87.            begin              
  88.                                                                         if(char_cnt <=5'd15)
  89.                                                                         begin   char_cnt <= char_cnt + 1'b1;   
  90.                                                                                                     lcd_rs<=1'b1;  lcd_data <= data_disp;
  91.                                                                                                     state <= write_ram1;  end   
  92.                                                                         else   begin   state <= set_ddram2; end        
  93.                                             end
  94. write_ram2:
  95.             begin      
  96.                                                                                     if(char_cnt <=5'd30)
  97.                                                                                     begin char_cnt <= char_cnt + 1'b1;
  98.                                                                                                                 lcd_rs<=1'b1;   lcd_data <= data_disp;
  99.                                                                                                                 state <= write_ram2;    end     
  100.                                                                                     else   begin  char_cnt <=5'd0; state <= shift;     end      
  101.                                                         end
  102. default:  state <= idle;
  103. endcase  
  104. end
  105. end
复制代码

2.6计费模块

计费模块其中clk是20MHz输入,clrn清零,people是有人没人的状态位,q0到q4为里程输入,qh为小时输入,用于判断白天计程和夜间计费,其中又分0~2km不计程,2~10km加20%费用,且白天和夜间的四个计费阶段都有相对应的指示灯闪烁(L12到L15),白天:7元2km内7元,2km-10km每公里收费1.6元,10km以上每公里收费2.4元;夜间:起步价8元2km内8元,2km-10km每公里收费2元,10km以上每公里收费3元。cost_q输出费用。10km以上加收费用,1000个上升沿即为1米,则1km——1.6元,1000000个上升沿对应160分,1分即6250个上升沿,由于程序数据转换太多,这里只给出一部分程序,后面的程序在附录。
基于FPGA的出租车计费器的设计
图2-10                            计费模块元件符号图
              计费模块程序:
  1.               module counter0_99_16(
  2.               clk,clr,cost_q,people,
  3.               q0,q1,q2,q3,q4,qh,
  4.               l12,l13,l14,l15
  5.               );
  6.                             input clk,clr,people;
  7.                             output              reg l12,l13,l14,l15;
  8.                             input [7:0] q0,q1,q2,q3,q4,qh;
  9.                             output reg [31:0] cost_q;
  10.                             reg [13:0] n;
  11.                             reg one='b1;
  12.                             initial              n=0;
  13.                             initial              cost_q='b0000_0000_0000_0000_0000_1000_0000_0000;
  14.                                           [email protected](  posedge clk or posedge clr or  negedge people )
  15.                                                         begin
  16.                                                         if(clr ) begin              l12=0;l13=0;l14=0;l15=0;cost_q=0;end
  17.                                                         else
  18.                                                         begin  if(!people)              begin l12=0;l13=0;l14=0;l15=0;
  19.               if(qh>'b00000110)cost_q='b0000_0000_0000_0000_0000_0111_0000_0000;
  20.                                                                                                   else              if(qh<='b00000110)cost_q='b0000_0000_0000_0000_0000_1000_0000_0000;              end
  21.                                                                     else
  22.                                                                                                   begin            
  23.                                                                                                   if(qh>8'b00000110)
  24.                                                                                                   begin
  25. if({q4,q3,q2,q0}<=32'b0000_0000_0001_0000_0000_0000_0000_0000
  26.                                                                                                   &&              {q4,q3,q2,q0}>32'b0000_0000_0000_0010_0000_0000_0000_0000              ) begin
  27.                                                                                                   //1000000电平除以160分,得出一分6250个上升沿
  28.                                                                                                                                             if(n              <              'd6250)              //1.6元
  29.                                                                                                                                             begin              n=n+'d1;              end            
  30.                                                                                                                                             if(n              >=              'd6250)
  31.                                                                                                                                             begin
  32.                                                                                                                                                           n<=0;            
  33.                                                                                                                                                           begin
  34.                                                                                                                                                           l12=~l12;l13=0;l14=0;l15=0;
  35.                                                                                                                                                           cost_q = cost_q+1;
  36.                                                                                                                                                           if(cost_q[3:0] >= 10)
  37.                                                                                                                                                           begin              cost_q[3:0] = 0;
  38.                                                                                                                                                           cost_q[7:4] = cost_q[7:4]+one;end            
  39.                                                                                                                                                           if(cost_q[7:4] >= 10)
  40.                                                                                                                                                           begin              cost_q[7:4] = 0;
  41.                                                                                                                                                           cost_q[11:8] = cost_q[11:8]+one;end            
  42.                                                                                                                                                           if(cost_q[11:8] >= 10)
  43.                                                                                                                                                           begin              cost_q[11:8] = 0;
  44.                                                                                                                                                           cost_q[15:12] = cost_q[15:12]+one;end
  45.                                                                                                                                                           if(cost_q[15:12] >= 10)
  46.                                                                                                                                                           begin              cost_q[15:12] = 0;
  47.                                                                                                                                                           cost_q[19:16] = cost_q[19:16]+one;end
  48.                                                                                                                                                           if(cost_q[19:16] >= 10)
  49.                                                                                                                                                           begin              cost_q[19:16] = 0;
  50.                                                                                                                                                           cost_q[23:20] = cost_q[23:20]+one;end
  51.                                                                                                                                                           if(cost_q[23:20] >= 10)
  52.                                                                                                                                                           begin              cost_q[23:20] = 0;
  53.                                                                                                                                                           cost_q[27:24] = cost_q[27:24]+one;end
  54.                                                                                                                                                           if(cost_q[27:24] >= 10)
  55.                                                                                                                                                           begin              cost_q[27:24] = 0;
  56.                                                                                                                                                           cost_q[31:28] = cost_q[31:28]+one;end
  57.                                                                                                                                                           end
  58.                                                                                                                                             end
  59.                                                                                                                               end else
  60.                                                                                     end
  61.                                                           end
  62.                         end                                                                                                  
  63.               end
  64.               endmodule
复制代码
基于FPGA的出租车计费器的设计
图2-11                                          计费模块仿真图

3  系统测试(调试)3.1 测试仪器与设备

① EDA实验仪一台。
② 计算机一台(装有Quartus Ⅱ软件)

3.2 性能指标测试

把程序下载进实验箱,按键控制有人和没人的状态,蜂鸣器能正常播放音乐,然后运行计费器,通过计算的出的费用和路程相符合,白天和夜间的起步价、2km到10km计费标准和10km以上的计费标准都正确,且能显示正确的速度,时间,路程,四个收费阶段都有相对应的指示灯闪烁提示,速度的各档速也有相对应的灯点亮。
基于FPGA的出租车计费器的设计
图3-1                            引脚锁定

 

基于FPGA的出租车计费器的设计
图3-2                            白天计费测试图
基于FPGA的出租车计费器的设计
图3-3                            夜间计费测试图