其他分享
首页 > 其他分享> > 杭电数字电路课程设计——出租车计费器

杭电数字电路课程设计——出租车计费器

作者:互联网

杭电数字电路课程设计——出租车计费器

实验目的

(1)学习数码管动态扫描方法,进一步熟悉模块调用的方法,锻炼编程设计数字系统的能力。
(2)掌握灵活运用Verilog HDL语言进行各种描述与建模的技巧和方法。

模块设计

(1)分频模块:因出租车计费器模拟以秒为单位,即分频1秒产生一个clk_out,控制其他模块工作。
(2)计程模块:用于根据有效的单位时间、速度来增加相应的里程数。
(3)出租车等红绿灯模块:用于进行等红绿灯时的计时,若为10秒,产生一个time_enable信号控制计费器是否进行等红绿灯计费。
(4)计费模块:根据传入的里程来计算相应的费用,以及根据time_enable信号判断是否增加额外的等红绿灯计费。
(5)数码管刷新模块:用于刷新数码管,以62.5Hz为刷新率保证人视觉上感受不到数码管的闪烁。
(6)二进制转BCD码模块:用于将传入的里程、费用转换成BCD码以便于数码管显示。
(7)数码管显示模块:根据相应的控制信号来将里程或费用转换成位选、段选信号来实现数码管的实现。
程序模块关系
(1)分频模块的分频1s有效的时钟信号控制计程模块、出租车等红绿灯模块、计费模块工作。
(2)计程模块的里程数用于计费模块的费用计算。
(3)出租车等红绿灯模块的time_enable用于控制计费模块是否产生出租车等红绿灯额外费用。
(4)数码管刷新模块产生的位选信号用于控制数码管显示。
(5)二进制转BCD码模块产生的里程BCD码、费用BCD码用于数码管显示。

程序源代码

module sy_last_code(reset, clk_M, start, pause, waitL, speedup, d_m, Seg, AN);
    input reset;
    input clk_M;
    input start;
    input pause;
    input waitL;
    input [1:0] speedup;
    input d_m;
    //段选
    output [7:0] Seg;
    //位选
    output [3:0] AN;
     
    wire [9:0] fee_before;
    wire [9:0] distance_before;
    wire [15:0] distance_b;
    wire [15:0] fee_b;
    wire time_enable;
    wire clk_out;
    wire [1:0] Bit_Sel;
    Fdiv u1(reset, clk_M, clk_out);
    // 计程
    Distance u2(clk_out, reset, start, speedup, waitL, pause, distance_before);
    // 等待红绿灯时间
    Time u3(clk_out, reset, pause, waitL, time_enable);
    // 计费
    Fee u4(clk_out, reset, waitL, pause, time_enable, distance_before, start, fee_before);
    // 分频刷新数码管
    Delay_4ms u5(clk_M, Bit_Sel);
    // 二进制转换为BCD码
    Binary u6(distance_before, distance_b);
    Binary u7(fee_before, fee_b);
    // 显示数码管
    Smg u8(d_m, fee_b, distance_b, Bit_Sel, Seg, AN);
 
