杭电数字电路课程设计——出租车计费器
作者:互联网
杭电数字电路课程设计——出租车计费器
实验目的
(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