文章目录
- 前言
- 一、原理
- 1、共阴极数码管or共阳极数码管
- 2、共阴极与共阳极的真值表
- 二、系统设计
- 1、总体框图:
- 2、模块调用
- 3、模块原理图
- 三、源码
- 1、计数模块
- 2、数码管驱动模块
- 3、顶层模块
- 四、运行效果
- 五、总结
- 六、参考资料
前言
环境:
1、Quartus18.1
2、vscode
3、板子型号:EP4CE6F17C8N
一、原理
视觉暂留原理:人眼在观察景物时,光信号传入大脑神经,需经过一段短暂的时间,光的作用结束后,视觉形象并不立即消失,这种残留的视觉称“后像”,视觉的这一现象则被称为“视觉暂留”。
这里我们的数码管其实是在一直切换的,但是由于切换得太快,产生了视觉暂留,从而影响我们的眼睛以为数码管没有变换。
1、共阴极数码管or共阳极数码管
共阴极:公共端为阴极,加阳极数码管点亮。即当真值为1时,数码管点亮;真值为0时,数码管不亮。
共阳极:公共端为阳极,加阴极数码管点亮。即当真值为0时,数码管点亮;真值为1时,数码管不亮。
所以在使用到数码管时,我们需要去判断板子的数码管是共阴极还是共阳极。
2、共阴极与共阳极的真值表
共阴极真值表:
共阳极真值表:
二、系统设计
1、总体框图:
2、模块调用
3、模块原理图
三、源码
1、计数模块
module counter(
input wire clk ,
input wire rst_n ,
output wire [16:0] dout
);
localparam [25:0] CNTMAX_1s = 26'd50_000_000;
localparam [16:0] CNTMAX_days = 17'd86400;
reg [25:0] cnt_1s;
reg [16:0] cnt_days;
wire [4:0] hour;
wire [5:0] min ;
wire [5:0] sec;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_1s<=26'd0;
else if(cnt_1s==CNTMAX_1s-1)
cnt_1s<=26'd0;
else
cnt_1s<=cnt_1s+1;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_days<=17'd0;
else if(cnt_days==CNTMAX_days-1&&cnt_1s==CNTMAX_1s-1)
cnt_days<=17'd0;
else if(cnt_1s==CNTMAX_1s-1)
cnt_days<=cnt_days+1;
else
cnt_days<=cnt_days;
end
assign hour=cnt_days/3600;
assign min =(cnt_days-(hour*3600))/60;
assign sec =cnt_days-(hour*3600+min*60);
assign dout= {hour,min,sec};
endmodule
2、数码管驱动模块
module seg_driver( //数码管驱动
input clk ,
input rst_n ,
input [16:0] din ,
output reg [5:0] sel , //片选
output reg [7:0] dig //段选
);
// parameter TIME_SCAN = 50_000 ; // 1MS 让片选一直扫描的移动
parameter TIME_SCAN = 50_000;
parameter ZER = 7'b100_0000, // 0亮 1灭
ONE = 7'b111_1001,
TWO = 7'b010_0100,
THR = 7'b011_0000,
FOR = 7'b001_1001,
FIV = 7'b001_0010,
SIX = 7'b000_0010,
SEV = 7'b111_1000,
EIG = 7'b000_0000,
NIN = 7'b001_0000;
reg [15:0] cnt_scan ; //扫描计数器
wire add_cnt_scan;
wire end_cnt_scan;
reg [3:0] data ; //寄存器 缓存数据
reg dot ; //小数点
wire [3:0] sec_l ; //秒低位
wire [3:0] sec_h ; //秒 高位
wire [3:0] min_l ; // 分地位
wire [3:0] min_h ; //分高位
wire [3:0] hou_l ;
wire [3:0] hou_h ;
assign sec_l = din[5:0] % 10 ; // 59 % 10 = 9
assign sec_h = din[5:0] / 10 ; // 59 / 10 = 5
assign min_l = din[11:6] % 10 ;
assign min_h = din[11:6] / 10 ;
assign hou_l = din[16:12] % 10 ;
assign hou_h = din[16:12] / 10 ;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_scan <= 16'b0;
end
else if(add_cnt_scan)begin
if(end_cnt_scan)begin
cnt_scan <= 16'b0;
end
else begin
cnt_scan <= cnt_scan + 1'b1;
end
end
else begin
cnt_scan <= cnt_scan ;
end
end
assign add_cnt_scan = 1'b1;
assign end_cnt_scan = add_cnt_scan && cnt_scan == TIME_SCAN - 1;
always @(posedge clk or negedge rst_n)begin // 片选
if(!rst_n)begin
sel <= 6'b011_111;
end
else if(end_cnt_scan)begin
sel <= {sel[0],sel[5:1]};//循环向右移动
end
else begin
sel <= sel;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data <= 3'b0;
dot <= 1'b1;
end
else begin
case(sel)
6'b011_111 : begin data <= sec_l; dot <= 1'b1; end
6'b101_111 : begin data <= sec_h; dot <= 1'b1; end
6'b110_111 : begin data <= min_l; dot <= 1'b0; end
6'b111_011 : begin data <= min_h; dot <= 1'b1; end
6'b111_101 : begin data <= hou_l; dot <= 1'b0; end
6'b111_110 : begin data <= hou_h; dot <= 1'b1; end
default : begin data <= 3'b0; dot <= 1'b1;end
endcase
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
dig <= 8'b0;
end
else begin
case(data)
0 : dig <= {dot,ZER};
1 : dig <= {dot,ONE};
2 : dig <= {dot,TWO};
3 : dig <= {dot,THR};
4 : dig <= {dot,FOR};
5 : dig <= {dot,FIV};
6 : dig <= {dot,SIX};
7 : dig <= {dot,SEV};
8 : dig <= {dot,EIG};
9 : dig <= {dot,NIN};
default : dig <= 8'b0;
endcase
end
end
endmodule
3、顶层模块
module Clock_top(
input clk ,
input rst_n ,
output [5:0] sel ,
output [7:0] dig
);
wire [16:0] dout;
counter counter_inst(
.clk (clk),
.rst_n (rst_n),
.dout(dout)
);
seg_driver seg_driver_inst( //数码管驱动
.clk (clk),
.rst_n (rst_n),
.din (dout),
.sel (sel), //片选
.dig (dig) //段选
);
endmodule
四、运行效果
数码管实现电子时钟
五、总结
此次的工程并不难,只是需要我们对基础有一定的理解能力即可。首先是必须的计时器的实现,还有就是对数码管的片选、段选的操作。
六、参考资料
1、共阴极和共阳数码管详解
2、数码管电子时钟