可编程逻辑器件之汽车速度指示系统设计

一、 实验目标

熟练掌握 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

油门功能按键,通过油门功能按键的按下汽车行驶速度不断增加。

图4.2

刹车功能按键,通过刹车功能按键的按下汽车行驶速度不断减少。

同时代码通过key_out变量的选择,使得两个按键的按下逻辑更为准确,且确保,两个按键都未按下时,数码管显示的汽车行驶速度保持原值不变。

五、测试验证(仿真、硬件测试)

仿真测试文件:

图5.1

仿真结果图:

图5.2

通过将仿真文件与仿真结果可以看到,在油门按键按下时,数码管所显示的汽车行驶速度不断增加;在刹车按键按下时,数码管所显示的汽车行驶速度不断减少;在两个按键都不按下时,数码管所显示的汽车行驶速度保持不变,这与编写的代码相符合,实验仿真结果与实验仿真测试文件预测结果一致,实验代码符合实验要求。

六、实验小结

汽车速度显示功能在实际的应用当中是十分广泛的,汽车在实际的道路行驶过程中,良好的速度显示不仅能够增加驾驶人对于道路安全以及控制的判断,同时也能够通过道路限速,驾驶人控制速度使得道路行驶更加顺畅,节约道路行驶时间,防止造成道路拥堵。

本次实验通过控制MINI_FPGA开发板上配有的6个七段数码管 DIG1-DIG6(当正放 MINI_FPGA 开发板时,从左至右依次数过去)模拟显示汽车行驶速度,然后通过刹车与油门按键的按下,数码管汽车行驶速度发生相应的变化。

本次实验也是综合了按键消抖实验以及数码管实验,同时隐藏性也添加了计数器功能,可见一些基础性实验对于复杂项目的必要性。多多做一些简单性基础实验,对于我们将来做大项目是十分有帮助的!

七、实验代码

