芯航线——普利斯队长精心奉献

实验目的:1.掌握BCD码的原理、分类以及优缺点

2.设计一个多位的8421码计数器并进行验证

3.学会基本的错误定位以及修改能力

实验平台:无

实验原理:

BCD码(Binary-Coded Decimal)又被称为二进码十进数、二-十进制代码是一种十进制的数字编码,用4位二进制数来表示十进制数中的0~9个十个数之一。BCD编码又可以分成有权码和无权码两种,其中有权码如:8421码、2421码以及5421等;无权码如:余3码、格雷码以及余3循环码等。

BCD码中最常用的是8421码,其四个bit权值分别是8,4,2,1;同理5421码各位的权依次为5,4,2,1,5421码特点是最高位连续5个0后连续5个1,故其当计数器采用这种编码时,最高位可产生对称方波输出;余3码是在8421码上加加0011的出来的;码格雷码的特点是任意两个相邻的代码只有一位二进制数不同,编码格式不唯一;余3循环具有格雷码的特点还具有编码的首尾可以连接来进行循环,这样可用反馈移位寄存器来实现,硬件实现简单。下面表6-1给出常见的几种编码格式:

十进制数

8421码

余3码

2421码

5421码

格雷码

余3循环码

0

0000

0011

0000

0000

0000

0010

1

0001

0100

0001

0001

0001

0110

2

0010

0101

0010

0010

0011

0111

3

0011

0110

0011

0011

0010

0101

4

0100

0111

0100

0100

0110

0100

5

0101

1000

1011

1000

0111

1100

6

0110

1001

1100

1001

0101

1101

7

0111

1010

1101

1010

0100

1111

8

1000

1011

1110

1011

1100

1110

9

1001

1100

1111

1100

1101

1010

表6-1 常见的BCD码

在实际使用中如不特指BCD码格式均为代指8421码。通过以上介绍将十进制895转换为BCD码就是1001_1001_0101,同理若将BCD码1001_0110_0100转换为十进制数即为964。

BCD码的运算规则:BCD码是十进制数,而运算器对数据做加减运算时,都是按二进制运算规则进行处理的。这样,当将BCD码传送给运算器进行运算时,其结果需要修正。修正的规则是:当两个BCD码相加,如果和等于或小于 1001(即十进制数9),不需要修正;如果相加之和在 1010 到1111(即十六进制数 0AH~0FH)之间,则需加 'd6也就是'b0110进行修正;如果相加时,本位产生了进位,也需加 6 进行修正。下面举例说明:计算5+8,将5和8转换为8421 BCD码后输入加法器,则运算如下:0 1 0 1 + 1 0 0 0 = 1 1 0 1 结果大于9,+ 0 1 1 0 即加 6 修正得出1 0 0 1 1,补充高位为0001_0011。5+8=13,结论正确。

BCD码的主要应用之一就是数码管,假设我们要将十进制数158显示,一般解决办法是先要除法运算158/100= 1得出百位,再取余158%100 = 58后继续进行除法运算58 / 10 = 5得出十位,再进行一次取余158%10 = 8,得到个位。以上过程可以看出需要除法,但是由于除法运算是比较消耗计算时间导致整体需要的指令周期太久。但是如果我们先将其转换为BCD码,则可大幅度减少运算时间。具体例子会在数码管一讲详细介绍。

实验步骤:

按照02章所讲,建立工程子文件夹后,新建一个以名为BCD_Counter的工程保存在prj下,并在本工程目录的rtl文件夹下新建verilog file文件在此文件下输入以下内容并以BCD_Counter.v保存。

module BCD_Counter(Clk, Cin, Rst_n, Cout, q);

input Clk;//计数基准时钟

input Cin; //计数器进位输入

input Rst_n; //系统复位

output reg Cout; //计数进位输出

output [3:0]q; //计数值输出

reg [3:0]cnt; //定义计数器寄存器

//执行计数过程

always@(posedge Clk or negedge Rst_n)

