21-数码管静态显示
1.数码管静态显示
- 数码管是一种半导体发光器件,其基本单元是发光二极管
- 常见的数码管有七段数码管和八段数码管(相差一个小数点),还有米字管,十六段管等
- 八段发光数码管每一段对应a,b,c,d,e,f,g,dp(小数点)
- 八段数码管有十个管教,八段+两个公共端com,与数码管内部是导通的
- 八段数码管又分为共阴极数码管和共阳极数码管,共阴极和共阳极数码管就是将二极管的阴极或者是阳极在数码管内部进行连接起来
1.1 数码管的信息显示
- 如果显示数字0,那么在0对应的段的端口输入低电平,就可以显示0,a,b,c,d,e,f都点亮,g和dp都是熄灭
- 十六进制断码中:a对应的二进制数的最低位
1.2 多位八段数码管
- 六位八段数码管
- 是否需要48个端口信号?在使用多位8段数码管的时候,为了减少段选的IO口,可以将多个数码管连接起来使用位选信号进行控制,可以通过哪几个数码管
- 段选信号连在一起,位选信号选择的数码管显示的值是一样的,这就是数码管的静态显示
- 使用段选+位选的方式只占据14个IO口,但是还是比较多,使用位移缓存器74HC595
- 74HC595将串行数据转换为并行数据,最低位对应q7,最高位对应q0
- 内部具有8位移位寄存器,存储器和三态输出
- 74HC595只有8bit,要满足14bit输入需要两片级联
1.3 串行数据传递顺序
- DIG6 - 对应位选的第0位,DIG1 - 对应位选的第5位
- 先传位选信号再传段选信号,位选信号从低位到高位,段选信号从高位到低位
1.4 74HC595使用
使用74HC595芯片,只需要将其四个端口连接到FPGA芯片,就可以使用,所以节省14-4 = 10个IO口
- DS\SHCP\STCP\OE'端
- MR'主复位端,低电平有效,MR'有效,可以将移位寄存器中的值进行清0,通常将其接到Vcc,使其为1
- DS端口,与FPGA芯片进行连接,通过这个端口将串行输入到移位寄存器中
- SHCP端口,是移位寄存器时钟输入,在上升沿将输入的串行数据移入到移位寄存器当中,注意是移位寄存器,当下一个时钟上升沿到来的之后,上一个上升沿传入的数据就会向下移动一位,如果是串行输入8bit数据,低位传入的数据就回移动到最后面,如果一次输入的超过8bit,比如14bit数据,最先输入的6bit就会通过Q7S端口输出,与下一个595芯片的DS端口连接,就相当于先前输入的6bit会输入到下一个595芯片当中
- STCP存储寄存器时钟,在上升沿时,会将移位寄存器中的数据写入到存储寄存器中
- OE'端口信号有效时,就可以将存储寄存器数据通过端口并行输出,输出端口与数码管相连接
- 通过DS端口传入串行数据,产生SHCP时钟,将DS输入的数据串行移入到移位寄存器中,产生STCP时钟将移位寄存器中的数据传入到存储寄存器中,产生OE信号将存储寄存器中的数据输出
2.FPGA
- 000000 - FFFFFF,实现六位数码管循环静态显示,每个数值显示时间是0.5s
2.1 框图
- 输入信号只有时钟和复位信号
- 输出信号有和595芯片连接的四个信号
2.1.1 子功能模块框图绘制
- 可以生成两个子功能模块,第一个模块生成位选和片选信号,第二个模块负责驱动595芯片
- 位选信号是6bit信号,控制6个数码管,段选信号是8bit
2.1.2 系统模块框图绘制
- 绘制系统框图,可以了解子功能模块的关系
- 了解子功能模块之间信号关系
2.2 波形图
2.2.1 产生段选和位选的控制信号
- 输入信号:时钟和复位
- 每个数字需要维持0.5s,需要计数器
- 数码管显示:通过一个变量(data)控制字符的切换,每经过一个0.5s就切换一个数值,16个循环
- 为了控制字符显示,生成cnt_flag信号
2.2.2 产生控制信号的模块波形
- 定义一个变量data 14bit进行拼接
- 进行时钟的分频,使用计数器进行时钟分频,时钟信号不能太高也不能太低
- 50M时钟进行四分频12.5M
- 再声明一个计数器对于输出的bit数进行计数cnt_bit,分频时钟每经过一个周期,输出一个数,cnt_bit计数器加1,计数到最大值13清0
- ds信号,初值为0,其他时刻ds等于data数据的从高到低的bit位的值(data[cnt_bit])
- shcp,为了能够准确采集到数据,要在分频时钟中间采样(上升沿位于分频时钟中间)
- shtp,14bit数据在存储在移位寄存器之后,产生一个高电平,将移位寄存器的数据移动存储寄存器
- oe信号,低电平有效,保持低电平有效即可
2.3 RTL
module seg_static
#(
parameter CNT_MAX = 25'd24_999_999
)
(
input wrie 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 + 1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 4'd0;
else if((cnt_flag == 1'b1) && (data == 4'd15))
data <= 4'd0;
else if(cnt_flag == 1'b1)
data <= data + 1'b1;
else data <= data;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_flag <= 1'b0
else if(cnt == 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 == 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'hff;
else case (data)
4'd0:seg <= 8'hc0;
4'd0:seg <= 8'hf9;
4'd0:seg <= 8'ha4;
4'd0:seg <= 8'hb0;
4'd0:seg <= 8'h99;
4'd0:seg <= 8'h92;
4'd0:seg <= 8'h82;
4'd0:seg <= 8'hf8;
4'd0:seg <= 8'h80;
4'd0:seg <= 8'h88;
4'd0:seg <= 8'h90;
4'd0:seg <= 8'h83;
4'd0:seg <= 8'hc6;
4'd0:seg <= 8'ha1;
4'd0:seg <= 8'h86;
4'd0:seg <= 8'h8e;
default:seg <= 8'hff;
endcase
endmodule
- 段码可以参数化
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};
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 + 1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_bit <= 4'd0;
else if((cnt_bit == 4'd13) && (cnt == 2'd3))
cnt_bit <= 4'd0;
else if(cnt == 2'd3)
cnt_bit <= cnt_bit + 1'b1;
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'b1;
else if(cnt == 2'd0)
shcp <= 1'b0;
else
shcp <= shcp;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
stcp <= 1'b0;
else if((cnt_bit == 4'd0) && (cnt == 2'd0))
stcp <= 1'b1;
else if((cnt_bit == 4'd0) && (cnt == 2'd2))
stcp <= 1'b1;
else
stcp <= stcp;
assign oe <= 1'b0;
endmodule
top
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] sel;
// 例化子模块
seg_static
# (
.CNT_MAX (25'd24);
)
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_clk),
.sel (sel),
.seg (seg),
.ds (ds),
.shcp (shcp),
.stcp (stcp),
.oe (oe)
);
endmodule
2.4 testbench
// tb
module tb_seg_static ();
reg sys_clk;
reg sys_rst_n;
wire [5;0] sel;
wire [7:0] seg;
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20;
sys_rst_n <= 1'b1;
end
always #10 sys_clk =~sys_clk;
seg_static
#(
.CNT_MAX (25'd24)
)
seg_static_inst(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.sel (sel),
.seg (seg)
);
endmodule
顶层模块tb
// tb
`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'b1;
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_clk),
.ds (ds),
.shcp (shcp),
.stcp (stcp),
.oe (oe)
);
endmodule