在项目设计中,经常需要显示一些数值,比如温湿度,时间等等。在数字电路中数据都是用二进制的形式存储,要想显示就需要进行转换,对于一个两位的数值,对10取除可以得到其十位的数值,对10取余可以得到个位的数值。对于Verilog来说它的标准是支持除法和取余运算的,综合器也会有IP可以进行除法运算。但是这样未免会耗费太多资源,使用移位加3算法就可以实现二进制到BCD码之间的转换。

BCD码(Binary-Coded Decimal‎)亦称二进码十进数或二-十进制代码。用4位二进制数来表示1位十进制数中的0~9这10个数码。

移位加3算法简单来说就是,有多少位二进制说,就进行多少次移位,以八位的二进制为例,其数值最高可为三位十进制数,进行如下表左移,在移位的过程中,如果移位出的数值大于4,则将改为的数值加3后再进行移位。

这里为什么大于四,BCD码是四位二进制数表示一个十进制数的一位,如果这以为大于4,比如5,4’b0101,下一次移位后变成了4’b1010,BCD码中是没有4’b1010的,所以要加6,向高位进位。这里就是移位后加6和移位前加3,两种方法修正,我这里选择了移位前加3。(4’b0011左移后也是4’b0110,移位前和移位后都是一样的对BCD码的位数进行修正)。

为什么用左移的方法呢?这是因为二进制数和十进制数之间的位权的关系。所以二进数和十进制数之间的转化是乘以2,也就是左移一位。转换公式大概就是这个样子。

公式编辑采用Markdown编辑器Typora完成,Typora支持LaTex语法,编写公式真是爽。

代码实现起来不是很复杂,博主在网上搜索到有些代码使用纯组合逻辑实现的,用了一个for循环,我个人认为这种写法不是很好,所以自己用状态机写了一个。模块设计如下,tran_en是转换使能信号,可以使电平使能也可以是脉冲使能,作为脉冲使能使用的时候,需要在数据来临之后的一个时钟周期给出使能(我的模块是这样的特点),电平使能有效时,需要18个时钟周期完成转换,输入二进制位16bit,输出为四组千百十个位。转换完成后输出一个转换完成标志tran_done。

内部的时序我采用了三段式状态机来完成。IDLE状态接收到使能信号,调到移位状态,经过16次移位。在shift_cnt为17时(这里是因为我状态机的原理所以shift_cnt会计数到17,但移位次数为16),数据转换完成。跳到DONE状态,输出转换完成标志。

采用组合逻辑来实现,移位后的数据值的判断,大于4加3后再进行移位。最后将转换完成后的结果输出。

