一、 实验目标
熟练掌握 Verilog HDL 硬件描述语言,能够在实际工程中熟练使用Quartus II 软件进行可编程逻辑器件的基本开发, 能够熟练使用 Modelsim 软件进行系统的功能仿真验证, 能够正确的使用实验室各种实验仪器设备如示波器、信号发生器进行问题分析,具备使用合适的实验仪器和仿真软件,对汽车电子信息领域的复杂工程问题能够进行合理的分析、优化、计算和设计,对工程故障能够快速的定位、解决的能力。
二、实验内容
各种汽车故障在行车过程中时有发生,如果发生严重故障车载电脑未及时上报可能会发生不可挽回的损失,严重时甚至危及生命,发生一般故障如果未及时上报,提醒驾驶人员到维修点处理也会对汽车造成各种损坏,本实验是一个模拟的汽车故障指示系统设计,对车载电脑发出的一系列串行数据进行序列检测,当检测到对应的故障,根据故障严重程度进行有效指示,提醒驾驶员采取有效措施。
三、实验要求
1、 根据 FPGA 开发流程对实验项目进行合理分析,设计系统方案;
2、 使用 Verilog HDL 硬件描述语言,设计汽车故障代码指示系统,使用按键操作模拟各种故障代码的产生;
3、 对设计的汽车故障代码指示系统进行功能仿真,验证设计正确性,对出现的错误进行记录、分析;
4、 在FPGA 开发平台上进行板上验证,观察实验现象,分析设计合理性,总结实验心得。
四、实验预习(实验原理、整体设计方案等)
(一)、实验基本原理:
本次实验通过控制MINI_FPGA开发板上配有的6个七段数码管 DIG1-DIG6(当正放 MINI_FPGA 开发板时,从左至右依次数过去)模拟显示汽车故障代码指示,同时通过按键操作,使得数码管上显示对应的故障指示代码。基于这两个实验要求,我们需要使用到数码管显示数值的功能,以及按键操作功能。同时,为了使按键操作能够被准确的判断,需要在按键操作功能中增加按键消抖功能。为了使得数码管显示的故障指示代码能够随着按键的按下显示出来,需要利用按键控制数码管功能将二者联系起来,使六位数码管的故障指示代码显示数值能够随着不同按键的按下,显示出不同的故障指示数字。
(二)、整体设计方案:
1.数码管正常显示对应数值
先确定控制动态扫描的周期为:Timex = 8'd200 ,然后通过Count变量重复在动态扫描周期内重复计数、清零产生片选信号cs(由于本次实验仅启用了两个数码管,所以cs的值在0和1之间变换),再将片选信号进行译码,使得所需的对应数码管启用,由此完成数码管的启用。然后将待显示的数据变量SingleNum初始化为零,然后通过片选信号的不断变化,控制由Testbench上的测试文件数据赋给待显示的数据变量SingleNum,再将待显示的数据变量SingleNum译码成共阴极数码管驱动格式,使得启用的数码管显示出对应的数字。
2.不同按键按下使数码管显示出不同的故障数字
首先,为保证按键操作判断的准确性,需要加入按键消抖功能,具体的按键消抖功能操作为:我们首先需要一个模块来检测按键是否抖动,如果抖动,给计时模块一个标志位开始计时,记满20ms,再给输出消抖后按键信号模块一个标志位进行采样。理清思路,整个程序分为三个模块,模块之间相互关联,关联之处需要一个起到连接作用的器件,也就是标志位。比如将flag作为标志位,检测到按键抖动之后,将flag作为计时开始的条件。
然后在代码中设置好对应按键按下后六个数码管所显示的对应故障数字,如下图代码:

图4.1
我所设置的三个按键所对应的三个数码管所显示的对应故障数字分别为:222222、333333、444444。

图4.2
由于我们所输入的显示,只与四位二进制变量Result有关,所以在实际的应用中我们也可以根据自己的需要设置自己需要的故障指示数字,仅仅只需要改动代码中的那六个数字即可,无需改动其他代码,这样方便又简单的可以满足自己的需求。
五、测试验证(仿真、硬件测试)
仿真测试文件:

图5.1
仿真结果图:

