找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5083|回复: 2
收起左侧

FPGA课程设计多功能数字钟

[复制链接]
ID:361200 发表于 2018-6-28 17:16 | 显示全部楼层 |阅读模式

多功能数字钟

说  明

  • 论文书写要求与说明
  • 严格按照模板进行书写。自己可以自行修改标题的题目
  • 关于字体:
    • 题目:三号黑体加粗。
    • 正文:小四号宋体,行距为1.25倍。
  • 严禁抄袭和雷同,一经发现,成绩即判定为不及格!!!
  • 设计提交说明
  • 设计需要提交“电子稿”和“打印稿”;
  • “打印稿”包括封面、说明(即本页内容)、设计内容三部分;订书机左边装订。
  • “电子稿”上交:文件名为 FPGA课程设计报告-班级-学号-姓名.doc,所有报告发送给班长,由班长统一打包后统一发送到付小倩老师。
  • “打印稿”由班长收齐后交到:12教305办公室;


第一章  绪论

关键词:FPGA,数字钟

第二章 FPGA的相关介绍

2.1  FPGA概述

2.2 FPGA特点

2.3 FPGA设计注意

第三章 Quartus II与Verilog HDL相关介绍

3.1 Quartus II

3.2  Verilog HDL

第四章 设计方案

4.1数字钟的工作原理

4.2 按键消抖

4.3时钟复位

4.4时钟校时

4.5数码管显示模块。

第五章 方案实现与验证

5.1产生秒脉冲

5.2秒个位进位

5.3按键消抖

5.4复位按键设置

5.5 数码管显示。

5.6 RTL结构总图

第六章 实验总结

第七章 Verilog HDL源代码附录


第一章  绪论

现代社会的标志之一就是信息产品的广泛使用,而且是产品的性能越来越强,复杂程度越来越高,更新步伐越来越快。支撑信息电子产品高速发展的基础就是微电子制造工艺水平的提高和电子产品设计开发技术的发展。前者以微细加工技术为代表,而后者的代表就是电子设计自动化(electronic design automatic, EDA)技术。

本设计采用的VHDL是一种全方位的硬件描述语言,具有极强的描述能力,能支持系统行为级、寄存器传输级和逻辑门级这三个不同层次的设计;支持结构、数据流、行为三种描述形式的混合描述,覆盖面广,抽象能力强,因此在实际应用中越来越广泛。ASIC是专用的系统集成电路,是一种带有逻辑处理的加速处理器;而FPGA是特殊的ASIC芯片,与其它的ASIC芯片相比,它具有设计开发周期短、设计制造成本低、开发工具先进、标准产品无需测试、质量稳定以及可实时在线检测等优点。

在控制系统中,键盘是常用的人机交换接口,当所设置的功能键或数字键按下的时候,系统应该完成该键所对应的功能。因此,按键信息输入是与软件结构密切相关的过程。根据键盘结构的不同,采用不同的编码方法,但无论有无编码以及采用什么样的编码,最后都要转换成为相应的键值,以实现按键功能程序的转移。[1]

钟表的数字化给人们生产生活带来了极大的方便,而且大大地扩展了钟表原先的报时功能。诸如定时自动报警、定时启闭电路、定时开关烘箱、通断动力设备,甚至各种定时电气的自动启用等,所有这些都是以钟表数字化为基础的。因此研究数字钟以及扩大其应用有着非常现实的意义。


第二章 FPGA的相关介绍
FPGA(Field-Programmable Gate Array),即现场可编程门阵列,它是在PAL、GAL、CPLD等可编程器件的基础上进一步发展的产物。它是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路数有限的缺点。
2.1  FPGA概述

系统设计师可以根据需要通过可编辑的连接把FPGA内部的逻辑块连接起来,就好像一个电路试验板被放在了一个芯片里。一个出厂后的成品FPGA的逻辑块和连接可以按照设计者而改变,所以FPGA可以完成所需要的逻辑功能。

