地铁自动售票机(基于FPGA)
西安电子科技大学
08级集成电路设计与集成系统专业
井站14082094 尹俊镖14082108 潘志友14082068 李波14082117 一 功能需求 1 市场目标
本工程设计是基于FPGA设计一个地铁自动售票系统。近年来,集成电路技术的迅猛发展,特别是可编程逻辑器件的高速发展,电子设计自动化EDA技术成为电子设计工程师的新宠。然而随着城市人口的迅速增加、车辆的增多,世界各地的城市交通变得愈发拥挤,地铁成为城市交通的重要组成部分。随着国民经济的发展,我国的地铁建设也日益成为人们日常生活中不可或缺的一部分。作为地铁运营服务的第一道关,改善地铁已逐渐落后于时代步伐的售票系统势在必行。本系统是结合行业管理中实际的地铁售票系统运行过程中的需求过程,经过实际的需求分析,开发出来的地铁自动
售票系统。整个系统的设计从符合操作简便快捷、灵活实用、保证稳定安全的要求出发,完成售票管理的基本过程。
2 功能定义
通过本设计,正确掌握数字系统的模块划分、并能自如应用硬件描述语言描述各模块功能,以实现系统设计。以Verilog语言和Quartue II,Modlesim为工具,实现了地铁自动售票系统。系统划分为几个功能模块,分模块进行分析和设计,系统给出相应的设计原理图和Verilog源程序,通过仿真实现预定的功能。
本组成员参与设计的自动售票机,就其功能特点来说,可以归纳如下:
1)该自动售票系统可对单价为3元、4元、5元,6元四种票售票。
2)能选择买1张或2张票;
3)有1元,5元、10元,20元四个投币口。当投入的钱币与选择的票款相等时,送出车票;若投入的钱币不够,1分钟后,退出钱币,无票送出;若投入的钱币超过票款,能自动找赎。 4)系统显示选择所选票单价面额、购买的票数、投入的钱币额及找赎的钱额。
3 应用案例
在广州地铁、北京地铁、南京地铁等全国十多条城市轨道交通线路都能见到广电运通自动售票机的身影。作为目前中国最具有成长力的AFC(自动售检票系统)设备提供商,广电运通在轨道交通领域已取得了众多成功案例。广电运通自动售票机支持硬币和成叠纸币找零、纸质磁票打印、成叠出票及钱票遗忘回收等多项功能,界面简洁、标识清晰,操作便利,极大缩短了旅客的购票时间,受到旅客们的欢迎。
二 开发计划
1 项目分工
井站:负责 选票模块,投币模块,找零模块,顶层模块代码的编写和测试仿真
尹俊镖:负责计数器序列模块,6选1选择器模块,数码管译码器模块,数码管位选模块等显示功能的代码编写和测试仿真和后期实验报告文档编写。
潘志友,李波:负责市场调研分析,查找参考资料等众多任务。
2 进度规划
第一天:选定设计题目,分析项目可行性,完成市场调
研分析,查找相关参考资料;进行工程的整体规划。
第二天和第三天 :用Modlesim软件完成各个子模块的代码编写和测试仿真;
第四天:学习QuartueII 软件,完成综合文件,最后书写实验报告,工程竣工。
3 技术重点及其预期难点分析
重点在于整体规划是否合理可行,代码是否成功编写,预期难点是不熟悉QuartueII 软件的开发环境。
4可行性分析
整体设计思路是:通过选择票的单价和数量,将总额和
投币总额比较,当投入的钱币与选择的票款相等时,送出车票;若投入的钱币不够,1分钟后,退出钱币,无票送出;若投入的钱币超过票款,能自动找赎。最后显示信息。通过成员的反复论证,确认该设计思路可行。
三设计方案及其验证测试
.1 系统的总体框架结构
地铁自动售票系统大致可分为四个功能模块:车票选择模块、钱币处理模块、余额计算模块、显示功能模块。[28]
系统总体框图如图所示:
车票选择模块 钱币处理模块 余额计算模块 显示功能模块
系统总体框图
1)车票选择模块。当自动售票机通电时,表示一次投币售票过程开始;乘客正常购买车票操作失误包括改变购买意向或不再购买,按rd按钮重新进入初始状态;在初始状态pri和qua生效时,顾客可以根据自己的需要,选择其中一种车票(只限一种)和票数,进入下一模块。
2)钱币处理模块。表示投入的钱币是1元,5元、10元,20元的coin_1,coin_5、coin_10,coin_20生效,记录所投钱币总额。
3)余额计算模块。当投人钱币总额大于或等于车票价格,并且按确认键后出票并找零;若投入钱币总额小于车票价格,售票机不出票,并退出所投钱币,进入初始状态。
4)显示功能模块。此模块根据输入提供的数据,用数码管来显示选择的是所选票面额、购买的票数、投入的钱币额及找赎的钱额。[29]
2 功能模块分析 顶层模块代码如下:
module top(pri_3,pri_4,pri_5,pri_6,qua_1,qua_2,coin_1, coin_5,coin_10,coin_20,
rd,finish,clk1,clk2,outw,outz,act_1,act); Input pri_3,pri_4,pri_5,pri_6,qua_1,
qua_2,coin_1,coin_5,coin_10, coin_20,rd,clk1,clk2,finish;
output act_1; output[3:0] act; output[5:0] outw; output[6:0] outz; wire act_1; wire[3:0] act; wire[5:0] outw; wire[6:0] outz;
wire[3:0] w1,w2,w3,w5,w6,w7,w8,w10; wire[2:0] w9; wire[4:0] w4;
Xuanpiao x1(.pri_3(pri_3),.pri_4(pri_4), .pri_5(pri_5),.pri_6(pri_6),
.qua_1(qua_1),.qua_2(qua_2),.clk(clk1), .rd(rd),.pri(w2),.qua(w3),.cost(w1));
Toubi t1(.coin_1(coin_1),.coin_5(coin_5), .coin_10(coin_10),.coin_20(coin_20), .clk(clk1),.rd(rd) ,.coinh(w5), .coinl(w6),.coin(w4));
zhaoling z1(.pri_in(w2),.cost_in(w1),.coin_in(w4), .finish(finish),.clk(clk1),.rd(rd),.act(act), .act_1(act_1),.rest(),.restl(w8),.resth(w7));
counter6 c1(.clk2(clk2),.out(w9));
select6_1 s1(.out(w10),.in0(w2),.in1(w3),.in2(w5), .in3(w6),.in4(w7),.in5(w8),.sel(w9)); weixuan w(.din(w9),.out(outw)); zixing z(.din(w10),.out(outz)); endmodule
顶层综合文件如下:
各个子模块分析 2.1 车票选择模块
车票选择模块是指对商品进行选择与购买。车票分为票价3元,4元,5元,6元,共4种车票,乘客可以选择所要购买的票数(1张票,2张票)。
车票选择模块如图4所示:
1)输入
①rd:模块复位信号,将所有输出信号清零。作为开始一次购票过程的按键,也可以作为让乘客重新选票的按键。
②clk:模块的时钟信号。
④pri_3,pri_4,pri_5,pri_6:将其中一个置高电平,作为选择一种票价(3元,4元,5元,6元)。
⑤qua_1,qua_2:将其中一个置高电平,作为选择购买车票的数量(一张票,两张票)。
2)输出
②pri[3:0]:表示所选票价,输出到余额计算模块和显示功能模块,作为判断出何种票的条件,并在数码管显示出车票单价。
③qua[3:0]:表示所买票数,输出到显示功能模块,在数码管显示出票数。
④cost[3:0]:表示应付总额,根据票价和票数来计算出应付的总额,输出到余额计算模块,用来计算找赎金额。
该车票选择模块的源程序如下:
module xuanpiao(pri_3,pri_4,pri_5,pri_6,qua_1,qua_2,clk,rd,
pri,qua,cost);
input pri_3,pri_4,pri_5,pri_6,qua_1,qua_2,rd,clk; output[3:0] pri; output[3:0] qua; output[3:0] cost; reg[3:0] pri; reg[3:0] qua; reg[3:0] cost; initial begin
pri=0; qua=0; cost=0; end
always@(rd) //清零 begin if(!rd) begin pri=0; qua=0; cost=0;
end
end
always@(posedge clk or negedge rd) begin
if(!rd) begin
pri=0; qua=0; cost=0; end
else if(pri_3&&qua_1) // 选1张3元票,总额3元 begin pri=3; qua=1; cost=3; end
else if(pri_4&&qua_1) // 选1张4元票,总额4元 begin pri=4; qua=1; cost=4;
end
else if(pri_5&&qua_1) // 选1张5元票,总额5元 begin pri=5; qua=1; cost=5;
end
else if(pri_6&&qua_1) // 选1张6元票,总额6元 begin pri=6; qua=1; cost=6; end
else if(pri_3&&qua_2) // 选2张3元票,总额6元 begin pri=3; qua=2; cost=6;
end
else if(pri_4&&qua_2) // 选2张4元票,总额8元 begin pri=4; qua=2;
cost=8;
end
else if(pri_5&&qua_2) // 选2张5元票,总额10元 begin pri=5; qua=2; cost=10;
end
else if(pri_6&&qua_2) // 选2张6元票,总额12元 begin pri=6; qua=2; cost=12; end end endmodule
经过编译后建立波形文件,波形仿真图如图所示:
在此波形仿真图中,将pri_3,qua_1;pri_5,qua_2;pri_4,qua_2;依次置高电平作为输入,输出显示为选择的3元票,1张票,应付总额3元;选择的5元票,2张票,应付总额10;选择的4元票,2张票,应付的总额8元,说明达到此车票选择模块的预期功能。
2.2 钱币处理模块
钱币处理模块是对投入的钱币进行处理的过程,输出参
数coin为投币数值计数器,以1元为单位进行计算。该模块入口参数coin1(投入1元)coin5(投入5元钱),coin10(投入10元钱),coin20(投入20元)。功能类似于计钱器,在清零的前提下,可准确计算,记录并保存所投入的总钱数。
钱币处理模块如图所示:
图 钱币处理模块
1)输入
①rd:模块复位信号,将所有输出信号清零。 ②clk:模块的时钟信号。
③coin_1,coin_5,coin_10,coin_20:表示投入1元,5元,10元,20元。一次时钟上升沿,若信号为‘1’时,表示投入一次1元,5元10元,20元。
2)输出
①coinh[3:0],coinl[3:0]:信号输出到显示功能模块,在数码管上显示出投入钱币总额的十位和个位。
②coin[4:0]:表示投入钱币的总额,输出到余额计算模块,与应付总额相比较,来计算出找赎金额。
该钱币处理模块的源程序如下:
module toubi(coin_1,coin_5,coin_10,coin_20,clk,rd, coinh,coinl,coin);
input coin_1,coin_5,coin_10,coin_20,rd,clk; output[3:0] coinh,coinl; output[4:0] coin; reg[3:0] coinh,coinl; reg[4:0] coin; /*initial begin
coinh=0; coinl=0; coin=0; end*/
/*always@(rd) // 清零 begin if(!rd) begin coinh=0; coinl=0; coin=0; end
end*/
always@(posedge clk or negedge rd) begin if(!rd) begin coinh=0; coinl=0; coin=0; end
else if(coin_1) //投入1元 begin
case(coinl) // coinl是投入总额的个位数字 0:
begin coinl=1;
coinh=coinh; // coinh是投入总额的十位数字
coin=coin+1; // coin是投入总额 end 1: begin
coinl=2; coinh=coinh; coin=coin+1; end 2: begin
coinl=3; coinh=coinh; coin=coin+1; end 3: begin
coinl=4; coinh=coinh; coin=coin+1; end 4:
begin
coinl=5; coinh=coinh; coin=coin+1; end 5:
begin
coin=6;
coinh=coinh; coin=coin+1; end 6: begin
coinl=7; coinh=coinh; coin=coin+1; end 7: begin coinl=8; coinh=coinh; coin=coin+1; end
8:
begin
coinl=9; coinh=coinh; coin=coin+1; end 9:
begin
coinl=0; coinh=coinh+1; coin=coin+1; end endcase end
else if(coin_5) //投入5元 begin
case(coinl) //coinl是投入总额的个位数字 0: begin coinl=6;
coinh=coinh; // coinh是投入总额的十位数字 coin=coin+5; // coin是投入总额 end 1: begin
coinl=6; coinh=coinh; coin=coin+5; end 2:
begin
coinl=7; coinh=coinh; coin=coin+5; end 3: begin
coinl=8; coinh=coinh; coin=coin+5; end 4: begin
coinl=9;
coinh=coinh; coin=coin+5; end 5: begin coinl=0; coinh=coinh+1; coin=coin+5; end 6:
begin
coinl=1; coinh=coinh+1; coin=coin+5; end 7:
begin
coinl=2;
coinh=coinh+1; coin=coin+5; end
8: begin
coinl=3;
coinh=coinh+1; coin=coin+5; end 9: begin
coinl=4; coinh=coinh+1; coin=coin+5; end endcase end
else if(coin_10) //投入10元 begin
coinl=coinl; // coinl是投入总额的个位数字 coinh=coinh+1; // coinh是投入总额的十位数字 coin=coin+5'b01010; // coin是投入总额 end
else if(coin_20) //投入10元 begin
coinl=coinl; // coinl是投入总额的个位数字
coinh=coinh+4'b0010;;// coinh是投入总额的十位数字 coin=coin+5'b10100; // coin是投入总额 end end endmodule
经过编译后建立波形文件,波形仿真图如图所示:
在此波形仿真图中,将coin_1,coin_5,coin_10依次置了一个时钟周期的高电平作为输入,输出显示总额低位为6,高位为1,所投钱币总额为16,说明达到此钱币处理模块的预期功能。
2.3 余额计算模块
余额计算模块主要完成出票找零操作。通过所投钱币总额coin和应付总额cost计算找赎余额,然后用发光二极管点亮表示出票和找零。钱数不够票价的,退出所投钱币数。
余额计算模块如图所示:
1)输入
①rd:模块复位信号,将所有输出信号清零。 ②clk:模块的时钟信号。
③finish:用户使用的确定按键。此信号置为高电平后,开始判断是否出票,计算找赎余额。
④pri_in[3:0]:输入乘客所选的线路和票价,用来判断出票时具体出哪张票。
⑤cost_in[3:0],coin_in[4:0]:输入应付总额和所投钱币总额,用来判断是否出票,是否找赎,计算找赎余额。
2)输出
①act[3:0]:表示出票。车票共有4种,用4个发光二极管的点亮来表示具体出哪张票,若都不亮则表示不出票。
②act_1:表示找赎。若信号为‘1’,用1个发光二极管
的点亮表示需要找赎。
③resth[3:0]:表示找赎余额十位,restl[3:0]:表示找赎余额个位,信号输出到显示功能模块,在数码管显示找赎余额。
该余额计算模块的源程序如下:
module zhaoling(pri_in,cost_in,coin_in,finish,clk,rd, act,act_1,rest,restl,resth); input[3:0] pri_in,cost_in; input[4:0] coin_in; input clk,finish,rd;
output[3:0] act,restl,resth; output[4:0] rest; output act_1;
reg[3:0] act,restl,resth; reg[4:0] rest; reg act_1;
/*initial begin
act=4'b0000; act_1=0; rest=0; resth=0; restl=0; end*/
/*always@(!rd) //清零 begin
act=4'b0000; act_1=0; rest=0; resth=0; restl=0; end*/
always@(posedge clk or negedge rd) begin if(!rd)
begin
act=4'b0000; act_1=0; rest=0;
resth=0; restl=0; end
else if(finish) begin
if(coin_in==cost_in) //投币总额等于总票价 begin
act_1=0; rest=0; resth=0; restl=0;
if(pri_in==3)
act=4'b0001; //出3元票 else if(pri_in==4)
act=4'b0010; //出4元票 else if(pri_in==5)
act=4'b0100; //出5元票 else if(pri_in==6)
act=4'b1000; //出6元票 end
else if(coin_in>cost_in) //投币总额大于总票价 begin
act_1=1;
rest=coin_in-cost_in; // 余额总价
restl=rest; // 余额总价个位数字 resth=(rest-restl)/10; // 余额总价十位数字
if(pri_in==3) act=4'b0001; else if(pri_in==4) act=4'b0010; else if(pri_in==5) act=4'b0100; else if(pri_in==6) act=4'b1000; end
else if(coin_in begin act=4'b0000; //不出票 act_1=1; rest=coin_in; //退钱 end end end endmodule 经过编译后建立波形文件,波形仿真图如图所示: 在此波形仿真图中,输入选择,3元票,应付总额为6元,所投钱币总额为10元,在finish确定键按下后,输出有找赎信号,且找赎余额为4元,出第1种车票(即3元票);4元票,应付总额为4元,所投钱币为20元,在finish确定键按下后,输出找零信号,且找零余额为16元(高位为1,低位为6),出第二种车票(即4元票),由此说明达到余额计算模块的预期功能。 2.4 显示功能模块 显示功能模块主要完成显示乘客选的票价、票数、投入钱数及找赎余额。实验系统主板上,每次只能点亮一个数码管,如果显示这些数据,必须要用扫描的方式使得所需数码 管依次点亮,选择较高的扫描频率,利用人眼的视觉暂留效果,视觉上可让数码管一起点亮。 此自动售票系统共需要6个数码管显示,此显示功能模块可分为四个部分: 1 模6计数器(counter6):每个时钟上升沿,计数器计数一次,产生3位二进制码,对6个数码管进行扫描,且对数据选择器的6个数据依次进行选择输出。 模6计数器模块 1)输入clk2:计数器的时钟,每个时钟上升沿,计数器计数一次 2)输出out[2:0] 产生模为6信号000,001,010,011,100,101 此模6计数器源程序如下: module counter6(clk2,out); //产生模为6的信号000,001,010,011,100,101// input clk2; output[2:0] out; reg[2:0] out; /*initial begin out=0; end*/ always@(posedge clk2) begin if(out<5) out=out+1; else out=0; end endmodule 经过编译后建立波形文件,波形仿真图如图所示: 在此波形仿真图中,输入为时钟信号,输出为0~5的6进制数(即序列信号为:000,001,010,011,100,101),说明达到此模6计数器的预期功能 2 6选1数据选择器(select6):每次只能点亮一个数码管,所以根据模6计数器输入的数,选择一个数据作为一次输出。 6选1数据选择器 1)输入 in0[3:0],in1[3:0],in2[3:0],in3[3:0],in4[3:0],in5[3:0]:表示6个需要显示的6个数据,即票价,票数,所投总额十位,所投总额个位,找赎余额十位,找赎余额个位。 2)输入sel[2:0]:6进制计数器提供的计数序列,用来做数据选择器的选择条件。 3)输出 out[3:0]:6选1数据选择器的输出到译码器进行译码。 此数据选择器的源程序如下: module select6_1(out,in0,in1,in2,in3,in4,in5,sel); output[3:0] out; input[3:0] in0,in1,in2,in3,in4,in5; input[2:0] sel; reg[3:0] out; always@(in0 or in1 or in2 or in3 or in4 or in5 or sel) case(sel) 3'b000:out=in0; //显示票的单价 3'b001:out=in1; // 显示票的数量 3'b010:out=in2; //显示投币总价十位数字 3'b011:out=in3; //显示投币总价个位数字 3'b100:out=in4; //显示余额总价十位数字 3'b101:out=in5; //显示投币总价个位数字 default: out=4’b0000; endcase endmodule 此6选1数据选择器波形仿真图如图所示: 在此波形仿真图中,随着选择信号的sel[2:0]的变化,输出也对应着6个数据选择输出,说明达到此6选1数据选择器的预期功能 3 译码器(zixing):7段数码管显示,需将4位二进制数,译成7位二进制数据,使得数码管显示出想要的数字。考虑的是共阴极的7段数码管(不带小数点)。 译码器模块 1)输入din [3:0]:连接6选1模块输出端。 2)输出out[6:0]:经过译码器的译码后,将4位二进制译成可让数码管显示的7位二进制数 此译码器源程序如下: module zixing(din,out); input[3:0] din; output[6:0] out; reg[6:0] out; always@(din) case(din) 4'b0000:out=7'b0111111;//显示〃'0' 4'b0001:out=7'b0000110;//显示'1' 4'b0010:out=7'b1011011;//显示‘2‘ 4'b0011:out=7'b1001111;//显示'3' 4'b0100:out=7'b1100110;//显示'4' 4'b0101:out=7'b1101101;//显示'5' 4'b0110:out=7'b1111101;//显示'6' 4'b0111:out=7'b0000111;//显示'7' 4'b1000:out=7'b1111111;//显示'8' 4'b1001:out=7'b1101111;//显示'9' default:out=7'b0000000; endcase endmodule 经过编译后建立波形文件,波形仿真图如图所示: 4 数码管位选模块 数码管扫描的信号,用模6计数器提供的计数序列使数码管依次点亮。 1)输入din[2:0] 与模6计数器输出端相连。 2)输出 out[5:0] 依次点亮数码管。 源程序如下 module weixuan(din,out); // 6个不带小数点的共阴极数码管 // input[2:0] din; // 公共端是‘0’的数码管工作// output[5:0] out; reg[5:0] out; always@(din) case(din) 3'b000:out=6'b111110; 3'b001:out=6'b111101; 3'b010:out=6'b111011; 3'b011:out=6'b110111; 3'b100:out=6'b101111; 3'b101:out=6'b011111; default:out=6'b111111; endcase endmodule 波形图如下 综合顶层文件如下: 3 硬件实现 3.1 连线布局与下载 在各个模块都设计完毕并编译生成模块后,建立顶层文件图,进行连线布局。 地铁自动售票机系统的顶层文件图如图 连线布局好后,对其进行编译,然后锁定管脚,观察其试验结果。 其中,车票选择模块,钱币处理模块,余额计算模块共用同一个时钟信号clk,在试验板上采用频率为2Hz的时钟信号。显示功能模块的时钟信号clk_2采用实验板上频率为2048Hz的时钟信号。 在已经烧入程序的实验板上,各个按键均符合预期按键功能,7个发光二极管的亮灭符合设计的亮灭要求,6个数码管也全部点亮并显示符合系统要求的数据。因此此设计的地铁售票系统能够完成所有选票、投币、找零、显示的功能要求,达到硬件实现。 4.系统不足 此系统设计,余额计算模块中要求,在所投钱币总额不 足应付票价总额时,一分钟后退出所投钱币。而此设计中未能达到一分钟后退出所投钱币,而是在按下确定键finish后直接退出钱币。 5 系统改进方向及设计总结 1 系统改进方向 可以对此地铁自动售票系统进行改进和扩展,在此提出以下几点改进方向: 1)完善钱币不足一分钟后自动退出钱币的功能。 2)根据乘客提供的起点站和终点站,自动判定票价。 3)增加投币的币种,比如50元、100元等。 4)投币过程增加对钱币验证真伪的模块。 5)此系统的选择票价、选择票数、投币过程存在顺序问题,以后可以将系统改进,让这些过程可以任意颠倒。 2 设计总结 本文主要论述了采用自顶向下的模块化设计方法,基于FPGA使用Verilog语言设计制作一个地铁自动售票控制系统。在此设计过程中,也遇到诸多困难和技术问题,如编写硬件描述语言不能像软件一样,其中存在着时序逻辑。通过本次工程设计,了解到EDA技术、FPGA、Verilog语言等基础知识,及Modlesim和Quartue II软件的使用,能够正确掌握数字 系统的模块划分、并能自如应用硬件描述语言描述各模块功能,以实现系统设计。