Course design of Hangdian digital circuit -- taxi meter

Posted by JohnMC on Thu, 03 Feb 2022 03:47:59 +0100

Course design of Hangdian digital circuit -- taxi meter

Experimental purpose

(1) Learn the dynamic scanning method of nixie tube, be further familiar with the method of module call, and exercise the ability of programming and designing digital system.
(2) Master the skills and methods of flexibly using Verilog HDL language for various description and modeling.

Module design

(1) Frequency division module: because the simulation of taxi meter is in seconds, i.e. a CLK is generated by dividing the frequency by 1 second_ Out to control the operation of other modules.
(2) Meter module: used to increase the corresponding mileage according to the effective unit time and speed.
(3) Taxi and other traffic lights module: it is used for timing when waiting for traffic lights. If it is 10 seconds, a time is generated_ The enable signal controls whether the meter charges for traffic lights.
(4) Billing module: calculate the corresponding fee according to the incoming mileage and time_ The enable signal determines whether to add additional traffic light charging.
(5) Nixie tube refresh module: used to refresh the nixie tube. The refresh rate is 62.5Hz to ensure that people can't feel the flicker of the nixie tube visually.
(6) Binary to BCD code module: used to convert the incoming mileage and expenses into BCD code for nixie tube display.
(7) Nixie tube display module: convert the mileage or cost into position selection and segment selection signals according to the corresponding control signals to realize the realization of nixie tube.
Program module relationship
(1) The frequency division 1s effective clock signal of the frequency division module controls the work of the meter module, taxi and other traffic light modules and billing modules.
(2) The mileage of the metering module is used for the cost calculation of the billing module.
(3) Design of traffic light module such as taxi_ Enable is used to control whether the billing module generates additional fees for traffic lights such as taxis.
(4) The bit selection signal generated by the nixie tube refresh module is used to control the nixie tube display.
(5) Mileage BCD code and expense BCD code generated by binary BCD code conversion module are used for nixie tube display.

program source code

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;
    //Segment selection
    output [7:0] Seg;
    //Bit selection
    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);
    // calculated by mileage
    Distance u2(clk_out, reset, start, speedup, waitL, pause, distance_before);
    // Waiting time for traffic lights
    Time u3(clk_out, reset, pause, waitL, time_enable);
    // charging
    Fee u4(clk_out, reset, waitL, pause, time_enable, distance_before, start, fee_before);
    // Frequency division refresh nixie tube
    Delay_4ms u5(clk_M, Bit_Sel);
    // Binary conversion to BCD code
    Binary u6(distance_before, distance_b);
    Binary u7(fee_before, fee_b);
    // Display nixie tube
    Smg u8(d_m, fee_b, distance_b, Bit_Sel, Seg, AN);
 
endmodule
 
 
//frequency divider 
// 1s
module Fdiv(
    input wire reset,
    input wire clk_M,
    output reg clk_out
);
    // Define counter
    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 to 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
 
//Meter module
module Distance(
    input wire clk,
    // Car reset
    input wire reset,
    // Car start
    input wire start,
    input wire [1:0] speedup,
    // Waiting for the bus (traffic light)
    input wire waitL,
    // Suspension of vehicle behavior
    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
       
// The timing module is used when waiting for a red light
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
 
       
// charging
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
 
// Frequency division refresh nixie tube 
module Delay_4ms(clk_M,Bit_Sel);
    input wire clk_M;
    output reg [1:0] Bit_Sel;
    // Define counter
    integer counter = 0;
    initial begin Bit_Sel <= 2'b00; end
    always@(posedge clk_M)
        begin
            counter <= counter + 1;
            // 25MHz clock pulse
            // The refresh frequency of 62.5Hz is adopted to obtain 16ms, and the time for each nixie tube to select the channel is 4ms
            if(counter == 100000)
            begin 
                Bit_Sel <= Bit_Sel + 2'b01;
                counter <= 0;
            end
  end
endmodule
 
// Nixie tube display
module Smg(
    input wire d_m,
    input wire [15:0] fee,
    input wire [15:0] distance, 
    //Nixie tube selection
    input wire [1:0] Bit_Sel,  
    //Segment selection
    output reg [7:0] Seg,
    //Bit selection
    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
            // It adopts common anode connection, low-level lighting, and 8 signals according to the nixie tube
				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;//Bit
              bcd [ 7:4]  = bin /10 % 10;//Ten
              bcd [11:8] = bin / 100 % 10;//Hundredth
              bcd [15:12] = bin / 1000 % 10;//Hundredth
         end 
endmodule

Test program source code

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

Thinking and problems encountered

1. Problems and solutions in the experiment
Problems:
In the binary to BCD module, the shift method of judging greater than 4 plus 3 is used to realize the conversion of BCD code. All cases are true, but in the conversion of 9, 3 is added every time.
Solution:
Finally, the integer division and remainder method is adopted, that is, the individual bit is the remainder of 10, the ten bit is the remainder of 10, the hundred bit is the remainder of 100 to 10, and the thousand bit is the remainder of 100 to 10. Finally, it is successfully debugged and tested.
2. Thinking and exploration
Question 1: if the system clock frequency is 20MHz, what changes should be made to the source program to achieve the required gear speed?
Because this experiment uses the system clock frequency of 25MHz to calculate, that is, to achieve the speed per second, modify the count value in the delay module. The original 25MHz is divided into 1Hz and the count value is 12_ 500_ 000; At present, 20MHz is divided into 1Hz and the count value is 10_ 000_ 000.
Question 2: if it is required to display the fare accurately to 1 yuan and the mileage accurately to 1 km, how should the program be modified?
In the binary to BCD code module, the single digit is set to 0 by default, that is, the number after the decimal point is not output, which means that it is accurate to 1 yuan or 1 kilometer, but the complete value is stored in the register, which meets the system requirements and can switch the accuracy at any time.

This article is original by the author. Please attach a link for reprint!!
The complete report content has been uploaded ~
Creation is not easy ~ ~

Topics: Single-Chip Microcomputer