├── sim ├── README.md ├── bcd_adder_tb.v ├── wait_count_tb.v ├── bcd_adder_4_tb.v ├── freq_div_tb.v ├── distance_fare_tb.v ├── wait_fare_tb.v ├── fare_total_tb.v ├── seg_disp_tb.v └── taxi_fare_tb.v ├── src ├── README.md ├── bcd_adder.v ├── bcd_seg_disp.v ├── wait_count.v ├── freq_div.v ├── wait_fare.v ├── bcd_adder_4.v ├── seg_disp.v ├── fare_total.v ├── taxi_fare.v └── distance_fare.v ├── README.md └── LICENSE /sim/README.md: -------------------------------------------------------------------------------- 1 | # 仿真文件存放 2 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # 源文件存放 2 | -------------------------------------------------------------------------------- /src/bcd_adder.v: -------------------------------------------------------------------------------- 1 | //一位BCD加法器 2 | //输入a,b两个加数和前位进位,输出和以及本位进位 3 | /* 4 | a -> 输入的加数a 5 | b -> 输入的加数b 6 | c_in -> 输入的前位进位 7 | 8 | sum -> 输出的和 9 | c_out -> 输出的本位进位 10 | */ 11 | module bcd_adder ( 12 | input wire [3:0] a, 13 | input wire [3:0] b, 14 | input wire c_in, 15 | 16 | output wire [3:0] sum, 17 | output wire c_out 18 | ); 19 | 20 | //计算ab两数之和 21 | wire [4:0] ab_sum = {1'b0, a} + {1'b0, b} + {4'b0, c_in}; 22 | //将两数之和转换成bcd码 23 | assign sum = (ab_sum[3:0] > 4'd9) ? (ab_sum[3:0]-4'd10) : ab_sum[3:0]; 24 | //优先进位计算 25 | assign c_out = (ab_sum[4]) ? 1'b1 : 26 | ((ab_sum[3:0] > 4'd9) ? 1'b1 : 1'b0); 27 | 28 | endmodule 29 | -------------------------------------------------------------------------------- /sim/bcd_adder_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | 仿真思路: 3 | 输入BCD码自加一来测试输出是不是正确的 4 | */ 5 | `timescale 1ns/1ns 6 | 7 | module bcd_adder_tb(); 8 | 9 | reg [3:0] a; 10 | reg [3:0] b; 11 | reg c_in; 12 | 13 | wire [3:0] sum; 14 | wire c_out; 15 | 16 | parameter CYCLE = 5'd20; 17 | always #10 a = (sum==4'd9) ? 4'b0 : sum + 1'd1; 18 | 19 | 20 | 21 | initial begin 22 | a = 4'b0000; 23 | b = 4'b0000; 24 | c_in = 1'b0; 25 | #(CYCLE * 50); 26 | $stop; 27 | end 28 | 29 | 30 | bcd_adder bcd_adder_test ( 31 | .a (a ), 32 | .b (b ), 33 | .c_in (c_in ), 34 | 35 | .sum (sum ), 36 | .c_out (c_out ) 37 | ); 38 | 39 | endmodule 40 | -------------------------------------------------------------------------------- /sim/wait_count_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | 仿真思路: 3 | 测试分频功能以及复位功能是否正常 4 | */ 5 | `timescale 1ns/1ns 6 | 7 | module wait_count_tb(); 8 | 9 | reg min_pulse; 10 | reg rst_n; 11 | 12 | wire wait_fare_pulse; 13 | 14 | parameter CYCLE = 5'd20; 15 | parameter WAIT_COUNT = 4'd5; 16 | 17 | always # 10 min_pulse = ~min_pulse; 18 | 19 | initial begin 20 | min_pulse = 1'b0; 21 | min_pulse = 1'b0; 22 | rst_n = 1'b0; 23 | #(CYCLE * 500) 24 | rst_n = 1'b1; 25 | #(CYCLE * 500) 26 | $stop; 27 | end 28 | 29 | wait_count#( 30 | .WAIT_COUNT(WAIT_COUNT) 31 | ) wait_count_test ( 32 | .min_pulse (min_pulse ), 33 | .rst_n (rst_n ), 34 | 35 | .wait_fare_pulse(wait_fare_pulse) 36 | ); 37 | 38 | endmodule 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 这是一个数字系统设计(EDA)课程的大作业 2 | 3 | 设计要求如下: 4 | 5 | ​ 1、设计一个出租车自动计费器,具有行车里程计费、等候时间计费、及起价三部分,用四位数码管显示总金额,最大值为99.99元; 6 | 7 | ​ 2、行车里程单价1元/公里,等候时间单价0.5元/10分钟,起价3元(3公里起价)均能通过人工输入; 8 | 9 | ​ 3、行车里程的计费电路将汽车行驶的里程数转换成与之成正比的脉冲数,然后由计数译码电路转换成收费金额,实验中以一个脉冲模拟汽车前进十米,则每100个脉冲表示1公里,每脉冲的价格可由开关预置。例如单价是1元/公里,则脉冲价格为0.01元/脉冲; 10 | 11 | ​ 4、用四个数码管显示行驶公里数,两个数码管显示收费金额。 12 | 13 | 疫情原因没有拿到开发板,所以本次课程设计的要求只需要仿真通过即可。 14 | 15 | # 主要功能模块 16 | 17 | 18 | 19 | | 模块 | 功能 | 20 | | ------------- | ----------------------------------------- | 21 | | freq_div | 分频模块,将50Mhz时钟分成分钟脉冲输出 | 22 | | distance_fare | 计算里程价格和里程模块,采用BCD码输出结果 | 23 | | wait_fare | 计算时长价,以BCD码形式输出 | 24 | |fare_total|计算总价格,若到了99.99,则停止| 25 | | seg_disp | 将总价和里程在数码管上显示 | 26 | 27 | -------------------------------------------------------------------------------- /sim/bcd_adder_4_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | 仿真思路: 3 | 输入BCD码自加一来测试输出是不是正确的 4 | */ 5 | `timescale 1ns/1ns 6 | 7 | module bcd_adder_4_tb(); 8 | 9 | reg [15:0] a; 10 | reg [15:0] b; 11 | reg c_in; 12 | 13 | wire [15:0] sum; 14 | wire c_out; 15 | 16 | parameter CYCLE = 5'd20; 17 | always #10 a = ((sum[3:0]==4'd9) & (sum[7:4]!=4'd9)) ? (sum + 5'b1_0001 - 5'b0_1010 ) : 18 | ((sum[3:0]==4'd9) & (sum[7:4]==4'd9) & (sum[11:8]!=4'd9)) ? (sum + 9'b1_0001_0001 - 9'b0_1010_1010) : 19 | ((sum[3:0]==4'd9) & (sum[7:4]==4'd9) & (sum[11:8]==4'd9) & (sum[15:12]!=4'd9)) ? (sum + 13'b1_0001_0001_0001 - 13'b0_1010_1010_1010) : 20 | sum + 1'd1; 21 | 22 | 23 | initial begin 24 | a = 16'h0000; 25 | b = 16'h0001; 26 | c_in = 1'b0; 27 | #(CYCLE * 100) 28 | $stop; 29 | end 30 | 31 | bcd_adder_4 bcd_adder_4_test ( 32 | .a (a ), 33 | .b (b ), 34 | .c_in (c_in ), 35 | 36 | .sum (sum ), 37 | .c_out (c_out ) 38 | ); 39 | 40 | endmodule -------------------------------------------------------------------------------- /sim/freq_div_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | 仿真思路: 3 | 测试en,max,rst_n信号对分频模块的分频功能影响是否正常 4 | */ 5 | `timescale 1ns/1ns 6 | 7 | module freq_div_tb(); 8 | 9 | reg clk; 10 | reg en; 11 | reg max; 12 | reg rst_n; 13 | 14 | wire min_pulse; 15 | 16 | parameter MIN_COUNT = 4'd10; 17 | parameter CYCLE = 5'd20; 18 | 19 | always # 10 clk = ~clk; 20 | 21 | initial begin 22 | clk = 1'b0; 23 | en = 1'b0; 24 | max = 1'b0; 25 | rst_n = 1'b0; 26 | #(CYCLE * 50) 27 | rst_n = 1'b1; 28 | en = 1'b1; 29 | #(CYCLE * 100); 30 | max = 1'd1; 31 | #(CYCLE * 100); 32 | max = 1'd0; 33 | #(CYCLE * 100); 34 | rst_n = 1'b0; 35 | #(CYCLE * 100); 36 | rst_n = 1'b1; 37 | #(CYCLE * 100); 38 | $stop; 39 | end 40 | 41 | freq_div#( 42 | .MIN_COUNT(MIN_COUNT) 43 | ) freq_div_test ( 44 | .clk (clk ), 45 | .rst_n (rst_n ), 46 | .en (en ), 47 | .max (max ), 48 | 49 | .min_pulse (min_pulse ) 50 | ); 51 | 52 | endmodule 53 | -------------------------------------------------------------------------------- /src/bcd_seg_disp.v: -------------------------------------------------------------------------------- 1 | //BCD七段数码管显示译码 2 | //共阳极 3 | //MAX信号为高电平时输出9 4 | /* 5 | in -> 输入的BCD码 6 | max -> 输入的计满信号,由fare_total模块产生 7 | 8 | out -> 输出的七段数码管对应的数字 9 | */ 10 | module bcd_seg_disp ( 11 | input wire [3:0] in, 12 | input wire max, 13 | 14 | output reg [6:0] out 15 | ); 16 | 17 | always@(*)begin 18 | //如果计满信号为高电平,则直接输出9 19 | if (max) begin 20 | out <= 7'b0010000; 21 | end 22 | //输入0-9十种BCD码判断,并输出对应的七段数码管显示信号 23 | else begin 24 | case (in) 25 | 4'b0000: 26 | out <= 7'b1000000; 27 | 4'b0001: 28 | out <= 7'b1111001; 29 | 4'b0010: 30 | out <= 7'b0100100; 31 | 4'b0011: 32 | out <= 7'b0110000; 33 | 4'b0100: 34 | out <= 7'b0011001; 35 | 4'b0101: 36 | out <= 7'b0010010; 37 | 4'b0110: 38 | out <= 7'b0000010; 39 | 4'b0111: 40 | out <= 7'b1111000; 41 | 4'b1000: 42 | out <= 7'b0000000; 43 | 4'b1001: 44 | out <= 7'b0010000; 45 | default: 46 | out <= 7'b1111111; 47 | endcase 48 | end 49 | end 50 | 51 | endmodule 52 | -------------------------------------------------------------------------------- /src/wait_count.v: -------------------------------------------------------------------------------- 1 | //等候时间计数模块 2 | //十分钟输出一个计费脉冲 3 | //这个模块可以整合进分频模块里面的,但是目前能稳定运行暂时就先不动了:D 4 | /* 5 | min_pulse -> 输入的分钟脉冲信号 6 | rst_n -> 输入的下降沿有效的复位信号 7 | 8 | wait_fare_pulse -> 输出的计费信号 9 | */ 10 | module wait_count ( 11 | input wire min_pulse, 12 | input wire rst_n, 13 | 14 | output wire wait_fare_pulse 15 | ); 16 | 17 | //定义参数WAIT_COUNT,等待的时间,单位是分钟,方便后续修改及仿真时覆写 18 | //每十分钟含有10个时钟周期,但是这里只检测了上跳沿 19 | //所以是每五个周期(五分钟)翻转一次输出脉冲信号 20 | parameter WAIT_COUNT = 4'd5; 21 | 22 | reg [3:0] counter = WAIT_COUNT; 23 | reg wait_fare = 1'd0; 24 | 25 | //防止出现不定态,先给寄存器赋初值,后赋给wire类型变量 26 | assign wait_fare_pulse = wait_fare; 27 | 28 | always@(posedge min_pulse or negedge rst_n) begin 29 | //判断复位信号,为低电平则将计数器初始化为WAIT_COUNT的值,并输出低电平 30 | if (!rst_n) begin 31 | counter <= WAIT_COUNT; 32 | wait_fare <= 1'd0; 33 | end 34 | //判断是否达到计费单位的分钟数,若达到则将输出脉冲翻转 35 | else if (counter == 1'd1) begin 36 | wait_fare <= ~wait_fare; 37 | counter <= WAIT_COUNT; 38 | end 39 | //若上述条件都不满足,则开始计数 40 | else begin 41 | counter <= counter - 1'd1; 42 | end 43 | end 44 | 45 | endmodule 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 achunbai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sim/distance_fare_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | 仿真思路: 3 | 输入起步价,每十米价格测试是否正常运行 4 | 主要测试使能,复位和计满停止功能是否正常 5 | */ 6 | `timescale 1ns/1ns 7 | 8 | module distance_fare_tb(); 9 | 10 | reg ten_meter_pulse; 11 | reg en; 12 | reg rst_n; 13 | reg [11:0] distance_fare_per_pulse; 14 | reg [11:0] s_fare; 15 | 16 | wire [7:0] distance_bcd; 17 | wire [15:0] distance_fare_bcd; 18 | 19 | parameter CYCLE = 5'd20; 20 | 21 | always # 100 ten_meter_pulse = ~ten_meter_pulse; 22 | 23 | initial begin 24 | en = 1'b0; 25 | rst_n = 1'b0; 26 | ten_meter_pulse = 1'b0; 27 | distance_fare_per_pulse = 12'b0000_0000_0011; 28 | s_fare = 12'b0011_0000_0000; 29 | #(CYCLE); 30 | rst_n = 1'b1; 31 | #(CYCLE * 50); 32 | en = 1'b1; 33 | #(CYCLE * 110000); 34 | rst_n = 1'b0; 35 | #(CYCLE * 100); 36 | $stop; 37 | end 38 | 39 | distance_fare distance_fare_test ( 40 | .ten_meter_pulse (ten_meter_pulse ), 41 | .en (en ), 42 | .distance_fare_per_pulse (distance_fare_per_pulse ), 43 | .s_fare (s_fare ), 44 | .rst_n (rst_n ), 45 | 46 | .distance_bcd (distance_bcd ), 47 | .distance_fare_bcd (distance_fare_bcd ) 48 | ); 49 | 50 | endmodule 51 | -------------------------------------------------------------------------------- /sim/wait_fare_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | 仿真思路: 3 | 输入每脉冲的价格(BCD码),测试复位,启用,计满停止和价格计算功能是否正常 4 | */ 5 | `timescale 1ns/1ns 6 | module wait_fare_tb (); 7 | 8 | reg wait_fare_pulse; 9 | reg rst_n; 10 | reg wait_en; 11 | reg max; 12 | reg [11:0] wait_fare_per_unit; 13 | 14 | wire [15:0] wait_fare_bcd; 15 | 16 | parameter CYCLE = 5'd20; 17 | 18 | always # 10 wait_fare_pulse = ~wait_fare_pulse; 19 | 20 | initial begin 21 | wait_en = 1'b0; 22 | wait_fare_pulse = 1'b0; 23 | max = 1'b0; 24 | wait_fare_per_unit = 12'b0000_0001_0011; 25 | rst_n = 1'b0; 26 | #(CYCLE) 27 | rst_n = 1'b1; 28 | wait_en = 1'b1; 29 | #(CYCLE * 100); 30 | wait_en = 1'b0; 31 | #(CYCLE * 100); 32 | wait_en = 1'b1; 33 | #(CYCLE * 100); 34 | max = 1'b1; 35 | #(CYCLE * 100); 36 | max = 1'b0; 37 | #(CYCLE * 1000); 38 | $stop; 39 | end 40 | 41 | wait_fare wait_fare_test ( 42 | .wait_fare_pulse (wait_fare_pulse ), 43 | .rst_n (rst_n ), 44 | .wait_en (wait_en ), 45 | .max (max ), 46 | .wait_fare_per_unit (wait_fare_per_unit ), 47 | 48 | .wait_fare_bcd (wait_fare_bcd ) 49 | ); 50 | 51 | endmodule 52 | -------------------------------------------------------------------------------- /src/freq_div.v: -------------------------------------------------------------------------------- 1 | //分频模块 2 | //将50MHz输入时钟分成分钟输出 3 | /* 4 | clk -> 输入的时钟信号 5 | rst_n -> 输入的复位信号 6 | en -> 输入的使能信号 7 | max -> 输入的计满信号,由fee_total模块产生 8 | 9 | min_pulse -> 输出的分钟脉冲 10 | */ 11 | module freq_div ( 12 | input wire clk, 13 | input wire rst_n, 14 | input wire en, 15 | input wire max, 16 | 17 | output wire min_pulse 18 | ); 19 | 20 | //定义参数MIN_COUNT,方便仿真模块覆写及后续改动 21 | //每分钟包含3_000_000_000个时钟周期,但是这里只检测了上跳沿 22 | //所以是每1_500_000_000个周期(半分钟)翻转一次输出脉冲信号 23 | parameter MIN_COUNT = 32'd1_500_000_000; 24 | 25 | reg [31:0] min_counter = MIN_COUNT; 26 | reg min = 1'd0; 27 | 28 | //防止出现不定态,先给寄存器赋初值,后赋给wire类型变量 29 | assign min_pulse = min; 30 | 31 | always@(posedge clk or negedge rst_n) begin 32 | //判断复位信号,为低电平则将计数器初始化为MIN_COUNT的值,并输出低电平 33 | if (!rst_n) begin 34 | min_counter <= MIN_COUNT; 35 | min <= 1'd0; 36 | end 37 | //判断是否达到一分钟,若达到一分钟则将输出脉冲翻转 38 | else if (min_counter == 1'd1) begin 39 | min_counter <= MIN_COUNT; 40 | min <= ~min; 41 | end 42 | //判断是否满足工作条件(en为高电平且max为低电平),满足则开始计数 43 | else if(en && !max) begin 44 | min_counter <= min_counter - 1'd1; 45 | end 46 | //若不满足工作条件则暂停技术,保持结果 47 | else begin 48 | min_counter <= min_counter; 49 | end 50 | end 51 | 52 | endmodule 53 | -------------------------------------------------------------------------------- /sim/fare_total_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | 仿真思路: 3 | 测试在特定情况瞎加法器的进位和计算功能是否正常 4 | */ 5 | `timescale 1ns/1ns 6 | 7 | module fare_total_tb(); 8 | 9 | reg [15:0] distance_fare_bcd; 10 | reg [15:0] wait_fare_bcd; 11 | 12 | wire [15:0] fare_total_bcd; 13 | wire max; 14 | 15 | parameter CYCLE = 5'd20; 16 | 17 | 18 | initial begin 19 | distance_fare_bcd = 16'b0000_0000_0000_0000; 20 | wait_fare_bcd = 16'b0000_0000_0000_0000; 21 | #(CYCLE * 20); 22 | distance_fare_bcd = 16'b0001_0001_0001_0001; 23 | wait_fare_bcd = 16'b0001_0001_0001_0001; 24 | #(CYCLE * 20); 25 | distance_fare_bcd = 16'b0001_0001_0001_0001; 26 | wait_fare_bcd = 16'b1000_1000_1000_1000; 27 | #(CYCLE * 20); 28 | distance_fare_bcd = 16'b0001_0001_0001_0001; 29 | wait_fare_bcd = 16'b0100_1000_1000_1001; 30 | #(CYCLE * 20); 31 | distance_fare_bcd = 16'b0001_0001_0001_0001; 32 | wait_fare_bcd = 16'b0110_1001_1001_1001; 33 | #(CYCLE * 20); 34 | distance_fare_bcd = 16'b0001_0001_0001_0001; 35 | wait_fare_bcd = 16'b1000_1001_1001_1001; 36 | #(CYCLE * 20); 37 | $stop; 38 | end 39 | 40 | fare_total fare_total_test ( 41 | .distance_fare_bcd (distance_fare_bcd ), 42 | .wait_fare_bcd (wait_fare_bcd ), 43 | 44 | .fare_total_bcd (fare_total_bcd ), 45 | .max (max ) 46 | ); 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /src/wait_fare.v: -------------------------------------------------------------------------------- 1 | //等候时间计费模块 2 | //可以实现输入每十分钟的费率计费 3 | //输入的wait_fare_pulse由wait_count模块产生 4 | /* 5 | wait_fare_pulse -> wait_count模块产生的计费脉冲 6 | rst_n -> 复位信号,下降沿有效 7 | wait_en -> 启用信号,开关闭合即有效 8 | max -> fare_total模块输出的计满信号 9 | wait_fare_per_unit -> 每十分钟的等待单价 10 | 11 | wait_fare_bcd -> 以BCD码输出的时长费 12 | */ 13 | module wait_fare ( 14 | input wire wait_fare_pulse, 15 | input wire rst_n, 16 | input wire wait_en, 17 | input wire max, 18 | input wire [11:0] wait_fare_per_unit, 19 | 20 | output wire [15:0] wait_fare_bcd 21 | ); 22 | 23 | reg [15:0] wait_fare = 16'b0; 24 | //费用是否计满的标志位 25 | reg max_wait = 1'b0; 26 | wire [15:0] fare_next; 27 | wire max_fare; 28 | 29 | //防止出现不定态,先给寄存器赋初值,后赋给wire类型变量 30 | assign wait_fare_bcd = wait_fare; 31 | 32 | always@(posedge wait_fare_pulse or negedge rst_n) begin 33 | if (!rst_n) begin 34 | wait_fare <= 16'd0; 35 | max_wait <= 1'b0; 36 | end 37 | //判断是否满足暂停计费条件(wait_en为低电平,max和max_wait为高电平) 38 | //满足则暂停计费 39 | else if(!wait_en || max || max_wait) begin 40 | wait_fare <= wait_fare; 41 | end 42 | //若有进位,则标志位置1 43 | else if(max_fare) begin 44 | max_wait <= 1'b1; 45 | end 46 | //若上述条件都不满足,则继续计费 47 | else begin 48 | wait_fare <= fare_next; 49 | end 50 | end 51 | 52 | //调用bcd_adder_4模块实现单位时长费和总价的相加 53 | bcd_adder_4 wait_fare_adder ( 54 | .a (wait_fare ), 55 | .b ({4'b0000,wait_fare_per_unit} ), 56 | .c_in (1'b0 ), 57 | 58 | .sum (fare_next ), 59 | .c_out (max_fare ) 60 | ); 61 | 62 | endmodule 63 | -------------------------------------------------------------------------------- /sim/seg_disp_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | 仿真思路: 3 | 测试显示输出是不是对劲的 4 | */ 5 | `timescale 1ns/1ns 6 | 7 | module seg_disp_tb(); 8 | 9 | reg [15:0] fare_total_bcd; 10 | reg [7:0] distance_bcd; 11 | 12 | wire [7:0] fare_a; 13 | wire [7:0] fare_b; 14 | wire [7:0] fare_c; 15 | wire [7:0] fare_d; 16 | wire [7:0] distance_a; 17 | wire [7:0] distance_b; 18 | 19 | 20 | initial begin 21 | fare_total_bcd = 16'b0000_0000_0000_0000; 22 | distance_bcd = 8'b0000_0000; 23 | #20 24 | fare_total_bcd = 16'b0001_0001_0001_0001; 25 | distance_bcd = 8'b0001_0001; 26 | #20 27 | fare_total_bcd = 16'b0011_0011_0011_0011; 28 | distance_bcd = 8'b0011_0011; 29 | #20 30 | fare_total_bcd = 16'b0100_0100_0100_0100; 31 | distance_bcd = 8'b0100_0100; 32 | #20 33 | fare_total_bcd = 16'b0101_0101_0101_0101; 34 | distance_bcd = 8'b0101_0101; 35 | #20 36 | fare_total_bcd = 16'b0110_0110_0110_0110; 37 | distance_bcd = 8'b0110_0110; 38 | #20 39 | fare_total_bcd = 16'b0111_0111_0111_0111; 40 | distance_bcd = 8'b0111_0111; 41 | #20 42 | fare_total_bcd = 16'b1000_1000_1000_1000; 43 | distance_bcd = 8'b1000_1000; 44 | #20 45 | fare_total_bcd = 16'b1001_1001_1001_1001; 46 | distance_bcd = 8'b1001_1001; 47 | #20 48 | fare_total_bcd = 16'b1011_1011_1011_1011; 49 | distance_bcd = 8'b1011_1011; 50 | #20 51 | fare_total_bcd = 16'b1111_1111_1111_1111; 52 | distance_bcd = 8'b1111_1111; 53 | #20 54 | $stop; 55 | end 56 | 57 | seg_disp seg_disp_test ( 58 | .fare_total_bcd (fare_total_bcd ), 59 | .distance_bcd (distance_bcd ), 60 | 61 | .fare_a (fare_a ), 62 | .fare_b (fare_b ), 63 | .fare_c (fare_c ), 64 | .fare_d (fare_d ), 65 | .distance_a (distance_a ), 66 | .distance_b (distance_b ) 67 | ); 68 | 69 | endmodule 70 | -------------------------------------------------------------------------------- /src/bcd_adder_4.v: -------------------------------------------------------------------------------- 1 | //四位BCD优先进位加法器 2 | //调用了四个bcd_adder模块 3 | //输入两个四位BCD码数字及前位进位 4 | //输出四位BCD码和以及本位进位 5 | /* 6 | a -> 输入的加数a 7 | b -> 输入的加数b 8 | c_in -> 输入的前位进位 9 | 10 | sum -> 输出的和 11 | c_out -> 输出的本位进位 12 | */ 13 | module bcd_adder_4 ( 14 | input wire [15:0] a, 15 | input wire [15:0] b, 16 | input wire c_in, 17 | 18 | output wire [15:0] sum, 19 | output wire c_out 20 | ); 21 | 22 | wire [3:0] a_1; 23 | wire [3:0] a_2; 24 | wire [3:0] a_3; 25 | wire [3:0] a_4; 26 | wire [3:0] b_1; 27 | wire [3:0] b_2; 28 | wire [3:0] b_3; 29 | wire [3:0] b_4; 30 | wire [3:0] a_o; 31 | wire [3:0] b_o; 32 | wire [3:0] c_o; 33 | wire [3:0] d_o; 34 | wire c_a; 35 | wire c_b; 36 | wire c_c; 37 | 38 | //按位拆分加数和相加的和 39 | assign a_1 = a [ 3:0 ]; 40 | assign a_2 = a [ 7:4 ]; 41 | assign a_3 = a [11:8 ]; 42 | assign a_4 = a [15:12]; 43 | assign b_1 = b [ 3:0 ]; 44 | assign b_2 = b [ 7:4 ]; 45 | assign b_3 = b [11:8 ]; 46 | assign b_4 = b [15:12]; 47 | assign sum [ 3:0 ] = a_o; 48 | assign sum [ 7:4 ] = b_o; 49 | assign sum [11:8 ] = c_o; 50 | assign sum [15:12] = d_o; 51 | 52 | //将拆分后的结果送入四个bcd_adder相加 53 | //计算最低和 54 | bcd_adder bcd_adder_a ( 55 | .a (a_1 ), 56 | .b (b_1 ), 57 | .c_in (c_in ), 58 | 59 | .sum (a_o ), 60 | .c_out (c_a ) 61 | ); 62 | 63 | //计算第二位和 64 | bcd_adder bcd_adder_b ( 65 | .a (a_2 ), 66 | .b (b_2 ), 67 | .c_in (c_a ), 68 | 69 | .sum (b_o ), 70 | .c_out (c_b ) 71 | ); 72 | 73 | //计算第三位和 74 | bcd_adder bcd_adder_c ( 75 | .a (a_3 ), 76 | .b (b_3 ), 77 | .c_in (c_b ), 78 | 79 | .sum (c_o ), 80 | .c_out (c_c ) 81 | ); 82 | 83 | //计算最高位和 84 | bcd_adder bcd_adder_d ( 85 | .a (a_4 ), 86 | .b (b_4 ), 87 | .c_in (c_c ), 88 | 89 | .sum (d_o ), 90 | .c_out (c_out ) 91 | ); 92 | 93 | endmodule 94 | -------------------------------------------------------------------------------- /sim/taxi_fare_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | 仿真思路: 3 | 设置等待单价为五毛钱每十分钟 4 | 里程费用为三块钱每公里 5 | 起步价为三块钱 6 | 测试复位,等待功能的使用 7 | 以及计满停止的功能 8 | 可以调整的参数: 9 | 分钟计时 10 | 等待计时 11 | 速度 12 | 速度为多少时间每十米 13 | */ 14 | `timescale 1ns/1ns 15 | 16 | module taxi_fare_tb(); 17 | 18 | reg clk; 19 | reg rst_n; 20 | reg en; 21 | reg wait_en; 22 | reg [11:0] distance_fare_per_pulse; 23 | reg [11:0] s_fare; 24 | reg ten_meter_pulse; 25 | reg [11:0] wait_fare_per_unit; 26 | wire [7:0] fare_a; 27 | wire [7:0] fare_b; 28 | wire [7:0] fare_c; 29 | wire [7:0] fare_d; 30 | wire [7:0] distance_a; 31 | wire [7:0] distance_b; 32 | 33 | parameter CYCLE = 5'd20; 34 | parameter MIN_COUNT = 4'd10; 35 | parameter WAIT_COUNT = 3'd5; 36 | parameter SPEED = 26'd50; 37 | 38 | always # 10 clk = ~clk; 39 | always # SPEED ten_meter_pulse = ~ten_meter_pulse; 40 | 41 | initial begin 42 | clk = 1'b0; 43 | wait_en = 1'd0; 44 | ten_meter_pulse = 1'b0; 45 | wait_fare_per_unit = 12'b0000_0101_0000; 46 | rst_n = 1'b0; 47 | en = 1'b0; 48 | distance_fare_per_pulse = 12'b0000_0000_0011; 49 | s_fare = 12'b0011_0000_0000; 50 | #(CYCLE); 51 | rst_n = 1'b1; 52 | en = 1'b1; 53 | #(CYCLE * 100); 54 | wait_en = 1'b1; 55 | #(CYCLE * 100); 56 | wait_en = 1'b0; 57 | #(CYCLE * 1000); 58 | $stop; 59 | end 60 | 61 | taxi_fare#( 62 | .MIN_COUNT (MIN_COUNT ), 63 | .WAIT_COUNT (WAIT_COUNT ) 64 | ) u_taxi_fare( 65 | .clk (clk ), 66 | .rst_n (rst_n ), 67 | .en (en ), 68 | .wait_en (wait_en ), 69 | .distance_fare_per_pulse (distance_fare_per_pulse ), 70 | .s_fare (s_fare ), 71 | .ten_meter_pulse (ten_meter_pulse ), 72 | .wait_fare_per_unit (wait_fare_per_unit ), 73 | 74 | .fare_a (fare_a ), 75 | .fare_b (fare_b ), 76 | .fare_c (fare_c ), 77 | .fare_d (fare_d ), 78 | .distance_a (distance_a ), 79 | .distance_b (distance_b ) 80 | ); 81 | 82 | endmodule 83 | -------------------------------------------------------------------------------- /src/seg_disp.v: -------------------------------------------------------------------------------- 1 | //显示模块 2 | //将输出的BCD码显示在七段数码管上 3 | //调用了留个bcd_seg_disp模块显示 4 | /* 5 | fare_total_bcd -> 输入的总价格信号,由fare_total模块产生 6 | distance_bcd -> 输入的里程信号,由distance_fare模块产生 7 | max -> 输入的计满信号,由fare_total模块产生 8 | 9 | fare_a -> 输出的总价第1位 10 | fare_b -> 输出的总价第2位 11 | fare_c -> 输出的总价第3位 12 | fare_d -> 输出的总价第4位 13 | distance_a -> 输出的里程第1位 14 | distance_b -> 输出的里程第2位 15 | */ 16 | module seg_disp ( 17 | input wire [15:0] fare_total_bcd, 18 | input wire [7:0] distance_bcd, 19 | input wire max, 20 | 21 | output wire [7:0] fare_a, 22 | output wire [7:0] fare_b, 23 | output wire [7:0] fare_c, 24 | output wire [7:0] fare_d, 25 | output wire [7:0] distance_a, 26 | output wire [7:0] distance_b 27 | ); 28 | 29 | //调整价格显示格式为xx.xx 里程显示格式为xx 30 | //控制数码管上的小数点亮灭,开发板使用共阳极数码管 31 | //1灭0亮 32 | assign fare_a[0] = 1'b1; 33 | assign fare_b[0] = 1'b1; 34 | assign fare_c[0] = 1'b0; 35 | assign fare_d[0] = 1'b1; 36 | assign distance_a[0] = 1'b1; 37 | assign distance_b[0] = 1'b1; 38 | 39 | //调用了六个bcd_seg_disp模块进行译码 40 | //按位拆分数据并译成七段译码器的信号 41 | //价格百分位显示 42 | bcd_seg_disp u_fare_a( 43 | .in (fare_total_bcd[3:0]), 44 | .max (max ), 45 | 46 | .out (fare_a[7:1] ) 47 | ); 48 | 49 | //价格十分位显示 50 | bcd_seg_disp u_fare_b( 51 | .in (fare_total_bcd[7:4]), 52 | .max (max ), 53 | 54 | .out (fare_b[7:1] ) 55 | ); 56 | 57 | //价格个位显示 58 | bcd_seg_disp u_fare_c( 59 | .in (fare_total_bcd[11:8] ), 60 | .max (max ), 61 | 62 | .out (fare_c[7:1] ) 63 | ); 64 | 65 | //价格十位显示 66 | bcd_seg_disp u_fare_d( 67 | .in (fare_total_bcd[15:12] ), 68 | .max (max ), 69 | 70 | .out (fare_d[7:1] ) 71 | ); 72 | 73 | //里程个位显示 74 | bcd_seg_disp u_distance_a( 75 | .in (distance_bcd[3:0] ), 76 | .max (1'd0 ), 77 | 78 | .out (distance_a[7:1] ) 79 | ); 80 | 81 | //里程十位显示 82 | bcd_seg_disp u_distance_b( 83 | .in (distance_bcd[7:4] ), 84 | .max (1'd0 ), 85 | 86 | .out (distance_b[7:1] ) 87 | ); 88 | 89 | endmodule 90 | -------------------------------------------------------------------------------- /src/fare_total.v: -------------------------------------------------------------------------------- 1 | //总价计算模块 2 | //调用了四个bcd_adder模块相加 3 | //实现总价的计算,如果总价达到了99.99,max输出高电平 4 | /* 5 | distance_fare_bcd -> 输入的里程费,由wait_fare模块产生 6 | wait_fare_bcd -> 输入的时长费,由distance_fare模块产生 7 | 8 | fare_total_bcd -> 输出的总价格 9 | max -> 输出的计满信号 10 | */ 11 | module fare_total ( 12 | input wire [15:0] distance_fare_bcd, 13 | input wire [15:0] wait_fare_bcd, 14 | 15 | output wire [15:0] fare_total_bcd, 16 | output wire max 17 | ); 18 | 19 | wire [3:0] a_1; 20 | wire [3:0] a_2; 21 | wire [3:0] a_3; 22 | wire [3:0] a_4; 23 | wire [3:0] b_1; 24 | wire [3:0] b_2; 25 | wire [3:0] b_3; 26 | wire [3:0] b_4; 27 | wire [3:0] a_o; 28 | wire [3:0] b_o; 29 | wire [3:0] c_o; 30 | wire [3:0] d_o; 31 | wire c_a; 32 | wire c_b; 33 | wire c_c; 34 | 35 | //将输入两个数字按位拆分 36 | //拆成单独的百分位(a),十分位(b),个位(c),十位(d) 37 | assign a_1 = distance_fare_bcd [ 3:0 ]; 38 | assign a_2 = distance_fare_bcd [ 7:4 ]; 39 | assign a_3 = distance_fare_bcd [11:8 ]; 40 | assign a_4 = distance_fare_bcd [15:12]; 41 | assign b_1 = wait_fare_bcd [ 3:0 ]; 42 | assign b_2 = wait_fare_bcd [ 7:4 ]; 43 | assign b_3 = wait_fare_bcd [11:8 ]; 44 | assign b_4 = wait_fare_bcd [15:12]; 45 | assign fare_total_bcd [ 3:0 ] = a_o; 46 | assign fare_total_bcd [ 7:4 ] = b_o; 47 | assign fare_total_bcd [11:8 ] = c_o; 48 | assign fare_total_bcd [15:12] = d_o; 49 | 50 | //调用bcd_adder模块相加 51 | //百分位上的数据相加 52 | bcd_adder bcd_adder_a ( 53 | .a (a_1 ), 54 | .b (b_1 ), 55 | .c_in (1'b0 ), 56 | 57 | .sum (a_o ), 58 | .c_out (c_a ) 59 | ); 60 | 61 | //十分位上的数据相加 62 | bcd_adder bcd_adder_b ( 63 | .a (a_2 ), 64 | .b (b_2 ), 65 | .c_in (c_a ), 66 | 67 | .sum (b_o ), 68 | .c_out (c_b ) 69 | ); 70 | 71 | //个位上的数据相加 72 | bcd_adder bcd_adder_c ( 73 | .a (a_3 ), 74 | .b (b_3 ), 75 | .c_in (c_b ), 76 | 77 | .sum (c_o ), 78 | .c_out (c_c ) 79 | ); 80 | 81 | //十位上的数据相加 82 | bcd_adder bcd_adder_d ( 83 | .a (a_4 ), 84 | .b (b_4 ), 85 | .c_in (c_c ), 86 | 87 | .sum (d_o ), 88 | .c_out (max ) 89 | ); 90 | 91 | endmodule 92 | -------------------------------------------------------------------------------- /src/taxi_fare.v: -------------------------------------------------------------------------------- 1 | //顶层模块 2 | /* 3 | clk -> 输入的时钟信号 4 | rst_n -> 输入的复位信号,下降沿有效 5 | wait_en -> 启用信号,开关闭合即有效 6 | en -> 输入的使能信号 7 | ten_meter_pulse -> 输入的十米脉冲 8 | distance_fare_per_pulse -> 以BCD码输入的每十米脉冲的价格 9 | s_fare -> 输入的起步价 10 | wait_fare_per_unit -> 每十分钟的等待单价 11 | 12 | fare_a -> 输出的总价第1位 13 | fare_b -> 输出的总价第2位 14 | fare_c -> 输出的总价第3位 15 | fare_d -> 输出的总价第4位 16 | distance_a -> 输出的里程第1位 17 | distance_b -> 输出的里程第2位 18 | */ 19 | module taxi_fare ( 20 | input wire clk, 21 | input wire rst_n, 22 | input wire wait_en, 23 | input wire en, 24 | input wire [11:0] distance_fare_per_pulse, 25 | input wire [11:0] s_fare, 26 | input wire ten_meter_pulse, 27 | input wire [11:0] wait_fare_per_unit, 28 | 29 | output wire [7:0] fare_a, 30 | output wire [7:0] fare_b, 31 | output wire [7:0] fare_c, 32 | output wire [7:0] fare_d, 33 | output wire [7:0] distance_a, 34 | output wire [7:0] distance_b 35 | ); 36 | 37 | //设置两个参数MIN_COUNT和WAIT_COUNT,方便后续调整和仿真时覆写 38 | //每分钟包含3_000_000_000个时钟周期,但是这里只检测了上跳沿 39 | //所以是每1_500_000_000个周期(半分钟)翻转一次输出脉冲信号 40 | parameter MIN_COUNT = 32'd1_500_000_000; 41 | //每十分钟含有10个时钟周期,但是这里只检测了上跳沿 42 | //所以是每五个周期(五分钟)翻转一次输出脉冲信号 43 | parameter WAIT_COUNT = 4'd5; 44 | wire min_pulse; 45 | wire max; 46 | wire wait_fare_pulse; 47 | wire [15:0] wait_fare_bcd; 48 | wire [7:0] distance_bcd; 49 | wire [15:0] distance_fare_bcd; 50 | wire [15:0] fare_total_bcd; 51 | 52 | freq_div#( 53 | .MIN_COUNT(MIN_COUNT) 54 | ) u_freq_div ( 55 | .clk (clk ), 56 | .rst_n (rst_n ), 57 | .en (en ), 58 | .max (max ), 59 | 60 | .min_pulse (min_pulse ) 61 | ); 62 | 63 | wait_count#( 64 | .WAIT_COUNT(WAIT_COUNT) 65 | ) 66 | u_wait_count ( 67 | .min_pulse (min_pulse ), 68 | .rst_n (rst_n ), 69 | 70 | .wait_fare_pulse (wait_fare_pulse) 71 | ); 72 | 73 | wait_fare u_wait_fare ( 74 | .wait_fare_pulse (wait_fare_pulse ), 75 | .rst_n (rst_n ), 76 | .max (max ), 77 | .wait_en (wait_en ), 78 | .wait_fare_per_unit (wait_fare_per_unit ), 79 | 80 | .wait_fare_bcd (wait_fare_bcd ) 81 | ); 82 | 83 | distance_fare u_distance_fare ( 84 | .ten_meter_pulse (ten_meter_pulse ), 85 | .en (en ), 86 | .max (max ), 87 | .rst_n (rst_n ), 88 | .wait_en (wait_en ), 89 | .distance_fare_per_pulse (distance_fare_per_pulse), 90 | .s_fare (s_fare ), 91 | 92 | .distance_bcd (distance_bcd ), 93 | .distance_fare_bcd (distance_fare_bcd ) 94 | ); 95 | 96 | fare_total u_fare_total ( 97 | .distance_fare_bcd (distance_fare_bcd ), 98 | .wait_fare_bcd (wait_fare_bcd ), 99 | 100 | .fare_total_bcd (fare_total_bcd ), 101 | .max (max ) 102 | ); 103 | 104 | seg_disp u_seg_disp ( 105 | .fare_total_bcd (fare_total_bcd ), 106 | .distance_bcd (distance_bcd ), 107 | .max (max ), 108 | 109 | .fare_a (fare_a ), 110 | .fare_b (fare_b ), 111 | .fare_c (fare_c ), 112 | .fare_d (fare_d ), 113 | .distance_a (distance_a ), 114 | .distance_b (distance_b ) 115 | ); 116 | 117 | endmodule 118 | -------------------------------------------------------------------------------- /src/distance_fare.v: -------------------------------------------------------------------------------- 1 | //计算里程和价格 2 | //输入里程单价 3 | //计算距离 4 | /* 5 | ten_meter_pulse -> 输入的十米脉冲 6 | en -> 输入的使能信号 7 | rst_n -> 输入的复位信号 8 | wait_en -> 输入的等待启用信号 9 | distance_fare_per_pulse -> 以BCD码输入的每脉冲的价格 10 | s_fare -> 输入的起步价 11 | max -> 输入的计满信号,由fare_total产生 12 | 13 | distance_bcd -> 以BCD码输出的距离 14 | distance_fare_bcd -> 以BCD码输出的里程费用 15 | */ 16 | module distance_fare ( 17 | input wire ten_meter_pulse, 18 | input wire en, 19 | input wire rst_n, 20 | input wire wait_en, 21 | input wire [11:0] distance_fare_per_pulse, 22 | input wire [11:0] s_fare, 23 | input wire max, 24 | 25 | output wire [7:0] distance_bcd, 26 | output wire [15:0] distance_fare_bcd 27 | ); 28 | 29 | //里程计满标志 30 | reg max_distance; 31 | //四位BCD码加法器输出费用计满信号 32 | wire max_fare; 33 | //下一个要加上的里程费用 34 | wire [15:0] fare_next; 35 | //里程费用计满标志 36 | reg distance_fare_flag = 1'b0; 37 | //当前的里程费用 38 | reg [15:0] fare = 16'b0; 39 | //当前的里程 40 | reg [16:0] distance = 16'b0; 41 | 42 | //结果输出,防止出现不定态,先给寄存器赋初值,后赋给wire类型变量 43 | //因里程需要用两位数码管输出,故只将高二位输出 44 | assign distance_bcd = distance[15:8]; 45 | assign distance_fare_bcd = fare; 46 | 47 | always@(posedge ten_meter_pulse or negedge rst_n) begin 48 | //判断复位信号,为低电平则将里程和里程计满标志置0 49 | if (!rst_n) begin 50 | distance <= 16'd0; 51 | max_distance <= 1'b0; 52 | end 53 | //判断是否达到暂停计里程条件(en为低电平,且wait_en为高电平) 54 | //满足该条件则暂停计算里程 55 | //费用计满后里程继续计费,直到计满,价格计满信号不影响里程计算 56 | else if(!en || wait_en) begin 57 | distance <= distance; 58 | end 59 | //因未使用BCD加法器计算里程(里程每脉冲10m),所以里程为16位,判断是否超过9999,超过则将标志位置1 60 | else if (distance > 16'h9999) begin 61 | max_distance <= 1'b1; 62 | end 63 | //判断里程计满标志是否为1,为1则直接输出最大值 64 | else if (max_distance) begin 65 | distance <= 16'h9999; 66 | end 67 | else begin 68 | //直接用BCD码计数,没用加法器 69 | //将二进制数转换成BCD码 70 | distance <= ((distance[3:0]==4'd9) & (distance[7:4]!=4'd9)) ? (distance + 8'h11-8'h0a) : 71 | ((distance[3:0]==4'd9) & (distance[7:4]==4'd9) & (distance[11:8]!=4'd9)) ? (distance + 12'h111-12'h0aa) : 72 | ((distance[3:0]==4'd9) & (distance[7:4]==4'd9) & (distance[11:8]==4'd9) & (distance[15:12]!=4'd9)) ? (distance + 16'h1111-16'h0aaa) : 73 | distance + 1'd1; 74 | end 75 | end 76 | 77 | always@(posedge ten_meter_pulse or negedge rst_n) begin 78 | //判断复位信号,为低电平则将里程费和里程费计满标志置0 79 | if (!rst_n) begin 80 | fare <= 16'd0; 81 | distance_fare_flag <= 1'b0; 82 | end 83 | //判断是否达到暂停计费条件(en为低电平,且wait_en和max为高电平) 84 | //满足该条件则暂停计费 85 | else if(!en || max || wait_en) begin 86 | fare <= fare; 87 | end 88 | //判断加法器是否有本位进位,有则将费用设置为最大值并将费用计满标志置1 89 | else if (max_fare) begin 90 | fare <= 16'h9999; 91 | distance_fare_flag <= 1'b1; 92 | end 93 | //判断费用计满标志是否为1,满足则将费用设置为最大值99.99 94 | else if (distance_fare_flag) begin 95 | fare <= 16'h9999; 96 | end 97 | //判断是否在起步价包含的里程数范围内,在则输出起步价 98 | else if (distance < 16'h300) begin 99 | fare <= s_fare; 100 | end 101 | //若属于正常计费区间,则计算里程费用 102 | else begin 103 | fare <= fare_next; 104 | end 105 | end 106 | 107 | //调用bcd_adder_4模块实现里程费用计算 108 | //调整了输入的每十米费用位宽,防止出现不定态 109 | bcd_adder_4 distance_fare_adder ( 110 | .a (fare ), 111 | .b ({4'b0000,distance_fare_per_pulse} ), 112 | .c_in (1'b0 ), 113 | 114 | .sum (fare_next ), 115 | .c_out (max_fare ) 116 | ); 117 | 118 | endmodule 119 | --------------------------------------------------------------------------------