FPGA一般由3种可编程电路和一个用于存放编程数据的静态存储器SRAM组成。这3种可编程电路是:可编程逻辑模块(CLB--Configurable Logic Block)、输入/输出模块(IOB--I/O Block)和互连资源(IR—Interconnect Resource)。可编程逻辑模块CLB是实现逻辑功能的基本单元,它们通常规则的排列成一个阵列,散布于整个芯片;可编程输入/输出模块(IOB)主要完成芯片上的逻辑与外部封装脚的接口,它通常排列在芯片的四周;可编程互连资源包括各种长度的连接线段和一些可编程连接开关,它们将各个CLB之间或CLB、IOB之间以及IOB之间连接起来,构成特定功能的电路。

FPGA一般来说比ASIC(专用集成芯片)的速度要慢,无法完成复杂的设计,而且消耗更多的电能。但是他们也有很多的优点比如可以快速成品,可以被修改来改正程序中的错误和更便宜的造价。厂商也可能会提供便宜的但是编辑能力差的FPGA。因为这些芯片有比较差的可编辑能力,所以这些设计的开发是在普通的FPGA上完成的,然后将设计转移到一个类似于ASIC的芯片上。另外一种方法是用CPLD(复杂可编程逻辑器件备)。


2.2 FPGA特点
FPGA的基本特点主要有:

1采用FPGA设计ASIC电路,用户不需要投片生产,就能得到合用的芯片。

2FPGA可做其它全定制或半定制ASIC电路的中试样片。

3FPGA内部有丰富的触发器和I/O引脚。

4FPGA是ASIC电路中设计周期最短、开发费用最低、风险最小的器件之一。

5FPGA采用高速CHMOS工艺,功耗低,可以与CMOS、TTL电平兼容。

可以说,FPGA芯片是小批量系统提高系统集成度、可靠性的最佳选择之一。
编程互连资源IR可以将FPGA内部的CLB和CLB之间、CLB和IOB之间连接起来,构成各种具有复杂功能的系统。
FPGA是由存放在片内RAM中的程序来设置其工作状态的,因此,工作时需要对片内的RAM进行编程。用户可以根据不同的配置模式,采用不同的编程方式。
加电时,FPGA芯片将EPROM中数据读入片内编程RAM中,配置完成后,FPGA进入工作状态。掉电后,FPGA恢复成白片,内部逻辑关系消失,因此,FPGA能够反复使用。FPGA的编程无须专用的FPGA编程器,只须用通用的EPROM、PROM编程器即可。当需要修改FPGA功能时,只需换一片EPROM即可。这样,同一片FPGA,不同的编程数据,可以产生不同的电路功能。因此,FPGA的使用非常灵活。
FPGA有多种配置模式:并行主模式为一片FPGA加一片EPROM的方式;主从模式可以支持一片PROM编程多片FPGA;串行模式可以采用串行PROM编程FPGA;外设模式可以将FPGA作为微处理器的外设,由微处理器对其编程。

2.3 FPGA设计注意
不管你是一名逻辑设计师、硬件工程师或系统工程师,甚或拥有所有这些头衔,只要你在任何一种高速和多协议的复杂系统中使用了FPGA,你就很可能需要努力解决好器件配置、电源管理、IP集成、信号完整性和其他的一些关键设计问题。不过,你不必独自面对这些挑战,因为在当前业内领先的FPGA公司里工作的应用工程师每天都会面对这些问题,而且他们已经提出了一些将令你的设计工作变得更轻松的设计指导原则和解决方案。

本次实验所采用的FPGA器件是Altera Cyclone V 5CSEMA5F31C6N

FPGA实物图


FPGA数码管介绍,每节数码管低电平点亮高电平熄灭。
LED序号如下图所示:




根据上图所示的顺序,可以得出显示的数组代码。



4'd0: HEX0=7'b1000000;                            //0              低电平点亮高电平熄灭

4'd1: HEX0=7'b1111001;                            //1

4'd2: HEX0=7'b0100100;                            //2

4'd3: HEX0=7'b0110000;                            //3

4'd4: HEX0=7'b0011001;                            //4

4'd5: HEX0=7'b0010010;                            //5

4'd6: HEX0=7'b0000010;                            //6

