基于EP3C40F780C8 FPGA 的出租车计价器

基于EP3C40F780C8 verilog语言 FPGA 的出租车计价器

本次出租车计费系统设计最终具有以下功能:
分辨率为1s的误时系统,1km里程的路程模块,同时将费用通过计算显示在数码管上面可以实现,路程和时间同时计费,以及含有两个按键输入,用来判断车辆是否在行驶过程中,以及是否开始计费,计费模块每1km,往上加1.3元,每1.5min,往上加1.5元。同时,用户可以从数码管看到费用,里程等信息。数码管的前两位是里程信息,后两位是时间信息,最后四位显示的则是费用信息。费用信息是通过一个500hz的动态数码管显示的。

一、系统模块

1.时钟分频模块

代码如下(示例):

module div_clk(clk,fs,clko);

input  				clk;	//输入系统时钟频率clk=50M
input	wire[31:0]	fs;
output	reg			clko;	//输出时钟clko 

parameter	N=25_000_000;	//注意N取值是系统时钟的二分频
reg[31:0]	Add;

always@(posedge clk) 
	begin 
		if(Add  < N/fs) 
			Add = Add + 1;		
		else 
			begin 		//满足累加器溢出条件
				Add = 0;
				clko = !clko;	
			end
	end
	
endmodule				//这里的分频fs值为多少,则分多少频率,但是有范围1—25000000

2.时间模块

代码如下:

module timewait (clk,reset,pluse_flag,min,time_enable);//clk为1HZ脉冲60个脉冲为1分钟

input clk;
input reset;
input pluse_flag;
output [7:0] min;	//输出的分
output time_enable;//输出的控制计费的信号

reg [7:0] min;
reg [7:0]cnt;

