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

 

实验目的: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的出来的;码格雷码的特点是循环具有格雷码的特点还具有编码的首尾可以连接来进行循环,这样可用反馈移位寄存器来实现,硬件实现简单。下面表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视图

为了测试仿真编写测试激励文件,新建,特将仿真时间进行了延长至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 ==
时输出进位信号,符合了原定的要求,我们可以再将显示格式修改为二进制数,如图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 毛刺信号

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

  1. 05-IP核应用之计数器——小梅哥FPGA设计思想与验证方法视频教程配套文档

    芯航线--普利斯顿队长精心奉献   实验目的:了解FPGA的IP核相关知识并以计数器IP核为例学会基本IP使用的流程 实验平台:无 实验原理:     IP核(Intellectual Propert ...

  2. 04-时序逻辑电路设计之计数器——小梅哥FPGA设计思想与验证方法视频教程配套文档

    芯航线--普利斯队长精心奉献 实验目的:以计数器为例学会简单的时序逻辑电路设计 实验平台:芯航线FPGA核心板 实验原理: 时序逻辑电路是指电路任何时刻的稳态输出不仅取决于当前的输入,还与前一时刻输入 ...

  3. 09B-独立按键消抖实验02——小梅哥FPGA设计思想与验证方法视频教程配套文档

    芯航线--普利斯队长精心奉献   实验目的: 1.复习按键的设计 2.用模块化设计的方式实现每次按下按键0,4个LED显示状态以二进制加法格式加1,每次按下按键1,4个LED显示状态以二进制加法格式减 ...

  4. 03-组合逻辑电路设计之译码器——小梅哥FPGA设计思想与验证方法视频教程配套文档

    芯航线——普利斯队长精心奉献 课程目标:    1. 再次熟悉Quartus II工程的建立以及完整的FPGA开发流程 2. 以译码器为例学会简单组合逻辑电路设计 实验平台:无 实验原理: 组合逻辑, ...

  5. 02-FPGA设计流程介绍——小梅哥FPGA设计思想与验证方法视频教程配套文档

    芯航线——普利斯队长精心奉献 课程目标: 1.了解并学会FPGA开发设计的整体流程 2.设计一个二选一选择器并进行功能仿真.时序仿真以及板级验证 实验平台:芯航线FPGA开发板.杜邦线 实验内容: 良 ...

  6. 10-8位7段数码管驱动实验——小梅哥FPGA设计思想与验证方法视频教程配套文档

    芯航线--普利斯队长精心奉献   实验目的: 1.实现FPGA驱动数码管动态显示: 2.使用In system sources and probes editor工具,输入需要显示在数码管上的的数据, ...

  7. 09A-独立按键消抖实验01——小梅哥FPGA设计思想与验证方法视频教程配套文档

    芯航线--普利斯队长精心奉献   实验目的: 1.复习状态机的设计思想并以此为基础实现按键消抖 2.单bit异步信号同步化以及边沿检测 3.在激励文件中学会使用随机数发生函数$random 4.仿真模 ...

  8. 08-FPGA状态机设计实例——小梅哥FPGA设计思想与验证方法视频教程配套文档

    芯航线--普利斯队长精心奉献   实验目的:1.学习状态机的相关概念 2.理解一段式.两段式以及三段式状态机的区别以及优缺点 实验平台:芯航线FPGA核心板 实验原理: 状态机全称是有限状态机(fin ...

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

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

随机推荐

  1. sublime text 3 package control

    使用Ctrl+`快捷键或者通过View->Show Console菜单打开命令行,粘贴如下代码: import urllib.request,os; pf = 'Package Control. ...

  2. .net 文件下载【转】

    方式一:TransmitFile实现下载.将指定的文件直接写入 HTTP 响应输出流,而不在内存中缓冲该文件.     protected void Button1_Click(object send ...

  3. Python 脚本 监控数据库状态

    打算用这个脚本通过zabbix 监控Mariadb的,无奈要等Mariadb完全上线才行,所以先写一个粗略大致功能的版本. #coding:utf-8 #author:shiyiwen #versio ...

  4. js中的text(),html() ,val()的区别

    js中的text(),html() ,val()的区别 text(),html() ,val()三个方法用于html元素的存值和取值,但是他们各有特点,text()用于html元素文本内容的存取,ht ...

  5. ThinkPHP 3.2.3 Widget 扩展的使用

    ThinkPHP3.2.3 手册中 Widget 扩展的地址是: http://www.kancloud.cn/manual/thinkphp/1862 Widget 扩展一般用于页面组件的扩展,和自 ...

  6. iOS中集成ijkplayer视频直播框架

    ijkplayer 是一款做视频直播的框架, 基于ffmpeg, 支持 Android 和 iOS, 网上也有很多集成说明, 但是个人觉得还是不够详细, 在这里详细的讲一下在 iOS 中如何集成ijk ...

  7. Sublime Text 3 3126 注册码

    转载自:https://fatesinger.com/78252 Sublime Text 3 3126 注册码 第一个测试通过 -– BEGIN LICENSE -– Michael Barnes ...

  8. SQL server2012怎么备份数据库(设置自动备份)

    1.打开SQL server配置管理器,设置sql server服务里的SQL server代理服务为自动并启动 2.启动Master Data Services Configuration Mana ...

  9. js 新窗口打开

    <script> function tj(){ window.open ('http://www.baidu.com', 'newwindow', 'height=500px, width ...

  10. cocos2d-x场景切换动画

    void StartScene::beginGame() {     CCLog("beginGame");          //CCTransitionScene *trans ...