数码管是一种半导体发光器件,其基本单元是发光二极管。数码管按段数一般分为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管(多一个小数点显示)。
八段数码管是一个八字型数码管,分为八段:a、b、c、d、e、f、g、dp,其中dp为小数点,每一段即为一个发光二极管,这样的八段我们称之为段选信号。数码管常用的有10根管脚,每一段有一根管脚,另外两根管脚为一个数码管的公共端,两根互相连接。
数码管分为共阳极数码管和共阴极数码管。共阳极数码管就是把发光二极管的正极连接在一起作为一个引脚,负极分开。相反的,共阴极数码管就是把发光二极管的阴极连接在一起作为一个引脚,正极分开。这两者的区别在于,公共端是连接到地还是高电平,对于共阳极数码管需要给对应段低电平才会使其点亮,而对于共阴极数码管则需要 给其高电平才会点亮。本次实验使用的是共阳极数码管,也就是说给对应段低电平才会被点亮。给不同的段点亮可显示0~f的值。
二进制段码右边为高位左边为低位。我们只要点亮相应的段码,就能显示我们需要显示的内容。
段式数码管工作方式有两种:静态显示和动态显示。静态显示的特点是每个数码管的段选必须接一个8位数据线来显示字形,显示字形可一直保持,直到送入新字形码为止。
引脚名 | 引脚编号 | 引脚功能 |
---|---|---|
Q0—Q7 | 15,1—7 | 并行数据输出 |
GND | 8 | 电源地 |
Q7S | 9 | 串行数据输出 |
10 | 主复位(低电平有效) | |
SHCP | 11 | 移位寄存器时钟输入 |
STCP | 12 | 存储寄存器时钟输入 |
13 | 输出使能输入(低电平有效) | |
DS | 14 | 串行数据输入 |
VCC | 16 | 电源电压 |
该芯片有个并行的数据输出,同时芯片的输入是串行数据,也就是说我们使用一个串行输入口就可以并行输出八个输入的串行数据。最先输入的数据会被移位到最后位进行输出。
总结一下74HC595的使用步骤:
控制六位数码管实现000000、111111到FFFFFF每隔0.5s循环显示。
模块名称 | 功能描述 |
---|---|
seg_static | 静态数码管驱动模块 |
hc595_ctrl | 74HC595控制模块 |
seg_595_static | 数码管静态显示顶层模块 |
cnt计数器每0.5s技术到最大值,同时产生cnt_flag标志信号用于控制数码管字符的跳转。sel:数码管的位选信号。我们是显示六个数码管,直接给其全点亮即可。seg:数码管的段选信号,给其相应段码点亮显示num里的值即可。
该模块的参考代码
module seg_static
#(
parameter CNT_MAX=25'd24_999_999
)
(
input wire sys_clk ,
input wire sys_rst_n ,
output reg [5:0] sel ,
output reg [7:0] seg
);
reg [24:0] cnt;
reg [3:0] data;
reg cnt_flag;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt<=25'd0;
else if(cnt==CNT_MAX)
cnt<=25'd0;
else
cnt<=cnt+25'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt_flag<=1'b0;
else if(cnt==CNT_MAX-25'd1)
cnt_flag<=1'b1;
else
cnt_flag<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
data<=4'd0;
else if((data==4'd15)&&(cnt_flag==1'b1))
data<=4'd0;
else if(cnt_flag==1'b1)
data<=data+4'd1;
else
data<=data;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
sel<=6'b000_000;
else sel<=6'b111_111;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
seg<=8'hc0;
else case(data)
4'd0:seg<=8'hc0;
4'd1:seg<=8'hf9;
4'd2:seg<=8'ha4;
4'd3:seg<=8'hb0;
4'd4:seg<=8'h99;
4'd5:seg<=8'h92;
4'd6:seg<=8'h82;
4'd7:seg<=8'hf8;
4'd8:seg<=8'h80;
4'd9:seg<=8'h90;
4'd10:seg<=8'h88;
4'd11:seg<=8'h83;
4'd12:seg<=8'hc6;
4'd13:seg<=8'ha1;
4'd14:seg<=8'h86;
4'd15:seg<=8'h8e;
default:seg<=8'hff;
endcase
endmodule
sys_clk | 1bit | Input | 系统时钟,频率50MHz |
---|---|---|---|
sys_rst_n | 1bit | Input | 复位信号,低有效 |
sel | 6bit | Input | 数码管位选信号 |
seg | 8bit | Input | 数码管段选信号 |
stcp | 1bit | Output | 存储寄存器时钟 |
shcp | 1bit | Output | 移位寄存器时钟 |
ds | 1bit | Output | 串行数据 |
oe | 1bit | Output | 输出使能,低有效 |
本实验我们使用系统时钟(50MHz)四分频得到的shcp时钟(12.5MHz)去进行驱动,而stcp时钟是在我们串行输入14位数 码管之后拉高的,其频率远远小于shcp,所以这里我们只要确定shcp的频率即可,至于oe信号我们一直让其拉低即可。
该部分代码
module hc595_ctrl
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [5:0] sel ,
input wire [7:0] seg ,
output reg ds ,
output reg shcp ,
output reg stcp ,
output wire oe
);
wire [13:0] data ;
reg [1:0] cnt ;
reg [3:0] cnt_bit;
assign data={seg[0],seg[1],seg[2],seg[3],seg[4],seg[5],seg[6],seg[7],sel[5],sel[4],sel[3],sel[2],sel[1],sel[0]};
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt<=2'd0;
else if(cnt==2'd3)
cnt<=2'd0;
else
cnt<=cnt+2'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt_bit<=4'b0;
else if((cnt_bit==4'd13)&&(cnt==2'd3))
cnt_bit<=4'b0;
else if(cnt==2'd3)
cnt_bit<=cnt_bit+4'd1;
else
cnt_bit<=cnt_bit;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
ds<=1'b0;
else if(cnt==2'd0)
ds<=data[cnt_bit];
else
ds<=ds;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
shcp<=1'b0;
else if(cnt==2'd2)
shcp<=1'd1;
else if(cnt==2'd0)
shcp<=1'd0;
else
shcp<=shcp;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
stcp<=1'd0;
else if((cnt_bit==4'd0)&&(cnt==2'd0))
stcp<=1'd1;
else if((cnt_bit==4'd0)&&(cnt==2'd2))
stcp<=1'd0;
else
stcp<=stcp;
assign oe=1'b0;
endmodule
顶层模块代码
module seg_595_static
(
input wire sys_clk ,
input wire sys_rst_n ,
output wire ds ,
output wire shcp ,
output wire stcp ,
output wire oe
);
wire [5:0] sel ;
wire [7:0] seg ;
seg_static
#(
.CNT_MAX(25'd24_999_999)
)
seg_static_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.sel (sel ),
.seg (seg )
);
hc595_ctrl hc595_ctrl_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.sel (sel ),
.seg (seg ),
.ds (ds ),
.shcp (shcp ),
.stcp (stcp ),
. oe ( oe )
);
endmodule
仿真代码
`timescale 1ns/1ns
module tb_seg_595_static();
reg sys_clk ;
reg sys_rst_n ;
wire ds ;
wire shcp ;
wire stcp ;
wire oe ;
initial
begin
sys_clk=1'b0 ;
sys_rst_n<=1'b0 ;
#20
sys_rst_n<=1'b1 ;
end
always #10 sys_clk=~sys_clk;
seg_595_static seg_595_static_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.ds (ds ),
.shcp (shcp ),
.stcp (stcp ),
.oe (oe )
);
endmodule