always@(posedge clk or negedge reset)//异步复位
	begin
		if(!reset)//低电平有效
			begin//复位
				min<=8'H00;
			end
		else if	(pluse_flag ==1'b1)      
			begin
				if(cnt>8'd59)//用于确定一分钟的分辨率 
					begin 
						cnt=0;
							if(min[3:0]==4'B1001)//分的低四位是9
								begin
									min[3:0]<=4'B0000;//清零
										if(min[7:4]==4'B0101)//分的高四位是5
											min[7:4]<=4'B0000;//清零
										else 
											min[7:4]<=min[7:4]+4'B0001;//分高四位非5加1
								end
							else 
								min[3:0]<=min[3:0]+4'B0001;//分的低四位不是9加一
					end
				else
					begin
						cnt=cnt+1'b1; 
					end
			end
	end
			  
assign time_enable=((min[7:0]>8'b0000_0010)?1'b1:1'b0) ;//标志位为1代表时间超过两分钟,开始计费

endmodule

由于出租车在行驶的过程中,会出现等候乘客、以及等候红绿灯的情况,这种情况仍然需要成本,按照设计要求超过两分钟,每分钟计费1.5元。clk为输入1hz信号,reset为复位按键,pluse_flag为选择等候时间计费信号,min为分的两个数据,time_enable是时间到达2分钟的标志。对于时间模块的操作则是每当来一个时钟脉冲,就开始判断pluse_flag是否为1,若为1则说明,系统开始停车,开始采用时间计费,同时,time_enable用来存储时间min是否超过2的标志位。

3. 里程模块

代码如下:

module distance (wheel,start_flag,reset, distance_enable,distance);//端口的定义

input wheel,start_flag,reset;
output distance_enable;
output [7:0]distance;

reg [7:0]distance;
reg [8:0]cnt; 

always @( posedge wheel or negedge reset)//车轮脉冲和异步复位配合按键决定是否开始计算里程
	begin
		if(!reset)//低电平复位
			begin
				distance<=8'H00;
			end
		else if(start_flag==1'b1)
			begin 
				if(cnt>9'd500)//用于确定distance分辨率 
					begin 
						cnt=0;
							if(distance[3:0]==4'B1001)//判断distance的低四位计到了9没有
								begin
									distance[3:0]<=4'B0000;//计到9清零
										if(distance[7:4]==4'B1001)//判断distance的高四位计到了9没有
											distance[7:4]<=4'B0000;//计到9清零
										else  
											distance[7:4]<= distance[7:4]+4'B0001;//distance的高四位没有计到9的时候加一
								end   
							else 
									distance[3:0]<=distance[3:0]+4'B0001;//distance的低四位没有计到9的时候加一
					end				 
				else
					begin 
						cnt=cnt+1'b1; 
					end
			end         
	end   
 
assign distance_enable=( distance [7:0]>8'b0000_0011)?1'b1:1'b0;//标志位为1代表里程超过三公里,开始按照第二种方案计费    
	
endmodule

由于硬件实物的板子内存有限,乘除运算会占用大量内存,因此本设计假设车轮20m给一个脉冲信号wheel,于是500个脉冲是1km,在3km之内是起步价,当公里数超过3km之后,按照1km收取1.3元的计算。本模块中cnt在1hz的触发下计数,1hz加一次,当加满500次时,distance加1,实现行程加1km,行程超过3km以上,1km收取1.3元。wheel为车轮脉冲信号,start_flag是开始整体计费模块,reset为复位, distance是输出的行程,distance_enable是三公里到达的标志。

4.费用模块

费用模块在本次设计中其实是分为三个模块的,首先介绍的是时间费用模块:时间费用模块便是根据时间模块的输出量time_enable和clk脉冲信号进行计算的,先由系统判断是否是误时计费状态,如果是,那就对feepay_time进行自加15操作,来对应实际操作中的每分钟15元。时间费用模块框图如u5所示,与时间费用模块类似的是里程费用模块,里程模块框图如u4所示:-图
在这里插入图片描述
代码如下:

module feepay_time ( reset,fee_time, clk,pluse_flag, time_enable);//时间计费模块1hz脉冲,60个为一分钟
input reset;
input clk;
input time_enable;
input pluse_flag;
output[14:0] fee_time; 
reg [14:0] fee_time;
reg [5:0] cnt;

always@(posedge clk or negedge reset)
	begin
		if(!reset)
			fee_time<=0;
		else if (cnt >= 60) 
			begin 
				cnt<=0;
					if ( time_enable>=1 && pluse_flag )
						begin
							if( fee_time>=9999 )
								begin
									fee_time<=0;
								end
							else
								fee_time<=fee_time+15;
						end
					else 
						fee_time<=fee_time;
			end
				else
					cnt=cnt+1'b1;
end

endmodule //结束时间计费模块

///
module feepay ( reset,fee, wheel, distance_enable,pluse_flag);//里程费用模块
input reset;
input wheel;
input distance_enable;
input pluse_flag;
output[14:0] fee; 
reg [14:0] fee;
reg [8:0] cnt;

always@(posedge wheel or negedge reset)
	begin
		if(!reset)
			fee<= 0;
		else if (cnt >= 500) //38
			begin 
				cnt=0;
					if ( distance_enable==1 && pluse_flag ==0 )
						begin
							if ( fee >= 9999 )
								begin
									fee <= 0;
								end
							else
								fee<=fee+13;
						end
					else 
						fee<= fee;
			 end
				else
					cnt=cnt+1'b1;
	end

endmodule //里程费用模块结束
/

module fee(start_flag,clk, reset,fee,fee_time,fee_a,fee_b,fee_c,fee_d);//整体费用模块端口的定义

input clk,reset,start_flag;
input [14:0]fee;
input [14:0]fee_time;

output [3:0]fee_a;
output [3:0]fee_b;
output [3:0]fee_c;
output [3:0]fee_d;
reg[3:0] fee_a;
reg[3:0] fee_b;
reg[3:0] fee_c;
reg[3:0] fee_d;

reg[14:0] fee_deal;

always@(posedge clk or negedge reset) 
	begin 
		if(!reset)
			begin
				fee_a=0;
				fee_b=0;
				fee_c=0;
				fee_d=0;
			end
		else if(start_flag==1) 
			begin
				fee_deal=fee+fee_time+50;
				fee_a[3:0]=fee_deal/1000;
				fee_b[3:0]=(fee_deal-1000*fee_a)/100;
				fee_c[3:0]=(fee_deal-1000*fee_a-100*fee_b)/10;
				fee_d[3:0]=fee_deal%10;
			end
				else 
					begin 
						fee_a[3:0]<= fee_a[3:0];
						fee_b[3:0]<= fee_b[3:0];
						fee_c[3:0]<= fee_c[3:0];
						fee_d[3:0]<= fee_d[3:0];
					end
	end
endmodule

5.显示模块

代码如下:

module  scan_led(clk,DA,DB,DC,DD,DE,DF,DG,DH,a,b,c,d,e,f,g,p,scan);  
input	clk;//数码管扫描时钟 共阴极
input	[3:0]	DA,DB,DC,DD,DE,DF,DG,DH;
output	a,b,c,d,e,f,g,p;
output	reg[2:0]	scan;

reg [7:0]sel;
reg [4:0]num;

always@(posedge clk)
	begin
	scan<=scan+1'b1;
	case(scan) //3-8译码器 和 数据选择器
		0: begin  num=DB; end
		1: begin  num=DC; end
		2: begin  num=DD; end
		3: begin  num=DE; end
		4: begin  num=DF; end
		5: begin  num=DG+10; end//要加小数点位
		6: begin  num=DH; end
		7: begin  num=DA; end
	endcase
	end

assign  {a,b,c,d,e,f,g,p} =	//字符译码器
	(num ==0)?  8'b11111100:		//"0"
	(num ==1)?  8'b01100000:		//"1"
	(num ==2)?  8'b11011010:		//"2"
	(num ==3)?  8'b11110010:		//"3"
	(num ==4)?  8'b01100110:		//"4"
	(num ==5)?  8'b10110110:		//"5"
	(num ==6)?  8'b10111110:		//"6"
	(num ==7)?  8'b11100000:		//"7"
	(num ==8)?  8'b11111110:		//"8"
	(num ==9)?  8'b11110110:		//"9"
	(num ==10)? 8'b11111101:		//"0."
	(num ==11)? 8'b01100001:		//"1."
	(num ==12)? 8'b11011011:		//"2."
	(num ==13)? 8'b11110011:		//"3."
	(num ==14)? 8'b01100111:		//"4."
	(num ==15)?  8'b10110111:		//"5."
	(num ==16)?  8'b10111111:		//"6."
	(num ==17)?  8'b11100001:		//"7."
	(num ==18)?  8'b11111111:		//"8."
	(num ==19)?  8'b11110111:		//"9."
	8'b00000000;		//"-";	

endmodule

显示方面,由于测试的开发板内部集成有3-8译码器,所以在输出的时候只写了一个三位的scan。

二、顶层模块以及实测结果

顶层模块代码如下所示:

module top(clk_50M, reset,start_flag,a,b,c,d,e,f,g,p,scan,wheel,pluse_flag);   // 端口的定义

input clk_50M,reset,start_flag,pluse_flag,wheel;//总的时钟信号,复位信号,开始信号,等待信号
output [2:0] scan;//数码管的输出
output a,b,c,d,e,f,g,p;

wire [7:0]distance;//公里
wire [7:0] min;//分

wire [14:0] fee;
wire [14:0] fee_time;
wire [3:0] fee_a;
wire [3:0] fee_b;
wire [3:0] fee_c;
wire [3:0] fee_d;

wire distance_enable;    //公里控制费用的信号
wire time_enable;        //时间控制费用的信号
wire time_hz,led_hz;
wire DA,DB,DC,DD,DE,DF,DG,DH;

div_clk     u0(.clk(clk_50M),.fs(60),.clko(time_hz));//调用计数分频模块 1Hz
div_clk     u1(.clk(clk_50M),.fs(350),.clko(led_hz));//调用数码管分频模块 350Hz

distance	   u2(.wheel(wheel),.start_flag(start_flag),.reset(reset),.distance_enable(distance_enable),.distance(distance));//调用里程模块
				   
timewait    u3(.clk(time_hz),.reset(reset),.pluse_flag(pluse_flag),.min(min), .time_enable(time_enable));//调用计时模块

feepay     u4(.reset(reset),.fee(fee),.wheel(wheel),.distance_enable(distance_enable),.pluse_flag(pluse_flag));

feepay_time u5(.reset(reset),.fee_time(fee_time),.pluse_flag(pluse_flag),.clk(time_hz),.time_enable(time_enable));
				   
fee        u6(.start_flag(start_flag),.clk(clk_50M),.reset(reset),.fee(fee),.fee_time(fee_time),.fee_a(fee_a),.fee_b(fee_b),.fee_c(fee_c),.fee_d(fee_d));
				   
scan_led    u7
(
	.clk(led_hz),  
	.DA(distance[7:4]),  .DB(distance[3:0]),  .DC(min[7:4]), .DD(min[3:0]), .DE(fee_a), .DF(fee_b), .DG(fee_c), .DH(fee_d), 
	.a(a), .b(b), .c(c), .d(d), .e(e), .f(f), .g(g), .p(p), .scan(scan)
);  

endmodule

顶层模块主要是对系统模块的调用

在这里插入图片描述
上图是整体的RTL级原理图
下图在实测结果中总费用是5+31.3+61.5=17.9元,所以实验结果也符合预期。
在这里插入图片描述

主要参考文献
(1)谭会生、瞿遂春,《EDA技术综合应用实例与分析》,西安电子科技大学出版社,2004
(2)曹昕燕、周凤臣等,《EDA技术实验与课程设计》,清华大学出版社,2006

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

renleni

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值