二进制转BCD8421码
8421码是BCD码中最常用的编码,使用4位二进制表示十进制数0~9,即0000~1001。例如十进制数12转二进制为1100,转化为8421码为0001 0010(十进制为18),两个编码相减得6。二进制转8421的规则是≥10就加6,否则不加6进行校正。
\[\begin{array}{r}
10010B\\
-1100B\\
\hline
0110B
\end{array}
\]
double dabble算法是先让要转换的二进制数左移一位(相当于乘2),原来的规则就变为了≥5就加3。
左移前的判断式:\(x≥10?+6:+0\),左移后变为\(2x≥10?+6:+0\),解出新的判断式\(x≥5?+3:+0\)
举个例子:将13转为8421码0001 0011
移位次数等于要转换的二进制位数。
使用Verilog实现20位二进制数转8421码
module bcd8421(
input wire clk,
input wire reset_n,
input wire [19:0] data, //要转换的二进制数据,0~999_999需要20bit
//分别输出6位
output reg [3:0] unit, //个位
output reg [3:0] ten, //十位
output reg [3:0] hun, //百位
output reg [3:0] tho, //千位
output reg [3:0] t_tho, //万位
output reg [3:0] h_tho //十万位
);
reg [43:0] data_all; //43~20是BCD码,19~0是要转换的二进制数据
//低20位数据每次左移一位至高24位
reg shift_flag; //左移标志位
reg [4:0] shift_cnt; //移位计数,原来有20位二进制数要左移20次
//完成一次判断和移位操作后,计数加一
always@(posedge clk or negedge reset_n)
if(!reset_n)
shift_cnt <= 5'b0;
else if((shift_cnt == 5'd21) && (shift_flag == 1'b1))
shift_cnt <= 5'b0;
else if(shift_flag == 1'b1)
shift_cnt <= shift_cnt + 1;
else
shift_cnt <= shift_cnt;
always@(posedge clk or negedge reset_n)
if(!reset_n)
data_all <= 44'b0;
else if(shift_cnt <= 5'd0)
data_all <= {24'b0,data};
else if((shift_cnt <= 5'd20) && (shift_flag == 1'b0)) //判断是否大于4,大于4则加3
begin
data_all[23:20] <= (data_all[23:20] > 4) ? (data_all[23:20] + 2'd3) : (data_all[23:20]);
data_all[27:24] <= (data_all[27:24] > 4) ? (data_all[27:24] + 2'd3) : (data_all[27:24]);
data_all[31:28] <= (data_all[31:28] > 4) ? (data_all[31:28] + 2'd3) : (data_all[31:28]);
data_all[35:32] <= (data_all[35:32] > 4) ? (data_all[35:32] + 2'd3) : (data_all[35:32]);
data_all[39:36] <= (data_all[39:36] > 4) ? (data_all[39:36] + 2'd3) : (data_all[39:36]);
data_all[43:40] <= (data_all[43:40] > 4) ? (data_all[43:40] + 2'd3) : (data_all[43:40]);
end
else if((shift_cnt <= 5'd20) && (shift_flag == 1'b1))
data_all <= data_all << 1;
else
data_all <= data_all;
always@(posedge clk or negedge reset_n)
if(!reset_n)
shift_flag <= 1'b0;
else
shift_flag <= ~shift_flag; //每次上升沿状态取反,0:大于4加三,1:执行左移操作
//当计数器等于20时,移位判断操作完成,对各个位数的BCD码进行赋值
always@(posedge clk or negedge reset_n)
if(!reset_n) begin
unit <= 4'b0;
ten <= 4'b0;
hun <= 4'b0;
tho <= 4'b0;
t_tho <= 4'b0;
h_tho <= 4'b0;
end
else if(shift_cnt == 5'd21) begin //shift_cnt等于21时表示所有操作已经完成
unit <= data_all[23:20];
ten <= data_all[27:24];
hun <= data_all[31:28];
tho <= data_all[35:32];
t_tho <= data_all[39:36];
h_tho <= data_all[43:40];
end
endmodule
编写testbench仿真文件
`timescale 1ns/1ns
module bcd8421_tb();
reg clk;
reg reset_n;
reg [19:0] data;
wire [3:0] unit; //个位
wire [3:0] ten; //十位
wire [3:0] hun; //百位
wire [3:0] tho; //千位
wire [3:0] t_tho; //万位
wire [3:0] h_tho; //十万位
initial
begin
clk = 1'b1;
data = 20'd123456;
reset_n <= 1'b0;
#100
reset_n <= 1'b1;
end
//clk:产生时钟
always #10 clk <= ~clk;
bcd8421 bcd8421_inst(
.clk (clk),
.reset_n (reset_n),
.data (data), //要转换的二进制数据,0~999_999需要20bit
.unit (unit), //个位
.ten (ten), //十位
.hun (hun), //百位
.tho (tho), //千位
.t_tho (t_tho), //万位
.h_tho (h_tho) //十万位
);
endmodule
将十进制数123456转为BCD码,仿真结果如图所示。
参考资料:野火FPGA