资源描述
目录
引言 1
1、设计内容 1
2、设计原理 1
3、 CPLD简介 2
3.1 、CPLD的基本结构 2
3.2、 CPLD的特点 3
4、系统功能模块设计 4
4.1、计算里程和车费模块 4
4.3、按键扫描模块 17
4.4结构描述实现出租车计费器电路系统设计 20
4.5、仿真电路图 21
5、硬件实现 22
5.1、引脚锁定 22
5.2、编程下载 23
6、总结与体会 23
7、参考文献 23
附录:电气信息学院课程设计评分表 24
引言
Verilog HDL是一种硬件描述语言(HDL:Hardware Discription Language),是一种用文本形式来描述数字系统硬件的结构和行为的语言,用它可以表示逻辑电路图、逻辑表达式,还可以表示数字逻辑系统所完成的逻辑功能。
Verilog HDL和VHDL是目前世界上最流行的两种硬件描述语言,都是在20世纪80年代中期开发出来的。现在,随着系统级FPGA以及片上系统的出现,软硬件协同设计和系统设计变得越来越重要。传统意义上的硬件设计越来越倾向于与系统设计和软件设计相结合。
随着出租车行业的发展,对出租车计费器的要求也越来越高,用户不仅要求计费器性能稳定计费准确,而且要求在乘坐出租车时,显示起步价、行车里程二部分,由自动计费器自动记录。安装在与汽车轮相连接的传感器在汽车行进时向自动计费器发送脉冲信号,在一定的公里数内,按起步价计费;超过这一里程后,自动计费器按里程计费;超过一定费用后,则则增加里程费用;如果停车等候,则不收费。
本文以Altera公司的DE2开发板为中心,Quartus Ⅱ软件作为开发平台,使用Verilog HDL语言编程,设计了一个出租车计费的计费器模型。在程序描述的过程中,用了行为描述方式和结构描述方式二种描述方式对计费器进行描述。该计费器能动态扫描电路,将车费和路显示出来,各有两位小数。整个自动控制系统由三个主要电路构成:里程和车费计算、译码和动态显示。最后给出了仿真的波形,并硬件实现。
1、设计内容
(1)实现计费功能,计费标准为:按行驶里程计费,起步价为8.00元,并在车行3Km后按2.50元/Km计费,当计费器达到或超过20元时,公里加收50%的车费,车停止不计费。
(2)现场模拟功能:能模拟汽车起动、停止、暂停以及加速等状态。
(3)按计动态扫描电路,将车费和路程显示出来,各有两位小数。
2、设计原理
本文设计了一个出租车计费器的模型,其接口信号如图(一) 所示。
图(一) 出租车计费器模型方框图
车的状态由传感器传回来当作控制信号,用控制信号来控制计算里程和车费模块,然后分别将里程和车费送到译码模块译码,输出的数据一起送到动态扫描模块,由片选信号控制哪部分译码模块输出的数据用数码管显示。
当车启动后,计算里程和车费模块就开始计数,起步价为7.00元,并在车行3Km后按2.5元/Km计费,当计费器达到或超过20元时,每公里回收50%的车费,车停止和暂停时不计费;然后将里程和车费送到译码模块译码和动态显示模块动态显示,最后显示在七段数码管上,动态显示的时间间隔为5秒钟。
3、 CPLD简介
复杂可编程逻辑器件CPLD与现场可编程门阵列FPGA都是在PLA、PAL、GAL等逻辑器件的基础上发展起来的。与以往的PLA、PAL、GAL等相比较,FPGA/CPLD的规模比较大,它可以替代几十甚至几千块通用IC芯片。这样的FPGA/CPLD实际上就是一个子系统部件。这种芯片受到世界范围内电子工程设计人员的广泛关注和普遍欢迎。
3.1 、CPLD的基本结构
CPLD的集成度在千门/片以上,其基本结构是由与阵列、或阵列、输入缓冲电路、输出宏单元组成。其与阵列比PAL大得多,但并非靠简单的增大阵列的输入、输出端口达到。阵列占用芯片的面积随其输入端数的增加而急剧增加,而芯片面积的增大不仅使芯片的成本增大,还使信号在阵列中传输延迟加大而影响其运行速度。所以CPLD通常是由多个类似PAL功能块组成,具有很大的固定于芯片上的布线资源,通过位于中心的互连矩阵连接在一起。
互连阵列要将来自I/O的信号和逻辑块的输出布线到器件内任何逻辑块的输入。一般互连矩阵有两种形式:基于阵列的互连和基于多路开关的互连。基于阵列的互连是纵横开关的实现方式,它允许任何输入到互连矩阵中的信号布线到任何逻辑块,是完全可布通的。基于多路开关的互连是对逻辑块的每个输入有一个多路转换器,输入到互连矩阵的信号被连接到每个逻辑块的大量多路开关的输入端,这些多路转换器的选择是可编程的,只允许其一个输入通过它进入逻辑块。所以布通率与多路转换器的输入宽度有关,宽度愈大,所占面积增加,性能降低。
与FPGA相比,CPLD不采用分段互连方式,因而具有较大的时间可预测性,产品可以给出引腿到引腿的最大延迟时间;此外,CPLD具有很宽的输入结构,适合于实现高级的有限状态机;具有ISP性能的CPLD,可以直接在系统内对其进行编程,因而类似于具有ISP性能的SRAM查找表类型的FPGA。
3.2、 CPLD的特点
20世纪80年代中期,Altera和Xilinx分别推出了类似于PAL结构的扩展型CPLD和与标准门阵列类似的FPGA ,它们都具有体系结构和逻辑单元灵活、集成度高以及适用范围宽等特点。这两种器件兼容了PLD和通用门阵列的优点,可实现较大规模的电路,编程也很灵活,具有以下特点:
(1) 目前的 CPLD主要是基于E2 PROM或 FLASH存储器编程 ,编程次数达 1万次。其优点是在系统断电后 ,编程信息不丢失。CPLD又可分为在编程器上编程和在系统编程 (ISP) CPLD两种。 ISP器件的优点是不需要编程器 ,可先将器件装焊于印制板 ,再经过编程电缆进行编程,编程、调试和维护都很方便 。
(2) CPLD是将多个可编程阵列逻辑 (PAL)器件集成到一个芯片 ,具有类似 PAL的结构。一般情况下CPLD器件中至少包含三种结构 :可编程逻辑功能块 (FB);可编程 I/ O单元 ;可编程内部连线 。
(3) 在速度上CPLD优于 FPGA。由于 FPGA是门级编程 ,且 CLB之间是采用分布式互连 ;而 CPLD是逻辑块级编程 ,且其逻辑块互连是集总式的。因此 ,CPLD比 FPGA有较高的速度和较大的时间可预测性 ,产品可以给出引腿到引腿的最大延迟时间 。
(4) FPGA/CPLD软件包中有各种输入工具和仿真工具,以及版图设计工具和编程器等全线产品,电路设计人员在很短的时间内就可完成电路的输入、编译、优化、仿真,直至最后芯片的制作。
(5) 电路设计人员使用FPGA/CPLD进行电路设计时,软件易学易用。
4、系统功能模块设计
4.1、计算里程和车费模块
本模块主要是计算里程和车费。按行驶里程计费,起步价为8.00元,并在车行3Km后按2.5元/Km计费,当计费器达到或超过20元时,每公里回收50%的车费,车停止和暂停时不计费。在本模块中,一个脉冲代表是里程要加1米。计算里程和车费的模块的功能结构框图如图4-1所示。
图4-1
根据模块实现的功能设计Verilog HDL源代码如下:
module dynamic_segled
(
input clk,
input rst_n,
input [2:0] key_value,
input key_flag,
input key_up_flag,
output reg [19:0] luchen,
output reg [19:0] chefei,
output reg [2:0] led,
output reg buzzer
);
parameter qqq = 20'd7809;
parameter qibj = 8'd80;
parameter dj = 8'd25;
parameter dj_1 = 8'd38;
reg [15:0] cnt;
reg [2:0] key;
always@(posedge key_flag or posedge key_up_flag or negedge rst_n)
begin
if(!rst_n)
begin
key =3'b1111;
end
else
begin
key = key_value;
end
end
reg stop,start;
reg[7:0] cheshu;
always@(posedge key_up_flag or negedge rst_n)
begin
if(!rst_n)
begin
start = 0;
start = 0;
led = 0;
cheshu = 5;
end
else
begin
if(key == 3'b110)
if(cheshu < 8'd30)
cheshu = cheshu + 2'd2;
else
cheshu = 5;
else
cheshu = cheshu;
if(key == 3'b101)
begin
start = ~start;
led[1] = ~led[1];
end
else
begin
start = start;
led[1] = led[1];
end
if(key == 3'b011)
begin
stop = ~stop;
led[2] = ~led[2];
end
else
begin
stop = stop;
led[2] = led[2];
end
end
end
reg [25:0] cnt1;
reg cnt1_r0,cnt1_r1,cnt1_r2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt1 <= 0;
cnt1_r0 <= 0;
end
else
begin
if(cnt1 < 26'd5000000)
begin
cnt1 <= cnt1 + 26'd1;
cnt1_r0 <= 0;
end
else
begin
cnt1 <= 0;
cnt1_r0 <= 1;
end
end
end
wire cnt1_flag;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt1_r1 <= 0;
cnt1_r2 <= 0;
end
else
begin
cnt1_r1 <= cnt1_r0;
cnt1_r2 <= cnt1_r1;
end
end
assign cnt1_flag = ~cnt1_r1&cnt1_r2;
always@(posedge cnt1_flag or negedge rst_n)
begin
if(!rst_n)
begin
luchen = 0;
chefei = 0;
end
else
begin
if(stop)
begin
if(start)
begin
luchen = luchen + cheshu;
if(luchen < 20'd3000)
chefei = qibj;
else if(luchen < qqq)
chefei = qibj + (luchen - 20'd3000) * dj /20'd1000;
else
chefei = 20'd200 +(luchen - qqq) * dj_1 /20'd1000;
end
else
luchen = luchen;
chefei = chefei;
end
else
begin
luchen = 0;
chefei = 0;
end
end
end
endmodule
该模块定义输入输出端口如下:
■ clk: 全局时钟信号,这里为1Hz的时钟。
■ key_value: 当stop=0时,车停止;stop=1时,车没停止。
■ led: 当start= 0时,车起动,但没有走;start= 1时,车开动了。
■ key_flag: 当pause =0时,车暂停;pause =1时,车不暂停。
■ chefei: 表示车费。
■ lucheng:表示里程。
在Altera公司的软件工具Quartus Ⅱ(Windows7环境下)中编译和波形仿真后得到的波形如图4-2所示:
图4-2计算里程和车费模块的仿真波形
2.显示译码器模块
本模块主要是将4位二进制数转换为十六进制表示。七段显示译码器模块的功能结构框图如图4-3所示:
图4-3 七段显示译码器的功能结构框图
根据模块实现的功能设计Verilog HDL源代码如下:
module seg
(
input clk,
input rst_n,
input [19:0] time_z,
input [19:0] time_y,
output reg [7:0] data,
output reg [7:0] sel
);
parameter se1 = 8'b1111_1110;
parameter se2 = 8'b1111_1101;
parameter se3 = 8'b1111_1011;
parameter se4 = 8'b1111_0111;
parameter se5 = 8'b1110_1111;
parameter se6 = 8'b1101_1111;
parameter se7 = 8'b1011_1111;
parameter se8 = 8'b0111_1111;
parameter se_1 = 8'hf9;
parameter se_2 = 8'ha4;
parameter se_3 = 8'hb0;
parameter se_4 = 8'h99;
parameter se_5 = 8'h92;
parameter se_6 = 8'h82;
parameter se_7 = 8'hf8;
parameter se_8 = 8'h80;
parameter se_9 = 8'h90;
parameter se_0 = 8'hc0;
parameter se_A = 8'h88;
parameter se_B = 8'h83;
parameter se_C = 8'hc6;
parameter se_D = 8'ha1;
parameter se_E = 8'h86;
parameter se_F = 8'h8e;
reg [15:0] cnt;
reg [2:0] flip_led;
always@(posedge clk or negedge rst_n) //
begin
if(!rst_n)
begin
cnt <= 0;
flip_led <= 0;
end
else
begin
cnt <= cnt + 1'b1;
flip_led <= cnt[15:13];
end
end
reg [7:0] time1_ge;
reg [7:0] time1_shi;
reg [7:0] time1_bai;
reg [7:0] time1_qia;
reg [7:0] time2_ge;
reg [7:0] time2_shi;
reg [7:0] time2_bai;
reg [7:0] time2_qia;
always@(flip_led or time_z or time_y)
begin
time1_ge = time_z/10%10;
time1_shi = time_z/100%10;
time1_bai = time_z/1000%10;
time1_qia = time_z/10000%10;
case(time1_ge)
0: time1_ge = se_0;
1: time1_ge = se_1;
2: time1_ge = se_2;
3: time1_ge = se_3;
4: time1_ge = se_4;
5: time1_ge = se_5;
6: time1_ge = se_6;
7: time1_ge = se_7;
8: time1_ge = se_8;
9: time1_ge = se_9;
default:time1_ge = 8'hz;
endcase
case(time1_shi)
0: time1_shi = se_0;
1: time1_shi = se_1;
2: time1_shi = se_2;
3: time1_shi = se_3;
4: time1_shi = se_4;
5: time1_shi = se_5;
6: time1_shi = se_6;
7: time1_shi = se_7;
8: time1_shi = se_8;
9: time1_shi = se_9;
default:time1_shi = 8'hz;
endcase
case(time1_bai)
0: time1_bai = se_0;
1: time1_bai = se_1;
2: time1_bai = se_2;
3: time1_bai = se_3;
4: time1_bai = se_4;
5: time1_bai = se_5;
6: time1_bai = se_6;
7: time1_bai = se_7;
8: time1_bai = se_8;
9: time1_bai = se_9;
default:time1_bai = 8'hz;
endcase
case(time1_qia)
0: time1_qia = se_0;
1: time1_qia = se_1;
2: time1_qia = se_2;
3: time1_qia = se_3;
4: time1_qia = se_4;
5: time1_qia = se_5;
6: time1_qia = se_6;
7: time1_qia = se_7;
8: time1_qia = se_8;
9: time1_qia = se_9;
default:time1_qia = 8'hz;
endcase
time2_ge = time_y%10;
time2_shi = time_y/10%10;
time2_bai = time_y/100%10;
time2_qia = time_y/1000%10;
case(time2_ge)
0: time2_ge = se_0;
1: time2_ge = se_1;
2: time2_ge = se_2;
3: time2_ge = se_3;
4: time2_ge = se_4;
5: time2_ge = se_5;
6: time2_ge = se_6;
7: time2_ge = se_7;
8: time2_ge = se_8;
9: time2_ge = se_9;
default:time2_ge = 8'hz;
endcase
case(time2_shi)
0: time2_shi = se_0;
1: time2_shi = se_1;
2: time2_shi = se_2;
3: time2_shi = se_3;
4: time2_shi = se_4;
5: time2_shi = se_5;
6: time2_shi = se_6;
7: time2_shi = se_7;
8: time2_shi = se_8;
9: time2_shi = se_9;
default:time2_shi = 8'hz;
endcase
case(time2_bai)
0: time2_bai = se_0;
1: time2_bai = se_1;
2: time2_bai = se_2;
3: time2_bai = se_3;
4: time2_bai = se_4;
5: time2_bai = se_5;
6: time2_bai = se_6;
7: time2_bai = se_7;
8: time2_bai = se_8;
9: time2_bai = se_9;
default:time2_bai = 8'hz;
endcase
case(time2_qia)
0: time2_qia = se_0;
1: time2_qia = se_1;
2: time2_qia = se_2;
3: time2_qia = se_3;
4: time2_qia = se_4;
5: time2_qia = se_5;
6: time2_qia = se_6;
7: time2_qia = se_7;
8: time2_qia = se_8;
9: time2_qia = se_9;
default:time2_qia = 8'hz;
endcase
case(flip_led)
0: begin
data = time1_qia; //'0'
sel = se1;
end
1: begin
data = time1_bai - 8'h80; //'1'
sel = se2;
end
2: begin
data = time1_shi; //'2'
sel = se3;
end
3: begin
data = time1_ge; //'3'
sel = se4;
end
4: begin
data = time2_qia; //'4'
sel = se5;
end
5: begin
data = time2_bai; //'5'
sel = se6;
end
6: begin
data = time2_shi - 8'h80; //'6'
sel = se7;
end
7: begin
data = time2_ge; //'7'
sel = se8;
end
default:
begin
data = 8'hz; //
sel = 8'bz;
end
endcase
end
endmodule
程序定义输入输出端口如下:
■ a: 输入的4位二进制数。
■ hex:输出的1位十六进制数。
在Altera公司的软件工具Quartus Ⅱ(Windows XP环境下)中编译和波形仿真后得到的波形如图4-4所示:
图4-4 七显示译码器的仿真波形
4.3、按键扫描模块
module key_scan_jitter
#(
parameter KEY_WIDTH = 3
)
(
input clk,
input rst_n,
input [KEY_WIDTH-1:0] key_data,
output key_flag,
output key_up_flag,
output reg [KEY_WIDTH-1:0] key_value
);
reg [19:0] cnt; //delay_5ms(249999)
reg [2:0] state;
//-----------------------------------
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <= 20'd0;
else
begin
cnt <= cnt + 1'b1;
if(cnt == 20'd249999)
cnt <= 20'd0;
end
end
//-----------------------------------
reg key_flag_r;
reg [KEY_WIDTH-1:0] key_data_r;
reg key__r;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
key_flag_r <= 1'b1;
key_value <= {KEY_WIDTH{1'b0}};
end
else if(cnt == 20'd249999) //Delay_5ms
begin
case(state)
0:
begin
if(key_data != {KEY_WIDTH{1'b1}})
state <= 1;
else
state <= 0;
end
1:
begin
if(key_data != {KEY_WIDTH{1'b1}})
state <= 2;
else
state <= 0;
end
2:
begin
key_value <= key_data; //lock the key_value
state <= 3;
end
3:
begin
key_flag_r <= 1'b0; //read the key_value
if(key_data == {KEY_WIDTH{1'b1}})
state <= 4;
else
state <= 3;
end
4:
begin
if(key_data == {KEY_WIDTH{1'b1}})
begin
state <= 0;
key_flag_r <= 1'b1;
end
else
begin
state <= 4;
key_flag_r <= key_flag_r ;
end
end
endcase
end
end
//---------------------------------------
//Capture the falling endge of the key_flag
reg key_flag_r0,key_flag_r1;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
key_flag_r0 <= 0;
key_flag_r1 <= 0;
end
else
begin
key_flag_r0 <= key_flag_r;
key_flag_r1 <= key_flag_r0;
end
end
assign key_flag = key_flag_r1 & ~key_flag_r0;
assign key_up_flag = ~key_flag_r1 & key_flag_r
4.4结构描述实现出租车计费器电路系统设计
module qljs
(
input clk,
input rst_n,
input [KEY_WIDTH-1:0] key_data,
output [KEY_WIDTH-1:0] led_value,
output [7:0] data,
output [7:0] sel,
output buzzer
);
parameter KEY_WIDTH = 3;
wire key_flag;
wire key_up_flag;
wire [KEY_WIDTH-1:0] key_value;
wire [19:0] luchen,chefei;
key_scan_jitter
#(
.KEY_WIDTH (KEY_WIDTH)
)
U_key_scan_jitter
(
.clk (clk),
.rst_n (rst_n),
.key_data (key_data),
.key_flag (key_flag),
.key_up_flag (key_up_flag),
.key_value (key_value),
);
dynamic_segled U_dynamic_segled
(
.clk (clk),
.rst_n (rst_n),
.key_value (key_value),
.key_flag (key_flag),
.key_up_flag (key_up_flag),
.luchen (luchen),
.chefei (chefei),
.led (led_value),
.buzzer (buzzer)
);
seg U_seg
(
.clk (clk),
.rst_n (rst_n),
.time_z (luchen),
.time_y (chefei),
.data (data),
.sel (sel)
);
Endmodule
4.5、仿真电路图
5、硬件实现
5.1、引脚锁定
对出租车计费器进行实验验证时,需要确定用DE2开发板的哪些输入/输出端口(PIO)来表示设计电路的输入输出。根据DE2开发板提供的实验模式,可选择电平开关SW2~SW0作为出租车计费器的控制信号;选择HEX4~HEX0作为里程和车费的输出显示。出租车计费器与DE2中的目标芯片引脚连接的全部关系见表1-1。
表1-1 出租车计费器与DE2中的目标芯片引脚连接关系表
端口名称
PIO名称
芯片引脚
端口名称
PIO名称
芯片引脚
stop
DPDT_SW[0]
PIN_N25
hex2[1]
HEX2[1]
PIN_V22
start
DPDT_SW[1]
PIN_N26
hex2[2]
HEX2[2]
PIN_AC25
pause
DPDT_SW[2]
PIN_P25
hex2[3]
HEX2[3]
PIN_AC26
cin
OSC_50
PIN_N2
hex2[4]
HEX2[4]
PIN_AB26
cin0
OSC_50
PIN_N2
hex2[5]
HEX2[5]
PIN_AB25
hex0[0]
HEX0[0]
PIN_AF10
hex2[6]
HEX2[6]
PIN_Y24
hex0[1]
HEX0[1]
PIN_AB12
hex3[0]
HEX3[0]
PIN_Y23
hex0[2]
HEX0[2]
PIN_AC12
hex3[1]
HEX3[1]
PIN_AA25
hex0[3]
HEX0[3]
PIN_AD11
hex3[2]
HEX3[2]
PIN_AA26
hex0[4]
HEX0[4]
PIN_AE11
hex3[3]
HEX3[3]
PIN_Y26
hex0[5]
HEX0[5]
PIN_V14
hex3[4]
HEX3[4]
PIN_Y25
hex0[6]
HEX0[6]
PIN_V13
hex3[5]
HEX3[5]
PIN_U22
hex1[0]
HEX1[0]
PIN_V20
hex3[6]
HEX3[6]
PIN_W24
hex1[1]
HEX1[1]
PIN_V21
hex4[0]
HEX4[0]
PIN_U9
hex1[2]
HEX1[2]
PIN_W21
hex4[1]
HEX4[1]
PIN_U1
hex1[3]
HEX1[3]
PIN_Y22
hex4[2]
HEX4[2]
PIN_U2
hex1[4]
HEX1[4]
PIN_AA24
hex4[3]
HEX4[3]
PIN_T4
hex1[5]
HEX1[5]
PIN_AA23
hex4[4]
HEX4[4]
PIN_R7
hex1[6]
HEX1[6]
PIN_AB24
hex4[5]
HEX4[5]
PIN_R6
hex2[0]
HEX2[0]
PIN_AB23
hex4[6]
HEX4[6]
PIN_T3
5.2、编程下载
将程序下载到DE2开发板上,扳动SW0~SW2,组成控制信号,从七段数码管HEX4~HEX0上观察里程和车费。
6、总结与体会
EDA的设计至今为止已经进入了令人鼓舞的阶段,在进行了长达两个星期的时间的摸索与实验,使我不仅仅是对于EDA入门软件与硬件的常用设计与功能,还使我对于一项设计研究的制作过程所需要的详细步骤和具体的实现方法的力度的掌握。
当然在这次宝贵的课程设计中,经验才是对于我们最大的收获,而且还增强了自身对未知问题以及对知识的深化认识的能力,用受益匪浅这个词语来概括这次难忘的活动我觉得再合适不过了。但是,光是完成了作品还是不可以自我满足的,在从一开始的时候就怀着将作品制作得更加人性化,更加令人满意,更加地使功能完美又方便地被应用领
展开阅读全文