FPGA中将十进制数在数码管中显示(verilog版)--二进制转换为BCD码
这周有朋友问怎样在fpga中用数码管来显示一个十进制数,比如1000。每个数码管上显示一位十进制数。如果用高级语言来分离各位,只需要分别对该数做1000,100,10对应的取商和取余即可分离出千百十个位。但是FPGA做除法非常耗资源。有没有其它解决办法?因为用verilog写程序时虽然形式上可以写为比如256,但是实际存储对应的还是0100H,且一个数码管只能显示一个十进制数。因此这个问题相当于二进制如何转换为一个BCD(Binary Code Decimal)码数。
本文只考虑最常见的8421码的转换,而且是压缩BCD码。
一、算法原理
根据二进制与十进制转换的定义可知,将二进制数按位加权求和即可得到。用公式描述为n位二进制转换10进制公式
A(n-1)*2^(n-1)+A(n-2)*2^(n-2)+........+A(0)*2^0=对应十进制数 (1)
将公式(1)一直提取公因子2,可很容易将公式(1)转换为公式(2),如下所示:
(A(n-1)*2+A(n-2))*2+A(n-3))*2........+a(0) =对应十进制数 (2)
即对于n位二进制数的按权展开求和,由最高的2的n-1次幂,转换为乘以n-1次2,以此类推n-2次幂,n-3次幂……。因为左移一位相当于乘以2,这样乘法操作就转换为了左移操作。
1、BCD码有0~9共计10个数码,用四位二进制表示0000~1001即可表示,而四位二进制可以表示数的范围为0000~1001~1111,即0~9~15。总计多处了 6个数码A~F。我们知道十进制逢十进一,十六进制逢十六进一。从而产生了一个非常关键的问题,转换到大于等于10以后的数字后本应由低位向紧邻的高位进位,但是只能到大于16以后进位。如DH(12D)十进制本应进位产生十位1,和个位2,但是却变成十六进制的DH。所以必须进行修正,修正的方法是加6。
2、BCD码是二进制编码的十进制,逢十进一,10/2=5.因此得到判断条件,即判断每四位是否大于4,因为5-9进一位(左移)溢出。
3、对于左移操作,相当于每进一位就会丢掉6,那么就要加上6/2=3(3左移一位后相当于6)。每次调整在左移之前完成。
*因此二进制转BCD的方法是通过左移,然后每四位判断是否大于4,满足则加3.
二、基于Verilog的代码实现
为了简便,本代码是以十进制数1000为例进行测试。1000D = 3E8H = 0011 1110 1000B。
1 /******************************************************************* 2 * 功能:将二进制数转换为BCD码数,在七段数码管上显示 3 * 原理:左移 + 3 4 * 作者:国静德远 5 * 时间:2017年4月16日 6 *******************************************************************/ 7 module BinaryToBCD(CLOCK_50, HEX3, HEX2, HEX1, HEX0); 8 9 input CLOCK_50; 10 output [7:0] HEX3, HEX2, HEX1, HEX0; 11 12 wire [9:0] TestData; 13 wire [15:0] ResultData; 14 assign TestData = 10\'d1001; 15 //Binary to BCD 16 Binary2BCD ConvertData(CLOCK_50, TestData, ResultData); 17 //Display 18 Seg7 H1(ResultData[ 3 : 0], HEX0); 19 Seg7 H2(ResultData[ 7 : 4], HEX1); 20 Seg7 H3(ResultData[11 : 8], HEX2); 21 Seg7 H4(ResultData[15 : 12], HEX3); 22 23 endmodule 24 25 //Convert Data by left + 3 26 module Binary2BCD(inClk, inData, outData); 27 input inClk; 28 input [9:0] inData; 29 output [15:0]outData; 30 31 32 reg [3:0]count10 = 9; 33 reg [15:0]ShiftReg; 34 35 36 always@(posedge inClk) 37 begin 38 if(count10 >= 0 && count10 <= 9) 39 begin 40 count10 <= count10 - 1\'b1; 41 end 42 else 43 count10 <= 4\'d15; 44 end 45 46 always @(posedge inClk) 47 begin 48 //for(i = 9; i >= 0; i = i - 1) 49 if(count10 >= 0 && count10 <= 9) 50 begin 51 // shift left 52 ShiftReg = (ShiftReg << 1); 53 ShiftReg[0] = inData[count10]; 54 //adjust by add 3 55 if(ShiftReg[15:12] > 4) 56 ShiftReg[15:12] = ShiftReg[15:12] + 2\'d3; 57 else 58 ShiftReg[15:12] = ShiftReg[15:12]; 59 60 if(ShiftReg[11:8] > 4) 61 ShiftReg[11:8] = ShiftReg[11:8] + 2\'d3; 62 else 63 ShiftReg[11:8] = ShiftReg[11:8]; 64 65 if(ShiftReg[7:4] > 4) 66 ShiftReg[7:4] = ShiftReg[7:4] + 2\'d3; 67 else 68 ShiftReg[7:4] = ShiftReg[7:4]; 69 70 if(ShiftReg[3:0] > 4) 71 ShiftReg[3:0] = ShiftReg[3:0] + 2\'d3; 72 else 73 ShiftReg[3:0] = ShiftReg[3:0]; 74 75 76 end 77 else 78 ShiftReg = ShiftReg; 79 end 80 81 assign outData = ShiftReg; 82 83 endmodule 84 85 //Display on 7seg 86 module Seg7(inData, outData); 87 input [3:0]inData; 88 output [7:0]outData; 89 //reg [3:0]inData; 90 reg [7:0]outData; 91 always@(inData) 92 begin 93 case(inData) 94 4\'d0: outData = 8\'b1100_0000; 95 4\'d1: outData = 8\'b1111_1001; 96 4\'d2: outData = 8\'b1010_0100; 97 4\'d3: outData = 8\'b1011_0000; 98 4\'d4: outData = 8\'b1001_1001; 99 4\'d5: outData = 8\'b1001_0010; 100 4\'d6: outData = 8\'b1000_0010; 101 4\'d7: outData = 8\'b1111_1000; 102 4\'d8: outData = 8\'b1000_0000; 103 4\'d9: outData = 8\'b1001_0000; 104 default: outData = 8\'b1111_1111; 105 endcase 106 end 107 endmodule
仿真结果如下图所示: