首先数码管的动态显示原理我们应该是稍微比较熟悉的,他主要是利用人眼的视觉残留效应来进行数码管动态扫描,实现数码管的显示的。一般我们动态扫描的频率分到1khz的频率就可以了。小梅哥AC620这块板子采用的是共阳的数码管,对应显示数字的断码控制值我贴在下面。
整个工程主要分为两个模块:
(这个是整个工程的RTL逻辑视图)
第一个就是正常的译码功能,第二个就是我们这个工程的难点,也就是外接了由两片8位74HC595移位寄存器级联后构成16位移位寄存器并将级联后的输出连接到位选及段选口,可以直接通过三个IO即可控制8位8段数码管,这样做大大节省了芯片引脚。这里放一张三线八位数码管的电路逻辑图。
代码讲解部分:
1. 译码模块
这里主要是一个动态扫描的问题,需要我们根据系统设置分出一个1khz的频率用作位选信号移位功能的实现,还有就是要区分数码管是共阴还是共阳的,用来写显示数据的断码控制值。
module hx8 (
clk,rst_n,sel_r,seg,disp_data
);
input clk,rst_n;
input [31:0] disp_data;
output reg [7:0] seg;
output [7:0] sel_r;
reg [14:0]divider_cnt;
reg clk_1K;
always@(posedge clk or negedge rst_n)//计数器
begin
if(!rst_n)
divider_cnt <= 15'd0;
else if(divider_cnt == 15'd24999)
divider_cnt <= 15'd0;
else
divider_cnt <= divider_cnt + 1'b1;
end
always@(posedge clk or negedge rst_n)//clk_1K
begin
if(!rst_n)
clk_1K <= 1'b0;
else if(divider_cnt == 15'd24999)
clk_1K <= ~clk_1K;
else
clk_1K <= clk_1K;
end
reg [7:0]sel_r;//第一到八个数码管
always@(posedge clk_1K or negedge rst_n)
begin
if(!rst_n)
sel_r <= 8'b0000_0001;
else if(sel_r == 8'b1000_0000)
sel_r <= 8'b0000_0001;
else
sel_r <= sel_r << 1;
end
reg [3:0]data_tmp;
always@(*)
begin
case(sel_r)
8'b0000_0001:data_tmp = disp_data[3:0];
8'b0000_0010:data_tmp = disp_data[7:4];
8'b0000_0100:data_tmp = disp_data[11:8];
8'b0000_1000:data_tmp = disp_data[15:12];
8'b0001_0000:data_tmp = disp_data[19:16];
8'b0010_0000:data_tmp = disp_data[23:20];
8'b0100_0000:data_tmp = disp_data[27:24];
8'b1000_0000:data_tmp = disp_data[31:28];
default:data_tmp = 4'b0000;
endcase
end
always@(*)
begin
case(data_tmp)
4'h0:seg = 7'b1000000;
4'h1:seg = 7'b1111001;
4'h2:seg = 7'b0100100;
4'h3:seg = 7'b0110000;
4'h4:seg = 7'b0011001;
4'h5:seg = 7'b0010010;
4'h6:seg = 7'b0000010;
4'h7:seg = 7'b1111000;
4'h8:seg = 7'b0000000;
4'h9:seg = 7'b0010000;
4'ha:seg = 7'b0001000;
4'hb:seg = 7'b0000011;
4'hc:seg = 7'b1000110;
4'hd:seg = 7'b0100001;
4'he:seg = 7'b0000110;
4'hf:seg = 7'b0001110;
endcase
end
endmodule
2. 74HC595驱动模块
这个地方主要是看三线数码管显示的原理图,首先要清楚三个IO口的功能是什么,原理图我们可以看到SEG7_DIO,SEG7_RCLK,SEG7SCLK三个输入端口,经由两片74HC595芯片输出连接到数码管段选位选端口。这三个端口的功能分别是串行数据输出(DIO),移位寄存器的时钟输出(RCLK),存储寄存器的时钟输出(SCLK)。
module hc59 (rst_n,clk, SH_CP,DS,ST_CP,sel_r,seg
);
input rst_n;
input clk;
input [7:0] seg;
input [7:0] sel_r;
output reg DS;
output reg SH_CP;
output reg ST_CP;
parameter CNT_MAX = 4; //分频数
reg [15:0] divider_cnt;//分频计数器
wire [15:0] r_data;
assign r_data[15:8] = seg [7:0];
assign r_data[7:0] = sel_r [7:0];
always@(posedge clk or negedge rst_n)
if(!rst_n)
divider_cnt <= 16'd0;
else if(divider_cnt == CNT_MAX)
divider_cnt <= 16'd0;
else
divider_cnt <= divider_cnt + 1'b1;
wire sck_pluse;
assign sck_pluse = (divider_cnt == CNT_MAX);
reg [4:0]SHCP_EDGE_CNT;//SH_CP EDGE counter
always@(posedge clk or negedge rst_n)
if(!rst_n)
SHCP_EDGE_CNT <= 5'd0;
else if(sck_pluse)begin
if(SHCP_EDGE_CNT == 5'd31)
SHCP_EDGE_CNT <= 5'd0;
else
SHCP_EDGE_CNT <= SHCP_EDGE_CNT + 1'd1;
end
else
SHCP_EDGE_CNT <= SHCP_EDGE_CNT;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
SH_CP <= 1'b0;
ST_CP <= 1'b0;
DS <= 1'b0;
end
else begin
case(SHCP_EDGE_CNT)
5'd0:begin SH_CP <= 1'b0; ST_CP <= 1'b1; DS <= r_data[15]; end
5'd1:begin SH_CP <= 1'b1; ST_CP <= 1'b0;end
5'd2:begin SH_CP <= 1'b0; DS <= r_data[14];end
5'd3:begin SH_CP <= 1'b1; end
5'd4:begin SH_CP <= 1'b0; DS <= r_data[13];end
5'd5:begin SH_CP <= 1'b1; end
5'd6:begin SH_CP <= 1'b0; DS <= r_data[12];end
5'd7:begin SH_CP <= 1'b1; end
5'd8:begin SH_CP <= 1'b0; DS <= r_data[11];end
5'd9:begin SH_CP <= 1'b1; end
5'd10:begin SH_CP <= 1'b0; DS <= r_data[10];end
5'd11:begin SH_CP <= 1'b1; end
5'd12:begin SH_CP <= 1'b0; DS <= r_data[9];end
5'd13:begin SH_CP <= 1'b1; end
5'd14:begin SH_CP <= 1'b0; DS <= r_data[8];end
5'd15:begin SH_CP <= 1'b1; end
5'd16:begin SH_CP <= 1'b0; DS <= r_data[7];end
5'd17:begin SH_CP <= 1'b1; end
5'd18:begin SH_CP <= 1'b0; DS <= r_data[6];end
5'd19:begin SH_CP <= 1'b1; end
5'd20:begin SH_CP <= 1'b0; DS <= r_data[5];end
5'd21:begin SH_CP <= 1'b1; end
5'd22:begin SH_CP <= 1'b0; DS <= r_data[4];end
5'd23:begin SH_CP <= 1'b1; end
5'd24:begin SH_CP <= 1'b0; DS <= r_data[3];end
5'd25:begin SH_CP <= 1'b1; end
5'd26:begin SH_CP <= 1'b0; DS <= r_data[2];end
5'd27:begin SH_CP <= 1'b1; end
5'd28:begin SH_CP <= 1'b0; DS <= r_data[1];end
5'd29:begin SH_CP <= 1'b1; end
5'd30:begin SH_CP <= 1'b0; DS <= r_data[0];end
5'd31:begin SH_CP <= 1'b1; end
endcase
end
endmodule
3. 顶层文件代码
module hx8_hc59 (rst_n,clk, SH_CP,DS,ST_CP
);
input rst_n;
input clk;
output DS;
output SH_CP;
output ST_CP;
wire [7:0] seg ;
wire [7:0] sel_r;
wire [31:0] disp_data;
assign disp_data= 32'h00000000;//需要显示的数字或字母
hc59 hc59 (
.clk (clk),
.rst_n (rst_n),
.DS (DS),
.sel_r (sel_r),
.seg (seg),
.SH_CP (SH_CP),
.ST_CP (ST_CP)
);
hx8 hx8(
.clk (clk),
.sel_r (sel_r),
.seg (seg),
.disp_data (disp_data ),
.rst_n (rst_n)
);
endmodule
以上就是整个工程的讲解过程及代码部分。