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

 

实验目的: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. [CareerCup] 17.14 Unconcatenate Words 断词

    17.14 Oh, no! You have just completed a lengthy document when you have an unfortunate Find/Replace m ...

  2. 聚合函数:sum,avg,max,min,count

    group by  分组的使用方法 数学函数:ABS.ceiling.floor.power.round.sqrt.square 练习:

  3. java笔记随笔

    基本语法 编写Java程序时,应注意以下几点: 大小写敏感:Java是大小写敏感的,这就意味着标识符Hello与hello是不同的. 类名:对于所有的类来说,类名的首字母应该大写.如果类名由若干单词组 ...

  4. HDU1443 模拟(难)

    Joseph Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  5. asp.net 获取当前项目的根目录路径

    获取网站根目录的方法有几种如: Server.MapPath(Request.ServerVariables["PATH_INFO"]) Server.MapPath(" ...

  6. asp.net自定义404页面

    网上有很多方法,不过大体相同,这只是其中一个方法,亲测有效,记录后面可能会有用 1. 先写好一个404页面 404.aspx在项目根目录下 然后在配置文件中添加 <!-- 注意这个模式,redi ...

  7. mysql中字段类型转换排序

    表中字段server_id是varchar类型,现在我们查询数据时想以server_id排一下序,排序后的结果 select server_id from cardserver where game_ ...

  8. 3G網絡容量和業務承載的壓力大大增加!

    在移動通信話音業務繼續保持發展的同時,對IP和高速數據業務的支持已經成為移動通信系統演進的方向.移動數據業務是推動目前移動通信技術發展的主要動力,TD-LTE作為準4G技術,以提高數據速率和頻譜利用率 ...

  9. php课程---练习(联系人信息表)

    做一个联系人表,实现增删改功能 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...

  10. IOS第一天多线程-02NSThread基本使用

    **** #import "HMViewController.h" @interface HMViewController () @end @implementation HMVi ...