4'd7: HEX0=7'b1111000;                            //7

4'd8: HEX0=7'b0000000;                            //8

4'd9: HEX0=7'b0010000;                            //9

default: HEX0=7'b1111111;              //不符合条件的显示零





第三章 Quartus II与Verilog HDL相关介绍3.1 Quartus II

Quartus II 是Altera公司的综合性PLD/FPGA开发软件,原理图、VHDL、VerilogHDL以及AHDL(Altera Hardware 支持Description Language)等多种设计输入形式,内嵌自有的综合器以及仿真器,可以完成从设计输入到硬件配置的完整PLD设计流程。

Quartus II支持Altera的IP核,包含了LPM/MegaFunction宏功能模块库,使用户可以充分利用成熟的模块,简化了设计的复杂性、加快了设计速度。对第三方EDA工具的良好支持也使用户可以在设计流程的各个阶段使用熟悉的第三方EDA工具。

Quartus II 软件拥有友好的界面,使用便捷,功能强大,当中可编程逻辑设计环境采用完成集成化,是先进的EDA工具软件。该软件具备诸多特点(例如:开放性,与结构无联系,多平台设计,完全集成化,设计库丰富、工具模块化等),支持原理图、VHDL、VerilogHDL以及AHDL等多种设计输入形式。Quartus II能够在多系统上使用,为用户的设计方式提供了完善的图形界面。具有运行速度快,界面统一,功能集中,学用简单等特点。



3.2  Verilog HDL

Verilog HDL是一种硬件描述语言(HDL:Hardware Description Language),以文本形式来描述数字系统硬件的结构和行为的语言,用它可以表示逻辑电路图、逻辑表达式,还可以表示数字逻辑系统所完成的逻辑功能。 Verilog HDL和VHDL是世界上最流行的两种硬件描述语言,都是在20世纪80年代中期开发出来的。前者由Gateway Design Automation公司(该公司于1989年被Cadence公司收购)开发。两种HDL均为IEEE标准。


第四章 设计方案4.1数字钟的工作原理
振荡器产生稳定的高频脉冲信号,作为数字钟的时间基准,然后经过分频器输出标准秒脉冲。秒计数器满60后向分计数器进位,分计数器满60后向小时计数器进位,小时计数器按照“24翻0”规律计数。计数满后各计数器清零,重新计数。计数器的输出分别经译码器送数码管显示。计时出现误差时,可以用校时电路校时、校分。控制信号由三个独立按键输入。输入信号选择FPGA器件上的50MHZ时钟信号。
4.2 按键消抖
因为按键的物理结构并非理想式开关,在按键按下后会在一个很短的时间内出现电平抖动的情况,因此需要对按键进行消抖处理。这里的按键消抖与单片机中的按键消抖问题有所不同,不能采用延时的方法进行按键消抖,这里我选用对时钟脉冲计数的方式来判断按键是否按下。采用50MHZ时钟信号,实测160ms的消抖时长较为合适,即8000000个时钟上升沿。
4.3时钟复位

按下复位按键后,所有位清零。


4.4时钟校时

时钟计时过程中,可对时钟进行校时。本次设计不考虑对秒位进行校时,分钟的个位和小时的个位加到10时会自动进位,因此只对分钟的个位和小时的个位设置可以加1的校时按钮,即可实现校时功能。整体比较容易实现。


4.5数码管显示模块。

选择需要显示的时钟位数作为敏感词,用上述给出的显示代码对时钟的每一位分别进行显示处理。

第五章 方案实现与验证5.1产生秒脉冲

always@(posedge clk)                                                                      //敏感词为50MHZ时钟上升沿

