产品功能
本次设计的出租车计价器所实现的功能如下:
1、能够实现计费的功能
费用是按行驶的里程进行计算,设出租车的起价为6元,当里程小于3km时,按起价计算费用;当里程大于3km时每km按1元计费。
2、能够实现显示的功能
1)左边四个数码管显示里程:用四位数字显示,显示方式为“XXXX”,单位为km。里程范围为0~999.9km,里程分辨率为0.1km。
2)右边四个数码管显示费用:用四位数字显示,显示方式为“XXXX”,单价为元。计价范围为0~999.9元,费用分辨率为0.1元。
系统框图
设计步骤
开发板提供的时钟信号CLK频率为1000Hz,应该设计一分频器得到1Hz的时钟信号作为里程计数脉冲,每一个脉冲表示0.1km。数码管显示采用动态扫描的方式。
设计思路
首先设计一个分频模块,将输入的1000HZ时钟分频为1HZ,用于驱动里程计数。然后定义一个内部变量flag,只要S1按下,flag=1,S2按下,flag=0。然后系统根据flag的值进行计数。如果flag为1,那么里程和费用就正常计数;如果flag为0,那么里程和费用就不计数,显示总的里程和费用不动。如果检测到S3被按下,那么费用和里程直接清0。显示部分直接调用现成的显示模块,将要显示的数据传过去即可。关于数码管动态显示的内容,具体参见我的另一篇博客:
https://blog.csdn.net/guangali/article/details/130754726?spm=1001.2014.3001.5501
代码
module taxi(
input clk,
input reset,
input S1,
input S2,
input S3,
output [2:0] sel, //数码管位选
output [7:0] sel_seg //数码管段选
);
parameter HZ_NUM=10'd1000; //得到1HZ信号的分频系数
//parameter HZ_NUM=10'd2; //仿真使用
reg [9:0] cnt;
reg clk_hz; //分频后得到的1HZ信号
reg [13:0] miles; //用于保存公里数
reg [13:0] cost; //用于保存路费
reg flag; //标志位 1-->系统运作 0-->系统暂停
reg i;
wire [31:0] data_show; //要送到数码管显示的数据
wire [3:0] data0 ; // 个位数
wire [3:0] data1 ; // 十位数
wire [3:0] data2 ; // 百位数
wire [3:0] data3 ; // 千位数
wire [3:0] data4 ; // 万位数
wire [3:0] data5 ; // 十万位数
wire [3:0] data6 ; // 百万位数
wire [3:0] data7 ; // 千万位数
always @(posedge clk or negedge reset) begin
if(!reset)
cnt<=10'd0;
else if(cnt==HZ_NUM/2-1)
begin
clk_hz<=~clk_hz;
cnt<=10'd0;
end
else
cnt<=cnt+10'd1;
end
always @(posedge clk or negedge reset) begin //根据按键控制标志位
if(!reset)
flag<=1'b0;
else if(S1==1'b0)
flag<=1'b1;
else if(S2==1'b0)
flag<=1'b0;
else
flag<=flag;
end
//里程数的控制
always @(posedge clk_hz or negedge reset) begin
if(!reset)
begin
miles<=14'd1234; //复位时显示学号
i<=1'b1;
end
else if(S3==1'b0) //按下S3 清0
miles<=14'd0;
else if(flag==1'b1)
begin
if(i==1'b1) //这里用变量i 来控制miles从学号跳变到0
begin
miles<=14'd0;
i<=1'b0;
end
else
miles<=miles+14'd1;
end
else
miles<=miles;
end
//路费控制模块
always @(posedge clk or negedge reset)begin
if(!reset)
cost<=14'd5678; //上电显示学号
else if(S3==1'b0) //按下S3 清0
cost<=14'd0;
else if(flag==1'b1)
begin
if((miles/10)<14'd3) //除以10 是因为 miles的单位为0.1km
cost<=14'd60; //cost的 单位 是0.1元
else
cost<=14'd60+(miles-30);
end
else
cost<=cost;
end
assign data7=miles/1000;
assign data6=(miles/100)%10;
assign data5=(miles/10)%10;
assign data4=miles%10;
assign data3=cost/1000;
assign data2=(cost/100)%10;
assign data1=(cost/10)%10;
assign data0=cost%10;
assign data_show={data7,data6,data5,data4,data3,data2,data1,data0};
//例化数码管模块
segshow segshow_u(
.sys_clk (clk),
.sys_rest (reset),
.data (data_show),
.sel (sel),
.seg_led (sel_seg)
);
endmodule
本次设计的关键在于上电显示学号。我采用的方案是将8位数字的学号按4位数为一组,分别给mile 和 cost显示。那么这样就会带来一个问题,上电后,再按下S1时,mile 和 cost都不是从0开始计数的,所以就要想办法让mile从学号跳变到0。所以我用了一个变量i,i的巧妙使用可以实现这种效果。