if(Rst_n == 1'b0)

cnt <= 4'd0;

else if(Cin == 1'b1)begin

if(cnt == 4'd9)

cnt <= 4'd0;

else

cnt <= cnt + 1'b1;

end

else

cnt <= cnt;

//产生进位输出信号

always@(posedge Clk or negedge Rst_n)

if (!Rst_n)

Cout <= 1'b0;

else if(Cin == 1'b1 && cnt ==4'd9)

Cout <= 1'b1;

else

Cout <= 1'b0;

assign q = cnt;

endmodule

进行分析和综合直至没有错误以及警告。

为了测试仿真编写测试激励文件,新建BCD_Counter_tb.v文件保存到testbench文件夹下,输入以下内容再次进行分析和综合直至没有错误以及警告。本激励文件除产生正常的时钟以及复位信号外,还生成了重复30次的占空比为1:5周期为120ns的cin信号。

`timescale 1ns/1ns

`define clock_period 20

module BCD_Counter_tb;

reg Clk;

reg Cin;

reg Rst_n;

wire Cout;

wire [3:0]q;

BCD_Counter BCD_Counter0(

.Clk(Clk),

.Cin(Cin),

.Rst_n(Rst_n),

.Cout(Cout),

.q(q)

);

initial Clk = 1'b1;

always#(`clock_period/2) Clk = ~Clk;

initial begin

Rst_n = 1'b0;

Cin = 1'b0;

#(`clock_period*200);

Rst_n = 1'b1;

#(`clock_period*20);

repeat(30)begin

Cin = 1'b1;

#`clock_period;

Cin = 1'b0;

#(`clock_period*5);

end

#(`clock_period*20);

$stop;

end

endmodule

设置好仿真脚本后进行功能仿真,可以看到如图6-1所示的波形文件,可以看出在复位信号置高后,每当进位输入信号cin为高时计数值输出q完成一次自加,直到计数值为9后清零重新计数并产生进位信号。

图6-1 功能仿真波形图

现在以上面的BCD计数器为基础设计级联的多位BCD计数器,这里我们将计数器位数设置为12,即3个BCD计数器级联既可以实现。新建verilog file文件在此文件下输入以下内容并以BCD_Counter_top.v保存至rtl文件夹下。本文件实现了例化与调用BCD_counter.v文件并将进位信号根据需要连接。

module BCD_Counter_top(Clk, Cin, Rst_n, Cout, q);

input Clk;//计数基准时钟

input Cin; //计数器进位输入

input Rst_n; //系统复位

output Cout; //计数进位输出

output [11:0]q; //计数值输出

wire Cout0,Cout1;

wire [3:0]q0,q1,q2;

assign q = {q2,q1,q0};

BCD_Counter BCD_Counter0(

.Clk(Clk),

.Cin(Cin),

.Rst_n(Rst_n),

.Cout(Cout0),

.q(q0)

);

BCD_Counter BCD_Counter1(

.Clk(Clk),

.Cin(Cout0),

.Rst_n(Rst_n),

.Cout(Cout1),

.q(q1)

);

BCD_Counter BCD_Counter2(

.Clk(Clk),

.Cin(Cout1),

.Rst_n(Rst_n),

.Cout(Cout),

.q(q2)

);

endmodule

将上述的文件设置为顶层,并再次进行分析和综合直至没有错误以及警告。点击RTL viewer,可以看到图6-2的模块结构,可以看出符合预期目的。

图6-2多级BCD计数器RTL视图

为了测试仿真编写测试激励文件,新建BCD_Counter_top_tb.v文件保存到testbench文件夹下,输入以下内容再次进行分析和综合直至没有错误以及警告。本激励文件为了简化分析,复位后将cin一直置高,并延迟一定的时间。由于现在为三级BCD计数器,计数器满值为十六进制的999,特将仿真时间进行了延长至5000个时钟周期。

`timescale 1ns/1ns

`define clock_period 20

module BCD_Counter_top_tb;

reg Clk;

reg Cin;

reg Rst_n;

wire Cout;

wire [11:0]q;

BCD_Counter_top BCD_Counter_top0(

.Clk(Clk),

.Cin(Cin),

.Rst_n(Rst_n),

.Cout(Cout),

.q(q)

);

initial Clk = 1'b1;

always#(`clock_period/2) Clk = ~Clk;

initial begin

Rst_n = 1'b0;

Cin = 1'b0;

#(`clock_period*200);

Rst_n = 1'b1;

#(`clock_period*20);

Cin = 1'b1;

#(`clock_period*5000);

$stop;

end

endmodule

设置好仿真脚本后进行功能仿真,可以看到如图6-3所示的波形文件,可以看到进位输出信号cout在计数值q变为十六进制999后延迟了两个系统周期才有输出,不符合既定设计,即设计存在错误。

图6-3 多级BCD计数器初次功能仿真

为了定位错误,将子模块的相关信号加入到wave栏,并再次仿真查看内部数据的信息进行分析解决。

在Modelsim找到Inatance窗口找到顶层文件,如图6-4-1所示点击加号后可以看到本顶层设计调用的模块。如图6-4-2所示单击不同的模块在Object栏可以看到其端口列表,选中需要的右键Add Wave,即可将内部信号加入到波形窗口。这里我门将每个模块的计数值输出信号q以及进位输出信号cout加入到波形窗口中。

图6-4-1 添加内部信号到wave窗口

图6-4-2 添加内部信号到wave窗口

单击工具栏中的Restart来复位仿真,在弹出对话框中全选后点击OK,点击Run-All来重启仿真。

图6-5-1 复位仿真

图6-5-2 复位仿真

图6-6 重启仿真

可以看到仿真后加入内部信号的波形较乱没有层次,这里介绍一个分组操作,我们首先ctrl+A选中所有wave窗口中的波形,后ctrl+G进行分组。分组后如图6-7所示,放大局部信号可以看到照成这个原因是由于每一级的BCD计数器的进位输出信号均延迟了一个时钟周期,从而导致顶层文件进位输出cout信号输出延迟了三个时钟周期的问题,此时的计数器值已经变为了十六进制的002,而不再是999。

图6-7 加入内部信号的功能仿真波形

这样我们就定位了错误,只需将修改进位输出信号cout修改为与计数值信号q计数到9时同时输出。将进位产生信号的逻辑修改为如下,且将Cout的类型改为普通wire型。

assign Cout = (Cin == 1'b1 && cnt == 4'd9);

再次仿真后可以看到在图6-8-1中十六进制的999时输出进位信号,符合了原定的要求,我们可以再将显示格式修改为二进制数,如图6-8-2中在计数值q为1001_1001_1001产生进位信号,通过前面所讲的BCD码原理将其转换为BCD码的格式也是999。

图6-8-1 修改后的BCD计数器波形图

图6-8-2 修改后的BCD计数器波形图

至此,就完成了一个BCD计数器的设计,并且学会了基本的调试修改能力。具体BCD计数器的板级验证,可以参考后续文档关于芯航线数码管的驱动设计。

备注:在修改设计后如果进行单独的功能仿真,会发现在图6-9中进位信号存在毛刺(glitch),这里的解决办法很多,其中之一就是在后续设计中通过预估正常信号与毛刺信号的时间宽度来进行筛选,也可以通过相关约束来解决;硬件方面可以外接滤波电容来消除其影响。

图6-9 毛刺信号

转载于:https://www.cnblogs.com/xiaomeige/p/5500950.html

06-BCD计数器设计与应用——小梅哥FPGA设计思想与验证方法视频教程配套文档相关推荐

  1. 07-阻塞赋值与非阻塞赋值原理分析——小梅哥FPGA设计思想与验证方法视频教程配套文档...

    芯航线--普利斯队长精心奉献 实验目的:掌握阻塞赋值与非阻塞赋值的区别 实验平台:无 实验原理: 阻塞赋值,操作符为"=","阻塞"是指在进程语句(initia ...

  2. 小梅哥FPGA:基于线性序列机的TLC5620型DAC驱动设计

    小梅哥FPGA:基于线性序列机的TLC5620型DAC驱动设计 目标:学会使用线性序列机的思想设计常见的有串行执行特征的时序逻辑 实验现象:在QuartusⅡ软件中,使用ISSP工具,输入希望输出的电 ...

  3. 小梅哥FPGA学习笔记

    小梅哥FPGA学习笔记 一.38译码器 功能: 译码器其任一时刻的稳态输出,仅仅与该时刻的输入变量的取值有关,它是一种多输入多输出的组合逻辑电路,负责将二进制代码翻译为特定的对象(如逻辑电平等).38 ...

  4. 【小梅哥FPGA进阶教程】第九章 基于串口猎人软件的串口示波器

    九.基于串口猎人软件的串口示波器 1.实验介绍 本实验,为芯航线开发板的综合实验,该实验利用芯航线开发板上的ADC.独立按键.UART等外设,搭建了一个具备丰富功能的数据采集卡,芯航线开发板负责进行数 ...

  5. 小梅哥FPGA视频教程学习总结(持续学习中……)

    首先附上小梅哥FPGA视频教程链接:https://www.bilibili.com/video/BV1va411c7Dz?p=2&spm_id_from=pageDriver 小梅哥yyds ...

  6. 学习小梅哥FPGA培训视频第一天

    ** 学习小梅哥FPGA培训视频第一天 ** 学习实现计数器 利用quartus II 编写代码并仿真 仿真为前仿真和后仿真 这是前仿真 这是后仿真 在后仿真中,会有毛刺的出现,例如在 1(0001) ...

  7. 小梅哥FPGA时序分析和约束实例演练课程

    看过了他的nios课程,对他的能力很认同 只有前5讲是开源的,后面需要在淘宝上购买,暂时用不到,我就没有买课程,只看了前5讲感觉还挺有用,需要的时候再说吧. 小梅哥 FPGA时序分析 FPGA时序约束 ...

  8. 小梅哥FPGA:嵌入式块RAM使用之FIFO

    小梅哥FPGA:嵌入式块RAM使用之FIFO 课程目标:学会调用QuartusⅡ软件中提供的FIFO核并通过仿真,了解其接口时序 实现现象:通过QuartusⅡ软件中调用FIFO核,通过仿真来验证其接 ...

  9. java计算机毕业设计中学网站设计与实现演示录像2020源码+mysql数据库+系统+部署+lw文档

    java计算机毕业设计中学网站设计与实现演示录像2020源码+mysql数据库+系统+部署+lw文档 java计算机毕业设计中学网站设计与实现演示录像2020源码+mysql数据库+系统+部署+lw文 ...

最新文章

  1. python文件操作(open()、write()、read()、readline()、readlines()、seek()、os)
  2. 从docker 中抓取jvm heap 信息, 并且分析
  3. VS2015 解决方案 或者项目 卡 正在加载 的解决办法
  4. python可以从事什么工作-对话极客晨星:现在学Python 长大可以从事什么工作?...
  5. css vertical-align
  6. java 制作动态手机壁纸_android 动态切换壁纸实例 利用service机制实现 附完整源码 带动态截图...
  7. Android优化方案之--Fragment的懒加载实现
  8. 【2020模拟考试T1】【PAT乙】1031 查验身份证 (15分)模拟
  9. python - 多线程、装饰器
  10. Windows下配置安装Git(一)
  11. vb2010 java,连接用vb成功连接access2010
  12. 微软官方提供的免费正版 Windows 8.1/Win10/7/XP/Vista 操作系统虚拟机镜像下载
  13. 微积分英文书籍第八版 CALCULUS eight edition
  14. 服务器运行速度测试方法,服务器如何测试运行速度
  15. linux如何结束at命令,Linux命令总结--at命令(atq.atrm)
  16. 基因加性方差、显性方差与上位性方差定义
  17. QT学习日记17——Qt数据库
  18. QT(1)- QString
  19. mysql安装时的英文_安装MySQL遇到的常见英文翻译
  20. L1-040. 最佳情侣身高差(有坑点)

热门文章

  1. Polygonal-Light Shading with LTC
  2. java ListMapString,Object遍历的方法
  3. Celery框架简单实例
  4. 【codecombat】 试玩全攻略 第十四关 已知敌人
  5. BZOJ4426 : [Nwerc2015]Better Productivity最大生产率
  6. 404页面 3秒后跳到首页 实现
  7. HDU 1003 Maxsum
  8. 巧用VC工程下的rc文件
  9. 在WPF的TreeView中实现右键选定
  10. validate+jquery+ajax表单验证