。。。。。。

                                          count=count+1;                                                                     

                                          if(count==32'd50000000)                            //产生一个一秒的脉冲,

                                                        begin

                                                                      count=0;

                                                                      count_s0=count_s0+1;              //秒个位计数

                                                        end


如代码展现,当计数器count记到50000000个时钟上升沿的时候,向秒个位进1.


5.2秒个位进位

                                          if(count_s0==4'd10)

                                                        begin

                                                                      count_s0=0;            

                                                                      count_s1=count_s1+1;              //产生秒十位进位

                                                        end


当秒的个位计数到10的时候,向秒的十位进位。


5.3按键消抖


                            if (!inrst_m0)

                                                        count0=count0+1;

                                                        if(count0==32'd8000000 && !inrst_m0)

                                                                      begin

                                                                      count0=0;

                                                                      count_m0=count_m0+1;

                                                                      end

对时钟秒冲进行计数,计数达到8000000时,判断此时的电平是否为0,若还是为0,则判断按键按下,执行分钟个位加1操作。


5.4复位按键设置

              begin

                            if (!reset)                                                                                                  //按键按下为逻辑0

                                          begin

                                          count=0;                                                                                                  //复位置零

                                          count_s0=0;count_s1=0;

                                          count_m0=0;count_m1=0;

                                          count_h0=0;count_h1=0;

                                          end

                            else


复位按键按下后所有位置零。


5.5 数码管显示。

always@(count_s0)                                                                                                  //秒个位显示

              begin

                            case(count_s0)

                                          4'd0: HEX0=7'b1000000;                            //0              低电平点亮高电平熄灭

                                          4'd1: HEX0=7'b1111001;                            //1

                                          4'd2: HEX0=7'b0100100;                            //2

                                          4'd3: HEX0=7'b0110000;                            //3

                                          4'd4: HEX0=7'b0011001;                            //4

                                          4'd5: HEX0=7'b0010010;                            //5

                                          4'd6: HEX0=7'b0000010;                            //6

                                          4'd7: HEX0=7'b1111000;                            //7

                                          4'd8: HEX0=7'b0000000;                            //8

                                          4'd9: HEX0=7'b0010000;                            //9

                                          default: HEX0=7'b1111111;              //不符合条件的显示零

                            endcase

              end

5.6 RTL结构总图

显示部分如下图:



判断主体如下图:



部分引脚图展现




最终实验现象:






  • 实验总结

其实本次的多功能数字钟设计其实应该还有很多其他的方法,比如用到外部中断功能进行时钟的校时,采用按键输入加数码管闪烁的方式进行校时位的选择,但限于时间较短,这部分知识空白,所以本次设计实有所缺陷。

经历了本次FPGA的设计,有很多感受,首先就是看了一点数字钟设计方面的资料,遇到很多不理解的地方,于是就需要再和同学进行研究讨论,在讨论的过程中,能听到其他人的思路,感觉特别有意思,同样的功能,实现的方法有许许多多,努力把自己的想法实现,或是选择一种你喜欢的设计借鉴一下,两者都是很好的选择。

通过这次设计实验,着实培养了我们独立思考、解决问题的能力,从最一开始的一筹莫展,没有一点思路,感觉像平底拔楼一样,从两手空空到产生一个控制电路,从无到有,这是创造的力量。同时,和其他同学讨论的过程也很重要,

要说的还有就是最后实验成功的喜悦是无可替代的,就好像你亲手种的果树长出了果实,养的鸡下了鸡蛋,是一种创造的喜悦,整个心就像是一个大箱子里面放着一块糖,隐隐约约总能感觉到一丝甜蜜。

数码管显示的数字钟是常见的技术,这次基于FPGA的多功能数字钟设计具有很高的工程价值和现实意义。让我们将知识服务于生活,将知识用于实践,锻炼了我们发现问题解决问题的能力。

这次FPGA的多功能数字钟设计,加深了我们对FPGA设计的理解,培养了我们的逻辑思维和动手操作能力,使我们将知识与技能链接起来,使我们每个人的都在不断进步,提高了专业技能,提高了动手实践的综合能力。

  • Verilog HDL源代码附录

  1. module clock (reset,inrst_m0,inrst_h0,clk,HEX0,HEX1,HEX2,HEX3,HEX4,HEX5);
  2. input clk,reset,inrst_m0,inrst_h0;
  3. output reg [6:0] HEX0,HEX1,HEX2,HEX3,HEX4,HEX5;
  4. reg [31:0] count=0,count0=0,count1=0;                                                                                    //实际宽度为25
  5. reg [3:0] count_s0=0,count_s1=0,
  6.                                           count_m0=0,count_m1=0,
  7.                                           count_h0=0,count_h1=0;
  8. always@(posedge clk)
  9.               begin
  10.                             if (!inrst_m0)
  11.                                                         count0=count0+1;
  12.                                                         if(count0==32'd8000000 && !inrst_m0)//按键消抖
  13.                                                                       begin
  14.                                                                       count0=0;
  15.                                                                       count_m0=count_m0+1;
  16.                                                                       end
  17.                             if (!inrst_h0)
  18.                                                         count1=count1+1;
  19.                                                         if(count1==32'd8000000 && !inrst_h0)
  20.                                                                       begin
  21.                                                                       count1=0;
  22.                                                                       count_h0=count_h0+1;
  23.                                                                       end            
  24.                             if (!reset)                                                                                                  //按键按下为逻辑0
  25.                                           begin
  26.                                           count=0;                                                                                                  //复位置零
  27.                                           count_s0=0;count_s1=0;
  28.                                           count_m0=0;count_m1=0;
  29.                                           count_h0=0;count_h1=0;
  30.                                           end
  31.                             else
  32.                                           count=count+1;                                                                     
  33.                                           if(count==32'd50000000)                            //产生一个一秒的脉冲,
  34.                                                         begin
  35.                                                                       count=0;
  36.                                                                       count_s0=count_s0+1;              //秒个位计数
  37.                                                         end
  38.                                           else            
  39.                                           if(count_s0==4'd10)
  40.                                                         begin
  41.                                                                       count_s0=0;            
  42.                                                                       count_s1=count_s1+1;              //产生秒十位进位
  43.                                                         end
  44.                                           else
  45.                                           if(count_s1==4'd6)
  46.                                                         begin
  47.                                                                       count_s1=0;
  48.                                                                       count_m0=count_m0+1;
  49.                                                         end
  50.                                           else
  51.                                           if(count_m0==4'd10)                                          //分个位计数
  52.                                                         begin
  53.                                                                       count_m0=0;
  54.                                                                       count_m1=count_m1+1;
  55.                                                         end
  56.                                           else
  57.                                           if(count_m1==4'd6)                                          //分十位计数
  58.                                                         begin
  59.                                                                       count_m1=0;
  60.                                                                       count_h0=count_h0+1;
  61.                                                         end
  62.                                           else
  63.                                           if(count_h0==4'd10)                                          //时个位计数
  64.                                                         begin
  65.                                                                       count_h0=0;
  66.                                                                       count_h1=count_h1+1;
  67.                                                         end
  68.                                           else
  69.                                           if(count_h0==4 && count_h1==2)              //满24判断
  70.                                                         begin
  71.                                                                       count_h0=0;
  72.                                                                       count_h1=0;
  73.                                                         end

  74. end
  75.             
  76. always@(count_s0)                                                                                                  //秒个位显示
  77.               begin
  78.                             case(count_s0)
  79.                                           4'd0: HEX0=7'b1000000;                            //0              低电平点亮高电平熄灭
  80.                                           4'd1: HEX0=7'b1111001;                            //1
  81.                                           4'd2: HEX0=7'b0100100;                            //2
  82.                                           4'd3: HEX0=7'b0110000;                            //3
  83.                                           4'd4: HEX0=7'b0011001;                            //4
  84.                                           4'd5: HEX0=7'b0010010;                            //5
  85.                                           4'd6: HEX0=7'b0000010;                            //6
  86.                                           4'd7: HEX0=7'b1111000;                            //7
  87.                                           4'd8: HEX0=7'b0000000;                            //8
  88.                                           4'd9: HEX0=7'b0010000;                            //9
  89.                                           default: HEX0=7'b1111111;              //不符合条件的显示零
  90.                             endcase
  91.               end

  92. always@(count_s1)                                                                                                  //秒十位显示
  93.               begin
  94.                             case(count_s1)
  95.                                           4'd0: HEX1=7'b1000000;                            //0              低电平点亮高电平熄灭
  96.                                           4'd1: HEX1=7'b1111001;                            //1
  97.                                           4'd2: HEX1=7'b0100100;                            //2
  98.                                           4'd3: HEX1=7'b0110000;                            //3
  99.                                           4'd4: HEX1=7'b0011001;                            //4
  100.                                           4'd5: HEX1=7'b0010010;                            //5
  101.                                           default: HEX1=7'b1111111;              //不符合条件的显示零
  102.                             endcase
  103.               end

  104. always@(count_m0)                                                                                                  //分个位显示
  105.               begin
  106.                             case(count_m0)
  107.                                           4'd0: HEX2=7'b1000000;                            //0              低电平点亮高电平熄灭
  108.                                           4'd1: HEX2=7'b1111001;                            //1
  109.                                           4'd2: HEX2=7'b0100100;                            //2
  110.                                           4'd3: HEX2=7'b0110000;                            //3
  111.                                           4'd4: HEX2=7'b0011001;                            //4
  112.                                           4'd5: HEX2=7'b0010010;                            //5
  113.                                           4'd6: HEX2=7'b0000010;                            //6
  114.                                           4'd7: HEX2=7'b1111000;                            //7
  115.                                           4'd8: HEX2=7'b0000000;                            //8
  116.                                           4'd9: HEX2=7'b0010000;                            //9
  117.                                           default: HEX2=7'b1111111;              //不符合条件的显示零
  118.                             endcase
  119.               end
  120. always@(count_m1)                                                                                                  //分十位显示
  121.               begin
  122.                             case(count_m1)
  123.                                           4'd0: HEX3=7'b1000000;                            //0              低电平点亮高电平熄灭
  124.                                           4'd1: HEX3=7'b1111001;                            //1
  125.                                           4'd2: HEX3=7'b0100100;                            //2
  126.                                           4'd3: HEX3=7'b0110000;                            //3
  127.                                           4'd4: HEX3=7'b0011001;                            //4
  128.                                           4'd5: HEX3=7'b0010010;                            //5
  129.                                           default: HEX3=7'b1111111;              //不符合条件的显示零
  130.                             endcase
  131.               end
  132. always@(count_h0)                                                                                                  //时个位显示
  133.               begin
  134.                             case(count_h0)
  135.                                           4'd0: HEX4=7'b1000000;                            //0              低电平点亮高电平熄灭
  136.                                           4'd1: HEX4=7'b1111001;                            //1
  137.                                           4'd2: HEX4=7'b0100100;                            //2
  138.                                           4'd3: HEX4=7'b0110000;                            //3
  139.                                           4'd4: HEX4=7'b0011001;                            //4
  140.                                           4'd5: HEX4=7'b0010010;                            //5
  141.                                           4'd6: HEX4=7'b0000010;                            //6
  142.                                           4'd7: HEX4=7'b1111000;                            //7
  143.                                           4'd8: HEX4=7'b0000000;                            //8
  144.                                           4'd9: HEX4=7'b0010000;                            //9
  145.                                           default: HEX4=7'b1111111;              //不符合条件的显示零
  146.                             endcase
  147.               End

  148. always@(count_h1)                                                                                                  //时十位显示
  149.               begin
  150.                             case(count_h1)
  151.                                           4'd0: HEX5=7'b1000000;                            //0              低电平点亮高电平熄灭
  152.                                           4'd1: HEX5=7'b1111001;                            //1
  153.                                           4'd2: HEX5=7'b0100100;                            //2
  154.                                           default: HEX5=7'b1111111;              //不符合条件的显示零
  155.                             endcase
  156.               end

  157. endmodule
复制代码

完整的Word格式文档51黑下载地址:

FPGA课程设计多功能数字钟.doc (2.32 MB, 下载次数: 84)

回复

使用道具 举报

ID:366599 发表于 2018-7-6 23:33 | 显示全部楼层
好详细,学习一下
回复

使用道具 举报

ID:632402 发表于 2019-10-30 10:52 来自手机 | 显示全部楼层
很好的学习案例,讲的比较清楚了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表