endmodule
 
 
//分频模块
// 1s
module Fdiv(
    input wire reset,
    input wire clk_M,
    output reg clk_out
);
    // 定义计数器
    reg [31:0] counter;
    initial begin counter = 32'd0; end
    initial begin clk_out = 0; end
    always @(posedge reset or posedge clk_M)
        begin
            if(reset)
                begin
                    // reset 置0
                    counter <= 32'd0;
                    clk_out <= 1'b0;
                end
            else if(counter == 32'd12_500_000)
                begin
                    clk_out <= ~clk_out;
                    counter <= 32'd0;
                end
            else 
                begin
                    counter <= counter + 1'b1;
                    clk_out <= 0;
                end
        end
endmodule
 
//计程模块
module Distance(
    input wire clk,
    // 汽车复位
    input wire reset,
    // 汽车启动
    input wire start,
    input wire [1:0] speedup,
    // 等车(红绿灯)
    input wire waitL,
    // 暂停汽车行为
    input wire pause,
    output reg [9:0] distance
);
    initial begin distance = 10'b0; end
    always @(posedge reset or posedge clk)
        begin
            if(reset)
                begin
                    distance <= 10'd0;
                end
            else if(start && !waitL && !pause)
                begin
                    case(speedup)
                        2'b0_0: begin distance <= distance + 10'd1; end
                        2'b0_1: begin distance <= distance + 10'd2; end
                        2'b1_0: begin distance <= distance + 10'd3; end
                        2'b1_1: begin distance <= distance + 10'd4; end
                    endcase
                end         
        end
endmodule
       
// 计时模块用于当等待红灯的时候
module Time(
     input wire clk,
    input wire reset,
    input wire pause,
    input wire waitL,
    output reg time_enable
);
  reg [7:0]count;
  initial begin count = 8'd0; end
  initial begin time_enable = 0; end
  always @(posedge reset or posedge clk)
    begin
        if(reset)
            begin
                count <= 8'd0;
                time_enable <= 0; 
            end
        else if(count == 8'd10)
                begin
                    time_enable <= ~time_enable;
                    count <= 8'd0;
                end
          else if(!pause && waitL)
            begin
                    count <= count + 1'd1;
                    time_enable <= 0;
            end
    end
endmodule
 
       
// 计费
module Fee(
    input wire clk,
    input wire reset,
    input wire waitL,
    input wire pause,
    input wire time_enable,
    input wire [9:0] distance,
    input wire start,
    output reg [9:0] fee
);
    initial begin fee <= 10'b0; end
    parameter s_fee = 10'd60;
    always @(posedge reset or posedge clk)
        begin
            if(reset)
                begin
                    fee <= 16'd0;
                end
            else if(start && !waitL && !pause)
                begin
                    if(distance <= 30)
                        begin
                            fee <= s_fee;
                        end
                    else if(fee < 10'd200)
                        begin
                            fee <= s_fee + (12 * (distance - 30)) / 10;
                                     if(fee > 10'd200)
                                        begin
                                            fee <= s_fee + (18 * (distance - 30)) / 10;
                                        end
                        end
                    else
                        begin
                            fee <= s_fee + (18 * (distance - 30)) / 10;
                        end
                end
            else if(time_enable)
                begin
                    fee <= fee + 10'd5;
                end
        end
endmodule
 
// 分频刷新数码管 
module Delay_4ms(clk_M,Bit_Sel);
    input wire clk_M;
    output reg [1:0] Bit_Sel;
    // 定义计数器
    integer counter = 0;
    initial begin Bit_Sel <= 2'b00; end
    always@(posedge clk_M)
        begin
            counter <= counter + 1;
            // 25MHz 时钟脉冲
            // 采用62.5Hz刷新频率,得到16ms一遍,每个数码管选通路的时间4ms
            if(counter == 100000)
            begin 
                Bit_Sel <= Bit_Sel + 2'b01;
                counter <= 0;
            end
  end
endmodule
 
// 数码管显示
module Smg(
    input wire d_m,
    input wire [15:0] fee,
    input wire [15:0] distance, 
    //数码管选择
    input wire [1:0] Bit_Sel,  
    //段选
    output reg [7:0] Seg,
    //位选
    output reg [3:0] AN
);
 
    reg [3:0]  Data_now;
    reg [7:0]  duan_ctrl;
     initial 
        begin 
            Data_now = 4'b0; 
            duan_ctrl = 8'b0;
        end
      
    always @(*)
        begin
            case(Bit_Sel)
                2'b00:AN<=4'b1000;
                2'b01:AN<=4'b1001;
                2'b10:AN<=4'b1010;
                2'b11:AN<=4'b1011;
                default:AN<=4'b1111;
            endcase
        end
    always  @(*)
        begin
            if(d_m)
                begin
                    case(Bit_Sel)
                        2'b00: Data_now[3:0] <= distance[15:12];
                        2'b01: Data_now[3:0] <= distance[11:8];
                        2'b10: Data_now[3:0] <= distance[7:4];
                        2'b11: Data_now[3:0] <= distance[3:0];
                        default: Data_now[3:0] <= distance[3:0];
                    endcase
                end
            else
                begin
                    case(Bit_Sel)
                        2'b00: Data_now[3:0] <= fee[15:12];
                        2'b01: Data_now[3:0] <= fee[11:8];
                        2'b10: Data_now[3:0] <= fee[7:4];
                        2'b11: Data_now[3:0] <= fee[3:0];
                        default: Data_now[3:0] <= fee[3:0];
                    endcase
                end
        end
    always @(*)
        begin
            // 0~9
            // 采用共阳极连接,低电平点亮,根据数码管8个信号
				if(Bit_Sel == 2'b10)
					begin 
							case(Data_now[3:0])
								 4'b0000: Seg[7:0] <= 8'b00000010;
								 4'b0001: Seg[7:0] <= 8'b10011110;
								 4'b0010: Seg[7:0] <= 8'b00100100;
								 4'b0011: Seg[7:0] <= 8'b00001100;
								 4'b0100: Seg[7:0] <= 8'b10011000;
								 4'b0101: Seg[7:0] <= 8'b01001000;
								 4'b0110: Seg[7:0] <= 8'b01000000;
								 4'b0111: Seg[7:0] <= 8'b00011110;
								 4'b1000: Seg[7:0] <= 8'b00000000;
								 4'b1001: Seg[7:0] <= 8'b00001000;
								 default:Seg[7:0]<=8'b11111111;
							endcase
						end
				else
					begin
						  case(Data_now[3:0])
								 4'b0000: Seg[7:0] <= 8'b00000011;
								 4'b0001: Seg[7:0] <= 8'b10011111;
								 4'b0010: Seg[7:0] <= 8'b00100101;
								 4'b0011: Seg[7:0] <= 8'b00001101;
								 4'b0100: Seg[7:0] <= 8'b10011001;
								 4'b0101: Seg[7:0] <= 8'b01001001;
								 4'b0110: Seg[7:0] <= 8'b01000001;
								 4'b0111: Seg[7:0] <= 8'b00011111;
								 4'b1000: Seg[7:0] <= 8'b00000001;
								 4'b1001: Seg[7:0] <= 8'b00001001;
								 default:Seg[7:0]<=8'b11111111;
							endcase
					end
					
        end
endmodule
 
module Binary(bin,bcd);
    input wire [9:0] bin;
    output reg [15:0] bcd;
    initial begin bcd = 16'b0; end
    always @(*)
         begin
              bcd [ 3:0]  = bin % 10;//个位
              bcd [ 7:4]  = bin /10 % 10;//十位
              bcd [11:8] = bin / 100 % 10;//百位
              bcd [15:12] = bin / 1000 % 10;//百位
         end 
endmodule

测试程序源代码

module test;
	// Inputs
	reg reset;
	reg clk_M;
	reg start;
	reg pause;
	reg waitL;
	reg [1:0] speedup;
	reg d_m;

	// Outputs
	wire [7:0] Seg;
	wire [3:0] AN;

	// Instantiate the Unit Under Test (UUT)
	sy_last_code uut (
		.reset(reset), 
		.clk_M(clk_M), 
		.start(start), 
		.pause(pause), 
		.waitL(waitL), 
		.speedup(speedup), 
		.d_m(d_m), 
		.Seg(Seg), 
		.AN(AN)
	);

	always begin #10 clk_M = ~clk_M; end
	
	initial begin
		// Initialize Inputs
		reset = 1;
		clk_M = 0;
		start = 1;
		pause = 0;
		waitL = 0;
		speedup = 0;
		d_m = 0;

		// Wait 100 ns for global reset to finish
		#100;
      reset = 0;
		start = 1;
		pause = 0;
		waitL = 0;
		speedup = 2'b00;
		d_m = 1;  
	end
endmodule

思考及遇到的问题

1.实验出现的问题与解决方案
出现的问题:
在二进制转BCD模块中,采用判断大于4加三移位法,来实现BCD码的转换,所有情况均成立,但在9的转换上每次都是多加3。
解决方案:
最终采用了整除取余法,即个位为对10取余,十位为整除10对10取余,百位为整除100对10取余,千位为对100整除对10取余。最终经过调试测试成功。
2.思考与探索
思考题1:如果系统时钟频率是20MHz,要实现要求的档位速度,源程序应做怎样的改动?
因本实验采用系统时钟频率为25MHz计算,即要实现每秒速度,在延时模块中将count值进行修改,原25MHz分成1Hz,计数值为12_500_000;现20MHz分成1Hz,计数值为10_000_000。
思考题2:如果要求显示车费精确到1元,而显示行驶里程精确到1公里,那么程序应该如果修改?
在二进制转BCD码模块中,将个位数默认定为0即不输出小数点后的数字,意思就为精确到1元或1公里,但是寄存器中存的是完整的值,这样符合系统需求又可随时切换精度。

本文为作者原创,转载请附链接!!
完整的报告内容已经上传~
创作不易~~

标签:reset,课程设计,wire,计费器,clk,杭电,数码管,pause,模块
来源: https://blog.csdn.net/weixin_47029534/article/details/122763312