设计流程图
/*信号说明:
clk:系统时钟
rst_n:复位(开始)信号;
finish:结束信号
mile_int:里程整数部分,最大为2047,单位km
mile_dec:里程小数部分,逢九进一
tmp_100price:路费的100倍
sel_seg:数码管位选
seg_led:数码管段选
flag_dec:进位信号
div_cnt:分频计数器
dri_clk:分频后的驱动时钟
display_num:显示数字
data 10-6表示里程(1位小数),5-0表示费用(2位小数)
2km内为起步价7元,超过2km收1.8元/km
*/
module taxi(
input clk,
input rst_n,
input finish,
output reg [10:0]mile_int,//计数行驶路程极限为2^11-1+1=2048km
output reg [3:0]mile_dec,
output reg[17:0]tmp_100price,
output reg [10:0]sel_seg,//数码管位选,前5位是路程,后6位是价格,精确到2位小数
output reg [7:0]seg_led//数码管段选
);
parameter MAX_NUM=2'd2;
parameter CLK_DIV=4'd2;
//车速为36km/h
//为使计费精确到两位小数,1个脉冲10s计数100m
//假设系统时钟5MHz
reg [23:0]sec_cnt;//10秒计数,dri_clk下sec_cnt计满5M次为10s
reg flag_dec;
//分频模块
reg [3:0]div_cnt;//分频计数
reg dri_clk;
wire [3:0]data10;//路程千位
wire [3:0]data9;//路程百位
wire [3:0]data8;//路程十位
wire [3:0]data7;//路程个位
wire [3:0]data6;//路程后1位小数
wire [3:0]data5;//价格千元
wire [3:0]data4;//价格百元
wire [3:0]data3;//价格十元
wire [3:0]data2;//价格元
wire [3:0]data1;//价格角
wire [3:0]data0;//价格分
assign data10=mile_int/10'd1000%4'd10;
assign data9=mile_int/10'd100%4'd10;
assign data8=mile_int/4'd10%4'd10;
assign data7=mile_int%4'd10;
assign data6=mile_dec;
assign data5=tmp_100price/17'd100000%4'd10;
assign data4=tmp_100price/15'd10000%4'd10;
assign data3=tmp_100price/10'd1000%4'd10;
assign data2=tmp_100price/10'd100%4'd10;
assign data1=tmp_100price/4'd10%4'd10;
assign data0=tmp_100price%4'd10;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
div_cnt<=1'b0;
dri_clk<=1'b0;
end
else if(div_cnt==CLK_DIV/2-1)begin
dri_clk<=~dri_clk;
div_cnt<=4'd0;
end
else begin
div_cnt<=div_cnt+1'b1;
dri_clk<=dri_clk;
end
end
//里程小数部分模块,mile_dec计一次为0.1km,满10进1
always @(posedge dri_clk or negedge rst_n or posedge finish)begin
if(!rst_n)begin
sec_cnt<=1'b0;//10s钟计数
mile_dec<=4'd0;
flag_dec<=1'b0;
end
else if(finish==0)begin
if(sec_cnt==24'd500)begin
if(mile_dec==4'd9)begin
sec_cnt<=24'd0;
mile_dec<=4'd0;
flag_dec<=1'b1;
end
else begin
flag_dec<=1'b0;
sec_cnt<=24'd0;
mile_dec<=mile_dec+1'b1;
end
end
else begin
flag_dec<=1'b0;
mile_dec<=mile_dec;
sec_cnt<=sec_cnt+1'b1;
end
end
else begin
sec_cnt<=sec_cnt;
end
end
//里程整数部分模块
always @(posedge dri_clk or negedge rst_n)begin
if(!rst_n)begin
mile_int<=8'd0;
end
else if(flag_dec)begin
mile_int<=mile_int+1'b1;
end
else
mile_int<=mile_int;
end
parameter sprice=2'd2;//起步价
//计费模块
//reg[17:0]tmp_price;
always@(posedge dri_clk or negedge rst_n or posedge finish)begin
if(!rst_n)begin
tmp_100price<=6'd0;
end
else if(finish==0)
if(mile_int<10'd2)begin
tmp_100price<=18'd700;
end
else tmp_100price<=(mile_int*4'd10-5'd20+mile_dec)*5'd18+18'd700;
else tmp_100price<=tmp_100price;
end
//数码管显示模块
//reg [10:0]sel,//数码管位选,前5位是路程,后6位是价格,精确到2位小数
//reg [7:0]seg_led//数码管段选
reg flag;
reg [3:0]cnt0;//位选计数
reg [13:0]cnt1;
reg [3:0]display_num;
always @(posedge dri_clk or negedge rst_n)begin//控制刷新速度
if(!rst_n)begin
cnt1<=14'd0;
flag<=1'b0;
end
else if(cnt1==MAX_NUM-1)begin
cnt1<=14'd0;
flag<=1'b1;
end
else begin
flag<=1'b0;
cnt1<=cnt1+1'b1;
end
end
always @(posedge dri_clk or negedge rst_n)begin//控制位选
if(!rst_n)begin
cnt0<=4'd0;
end
else if(flag)begin
if(cnt0==4'd10)
cnt0<=4'd0;
else cnt0<=cnt0+1'b1;
end
else cnt0<=cnt0;
end
always @(posedge clk or negedge rst_n)begin//低电平数码管选通
if(!rst_n)begin
sel_seg<=11'b11111111111;
display_num<=4'd0;
end
else begin
case(cnt0)
4'd0:begin
sel_seg<=11'b11111111110;
display_num<=data0;
end
4'd1:begin
sel_seg<=11'b11111111101;
display_num<=data1;
end
4'd2:begin
sel_seg<=11'b11111111011;
display_num<=data2;
end
4'd3:begin
sel_seg<=11'b11111110111;
display_num<=data3;
end
4'd4:begin
sel_seg<=11'b11111101111;
display_num<=data4;
end
4'd5:begin
sel_seg<=11'b11111011111;
display_num<=data5;
end
4'd6:begin
sel_seg<=11'b11110111111;
display_num<=data6;
end
4'd7:begin
sel_seg<=11'b11101111111;
display_num<=data7;
end
4'd8:begin
sel_seg<=11'b11011111111;
display_num<=data8;
end
4'd9:begin
sel_seg<=11'b10111111111;
display_num<=data9;
end
4'd10:begin
sel_seg<=11'b01111111111;
display_num<=data10;
end
default:begin
sel_seg<=11'b11111111111;
display_num<=4'd0;
end
endcase
end
end
//数码管显示
always@(posedge dri_clk or negedge rst_n)begin
if(!rst_n)
seg_led<=8'd11111111;//数码管段选低电平有效
else begin
case(display_num)
4'd0:begin
if(cnt0==4'd3||cnt0==4'd8)
seg_led<=8'b01000000;
else seg_led<=8'b11000000;
end
4'd1:begin
if(cnt0==4'd3||cnt0==4'd8) seg_led<=8'b01111001;
else seg_led<=8'b11111001;
end
4'd2:begin
if(cnt0==4'd3||cnt0==4'd8)
seg_led<=8'b00100100;
else seg_led<=8'b10100100;
end
4'd3:begin
if(cnt0==4'd3||cnt0==4'd8)
seg_led<=8'b00110000;
else seg_led<=8'b10110000;
end
4'd4:begin
if(cnt0==4'd3||cnt0==4'd8)
seg_led<=8'b00011001;
else seg_led<=8'b10011001;
end
4'd5:begin
if(cnt0==4'd3||cnt0==4'd8)
seg_led<=8'b00010010;
else
seg_led<=8'b10010010;
end
4'd6:begin
if(cnt0==4'd3||cnt0==4'd8)
seg_led<=8'b00000010;
else seg_led<=8'b10000010;
end
4'd7:begin
if(cnt0==4'd3||cnt0==4'd8)
seg_led<=8'b01111000;
else seg_led<=8'b11111000;
end
4'd8:begin
if(cnt0==4'd3||cnt0==4'd8)
seg_led<=8'b00000000;
else seg_led<=8'b10000000;
end
4'd9:begin
if(cnt0==4'd3||cnt0==4'd8)
seg_led<=8'b00010000;
else seg_led<=8'b10010000;
end
default:seg_led<=8'b1111111;
endcase
end
end
endmodule
复位信号开始为0,拉高后开始计费,可见当路程小于2km时,收费为起步价7元,超过2km后按1.8元/km收费。如图行驶了2.1km,收费7.18元,数码管刷到第1位(路费的角位),数字为1,符合预期。
路程为14.9km,路费此时为30.22元(7+12.9*1.8),此时位选cnt0=1 ,data1为路费(角)为2,数码管刷新到第1位,显示数字为2,符合预期。
此时finish信号被拉高,mile_int,mile_dec和tmp_100price一直保持不变,全程行驶了24.9km,路费为7+22.9*1.8=48.22符合要求,此时位选是第9位(路程百位),数码管显示为0,符合预期。