ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-02-01 12:00:29  阅读:209  来源: 互联网

标签:reset 课程设计 wire 计费器 clk 杭电 数码管 pause 模块


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

实验目的

(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有