图5.2
通过将仿真文件与仿真结果可以看到,由三个按键按下显示的对应故障代码为:222222、333333、444444,这与编写的代码相符合,实验仿真结果与实验仿真测试文件预测结果一致,实验代码符合实验要求。
六、实验小结
汽车故障指示在实际的应用当中是十分有必要的,这对于行车安全十分重要,能够极大的保证司机与乘客避免因为车辆故障上路而造成的不必要伤害。所以本次实验十分具有现实意义,能够为社会带来一定价值!
本次实验通过控制MINI_FPGA开发板上配有的6个七段数码管 DIG1-DIG6(当正放 MINI_FPGA 开发板时,从左至右依次数过去)模拟显示汽车故障代码指示,然后通过不同按键的按下,显示出不同的故障指示数字。
本次实验也是综合了按键消抖实验以及数码管实验,可见一些基础性实验对于复杂项目的必要性。对于FPGA的学习我们要一点点的积累,才能有不断的进步,相信自己一定会有所提高的!
七、实验代码
module sy41(
clk ,
rst_n ,
key_in ,
key_in1 ,
key_in2 ,
Digitron_Out ,
DigitronCS_Out
);
// parameter TIME_20MS = 1000000 ;//为了缩短仿真周期,仿真时可适当缩小
parameter TIME_20MS = 100;
//数码管*******************************************************************
parameter Timex = 8'd200 ;//控制动态扫描周期
parameter CS_NUM= 3'd6 ;//需要用到的数码管个数
parameter N_0 = 8'b0011_1111, N_1 = 8'b0000_0110, N_2 = 8'b0101_1011,
N_3 = 8'b0100_1111, N_4 = 8'b0110_0110, N_5 = 8'b0110_1101,
N_6 = 8'b0111_1101, N_7 = 8'b0000_0111, N_8 = 8'b0111_1111,
N_9 = 8'b0110_1111;
//输入信号定义
input clk ;
input rst_n ;
input key_in;
input key_in1;
input key_in2;
//数码管**********************************************************************
output [7:0]Digitron_Out ;//数码管译码显示数据
output [5:0]DigitronCS_Out;//数码管片选
//输出信号reg定义
reg key_out;
reg key_out1;
reg key_out2;
reg uart_txd_d0;
reg uart_txd_d1;
reg uart_txd_d2;
reg uart_txd_d3;
reg uart_txd_d4;
reg uart_txd_d5;
reg key_ff0;
reg key_ff1;
reg key_ff2;
reg key_ff3;
reg key_ff4;
reg key_ff5;
reg[15:0] shake_cnt;
wire shake_flag;
wire flag;
reg[15:0] shake_cnt1;
wire shake_flag1;
wire flag1;
reg[15:0] shake_cnt2;
wire shake_flag2;
wire flag2;
//数码管**************************************************************************
reg [7:0]Digitron_Out ;
reg [5:0]DigitronCS_Out;
reg [23:0]Result ;//待显示数据
//reg [7:0]Result2 ;//待显示数据
reg [7:0]Count ;//控制动态扫描周期
reg [3:0]SingleNum ;//待显示数据
reg [2:0]cs ;//片选相关中间信号
/*************************
**************************/
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
key_ff0 <= 1'b1;
key_ff1 <= 1'b1;
end
else begin
key_ff0 <= key_in ;
key_ff1 <= key_ff0;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
key_ff2 <= 1'b1;
key_ff3 <= 1'b1;
end
else begin
key_ff2 <= key_in1 ;
key_ff3 <= key_ff2;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
key_ff4 <= 1'b1;
key_ff5 <= 1'b1;
end
else begin
key_ff4 <= key_in2 ;
key_ff5 <= key_ff4;
end
end
/************************
消抖 20MS
**************************/
//按键一
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
shake_cnt <= 0;
end
else if(key_ff1!=1'h1)begin
if(shake_flag)
shake_cnt <= shake_cnt;
else
shake_cnt <= shake_cnt + 1;
end
else begin
shake_cnt <= 0;
end
end
assign shake_flag = shake_cnt>=TIME_20MS-1;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
key_out <= 1'b1;
end
else if(shake_flag)begin
key_out <= 1'b0;
end
else begin
key_out <= 1'b1;
end
end
assign flag = (~uart_txd_d0) && (uart_txd_d1);
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
uart_txd_d0 <= 1'b1;
uart_txd_d1 <= 1'b1;
end
else begin
uart_txd_d0 <= key_out;
uart_txd_d1 <= uart_txd_d0;
end
end
//按键二
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
shake_cnt1 <= 0;
end
else if(key_ff3!=1'h1)begin
if(shake_flag1)
shake_cnt1 <= shake_cnt1;
else
shake_cnt1 <= shake_cnt1 + 1;
end
else begin
shake_cnt1 <= 0;
end
end
assign shake_flag1 = shake_cnt1>=TIME_20MS-1;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
key_out1 <= 1'b1;
end
else if(shake_flag1)begin
key_out1 <= 1'b0;
end
else begin
key_out1 <= 1'b1;
end
end
assign flag1 = (~uart_txd_d2) && (uart_txd_d3);
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
uart_txd_d2 <= 1'b1;
uart_txd_d3 <= 1'b1;
end
else begin
uart_txd_d2 <= key_out1;
uart_txd_d3 <= uart_txd_d2;
end
end
//按键三
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
shake_cnt2 <= 0;
end
else if(key_ff5!=1'h1)begin
if(shake_flag2)
shake_cnt2 <= shake_cnt2;
else
shake_cnt2 <= shake_cnt2 + 1;
end
else begin
shake_cnt2 <= 0;
end
end
assign shake_flag2 = shake_cnt2>=TIME_20MS-1;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
key_out2 <= 1'b1;
end
else if(shake_flag2)begin
key_out2 <= 1'b0;
end
else begin
key_out2 <= 1'b1;
end
end
assign flag2 = (~uart_txd_d4) && (uart_txd_d5);
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
uart_txd_d4 <= 1'b1;
uart_txd_d5 <= 1'b1;
end
else begin
uart_txd_d4 <= key_out2;
uart_txd_d5 <= uart_txd_d4;
end
end
//*******************************************
//按键触发result计数
//*******************************************
/*always @( posedge clk )
begin
if(!rst_n)
Result <= 8'd0 ;
else if(key_out == 1'b0)
begin
Result[3:0]<=Result[3:0]+4'd1;
if(Result[3:0]==4'd9)
Result[7:4]<=Result[7:4]++4'd1;
else
Result[7:4]<=Result[7:4];
end
else
Result[3:0]<=Result[3:0];
end
*/
//***********************************************if(keyout==1)
/*always @( posedge clk )
begin
if(!rst_n)
begin
Result <= 8'd0 ;
end
else
begin
if(flag==1'b1)begin
Result[3:0]<=Result[3:0]+4'd1;
if(Result[3:0]==4'd9)begin
Result[7:4]<=Result[7:4]+4'd1;
Result[3:0]<=4'd0;
end
else
Result[7:4]<=Result[7:4];
end
end
end
*/
//**************************************************************************
always @( posedge clk )
begin
if(!rst_n)
begin
Result<= 24'd0;
end
else
begin
if(flag==1'b1)
begin
Result[3:0]<=4;//个位
Result[7:4]<=4;//十位
Result[11:8]<=4;//百位
Result[15:12]<=4;//千位
Result[19:16]<=4;//万位
Result[23:20]<=4;//十万位
end
else if(flag1==1'b1)
begin
Result[3:0]<=3;//个位
Result[7:4]<=3;//十位
Result[11:8]<=3;//百位
Result[15:12]<=3;//千位
Result[19:16]<=3;//万位
Result[23:20]<=3;//十万位
end
else if(flag2==1'b1)
begin
Result[3:0]<=2;//个位
Result[7:4]<=2;//十位
Result[11:8]<=2;//百位
Result[15:12]<=2;//千位
Result[19:16]<=2;//万位
Result[23:20]<=2;//十万位
end
end
end
//数码管**********************************************************************
//-----设置动态扫描周期-------------------
always @( posedge clk )
begin
if(!rst_n)
Count <= 8'd0 ;
else if(Count == Timex)
Count <= 8'd0 ;
else
Count <= Count + 8'd1 ;
end
//---根据扫描周期产生片选信号----------
always @ ( posedge clk )
begin
if(!rst_n)
cs <= 3'd0 ;
else if(Count == Timex)
begin
if(cs == CS_NUM - 3'd1)
cs <= 3'd0 ;
else
cs <= cs + 3'd1 ;
end
end
//------结合电路将片选信号译码---------
always @ ( posedge clk )
begin
if(!rst_n)
DigitronCS_Out <= 6'd0 ;
else
begin
case(cs)
3'd0: DigitronCS_Out <= 6'b11_1110;
3'd1: DigitronCS_Out <= 6'b11_1101;
3'd2: DigitronCS_Out <= 6'b11_1011;
3'd3: DigitronCS_Out <= 6'b11_0111;
3'd4: DigitronCS_Out <= 6'b10_1111;
3'd5: DigitronCS_Out <= 6'b01_1111;
default: DigitronCS_Out <= 6'b11_1111;
endcase
end
end
//---------根据输入将待显示分配到个位、十位----------------
always @ ( posedge clk )
begin
if(!rst_n)
SingleNum <= 4'd0 ;
else
begin
case(cs)
3'd0: SingleNum <= Result[3:0];//个位
3'd1: SingleNum <= Result[7:4];//十位
3'd2: SingleNum <= Result[11:8];//百位
3'd3: SingleNum <= Result[15:12];//千位
3'd4: SingleNum <= Result[19:16];//万位
3'd5: SingleNum <= Result[23:20];//十万位
/*3'd5: SingleNum <= Result2[3:0];//个位
3'd6: SingleNum <= Result2[7:4];//十位*/
default: SingleNum <= 4'd0;
endcase
end
end
//---待显示数据译码成共阴极数码管驱动格式-------
always @( posedge clk )
begin
if(!rst_n)
Digitron_Out <= 8'd0 ;
else
begin
case(SingleNum)
4'd0: Digitron_Out <= N_0;//个位
4'd1: Digitron_Out <= N_1;//十位
4'd2: Digitron_Out <= N_2;//个位
4'd3: Digitron_Out <= N_3;//十位
4'd4: Digitron_Out <= N_4;//个位
4'd5: Digitron_Out <= N_5;//十位
4'd6: Digitron_Out <= N_6;//个位
4'd7: Digitron_Out <= N_7;//十位
4'd8: Digitron_Out <= N_8;//个位
4'd9: Digitron_Out <= N_9;//十位
default: Digitron_Out <= 8'd0;
endcase
end
end
endmodule
八、测试代码
// Copyright (C) 1991-2013 Altera Corporation
// Your use of Altera Corporation's design tools, logic functions
// and other software and tools, and its AMPP partner logic
// functions, and any output files from any of the foregoing
// (including device programming or simulation files), and any
// associated documentation or information are expressly subject
// to the terms and conditions of the Altera Program License
// Subscription Agreement, Altera MegaCore Function License
// Agreement, or other applicable license agreement, including,
// without limitation, that your use is for the sole purpose of
// programming logic devices manufactured by Altera and sold by
// Altera or its authorized distributors. Please refer to the
// applicable agreement for further details.
// *****************************************************************************
// This file contains a Verilog test bench template that is freely editable to
// suit user's needs .Comments are provided in each section to help the user
// fill out necessary details.
// *****************************************************************************
// Generated on "11/23/2022 11:24:08"
// Verilog Test Bench template for design : sy41
//
// Simulation tool : ModelSim (Verilog)
//
`timescale 1 ps/ 1 ps
module sy41_vlg_tst();
// constants
// general purpose registers
reg eachvec;
// test vector input registers
reg clk;
reg key_in;
reg key_in1;
reg key_in2;
reg rst_n;
// wires
wire [5:0] DigitronCS_Out;
wire [7:0] Digitron_Out;
// assign statements (if any)
sy41 i1 (
// port map - connection between master ports and signals/registers
.DigitronCS_Out(DigitronCS_Out),
.Digitron_Out(Digitron_Out),
.clk(clk),
.key_in(key_in),
.key_in1(key_in1),
.key_in2(key_in2),
.rst_n(rst_n)
);
initial
begin
clk = 0 ;
rst_n = 0 ;
key_in = 1'b1 ;
key_in1 = 1'b1 ;
key_in2 = 1'b1 ;
#10000;
rst_n= 1 ;
key_in= 1'b0 ;
#10000;
key_in = 1'b1 ;
#10000;
key_in1 = 1'b0 ;
#10000;
key_in1 = 1'b1 ;
#10000;
key_in2 = 1'b0 ;
#10000;
key_in2 = 1'b1 ;
#10000;
$stop;
end
always #10 clk = ~clk ;
endmodule