一、目的
控制六位数码管让其以000000、111111、222222一直到FFFFFF循环显示。每个字符显示0.5s后变化。
二、原理介绍
数码管显示对应内容时,对应的段码如下图所示:
74HC595芯片的引脚图及各引脚功能如下:
数码管和74HC595原理图如下:
注意:先传位选信号再传段选信号,位选信号sel[0]~sel[5]先传低位再传高位,与DIG6~DIG1分别对应。段选信号seg[7:0]先传高位再传低位,才能使段码和引脚对应。
三、子模块分析
1:产生位选sel和段选信号seg。
位选信号控制哪几个数码管点亮,段选信号显示哪个字符(0~F),静态显示中段选信号显示的数字是一样的。
2:产生控制74HC595的信号:shcp、stcp、ds、oe
ds(串行数据)就是输入的数码管位选信号和段选信号;
shcp(移位寄存器时钟)是ds数据进入移位寄存器的时钟;
stcp(存储寄存器时钟) 当数码管控制信号传输完之后我们需要拉高一个stcp时钟来将信号存入存储寄存器之中;
oe (存储寄存器数据输出使能信号)低电平有效
四、程序设计
1、seg_static模块时序图如下:
时序图对应代码如下:
module seg_static
(
input sys_clk,
input rst_n ,
output reg [5:0] sel ,
output reg [7:0] seg
);
parameter CNT_MAX = 25'd25_000_000;
reg [24:0] time_cnt;
reg cnt_flag;
reg [3:0] num;
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)
time_cnt <= 25'b0;
else if(time_cnt == CNT_MAX - 1)
time_cnt <= 25'b0;
else
time_cnt <= time_cnt + 1'b1;
end
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)
cnt_flag <= 1'b0;
else if(time_cnt == CNT_MAX - 1)
cnt_flag <= 1'b1;
else
cnt_flag <= 1'b0;
end
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)
num <= 4'd0;
else if(cnt_flag==1)
num <= num + 1'b1;
else
num <= num;
end
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)
sel <= 6'd0;
else
sel <= 6'b111_111;
end
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)
seg <= 8'hff;
else
case(num)
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
end
endmodule
2、595控制模块时序图如下:
时序图对应代码如下:
module hc595_control
(
input sys_clk,
input rst_n ,
input wire [7:0]seg ,
input wire [5:0]sel ,
output reg shcp ,
output reg stcp ,
output reg ds ,
output reg oe
);
reg [1:0] div_cnt;
reg [3:0] bit_cnt;
wire [13:0]data ;
assign data = {seg[0],seg[1],seg[2],seg[3],seg[4],seg[5],seg[6],seg[7],sel[5:0]};
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)
div_cnt <= 2'b0;
else if(div_cnt == 2'd3)
div_cnt <= 2'b0;
else
div_cnt <= div_cnt + 1'b1;
end
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)
bit_cnt <= 4'd0;
else if((bit_cnt == 4'd13)&&(div_cnt == 2'd3))
bit_cnt <= 4'd0;
else if(div_cnt == 2'd3)
bit_cnt <= bit_cnt + 1'b1;
else
bit_cnt <= bit_cnt;
end
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)
shcp <= 1'b0;
else if((div_cnt == 2'd2)||(div_cnt == 2'd3))
shcp <= 1'b1;
else
shcp <= 1'b0;
end
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)
stcp <= 1'b0;
else if((bit_cnt == 4'd13)&&(div_cnt == 2'd3))
stcp <= 1'b1;
else
stcp <= 1'b0;
end
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)
ds <= 1'd0;
else
ds <= data[bit_cnt];
end
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)
oe <= 1'b1;
else
oe <= 1'b0;
end
endmodule
3、顶层模块
顶层模块简单例化两个子模块即可
五、仿真波形
六、总结
1、数码管显示的数字对应的二进制段码在传输时需要先传高位再传低位(在此块开发板原理图中是这样),为什么呢?
eg:传输数字3时,二进制段码为:1011_0000(是逆序排的噢,DP在前,A在后),对应的十六进制段码为8’hb0,若seg[7:0],直接传输是低位在前高位在后,那么595原理图中就是seg[0]对应的引脚为LEDSD_DP,seg[7]对应的就是LEDSD_A,这样传输八位数码管对应位就会显示错误。所以这里需要先传高位seg[7],数码管各引脚就会对应正确。