一、简介
Key1按下时数码管显示数字加一,Key2按下时数码管显示数字减一。采用4位共阳数码管显示,模块某宝可买到。其中模块接口SLCK与程序中shcp连接,RLCK与stcp相连,DIO与ds相连
二、设计
硬件方面
从商家得到的数码管原理图如下:
通过观察原理图可知,数码管模块采用两片74HC595驱动,第一片74HC595输出用于选中数码管,第二片用于控制数码管内容的显示。

其中Q0~Q7为并行输出端,当串行输入8位数据时时第一位在Q7端输出。
Q7S(9号引脚)为串行数据输出端,通过观察数码管原理图可以发现第一片74HC595的 串行数据输出端连接到第二片74HC595的数据输入端(DS)。
SHCP为移位寄存器时钟输入端
STCP为存储时钟输入端
DS为串行数据输入端
OE输出使能端,低电平有效
MR为主复引脚,低电平有效。
(完整数据手册可在立创商城或半岛小芯找到)
74HC595的使用流程如下:
根据代码综合出来的RTL视图如下
程序设计如下:
(1)按键消抖程序
(由于我所使用的开发板复位引脚默认为低电平,当复位按键按下按下时为高电平,因此我这里采用了if(sys_rst==1'b1)来判断是否复位)
module key
(
input wire sys_clk,
input wire sys_rst,
input wire Key_1,
input wire Key_2,
output reg Key1,
output reg Key2
);
parameter CNT_MAX = 20'd999_999; //计数最大值
reg [19:0] cnt1_20ms;//20ms计时
reg [19:0] cnt2_20ms;//20ms计时
/*按键1消抖*/
always@(posedge sys_clk or posedge sys_rst)
begin
if(sys_rst==1'b1)
cnt1_20ms<=20'd0;
else if(Key_1==1'b1)
cnt1_20ms<=20'd0;
else if((cnt1_20ms==CNT_MAX)&&(Key_1==1'b0))
cnt1_20ms<=CNT_MAX;
else
cnt1_20ms<=cnt1_20ms+20'd1;
end
always@(posedge sys_clk or posedge sys_rst)
begin
if(sys_rst==1'b1)
Key1<=1'b0;
else if(cnt1_20ms==(CNT_MAX-20'd1))
Key1<=1'b1;
else
Key1<=1'b0;
end
/*按键2消抖*/
always@(posedge sys_clk or posedge sys_rst)
begin
if(sys_rst==1'b1)
cnt2_20ms<=20'd0;
else if(Key_2==1'b1)
cnt2_20ms<=20'd0;
else if((cnt2_20ms==CNT_MAX)&&(Key_2==1'b0))
cnt2_20ms<=CNT_MAX;
else
cnt2_20ms<=cnt2_20ms+20'd1;
end
always@(posedge sys_clk or posedge sys_rst)
begin
if(sys_rst==1'b1)
Key2<=1'b0;
else if(cnt2_20ms==(CNT_MAX-20'd1))
Key2<=1'b1;
else
Key2<=1'b0;
end
(2) 数码管显示代码
由于第一位74HC595用于选中数码管,其中Q4~Q7端,为防止数据在输出时产生错误,将sel设位8位有效数据,即sel <= 8'b1111_1111;如需改动选中数码管,只需对高位数字改动即可
module seg_static
(
input wire sys_clk,
input wire sys_rst,
input wire Key1,
input wire Key2,
output reg [7:0] sel, //数码管位选信号
output reg [7:0] seg //数码管段选信号
);
//十六进制数显示编码
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;
parameter IDLE = 8'b1111_1111; //不显示状态
reg [3:0] num=4'd0;
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst == 1'b1)
num <= 4'd0;
else if((Key1 == 1'd1)&&(num == 4'd9))
num <= 4'd0;
else if((Key2 == 1'd1)&&(num == 4'd0))
num <= 4'd9;
else if(Key1 == 1'd1)
num <= num + 1'd1;
else if(Key2 == 1'd1)
num <= num - 1'd1;
else
num <= num;
//sel:选中4个数码管
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst == 1'b1)
sel <= 8'b0000_0000;
else
sel <= 8'b1111_1111;
//给要显示的值编码
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst == 1'b1)
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;
default:seg <= IDLE ; //闲置状态,不显示
endcase
endmodule
(3)74HC595控制代码(此代码根据野火的控制代码进行改动,具体可参考野火的教程)
module hc595_ctrl
(
input wire sys_clk ,
input wire sys_rst ,
input wire [7:0] sel , //数码管位选信号
input wire [7:0] seg , //数码管段选信号
output reg stcp , //数据存储器时钟
output reg shcp , //移位寄存器时钟
output reg ds //串行数据输入
);
reg [1:0] cnt_4 ; //分频计数器
reg [3:0] cnt_bit ; //传输位数计数器
wire [15:0] data ; //数码管信号寄存
//将数码管信号寄存
assign data = {sel,seg[0],seg[1],seg[2],seg[3],seg[4],seg[5],seg[6],seg[7]};//两片595 8位sel选中数码管
//分频计数器:0~3循环计数
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst == 1'b1)
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 posedge sys_rst)
if(sys_rst == 1'b1)
cnt_bit <= 4'd0;
else if(cnt_4 == 2'd3 && cnt_bit == 4'd15)
cnt_bit <= 4'd0;
else if(cnt_4 == 2'd3)
cnt_bit <= cnt_bit + 1'b1;
else
cnt_bit <= cnt_bit;
//stcp:16个信号传输完成之后产生一个上升沿
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst == 1'b1)
stcp <= 1'b0;
else if(cnt_bit == 4'd15 && cnt_4 == 2'd3)
stcp <= 1'b1;
else
stcp <= 1'b0;
//shcp:产生四分频移位时钟
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst == 1'b1)
shcp <= 1'b0;
else if(cnt_4 >= 4'd2)
shcp <= 1'b1;
else
shcp <= 1'b0;
//ds:将寄存器里存储的数码管信号输入即
always@(posedge sys_clk or posedge sys_rst)
if(sys_rst == 1'b1)
ds <= 1'b0;
else if(cnt_4 == 2'd0)
ds <= data[cnt_bit];
else
ds <= ds;
endmodule
(4)顶层模块代码
module key_seg
(
input wire sys_clk,
input wire sys_rst,
input wire Key_1,
input wire Key_2,
output wire ds,
output wire shcp,
output wire stcp
);
wire Key1;
wire Key2;
wire [7:0] sel;
wire [7:0] seg;
key key_inst
(
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.Key_1(Key_1),
.Key_2(Key_2),
.Key1(Key1),
.Key2(Key2)
);
seg_static seg_static_inst
(
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.Key1(Key1),
.Key2(Key2),
.sel(sel),
.seg(seg)
);
hc595_ctrl hc595_ctrl
(
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.sel(sel),
.seg(seg),
.stcp(stcp),
.shcp(shcp),
.ds(ds)
);
endmodule
实现效果如下:
如有错误,欢迎指出!