上篇写了倒计时系统的计时模块,这篇接着写倒计时系统的BCD编码模块。首先介绍下,BCD码的定义。 BCD码是指用4位二进制数来表示1位十进制数0——9中的一个。
设计此模块的原因:假如上一篇计时模块的输出cnt_s=21、cnt_ms=45(即21.45),它是二进制数;而数码管显示是将cnt_s=21/cnt_ms=45的个位和十位分别显示的。故此需要将二进制数转化成BCD码。
(一)二进制数转BCD码的原理(加3移位算法)
首先,定义一个4*N位的BCD码,如bcd_data[7:0]=8'h00,需被转换的二进制数定义成din[7:0]。
然后,将din[7]移入bcd_data[0],将bcd_data[7:0]每四位分成一组,这4位组成的二进制数若>=5,则加3后再赋值于bcd_data[7:0];若<5,则将bcd_data[7:0]保持不变。依次进行上步操作,直至将din[7:0]的数值全部移入bcd_data[7:0]中。
需要注意的是,被转换的二进制数din是N位,则需要转移的次数就是N次,判断的次数是(N-1)次。
(二) BCD编码的模块框图:
(三)源代码:
- module bcd(
- //System Signals
- input sclk ,
- input rst_n ,
- //Others
- input bcd_trig ,
- input [7:0] din , //max is 99
- //cnt_ms[7:0],cnt_s[7:0]
- output reg [7:0] bcd_data , //two smg:4bit+4bit
- //bcd_cnt_ms[7:0],bcd_cnt_s[7:0]
- output reg bcd_data_vld
- );
- //========================================================================\
- // **********Define Parameter and Internal Signals*******************
- //========================================================================/
- parameter END_SHIFT = 8 ; //din is 8 bit
- parameter IDLE = 3'b001 ;
- parameter SHIFT = 3'b010 ;
- parameter ADD = 3'b100 ;
- reg [7:0] din_temp ;
- reg [3:0] bcd_data_r1 ; //unit
- reg [3:0] bcd_data_r2 ; //ten
- reg [2:0] state ;
- reg [3:0] cnt_shift ;
- reg flag_bcd ;
- //========================================================================\
- // **********Main Code*******************
- //========================================================================/
- //flag_bcd
- always @(posedge sclk or negedge rst_n)
- begin
- if(!rst_n)
- flag_bcd<=1'b0;
- else if(bcd_trig==1'b1)
- flag_bcd<=1'b1;
- else if(bcd_data_vld==1'b1)
- flag_bcd<=1'b0;
- end
- always @(posedge sclk or negedge rst_n)
- begin
- if(!rst_n)
- begin
- bcd_data_r1<=4'b0000;
- bcd_data_r2<=4'b0000;
- bcd_data<=8'd0;
- bcd_data_vld<=1'b0;
- cnt_shift<=4'd0;
- din_temp<=8'd0;
- state<=IDLE;
- end
- else //if(flag_bcd)
- begin
- case(state)
- IDLE: begin
- bcd_data_vld<=1'b0;
- if(flag_bcd==1'b1)
- begin
- din_temp<=din;
- bcd_data_r1<=4'b0000;
- bcd_data_r2<=4'b0000;
- state<=SHIFT;
- end
- else state=IDLE;
- end
- SHIFT: begin
- if(cnt_shift<END_SHIFT)
- begin
- bcd_data_r1<={bcd_data_r1[2:0],din_temp[7]};
- bcd_data_r2<={bcd_data_r2[2:0],bcd_data_r1[3]};
- din_temp<={din_temp[6:0],1'b0};
- cnt_shift<=cnt_shift+1'b1;
- state<=ADD;
- end
- else begin
- bcd_data_vld<=1'b0;
- state<=IDLE;
- end
- end
- ADD: begin
- if(cnt_shift<END_SHIFT)
- begin
- if(bcd_data_r1>='d5)
- bcd_data_r1<=bcd_data_r1+'d3;
- else bcd_data_r1<=bcd_data_r1;
-
- if(bcd_data_r2>='d5)
- bcd_data_r2<=bcd_data_r2+'d3;
- else bcd_data_r2<=bcd_data_r2;
-
- state<=SHIFT;
- end
- else begin
- bcd_data<={bcd_data_r2,bcd_data_r1};
- bcd_data_vld<=1'b1;
- cnt_shift<='d0;
- state<=IDLE;
- end
- end
- default: begin
- state<=IDLE;
- cnt_shift<='d0;
- end
- endcase
- end
- end
- endmodule
(四)这个模块主要使用了一个状态机。这个状态机也比较简单,一共三个状态,分别是初始态(IDLE)、移位态(SHIFT)和判断加3态(ADD)。下面是其状态转移图:
(五)总结
在这个模块中也使用了自己代码的一贯风格:
A. 定义了此模块被触发的开始信号bcd_trig;
B. BCD编码正在工作状态的信号flag_bcd;
C. BCD编码完成信号bcd_data_vld.
|