module sy5(

clk ,

rst_n ,

key_in ,

key_in1 ,

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;

//数码管**********************************************************************

output [7:0]Digitron_Out ;//数码管译码显示数据

output [5:0]DigitronCS_Out;//数码管片选

//输出信号reg定义

reg key_out;

reg key_out1;

/*reg uart_txd_d0;

reg uart_txd_d1;

reg uart_txd_d2;

reg uart_txd_d3;*/

reg key_ff0;

reg key_ff1;

reg key_ff2;

reg key_ff3;

reg flag1;

reg flag2;

reg flag3;

reg flag4;

reg flag5;

reg[15:0] shake_cnt;

wire shake_flag;

//wire flag;

reg[15:0] shake_cnt1;

wire shake_flag1;

// wire flag1;

//数码管**************************************************************************

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 ;//片选相关中间信号

reg [15:0]CK ;//

/*************************

**************************/

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

/************************

消抖 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

*/

//*******************************************

//按键触发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

CK <= 16'd0 ;

//flag <= 1'b0;

end

else if(CK == 16'd10000)begin

CK <= 16'd0 ;

//flag <=~flag;

end

else

CK <= CK + 16'd1 ;

end

//**************************************************************************

always @( posedge clk )

begin

//if(flag==1'b1)begin //*******************************************

if(!rst_n)

begin

Result<= 24'd0;

flag1<= 1'b1;

flag2<= 1'b1;

flag3<= 1'b1;

flag4<= 1'b1;

flag5<= 1'b1;

end

else

begin

if(key_out==1'd0&&key_out1==1'd1)

begin

if(CK == 16'd10000)begin //*******************************************

Result[3:0]<=Result[3:0]+4'd1;

if(Result[3:0]==4'd10)begin

Result[7:4]<=Result[7:4]+4'd1;//个位进十位

Result[3:0]<=4'd0;

end

else if(Result[7:4]==4'd10)begin

Result[11:8]<=Result[11:8]+4'd1;//十位进百位

Result[7:4]<=4'd0;

end

else if(Result[11:8]==4'd10)begin

Result[15:12]<=Result[15:12]+4'd1;//百位进千位

Result[11:8]<=4'd0;

end

else if(Result[15:12]==4'd10)begin

Result[19:16]<=Result[19:16]+4'd1;//千位进万位

Result[15:12]<=4'd0;

end

else if(Result[19:16]==4'd10)begin

Result[23:20]<=Result[23:20]+4'd1;//万位进十万位

Result[19:16]<=4'd0;

end

else if(Result[23:20]==4'd10)begin

Result<= Result; //十万位满清零

end

//&&Result[19:16]==4'd9&&Result[15:12]==4'd9&&Result[11:8]==4'd9&&Result[7:4]==4'd9&&Result[3:0]==4'd9

end //**************************

end

else if(key_out1==1'd0&&key_out==1'd1)

begin

if(CK == 16'd10000)begin //*******************************************

if(Result!= 24'd0)

begin

Result[3:0]<=Result[3:0]-4'd1;

if(Result[3:0]==4'd0&&Result[23:4]!=4'd0)

flag1<=1'b0;

else if(flag1==1'b0&&Result[23:4]!=4'd0)begin

flag1<=1'b1;

Result[3:0]<=4'd9;

Result[7:4]<=Result[7:4]-4'd1;//个位不足十位减一

if(Result[7:4]==4'd0&&Result[23:8]!=4'd0)

flag2<=1'b0;

end

//*******************************************

else if(flag2==1'b0&&Result[23:8]!=4'd0)begin

//if(Result[23:8]!=4'd0)begin

flag2<=1'b1;

Result[7:4]<=4'd9;

Result[11:8]<=Result[11:8]-4'd1;//十位不足百位减一

if(Result[11:8]==4'd0&&Result[23:12]!=4'd0)

flag3<=1'b0;

/*end

else

Result[7:4]<=4'd0;*/

end

else if(flag3==1'b0&&Result[23:12]!=4'd0)begin

//if(Result[23:12]!=4'd0)begin

flag3<=1'b1;

Result[11:8]<=4'd9;

Result[15:12]<=Result[15:12]-4'd1;//百位不足千位减一

if(Result[15:12]==4'd0&&Result[23:16]!=4'd0)

flag4<=1'b0;

/*end

else

Result[11:8]<=4'd0;*/

end

else if(flag4==1'b0&&Result[23:16]!=4'd0)begin

//if(Result[23:16]!=4'd0)begin

flag4<=1'b1;

Result[15:12]<=4'd9;

Result[19:16]<=Result[19:16]-4'd1;//千位不足万位减一

if(Result[19:16]==4'd0&&Result[23:20]!=4'd0)

flag5<=1'b0;

/*end

else

Result[15:12]<=4'd0;*/

end

else if(flag5==1'b0&&Result[23:20]!=4'd0)begin

//if(Result[23:20]!=4'd0)begin

flag5<=1'b1;

Result[19:16]<=4'd9;

Result[23:20]<=Result[23:20]-4'd1;//万位不足十万位减一

/*end

else

Result[19:16]<=4'd0;*/

end

else if(Result[23:20]==4'd0)begin

Result[23:20]<=4'd0;//万位不足十万

end

else

Result<=Result;

end

else

Result<= 24'd0;

//end//*********************************************************

end

end

else if(key_out1==1'd0&&key_out==1'd0)

Result<= 24'd0;

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 10:19:44"

// Verilog Test Bench template for design : sy5

//

// Simulation tool : ModelSim (Verilog)

//

`timescale 1 ps/ 1 ps

module sy5_vlg_tst();

// constants

// general purpose registers

reg eachvec;

// test vector input registers

reg clk;

reg key_in;

reg key_in1;

reg rst_n;

// wires

wire [5:0] DigitronCS_Out;

wire [7:0] Digitron_Out;

// assign statements (if any)

sy5 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),

.rst_n(rst_n)

);

initial

begin

clk = 0 ;

rst_n = 0 ;

key_in = 1'b1 ;

key_in1 = 1'b1 ;

#1000000;

rst_n= 1 ;

key_in= 1'b0 ;

#1000000;

key_in = 1'b1 ;

#1000000;

key_in1 = 1'b0 ;

#1000000;

key_in1 = 1'b1 ;

#1000000;

$stop;

end

always #10 clk = ~clk ;

endmodule

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值