目标:设计一个 6 位数码管静态显示:控制六位数码管让其以 000000、111111、222222 一直到 FFFFFF 循环显示。每个字符显示 0.5s 后变化。
一、理论知识:
1.八段数码管结构图
八段数码管分为共阴极和共阳极数码管。这两者的区别在于,公共端是连接到地还是高电平,对
于共阳极数码管需要给对应段低电平才会使其点亮,而对于共阴极数码管则需要给其高电平才会点亮。此次使用的是共阳极数码管,给对应段低电平才会被点亮。
数码管编码译码表
六位数码管等效电路图
注:sel为位选信号,控制着数码管的亮灭。
74HC595简介
74HC595芯片内部结构图
1)SHCP 为移位寄存器时钟输入,上升沿时将输入的串行数据(DS 端输入)移入移位寄存器中。需要注要的是它是一个移位寄存器,也就是说当下一个脉冲(时钟上升沿)到来时,上一个脉冲移入的数据就会往下移动一位。
如果我们串行输入 8bit 数据,8bit 数据输入完之后,那么第一位输入的数据将会移动到最后面。
若我们一次输入的数据超过 8bit,那么后面的数据就会通过 Q7S 端口输出,此时我们可以将该接口接到另一片74HC595 芯片的串行输入端(级联),这样数据就会随着脉冲依次移位到另一片 74HC595芯片上。
74HC595的使用步骤
1、 首先把要传输的数据通过引脚 DS 输入到 74HC595 中。
2、 产生 SHCP 时钟,将 DS 上的数据串行移入移位寄存器。
3、 产生 STCP 时钟,将移位寄存器里的数据送入存储寄存器。
4、 将OE引脚置为低电平,存储寄存器的数据会在 Q0—Q7 并行输出,同时并行输出
的数据会被锁存起来。
74HC595原理图
我们将两片 74HC595 进行级联,一片的 Q7S 输出端接到另一片的数据输入端 DS,这样我
们输入的 14 位串行输入数码管信号的前六位就会在第二片就行输出。
二、程序设计
1.模块框图
系统框图
静态数码管驱动模块框图
输入信号为sys_clk和sys_rst_n,输出信号为6位位选信号和8位段选信号
数码管静态显示参考代码:
module seg_static
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低电平有效
output reg [5:0] sel , //数码管位选信号
output reg [7:0] seg //数码管段选信号
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter CNT_WAIT_MAX = 25'd24_999_999; //计数器最大值(0.5s)
//十六进制数显示编码
parameter SEG_0 = 8'b1100_0000, SEG_1 = 8'b1111_1001,
SEG_2 = 8'b1010_0100, SEG_3 = 8'b1011_0000,
SEG_4 = 8'b1001_1001, SEG_5 = 8'b1001_0010,
SEG_6 = 8'b1000_0010, SEG_7 = 8'b1111_1000,
SEG_8 = 8'b1000_0000, SEG_9 = 8'b1001_0000,
SEG_A = 8'b1000_1000, SEG_B = 8'b1000_0011,
SEG_C = 8'b1100_0110, SEG_D = 8'b1010_0001,
SEG_E = 8'b1000_0110, SEG_F = 8'b1000_1110;
parameter IDLE = 8'b1111_1111; //不显示状态
//reg define
reg add_flag ; //数码管数值+1标志信号
reg [24:0] cnt_wait ; //时钟分频计数器
reg [3:0] num ; //数码管显示的十六进制数
//********************************************************************//
//*************************** Main Code ******************************//
//********************************************************************//
//cnt_wait:0.5秒计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_wait <= 25'd0;
else if(cnt_wait == CNT_WAIT_MAX)
cnt_wait <= 25'd0;
else
cnt_wait <= cnt_wait + 1'b1;
//add_flag:0.5s拉高一个标志信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
add_flag <= 1'b0;
else if(cnt_wait == CNT_WAIT_MAX)
add_flag <= 1'b1;
else
add_flag <= 1'b0;
//num:从 4'h0 加到 4'hf 循环
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
num <= 4'd0;
else if(add_flag == 1'b1)
num <= num + 1'b1;
else
num <= num;
//sel:选中六个数码管
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sel <= 6'b000000;
else
sel <= 6'b111111;
//给要显示的值编码
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
seg <= IDLE;
else case(num)
4'd0: seg <= SEG_0;
4'd1: seg <= SEG_1;
4'd2: seg <= SEG_2;
4'd3: seg <= SEG_3;
4'd4: seg <= SEG_4;
4'd5: seg <= SEG_5;
4'd6: seg <= SEG_6;
4'd7: seg <= SEG_7;
4'd8: seg <= SEG_8;
4'd9: seg <= SEG_9;
4'd10: seg <= SEG_A;
4'd11: seg <= SEG_B;
4'd12: seg <= SEG_C;
4'd13: seg <= SEG_D;
4'd14: seg <= SEG_E;
4'd15: seg <= SEG_F;
default:seg <= IDLE ; //闲置状态,不显示
endcase
endmodule
74HC595控制模块框图
74HC595控制模块参考代码
module hc595_ctrl
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低有效
input wire [5:0] sel , //数码管位选信号
input wire [7:0] seg , //数码管段选信号
output reg stcp , //数据存储器时钟
output reg shcp , //移位寄存器时钟
output reg ds , //串行数据输入
output wire oe //使能信号,低有效
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg define
reg [1:0] cnt_4 ; //分频计数器
reg [3:0] cnt_bit ; //传输位数计数器
//wire define
wire [13:0] data ; //数码管信号寄存
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//将数码管信号寄存
assign data = {seg[0],seg[1],seg[2],seg[3],seg[4],seg[5],seg[6],seg[7],sel};
//将复位取反后赋值给其即可
assign oe = ~sys_rst_n;
//分频计数器:0~3循环计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_4 <= 2'd0;
else if(cnt_4 == 2'd3)
cnt_4 <= 2'd0;
else
cnt_4 <= cnt_4 + 1'b1;
//cnt_bit:每输入一位数据加一
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_bit <= 4'd0;
else if(cnt_4 == 2'd3 && cnt_bit == 4'd13)
cnt_bit <= 4'd0;
else if(cnt_4 == 2'd3)
cnt_bit <= cnt_bit + 1'b1;
else
cnt_bit <= cnt_bit;
//stcp:14个信号传输完成之后产生一个上升沿
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
stcp <= 1'b0;
else if(cnt_bit == 4'd13 && cnt_4 == 2'd3)
stcp <= 1'b1;
else
stcp <= 1'b0;
//shcp:产生四分频移位时钟
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
shcp <= 1'b0;
else if(cnt_4 >= 4'd2)
shcp <= 1'b1;
else
shcp <= 1'b0;
//ds:将寄存器里存储的数码管信号输入即
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
ds <= 1'b0;
else if(cnt_4 == 2'd0)
ds <= data[cnt_bit];
else
ds <= ds;
endmodule
顶层模块
顶层模块参考代码
module seg_595_static
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低有效
output wire stcp , //输出数据存储寄时钟
output wire shcp , //移位寄存器的时钟输入
output wire ds , //串行数据输入
output wire oe //输出使能信号
);
//********************************************************************//
//******************** Parameter And Internal Signal *****************//
//********************************************************************//
//wire define
wire [5:0] sel;
wire [7:0] seg;
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//---------- seg_static_inst ----------
seg_static seg_static_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
.sel (sel ), //数码管位选信号
.seg (seg ) //数码管段选信号
);
//---------- hc595_ctrl_inst ----------
hc595_ctrl hc595_ctrl_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n), //复位信号,低有效
.sel (sel ), //数码管位选信号
.seg (seg ), //数码管段选信号
.stcp (stcp ), //输出数据存储寄时钟
.shcp (shcp ), //移位寄存器的时钟输入
.ds (ds ), //串行数据输入
.oe (oe ) //输出使能信号
);
endmodule
注:本文参考野火fpga教程