23- 数码管动态显示02-转换BCD码
1.BCD码
- 数码管动态显示的data[19:0]使用二进制数表示的多位十进制数,不能直接生成段选和片选信号,需要使用BCD码表示的十进制数
- BCD码(Binary-Coded Decimal),又称为二-十进制码,使用四位二进制数来表示1位十进制数中的0-9这十个数,是一种二进制的数字编码形式,用二进制编码的十进制代码
- 分类:有权码和无权码,这里的权字表示权值,有权码四位二进制数中的
- 有权码:8421码,5421码,2421码
- 无权码:余三码,余三循环码,格雷码
- 使用多位数码管表示234,二进制表示就是1110_1010,使用8421码表示0010_0011_0100
- 使用多位数码管显示234,需要使用动态扫描的方式,要依次显示个位,十位,百位,要求能从传入的数据中得到个位,十位,百位,所以使用BCD码可以直接得到位选信号和段选信号
1.1 二进制数转换为BCD码
- 实现转换的第一步,就是在输入的二进制码之前补多少个0,补(十进制数位数*4)个0
- 234 -- 前面补12个0,然后看BCD码每一位,如果小于等于4,就保持不变,进行移位操作(左移);如果大于4,就将补的BCD码进行加3
- 直到二进制数为0,补充的BCD码位就是对应的二进制数的BCD码,十进制数-->二进制数-->BCD码
- 移位次数:输入多少位二进制数,就会移位多少次
2.BCD码转换模块
2.1 模块框图
添加BCD码转换模块
- 输入时钟和复位信号
- 输入十进制数的二进制编码
- 输出六路BCD码4bit,输出的6路BCD码分别用个位,十位,百位,千位,万位,十万位表示
系统框图需要进行修改
2.2 波形图
- 二进制码向BCD码的转换是通过判断运算加移位操作实现的,移位次数是与二进制数的位数相关的,需要移位计数器对于判断运算和移位次数进行计数,移位次数是20次,所以位宽为5bit
- 需要一个中间变量存储中间的数据,data_shift[43:0],(二进制数位数+BCD码位数)
- 判断运算在前,移位操作在后,需要一个标志信号区分这两个操作(shift_flag),但是这两个操作是在一个时钟周期内完成的,每次移位操作都是在判断计算之后进行的
2.3 RTL
module bcd_8421(
input wire sys_clk,
input wire sys_rst_n,
input wire [19:0] data,
output reg [3:0] unit ,
output reg [3:0] ten ,
output reg [3:0] hun ,
output reg [3:0] thou ,
output reg [3:0] t_thou ,
output reg [3:0] h_hun ,
);
reg [4:0] cnt_shift;
reg [43:0] data_shift;
reg shift_flag;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_clk == 1'b1)
cnt_shift <= 5'd0;
else if((cnt_shift == 5'd21)&&(shift_flag == 1'b1))
cnt_shift <= 5'd0;
else if(shift_flag == 1'b1)
cnt_shift <= cnt_shift + 1'b1;
else
cnt_shift <= cnt_shift;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_clk == 1'b1)
data_shift <= 44'b0;
else if(cnt_shift == 5'd0)
data_shift <= {24'b0,data};
else if((shift_flag == 1'b0) && (cnt_shift <= 20))
begin
data_shift[23:20] <= (data_shift[23:20] > 4) ? (data_shift[23:20] + 2'd3) : data_shift[23:20];
data_shift[27:24] <= (data_shift[27:24] > 4) ? (data_shift[27:24] + 2'd3) : data_shift[27:24];
data_shift[31:28] <= (data_shift[31:28] > 4) ? (data_shift[31:28] + 2'd3) : data_shift[31:28];
data_shift[35:32] <= (data_shift[35:32] > 4) ? (data_shift[35:32] + 2'd3) : data_shift[35:32];
data_shift[39:36] <= (data_shift[39:36] > 4) ? (data_shift[39:36] + 2'd3) : data_shift[39:36];
data_shift[43:40] <= (data_shift[43:40] > 4) ? (data_shift[43:40] + 2'd3) : data_shift[43:40];
end
else if((shift_flag == 1'b1)&&(cnt_shift <= 20))
data_shift <= data_shift << 1;
else
data_shift <= data_shift;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_clk == 1'b1)
shift_flag <= 1'b0;
else
shift_flag <= ~shift_flag;
// 输出信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_clk == 1'b1)
begin
unit <= 4'b0;
ten <= 4'b0;
hun <= 4'b0;
thou <= 4'b0;
t_thou <= 4'b0;
h_hun <= 4'b0;
end
else if(data_shift == 5'd21)
begin
unit <= data_shift[23:20];
ten <= data_shift[27:24];
hun <= data_shift[31:28];
thou <= data_shift[35:32];
t_thou <= data_shift[39:36];
h_hun <= data_shift[43:40];
end
endmodule
2.4 Testbench
`timescale 1ns/1ns
module tb_bcd_8421();
reg sys_clk ;
reg sys_rst_n ;
reg [19:0] data ;
wire [3:0] unit ;
wire [3:0] ten ;
wire [3:0] hun ;
wire [3:0] thou ;
wire [3:0] t_thou ;
wire [3:0] h_hun ;
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
data <= 20'd0;
#30
sys_rst_n <= 1'b1;
data <= 20'd123_456;
#3000;
data <= 20'd654_321;
#3000;
data <= 20'd987_654;
#2000;
data <= 20'd999_999;
end
always #10 sys_clk = ~sys_clk;
bcd_8421 bcd_8421_inst(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n ) ,
.data (data ) ,
.unit (unit ) ,
.ten (ten ) ,
.hun (hun ) ,
.thou (thou ) ,
.t_thou (t_thou ) ,
.h_hun (h_hun ) ,
);
endmodule