代码如下:

 `timescale      1ns/1ps
// *********************************************************************************
// Project Name :
// Author : NingHeChuan
// Email : ninghechuan@foxmail.com
// Blogs : http://www.cnblogs.com/ninghechuan/
// File Name : Bin_BCD.v
// Module Name :
// Called By :
// Abstract :
//
// CopyRight(c) 2018, NingHeChuan Studio..
// All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// 2018/8/12 NingHeChuan 1.0 Original
//
// ********************************************************************************* module Bin_BCD
#(
parameter DATA_WIDTH = ,
parameter SHIFT_WIDTH = ,
parameter SHIFT_DEPTH = )
(
input clk,
input rst_n,
input tran_en,
input [DATA_WIDTH - :] data_in,
output reg tran_done,
output [:] thou_data, //千位
output [:] hund_data, //百位
output [:] tens_data, //十位
output [:] unit_data //个位 );
//-------------------------------------------------------
localparam IDLE = 'b001;
localparam SHIFT = 'b010;
localparam DONE = 'b100; //-------------------------------------------------------
reg [:] pre_state;
reg [:] next_state;
//
reg [SHIFT_DEPTH-:] shift_cnt;
//
reg [DATA_WIDTH:] data_reg;
reg [:] thou_reg;
reg [:] hund_reg;
reg [:] tens_reg;
reg [:] unit_reg;
reg [:] thou_out;
reg [:] hund_out;
reg [:] tens_out;
reg [:] unit_out;
wire [:] thou_tmp;
wire [:] hund_tmp;
wire [:] tens_tmp;
wire [:] unit_tmp; //-------------------------------------------------------
//FSM step1
always @(posedge clk or negedge rst_n)begin
if(rst_n == 'b0)begin
pre_state <= IDLE;
end
else begin
pre_state <= next_state;
end
end //FSM step2
always @(*)begin
case(pre_state)
IDLE:begin
if(tran_en == 'b1)
next_state = SHIFT;
else
next_state = IDLE;
end
SHIFT:begin
if(shift_cnt == SHIFT_DEPTH + )
next_state = DONE;
else
next_state = SHIFT;
end
DONE:begin
next_state = IDLE;
end
default:next_state = IDLE;
endcase
end //FSM step3
always @(posedge clk or negedge rst_n)begin
if(rst_n == 'b0)begin
thou_reg <= 'b0;
hund_reg <= 'b0;
tens_reg <= 'b0;
unit_reg <= 'b0;
tran_done <= 'b0;
shift_cnt <= 'd0;
data_reg <= 'd0;
end
else begin
case(next_state)
IDLE:begin
thou_reg <= 'b0;
hund_reg <= 'b0;
tens_reg <= 'b0;
unit_reg <= 'b0;
tran_done <= 'b0;
shift_cnt <= 'd0;
data_reg <= data_in;
end
SHIFT:begin
if(shift_cnt == SHIFT_DEPTH + )
shift_cnt <= 'd0;
else begin
shift_cnt <= shift_cnt + 'b1;
data_reg <= data_reg << ;
unit_reg <= {unit_tmp[:], data_reg[]};
tens_reg <= {tens_tmp[:], unit_tmp[]};
hund_reg <= {hund_tmp[:], tens_tmp[]};
thou_reg <= {thou_tmp[:], hund_tmp[]};
end
end
DONE:begin
tran_done <= 'b1;
end
default:begin
thou_reg <= thou_reg;
hund_reg <= hund_reg;
tens_reg <= tens_reg;
unit_reg <= unit_reg;
tran_done <= tran_done;
shift_cnt <= shift_cnt;
end
endcase
end
end
//-------------------------------------------------------
always @(posedge clk or negedge rst_n)begin
if(rst_n == 'b0)begin
thou_out <= 'd0;
hund_out <= 'd0;
tens_out <= 'd0;
unit_out <= 'd0;
end
else if(tran_done == 'b1)begin
thou_out <= thou_reg;
hund_out <= hund_reg;
tens_out <= tens_reg;
unit_out <= unit_reg;
end
else begin
thou_out <= thou_out;
hund_out <= hund_out;
tens_out <= tens_out;
unit_out <= unit_out;
end
end //-------------------------------------------------------
assign thou_tmp = (thou_reg > 'd4)? (thou_reg + 2'd3) : thou_reg;
assign hund_tmp = (hund_reg > 'd4)? (hund_reg + 2'd3) : hund_reg;
assign tens_tmp = (tens_reg > 'd4)? (tens_reg + 2'd3) : tens_reg;
assign unit_tmp = (unit_reg > 'd4)? (unit_reg + 2'd3) : unit_reg; assign thou_data = thou_out;
assign hund_data = hund_out;
assign tens_data = tens_out;
assign unit_data = unit_out; endmodule

Bin_BCD

转载请注明出处:NingHeChuan(宁河川)

个人微信订阅号:开源FPGA

如果你想及时收到个人撰写的博文推送,可以扫描左边二维码(或者长按识别二维码)关注个人微信订阅号

知乎ID:NingHeChuan

微博ID:NingHeChuan

原文地址:https://www.cnblogs.com/ninghechuan/p/9464037.html

基于Verilog HDL的二进制转BCD码实现的更多相关文章

  1. FPGA中将十进制数在数码管中显示(verilog版)--二进制转换为BCD码

    这周有朋友问怎样在fpga中用数码管来显示一个十进制数,比如1000.每个数码管上显示一位十进制数.如果用高级语言来分离各位,只需要分别对该数做1000,100,10对应的取商和取余即可分离出千百十个 ...

  2. 基于Verilog HDL 的数字电压表设计

    本次实验是在“基于Verilog HDL的ADC0809CCN数据采样”实验上进一步改进,利用ADC0809采集到的8位数据,进行BCD编码,以供查表方式相加进行显示,本次实验用三位数码管. ADC0 ...

  3. 基于Verilog HDL整数乘法器设计与仿真验证

    基于Verilog HDL整数乘法器设计与仿真验证 1.预备知识 整数分为短整数,中整数,长整数,本文只涉及到短整数.短整数:占用一个字节空间,8位,其中最高位为符号位(最高位为1表示为负数,最高位为 ...

  4. 基于Verilog HDL 各种实验

    菜鸟做的的小实验链接汇总:           1.基于Verilog HDL 的数字时钟设计 2.乘法器 3.触发器(基本的SR触发器.同步触发器.D触发器) 4.基于Verilog HDL的ADC ...

  5. 基于Verilog HDL 的数字时钟设计

    基于Verilog HDL的数字时钟设计 一.实验内容:     利用FPGA实现数字时钟设计,附带秒表功能及时间设置功能.时间设置由开关S1和S2控制,分别是增和减.开关S3是模式选择:0是正常时钟 ...

  6. FPGA加三移位算法:硬件逻辑实现二进制转BCD码

    本文设计方式采用明德扬至简设计法.利用FPGA来完成显示功能不是个很理想的方式,当显示任务比较复杂,要通过各种算法显示波形或者特定图形时,当然要用单片机通过C语言完成这类流程控制复杂,又对时序要求不高 ...

  7. C语言之linux内核--BCD码转二进制与二进制转BCD码(笔试经典)

    在分析代码之前,我们先来了解一下,BCD码和二进制到底区别在哪? 学习过计算机原理的和数字电子技术这两门课的都会知道这两个到底是什么含义,也有的同学学过了,考过了,过了一段时间又忘记了,今天,我们通过 ...

  8. 基于Verilog HDL的超前进位全加器设计

    通常我们所使用的加法器一般是串行进位,将从输入的ci逐位进位地传递到最高位的进位输出co,由于电路是有延迟的,这样的长途旅行是需要时间的,所以为了加快加法器的运算,引入了超前进位全加器. 全加器的两个 ...

  9. 基于Verilog HDL的ADC0809CCN数据采样

    本实验是用ADC0809CCN进行数据采样,并用7段数码管进行显示. ADC0809由一个8路模拟开关.一个地址锁存与译码器.一个A/D转换器和一个三态输出锁存器组成.多路开关可选通8个模拟通道,允许 ...

随机推荐

  1. Maven(Eclipse版)

    前言: 由于最近工作学习,总是能碰到Maven的源码.虽然平时工作并不使用Maven,但是为了学习一些源码,还是必须要了解下.这篇文章不是一个全面的Maven解析,而是一个简单的介绍,包括Eclips ...

  2. cdoj841-休生伤杜景死惊开 (逆序数变形)【线段树 树状数组】

    http://acm.uestc.edu.cn/#/problem/show/841 休生伤杜景死惊开 Time Limit: 3000/1000MS (Java/Others)     Memory ...

  3. 获取客户端真实IP地址

    Java-Web获取客户端真实IP: 发生的场景:服务器端接收客户端请求的时候,一般需要进行签名验证,客户端IP限定等情况,在进行客户端IP限定的时候,需要首先获取该真实的IP. 一般分为两种情况: ...

  4. boost x64 lib

    libboost_atomic-vc150-mt-gd-x64-1_66.liblibboost_atomic-vc150-mt-s-x64-1_66.liblibboost_atomic-vc150 ...

  5. SourceTree下载 及使用

    SourceTree 代码库管理工具 https://www.cnblogs.com/QianChia/p/8531725.html#_label0 SourceTree的基本使用 https://w ...

  6. IBM关闭触摸板的方法

    开始按Enter进入BIOS > Configure > Keyboard/Mouse > TouchPad,设置为DisabledF10保存退出

  7. debuginfo介绍

    一.简介 深入理解debuginfo http://blog.csdn.net/chinainvent/article/details/24129311?reload 关于DWARF http://w ...

  8. EXPAT(XML解析库)

    一.简介 expat是一个由C语言编写的XML解析库.James Clark创建了这个库,现在是制定XML标准的W3组织的技术leader.现在的版本是2.0.2.0开始就由Clark Cooper领 ...

  9. 品味性能之道<一>:性能测试思维与误区

           <java performance><品悟性能优化 oracle><面向模式的软件架构-模式系统>读书笔记应用调优分享.      性能问题的解决,首 ...

  10. apache的80端口被占用

    1.netstart -ano | findstr "80":查看80端口是否被占用,并找出对应的pid 2.关掉pid对应的进程