一、设计要求
用拨码开关的开闭充当1与0,总的使用4个拨码开关,将其所组成二进制,使用六位数码管最高位进行十进制显示,后四位显示拨码开关所对应的BCD码。
解析
8421码 | 十进制数 |
0000 | 0 |
0001 | 1 |
0010 | 2 |
0011 | 3 |
0100 | 4 |
0101 | 5 |
0110 | 6 |
0111 | 7 |
1000 | 8 |
1001 | 9 |
(2)数码管显示原理
数码管显示分为静态显示和动态显示,静态显示所有数码管显示相同的数值,动态显示不同数码管显示不同数值。
静态显示:控制数码管需要控制两个信号,位选信号和段选信号。位选信号是独立控制的,用来控制单个数码管的亮灭。段选信号控制数码管显示数值,在电路中六个数码管的段选信号连接在一起,所以在同一时间,位选信号控制点亮的数码管显示的值是相同的。
动态显示:由“人眼视觉暂留”和“数码管余晖效应”,当我们让每个数码管快速轮流显示,当速度快到人眼无法分辨时,我们所看到的数码管就是同时显示了不同的数值。
二、模块设计
分析
整个系统分为三个模块:
Top_seg | 顶层模块,连接各模块对应信号 |
data_change | 数据转化模块,将拨码开关对应二进制转化为数字信号 |
Seg_dynamic | 动态数码管扫描模块 |
三、波形设计
分析
Data_BCD信号将四个输入转为二进制编码,seg_en信号为控制数码管动态扫描信号,在此次项目中可一直拉高。
分析
在编写过程中,想到时序逻辑,数据会延迟一拍,为了保证数据同步需要编写寄存器,用来寄存数据。
四、代码编写
顶层模块
module top_seg(
input wire sys_clk ,
input wire sys_rst_n ,
input wire key_in_0 ,
input wire key_in_1 ,
input wire key_in_2 ,
input wire key_in_3 ,
output wire [5:0] sel ,
output wire [7:0] seg
);
wire [3:0] data_bcd ;
wire seg_en ;
data_change data_change_inst(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n ),
.key_in_0 (key_in_0 ),
.key_in_1 (key_in_1 ),
.key_in_2 (key_in_2 ),
.key_in_3 (key_in_3 ),
.data_bcd (data_bcd ),
.seg_en (seg_en )
);
seg_dynamic seg_dynamic_inst(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.data_bcd (data_bcd ),
.seg_en (seg_en ),
.sel (sel ),
.seg (seg )
);
endmodule
数据转化模块:
module data_change(
input wire sys_clk ,
input wire sys_rst_n ,
input wire key_in_0 ,
input wire key_in_1 ,
input wire key_in_2 ,
input wire key_in_3 ,
output reg [3:0] data_bcd ,
output reg seg_en
);
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)begin
data_bcd <= 4'd0;
seg_en <= 1'b0;
end
else begin
data_bcd <= {key_in_0,key_in_1,key_in_2,key_in_3};
seg_en <= 1'b1;
end
endmodule
数码管动态扫描模块:
module seg_dynamic(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [3:0] data_bcd,
input wire seg_en ,
output reg [5:0] sel ,
output reg [7:0] seg
);
parameter CNT_MAX = 16'd49_999;
reg [24:0] cnt_1ms ;
reg cnt_flag ;
reg [2:0] cnt_sel ;
reg [5:0] sel_reg ;
reg [3:0] data_reg ;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_1ms <= 16'd0;
else if(cnt_1ms==CNT_MAX)
cnt_1ms <= 16'd0;
else
cnt_1ms <= cnt_1ms + 1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_flag <= 1'b0;
else if(cnt_1ms==CNT_MAX-1)
cnt_flag <= 1'b1;
else
cnt_flag <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_sel <= 3'd0;
else if(cnt_flag==1'b1)
cnt_sel <= cnt_sel + 1'b1;
else if((cnt_sel==3'd5)&&(cnt_flag==1'b1))
cnt_sel <= 3'd0;
else
cnt_sel <= cnt_sel;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
sel_reg <= 6'd0 ;
else case(cnt_sel)
3'b000 : sel_reg <= 6'b111_110 ;
//3'b001 : sel_reg <= 6'b111_101 ;
3'b010 : sel_reg <= 6'b111_011 ;
3'b011 : sel_reg <= 6'b110_111 ;
3'b100 : sel_reg <= 6'b101_111 ;
3'b101 : sel_reg <= 6'b011_111 ;
default sel_reg <= 6'b111_111 ;
endcase
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
data_reg <= 3'd0 ;
else case(cnt_sel)
3'b000 : data_reg <= data_bcd ;
//3'b001 : data_reg <= 6'b000_010 ;
3'b010 : data_reg <= {4'b00,data_bcd[3]} ;
3'b011 : data_reg <= {4'b00,data_bcd[2]} ;
3'b100 : data_reg <= {4'b00,data_bcd[1]} ;
3'b101 : data_reg <= {4'b00,data_bcd[0]} ;
default data_reg <= 4'b0000 ;
endcase
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
seg <= 8'h79 ;
else case(data_reg)
4'd0 : seg <= 8'h3f;
4'd1 : seg <= 8'h06;
4'd2 : seg <= 8'h5b;
4'd3 : seg <= 8'h4f;
4'd4 : seg <= 8'h66;
4'd5 : seg <= 8'h6d;
4'd6 : seg <= 8'h7d;
4'd7 : seg <= 8'h07;
4'd8 : seg <= 8'h7f;
4'd9 : seg <= 8'h6f;
default seg <= 8'h79 ;
endcase
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
sel <= 6'd0;
else
sel <= sel_reg;
endmodule
五、RTL视图
由RTL视图发现该代码有待改进,多路选择部分没有写完整。
六、Testbench编写
module tb_seg();
reg sys_clk ;
reg sys_rst_n ;
reg key_in_0 ;
reg key_in_1 ;
reg key_in_2 ;
reg key_in_3 ;
wire [5:0] sel ;
wire [7:0] seg ;
initial
begin
sys_clk <= 1'b1;
sys_rst_n <= 1'b0;
key_in_0 <= 1'b0;
key_in_1 <= 1'b0;
key_in_2 <= 1'b0;
key_in_3 <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
always#10 sys_clk <= ~sys_clk;
always#100_0007 key_in_1 <= {$random} % 2;
always#100_0007 key_in_2 <= {$random} % 2;
always#100_0007 key_in_3 <= {$random} % 2;
top_seg top_seg_inst(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n),
.key_in_0 (key_in_0),
.key_in_1 (key_in_1),
.key_in_2 (key_in_2),
.key_in_3 (key_in_3),
.sel (sel) ,
.seg (seg)
);
endmodule
七、仿真结果
仿真波形主要查看动态数码管扫描模块部分是否正确。
八、上板实测
如图所示,用左下方四个拨码开关进行输入,数码管进行输出。
九、下期内容
没有系统的跟谁学习,每次做完一个项目不知道下个项目学什么,每次都提前想好吧!
下个项目FPGA部分最后一个项目——摄像头驱动,可以学到:IIC通信协议、SPI通信协议、UART通信、FIFO、SDRAM 等等。
行而不辍,未来可期。