版权声明:本文为博主原创文章,转载请注明作者和出处。
文章目录
前言
本文章是总结EDA设计与实践课程的成果,设计题目为出租车计价器
以下是本篇文章正文内容
一、系统功能及设计要求
1.系统功能
出租车启动和停驶由司机控制。启动后显示里程,用四位数字显示,精确到1公里;停止后显示金额,四位显示,格式为XXXX,精确到1元。
功能:
1、当行程小于基本里程时,显示起步价,基本里程设3公里,起步价设5元。
2、当行程大于基本里程时,每多行一公里,在起步价上加2元;不足一公里按一公里收费。
3、当出租车等待时,由司机按下等候键,每等待一分钟加1元,不足一分钟的按一分钟计算。
4、此处用脉冲信号模拟轮胎的转数,设每计一个脉冲汽车前进100米。
2.设计要求
系统设计一个频率为1Hz的基本脉冲,该脉冲用于等待计时和轮胎转数。
一个该脉冲表征1s;用于计轮胎转数时,计10个记为1公里。用于等待计时时,计60个记为1分钟。
设计拨动开关A 用于控制和表征模拟出租车的钥匙(插入钥匙和拔出钥匙)。
拨动开关B 用于控制和表征模拟客人的上下车行为(预备上车和即将下车)。
拨动开关C 用于控制和表征模拟出租车行驶状态(行驶或等待)。
一个四位七段数码管用于分时分状态表示里程数或总计价。
二、系统设计方案、Verilog源程序与仿真结果分析
本系统采用层次化、模块化的设计方法,设计顺序为自下向上。首先实现系统框图中的各子模块,然后由顶层模块调用各子模块来完成整个系统。
1.计数分频模块div
输入:基准时钟100MHz,频率信号CLK_100M,重置信号reset
输出:1Hz频率时钟信号CLK
module div(
input clk_100M,
input reset,
output reg clk
);
reg [31:0] count;
always@(posedge clk_100M , negedge reset)
begin
if(!reset)
begin
clk<=1'd0;
count=32'd0;
end
else if(count==32'd50_000000)
begin
count<=32'd0;
clk<=!clk;
end
else
count<=count+1'd1;
end
endmodule
clk_100M为主频,当reset为1时,div模块工作,此处为了仿真采取六分频,clk_100M触发6个周期,clk输出1个周期。
2.计程模块distancecount
输入:1HZ频率时钟信号CLK,模块使能信号work,计程开始信号start,计程重置信号reset
输出:16位二进制里程计数值distance,里程使能输出distance_enable
module distanceCount(
input clk,
input work,
input start,
input reset,
output reg [15:0] distance,
output reg distance_enable
);
always@(posedge clk or negedge reset)
begin
if(!reset)
begin
distance<=16'd0;
end
else if(start&&work)
begin
if(distance[3:0]==9)
begin
distance[3:0]<=4'd0;
if(distance[7:4]==9)
begin
distance[7:4]<=4'd0;
if(distance[11:8]==9)
begin
distance[11:8]<=4'd0;
if(distance[15:12]==9)
distance[15:12]<=4'd0;
else
distance[15:12]<=distance[15:12]+1'd1;
end
else
distance[11:8]<=distance[11:8]+1'd1;
end
else
distance[7:4]<=distance[7:4]+1'd1;
end
else
distance[3:0]<=distance[3:0]+1'd1;
end
end
//产生distance_enable信号
always@(posedge clk or negedge reset)
begin
if(!reset)
begin
distance_enable<=1'd0;
end
else
if(distance>=16'd2)
begin
distance_enable<=1'd1;
end
end
endmodule
当reset为1时,distancecount模块工作。当work为0时,车无顾客,不论start为0还是为1,即不论此时车停止还是行驶,distance里程均为0,distance_enable也为0;当work为1时,车有顾客,start为0时车停止,distance里程不增即为0,start为1时车行驶,distance里程增加;当distance大于3公里时,distance_enable为1,代表此时里程增加就要计费。
3.计时模块timecount
输入:1HZ频率时钟信号CLK,计时开始信号start,计时重置信号reset
输出:8位二进制计时秒输出s,8位二进制计时分输出m,计时使能输出time_enable
module timeCount(
input clk,
input reset,
input start,
output reg [7:0] s,
output reg [7:0] m,
output wire time_enable
);
always@(posedge clk or negedge reset)
begin
if(!reset)
begin
s<=8'd0;
m<=8'd0;
end
else if(!start)
begin
if(s[3:0]==9)
begin
s[3:0]<=4'd0;
if(s[7:4]==5)
begin
s[7:4]<=4'd0;
if(m[3:0]==9)
begin
m[3:0]<=4'd0;
if(m[7:4]==5)
m[7:4]<=4'd0;
else
m[7:4]<=m[7:4]+1'd1;
end
else
m[3:0]<=m[3:0]+1'd1;
end
else
s[7:4]<=s[7:4]+1'd1;
end
else
s[3:0]<=s[3:0]+1'd1;
end
end
assign time_enable=((m[7:0]>=8'd1)&&(s[7:0]==8'd0))?1'd1:1'd0;
endmodule
当reset为1时,timecount模块工作。Start为1时,不计算等待时间。当start为0时,计算等待时间。每过一秒,s增加1,当s计到60时清零,m进1,同时time_enable产生一个脉冲,代表一分钟增一次等待费用。
4.控制模块control
输入:控制开始信号start,计程使能信号distance_enable,计时使能信号time_enable
输出:选择脉冲信号select_clk
module control(
input start,
input distance_enable,
input time_enable,
output wire select_clk
);
assign select_clk=start?distance_enable:time_enable;
endmodule
当start为0时,select_clk的值为time_enable的值;当start为1时,select_clk的值为distance_enable的值。
5.计费模块fee
输入:计费工作信号work,计费使能信号start,选择脉冲信号select_clk,计费重置信号reset,1HZ频率时钟工作信号CLK
输出:16位二进制费用输出fee
module fee(
input work,
input start,
input select_clk,
input reset,
input clk,
output reg [15:0] fee
);
reg [3:0]cnt=0;
always@(posedge clk or negedge reset or negedge work)
begin
if(!reset&&!work)
fee<=16'd5;
else if(select_clk==1'd1&&start==0&&work==1)
begin
if(fee[3:0]==4'd9)
begin
fee[3:0]<=4'd0;
if(fee[7:4]==4'd9)
begin
fee[7:4]<=4'd0;
if(fee[11:8]==4'd9)
begin
fee[11:8]<=4'd0;
if(fee[15:12]==4'd9)
fee[15:12]<=4'd0;
else
fee[15:12]<=fee[15:12]+1'd1;
end
else
fee[11:8]<=fee[11:8]+1'd1;
end
else
fee[7:4]<=fee[7:4]+1'd1;
end
else
fee[3:0]<=fee[3:0]+1'd1;
end
else if(select_clk==1'd1&&start==1&&work===1)
begin
cnt<=cnt+1;
if(cnt==11)
begin
cnt<=0;
repeat(2)
begin
if(fee[3:0]==4'd9)
begin
fee[3:0]=4'd0;
if(fee[7:4]==4'd9)
begin
fee[7:4]=4'd0;
if(fee[11:8]==4'd9)
begin
fee[11:8]=4'd0;
if(fee[15:12]==4'd9)
fee[15:12]=4'd0;
else
fee[15:12]=fee[15:12]+1'd1;
end
else
fee[11:8]=fee[11:8]+1'd1;
end
else
fee[7:4]=fee[7:4]+1'd1;
end
else
fee[3:0]=fee[3:0]+1'd1;
end
end
end
end
endmodule
当reset为1时,fee模块工作。Select_clk为1代表计费使能。work为0时无顾客,费用一直为起步价5,当work为1时,有顾客开始计价。当start为0时,车停止,代表此时等待计费,每等一分钟,费用加1;当start为1时,车行驶,代表此时行驶计费,每行驶1公里,费用加2。
6.数码管显像模块smg_ip_model
输入:1HZ频率时钟工作信号CLK,显像工作信号work,显像使能信号start,显像重置信号reset,16位二进制费用输入fee,16位二进制里程输入dis
输出:4位数码管位选信号sm_wei,8位数码管段选信号sm_duan
module smg_ip_model(
input clk,
input work,
input start,
input reset,
input [15:0] fee,
input [15:0] dis,
output [3:0] sm_wei,
output [7:0] sm_duan
);
//分频
integer clk_cnt;
reg clk_400Hz;
always@(posedge clk, negedge reset)
begin
if(!reset)
begin
clk_400Hz<=1'd0;
clk_cnt=32'd0;
end
else if(clk_cnt==32'd1000)
begin
clk_cnt<=32'b0;
clk_400Hz<=!clk_400Hz;
end
else
clk_cnt<=clk_cnt+1'd1;
//位控制
end
reg [3:0] wei_ctrl = 4'b1110;
always@(posedge clk_400Hz)
wei_ctrl<={wei_ctrl[2:0],wei_ctrl[3]};
//段控制
reg [3:0] duan_ctrl;
always@(wei_ctrl)
begin
if(work)
case(wei_ctrl)
4'b1110:duan_ctrl=dis[3:0];
4'b1101:duan_ctrl=dis[7:4];
4'b1011:duan_ctrl=dis[11:8];
4'b0111:duan_ctrl=dis[15:12];
default:duan_ctrl=4'hf;
endcase
else if(!work)
case(wei_ctrl)
4'b1110:duan_ctrl=fee[3:0];
4'b1101:duan_ctrl=fee[7:4];
4'b1011:duan_ctrl=fee[11:8];
4'b0111:duan_ctrl=fee[15:12];
default:duan_ctrl=4'hf;
endcase
end
//解码
reg [7:0]duan;
always@(duan_ctrl)
case(duan_ctrl)
4'h0:duan=8'b1100_0000;
4'h1:duan=8'b1111_1001;
4'h2:duan=8'b1010_0100;
4'h3:duan=8'b1011_0000;
4'h4:duan=8'b1001_1001;
4'h5:duan=8'b1001_0010;
4'h6:duan=8'b1000_0010;
4'h7:duan=8'b1111_1000;
4'h8:duan=8'b1000_0000;
4'h9:duan=8'b1001_0000;
default:duan=8'b1100_0000;
endcase
assign sm_wei=wei_ctrl;
assign sm_duan=duan;
endmodule
当reset为1时,smg_ip_model模块工作。sm_wei在e、d、b、7间循环,即是在1110、1101、1011、0111间循环,循环选中数码管。work为1时,数码管显示里程数,dis为7,即为f8,而且显示在e选中的个位数码管上,其他位的数码管均显示0,即为c0。
7.顶层模块taximeter
输入:100MHZ频率时钟工作信号CLK_100M,模块复位信号reset,模块工作信号start,模块使能信号work
输出:4位数码管位选信号sm_wei,8位数码管段选信号sm_duan
module taximeter(clk_100M, reset,start,sm_wei,sm_duan,work);
input clk_100M,reset,start,work;
output [3:0] sm_wei;
output [7:0] sm_duan;
wire [15:0]distance;
wire [7:0] s;
wire [7:0] m;
wire [15:0] fee;
wire clk;
wire distance_enable;
wire time_enable;
wire select_clk;
reg clk_car;
reg [31:0] count;
always@(posedge clk , negedge reset)
begin
if(!reset)
begin
clk_car<=1'd0;
count=32'd0;
end
else if(count==32'd5)
begin
count<=32'd0;
clk_car<=!clk_car;
end
else
count<=count+1'd1;
end
div u0(.clk_100M(clk_100M),.clk(clk),.reset(reset));
distanceCount u2(.work(work),.clk(clk_car),.start(start),.reset(reset),.distance(distance),.distance_enable(distance_enable));
timeCount u4(.clk(clk),.reset(reset),.start(start),.s(s),.m(m), .time_enable(time_enable));
control u3(.start(start),.distance_enable(distance_enable),.time_enable(time_enable),.select_clk(select_clk));
fee u5(.work(work),.start(start),.reset(reset),.fee(fee),.select_clk(select_clk),.clk(clk));
smg_ip_model u6(.work(work),.start(start),.fee(fee),.reset(reset),.clk(clk_100M),.dis(distance),.sm_wei(sm_wei),.sm_duan(sm_duan));
endmodule
当reset为1时,taximeter模块工作。work为0时,无顾客,distance里程、fee费用一直为0。work为1时,有顾客,当start为1是,汽车行驶,distance里程加1,费用为起步价5,当distance大于3时,每公里2元。当start为0时,汽车停止行驶,开始等待计费,每等待1分钟,费用加1元,此时distance不变化。最后work为0,顾客下车,distance里程和fee费用都不再变化。
三、约束与综合
1.原理图
2.引脚配置图
W7,W6,U8,V8,U5,V5,U7,V7:八段数码管显示0-7
W4,V4,U4,U2:四个片选信号
W5:clk时钟
reset:车钥匙,1为启动汽车
start:油门,1汽车行驶,0汽车停止
work:代表顾客,1代表接客,0代表接待结束
四、系统硬件测试
启动油门,显示起步价5元。
顾客上车,汽车行驶,里程开始增加。
若此时下车,费用为起步价5元。
行驶至5公里时,价格为9元。
当汽车停止行驶,每等待1分钟,价格加1,顾客下车显示价格。
总结
以上就是本文章所有内容,详细总结了出租车计价器设计的全过程。
版权声明:本文为博主原创文章,转载请注明作者和出处。