马上注册,看完整文章,学更多FPGA知识。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
至简设计系列_BCD译码实现 【上板现象】
BCD译码实现在MP801的上板现象
https://www.bilibili.com/video/BV1Af4y117H4?p=24
BCD译码实现在点拨开发板的上板现象
https://www.bilibili.com/video/BV1Af4y117H4?p=25
BCD译码实现在实验箱的上板现象
https://www.bilibili.com/video/BV1Af4y117H4?p=23
--作者:肖肖肖
本文为明德扬原创及录用文章,转载请注明出处!
1.1 总体设计1.1.1 概述BCD码(Binary-Coded Decimal‎),用4位二进制数来表示1位十进制数中的0~9这10个数码,是一种二进制的数字编码形式,用二进制编码的十进制代码。BCD码这种编码形式利用了四个位元来储存一个十进制的数码,使二进制和十进制之间的转换得以快捷的进行。
1.1.2 设计目标实现BCD译码并显示十进制结果的程序,具体功能要求如下: 2. FPGA接收串口数据并对其进行BCD译码; 3. 在数码管上以十进制显示串口发送的数值。
1.1.3 系统结构框图系统结构框图如下图一所示:
图一 1.1.4模块功能Ø 串口接收模块实现功能1、 接收上位机PC发来的位宽为8的十六进制数据。 Ø BCD译码模块实现功能1、 对接收到的8位十六进制数据进行BCD译码。 Ø 数码管显示模块实现功能1、 显示BCD译码后的十进制数值。 1.1.5顶层信号
1.1.6参考代码下面是使用工程的顶层代码: - module top(
- clk ,
- rst_n ,
- rx_uart ,
- seg_sel ,
- segment
- );
- parameter DATA_W = 8;
- parameter SEG_WID = 8;
- parameter SEL_WID = 3;
- parameter BCD_OUT = 12;
- input clk ;
- input rst_n ;
- input rx_uart ;
- output[SEL_WID-1:0] seg_sel ;
- output[SEG_WID-1:0] segment ;
- wire [SEL_WID-1:0] seg_sel ;
- wire [SEG_WID-1:0] segment ;
- wire [DATA_W-1 :0] rx_dout ;
- wire rx_dout_vld ;
- wire [BCD_OUT-1:0] bcd_dout ;
- wire bcd_dout_vld ;
- uart_rx u1(
- .clk ( clk ),
- .rst_n ( rst_n ),
- .din ( rx_uart ),
- .dout ( rx_dout ),
- .dout_vld ( rx_dout_vld )
- );
- bcd_water u2(
- .clk ( clk ),
- .rst_n ( rst_n ),
- .din ( rx_dout ),
- .din_vld ( rx_dout_vld ),
- .dout ( bcd_dout ),
- .dout_vld ( bcd_dout_vld )
- );
- seg_disp#(.SEG_NUM(SEL_WID)) u3(
- .clk ( clk ),
- .rst_n ( rst_n ),
- .din ( bcd_dout ),
- .din_vld ( bcd_dout_vld ),
- .seg_sel ( seg_sel ),
- .segment ( segment )
- );
- endmodule
复制代码
1.2 串口接收模块设计1.2.1接口信号
1.2.2 设计思路在前面的案例中已经有串口接收模块的介绍,所以这里不在过多介绍,详细介绍请看下方链接:
1.2.3参考代码
1.3 BCD译码模块设计1.3.1接口信号 信号名 | | | | | | | | | | | | | | | | | | | | | | | 12bit的输出BCD译码数据,每 4 bit一 组,分别表示百、十、个位的值 | | | | |
1.3.2设计思路Ø 左移加3算法 此处二进制转 BCD 码的硬件实现,采用左移加 3 的算法,具体描述如下:(此处以 8-bit 二进制码为例) 1、左移要转换的二进制码 1 位 2、左移之后,BCD 码分别置于百位、十位、个位 3、如果移位后所在的 BCD 码列大于或等于 5,则对该值加 3 4、继续左移的过程直至全部移位完成
举例:将十六进制码 0xFF 转换成 BCD 码
- module bcd_water(
- clk ,
- rst_n ,
- din ,
- din_vld ,
- dout ,
- dout_vld
- );
- input clk ;
- input rst_n ;
- input [ 7:0] din ;
- input din_vld ;
- output [11:0] dout ;
- wire [11:0] dout ;
- output dout_vld ;
- wire dout_vld ;
- reg [19:0] din_temp ;
- reg [19:0] din_temp_ff0 ;
- reg [19:0] din_temp_ff1 ;
- reg [19:0] din_temp_ff2 ;
- reg [19:0] din_temp_ff3 ;
- reg [19:0] din_temp_ff4 ;
- wire [20:0] din_shift_temp ;
- wire [20:0] din_shift_temp_ff0 ;
- wire [20:0] din_shift_temp_ff1 ;
- wire [20:0] din_shift_temp_ff2 ;
- wire [20:0] din_shift_temp_ff3 ;
- wire [ 7:0] din_a_temp ;
- wire [ 3:0] din_b_temp ;
- wire [ 3:0] din_c_temp ;
- wire [ 3:0] din_d_temp ;
- wire [ 7:0] din_add_a_temp ;
- wire [ 3:0] din_add_b_temp ;
- wire [ 3:0] din_add_c_temp ;
- wire [ 3:0] din_add_d_temp ;
- wire [ 7:0] din_a_temp_ff0 ;
- wire [ 3:0] din_b_temp_ff0 ;
- wire [ 3:0] din_c_temp_ff0 ;
- wire [ 3:0] din_d_temp_ff0 ;
- wire [ 7:0] din_a_temp_ff1 ;
- wire [ 3:0] din_b_temp_ff1 ;
- wire [ 3:0] din_c_temp_ff1 ;
- wire [ 3:0] din_d_temp_ff1 ;
- wire [ 7:0] din_a_temp_ff2 ;
- wire [ 3:0] din_b_temp_ff2 ;
- wire [ 3:0] din_c_temp_ff2 ;
- wire [ 3:0] din_d_temp_ff2 ;
- wire [ 7:0] din_a_temp_ff3 ;
- wire [ 3:0] din_b_temp_ff3 ;
- wire [ 3:0] din_c_temp_ff3 ;
- wire [ 3:0] din_d_temp_ff3 ;
- wire [ 7:0] din_add_a_temp_ff0 ;
- wire [ 3:0] din_add_b_temp_ff0 ;
- wire [ 3:0] din_add_c_temp_ff0 ;
- wire [ 3:0] din_add_d_temp_ff0 ;
- wire [ 7:0] din_add_a_temp_ff1 ;
- wire [ 3:0] din_add_b_temp_ff1 ;
- wire [ 3:0] din_add_c_temp_ff1 ;
- wire [ 3:0] din_add_d_temp_ff1 ;
- wire [ 7:0] din_add_a_temp_ff2 ;
- wire [ 3:0] din_add_b_temp_ff2 ;
- wire [ 3:0] din_add_c_temp_ff2 ;
- wire [ 3:0] din_add_d_temp_ff2 ;
- wire [ 7:0] din_add_a_temp_ff3 ;
- wire [ 3:0] din_add_b_temp_ff3 ;
- wire [ 3:0] din_add_c_temp_ff3 ;
- wire [ 3:0] din_add_d_temp_ff3 ;
- reg dout_vld_temp ;
- reg dout_vld_temp_ff0 ;
- reg dout_vld_temp_ff1 ;
- reg dout_vld_temp_ff2 ;
- reg dout_vld_temp_ff3 ;
- reg dout_vld_temp_ff4 ;
-
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- din_temp <= 20'b0;
- end
- else if(din_vld)begin
- din_temp <= {9'b0,din,3'b0};
- end
- end
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- dout_vld_temp <= 1'b0;
- end
- else if(din_vld)begin
- dout_vld_temp <= 1'b1;
- end
- else begin
- dout_vld_temp <= 1'b0;
- end
- end
- assign din_a_temp = din_temp[ 7: 0] ;
- assign din_b_temp = din_temp[11: 8] ;
- assign din_c_temp = din_temp[15:12] ;
- assign din_d_temp = din_temp[19:16] ;
- assign din_add_a_temp = din_a_temp ;
- assign din_add_b_temp = din_b_temp + ((din_b_temp>=5)?4'd3:4'd0) ;
- assign din_add_c_temp = din_c_temp + ((din_c_temp>=5)?4'd3:4'd0) ;
- assign din_add_d_temp = din_d_temp + ((din_d_temp>=5)?4'd3:4'd0) ;
- assign din_shift_temp = {din_add_d_temp,din_add_c_temp,din_add_b_temp,din_add_a_temp,1'b0} ;
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- din_temp_ff0 <= 20'b0;
- end
- else begin
- din_temp_ff0 <= din_shift_temp[19:0];
- end
- end
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- dout_vld_temp_ff0 <= 1'b0 ;
- end
- else begin
- dout_vld_temp_ff0 <= dout_vld_temp;
- end
- end
- assign din_a_temp_ff0 = din_temp_ff0[ 7: 0] ;
- assign din_b_temp_ff0 = din_temp_ff0[11: 8] ;
- assign din_c_temp_ff0 = din_temp_ff0[15:12] ;
- assign din_d_temp_ff0 = din_temp_ff0[19:16] ;
- assign din_add_a_temp_ff0 = din_a_temp_ff0 ;
- assign din_add_b_temp_ff0 = din_b_temp_ff0 + ((din_b_temp_ff0>=5)?4'd3:4'd0) ;
- assign din_add_c_temp_ff0 = din_c_temp_ff0 + ((din_c_temp_ff0>=5)?4'd3:4'd0) ;
- assign din_add_d_temp_ff0 = din_d_temp_ff0 + ((din_d_temp_ff0>=5)?4'd3:4'd0) ;
- assign din_shift_temp_ff0 = {din_add_d_temp_ff0,din_add_c_temp_ff0,din_add_b_temp_ff0,din_add_a_temp_ff0,1'b0};
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- din_temp_ff1 <= 20'b0;
- end
- else begin
- din_temp_ff1 <= din_shift_temp_ff0[19:0];
- end
- end
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- dout_vld_temp_ff1 <= 1'b0;
- end
- else begin
- dout_vld_temp_ff1 <= dout_vld_temp_ff0;
- end
- end
- assign din_a_temp_ff1 = din_temp_ff1[ 7: 0] ;
- assign din_b_temp_ff1 = din_temp_ff1[11: 8] ;
- assign din_c_temp_ff1 = din_temp_ff1[15:12] ;
- assign din_d_temp_ff1 = din_temp_ff1[19:16] ;
- assign din_add_a_temp_ff1 = din_a_temp_ff1 ;
- assign din_add_b_temp_ff1 = din_b_temp_ff1 + ((din_b_temp_ff1>=5)?4'd3:4'd0) ;
- assign din_add_c_temp_ff1 = din_c_temp_ff1 + ((din_c_temp_ff1>=5)?4'd3:4'd0) ;
- assign din_add_d_temp_ff1 = din_d_temp_ff1 + ((din_d_temp_ff1>=5)?4'd3:4'd0) ;
- assign din_shift_temp_ff1 = {din_add_d_temp_ff1,din_add_c_temp_ff1,din_add_b_temp_ff1,din_add_a_temp_ff1,1'b0};
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- din_temp_ff2 <= 20'b0;
- end
- else begin
- din_temp_ff2 <= din_shift_temp_ff1[19:0];
- end
- end
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- dout_vld_temp_ff2 <= 1'b0;
- end
- else begin
- dout_vld_temp_ff2 <= dout_vld_temp_ff1;
- end
- end
- assign din_a_temp_ff2 = din_temp_ff2[ 7: 0] ;
- assign din_b_temp_ff2 = din_temp_ff2[11: 8] ;
- assign din_c_temp_ff2 = din_temp_ff2[15:12] ;
- assign din_d_temp_ff2 = din_temp_ff2[19:16] ;
- assign din_add_a_temp_ff2 = din_a_temp_ff2 ;
- assign din_add_b_temp_ff2 = din_b_temp_ff2 + ((din_b_temp_ff2>=5)?4'd3:4'd0) ;
- assign din_add_c_temp_ff2 = din_c_temp_ff2 + ((din_c_temp_ff2>=5)?4'd3:4'd0) ;
- assign din_add_d_temp_ff2 = din_d_temp_ff2 + ((din_d_temp_ff2>=5)?4'd3:4'd0) ;
- assign din_shift_temp_ff2 = {din_add_d_temp_ff2,din_add_c_temp_ff2,din_add_b_temp_ff2,din_add_a_temp_ff2,1'b0};
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- din_temp_ff3 <= 20'b0;
- end
- else begin
- din_temp_ff3 <= din_shift_temp_ff2[19:0];
- end
- end
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- dout_vld_temp_ff3 <= 1'b0;
- end
- else begin
- dout_vld_temp_ff3 <= dout_vld_temp_ff2;
- end
- end
- assign din_a_temp_ff3 = din_temp_ff3[ 7: 0] ;
- assign din_b_temp_ff3 = din_temp_ff3[11: 8] ;
- assign din_c_temp_ff3 = din_temp_ff3[15:12] ;
- assign din_d_temp_ff3 = din_temp_ff3[19:16] ;
- assign din_add_a_temp_ff3 = din_a_temp_ff3 ;
- assign din_add_b_temp_ff3 = din_b_temp_ff3 + ((din_b_temp_ff3>=5)?4'd3:4'd0) ;
- assign din_add_c_temp_ff3 = din_c_temp_ff3 + ((din_c_temp_ff3>=5)?4'd3:4'd0) ;
- assign din_add_d_temp_ff3 = din_d_temp_ff3 + ((din_d_temp_ff3>=5)?4'd3:4'd0) ;
- assign din_shift_temp_ff3 = {din_add_d_temp_ff3,din_add_c_temp_ff3,din_add_b_temp_ff3,din_add_a_temp_ff3,1'b0};
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- din_temp_ff4 <= 20'b0;
- end
- else begin
- din_temp_ff4 <= din_shift_temp_ff3[19:0];
- end
- end
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- dout_vld_temp_ff4 <= 1'b0;
- end
- else begin
- dout_vld_temp_ff4 <= dout_vld_temp_ff3;
- end
- end
- assign dout = din_temp_ff4[19:8];
- assign dout_vld = dout_vld_temp_ff4 ;
- endmodule
复制代码
1.4 数码管显示模块设计1.4.1接口信号
1.4.2设计思路在前面的案例中已经有数码管显示的介绍,所以这里不在过多介绍,详细介绍请看下方链接:
1.4.3参考代码
1.5 效果和总结
Ø 下图是该工程在db603开发板上的现象——串口发送数据8’h93,数码管显示12’d147。
Ø 下图是该工程在mp801试验箱上的现象——串口发送数据8’he9,数码管显示12’d233。
Ø 下图是该工程在ms980试验箱上的现象——串口发送数据8’h52,数码管显示12’d082。
由于该项目的上板现象是串口发送8位的十六进制数经过BCD译码后,在数码管上显示对应的十进制数值,想观看完整现象的朋友可以看一下上板演示的视频。 感兴趣的朋友也可以访问明德扬论坛(http://www.fpgabbs.cn/)进行FPGA相关工程设计学习,也可以看一下我们往期的文章:
1.6 公司简介明德扬是一家专注于FPGA领域的专业性公司,公司主要业务包括开发板、教育培训、项目承接、人才服务等多个方向。点拨开发板——学习FPGA的入门之选。
MP801开发板——千兆网、ADDA、大容量SDRAM等,学习和项目需求一步到位。网络培训班——不管时间和空间,明德扬随时在你身边,助你快速学习FPGA。周末培训班——明天的你会感激现在的努力进取,升职加薪明德扬来助你。就业培训班——七大企业级项目实训,获得丰富的项目经验,高薪就业。专题课程——高手修炼课:提升设计能力;实用调试技巧课:提升定位和解决问题能力;FIFO架构设计课:助你快速成为架构设计师;时序约束、数字信号处理、PCIE、综合项目实践课等你来选。项目承接——承接企业FPGA研发项目。人才服务——提供人才推荐、人才代培、人才派遣等服务。
|