今天来看看入门级必备代码之–数码管显示。
简单的说,理解了原理,哪种语言都可以描述,第一次接触数码管是在学习单片机的时候,后来学习verolog HDL也就顺其自然的会了。
点亮数码管原理:
输入相应的电平点亮一根根小火柴a-b-c-d-e-f-g-dp。如果数码管是共阴极,给高电平1即可相应点亮,反之如果是共阳极,给低电平0即可相应点亮。所以才有:
/******数字0-9的显示******/
case (digit)
0:a_to_g<=7'b0000001;
1:a_to_g<=7'b1001111;
2:a_to_g<=7'b0010010;
3:a_to_g<=7'b0000110;
4:a_to_g<=7'b1001100;
5:a_to_g<=7'b0100100;
6:a_to_g<=7'b0100000;
7:a_to_g<=7'b0001111;
8:a_to_g<=7'b0000000;
9:a_to_g<=7'b0000100;
default:a_to_g<=7'b0000001;
endcase
除此之外,我们要知道动态扫描比静态扫描更节省资源,静态扫描占用的端口多,所以我们一般都采用动态扫描方式点亮数码管。
那么扫描的时间,我这边给的是190HZ,不固定,你开心给多少都行,一般时间设置小于40ms即可。
这里提供的代码是四个数码管动态显示的。
/**************共阳极数码管**************/
module digital_number(
input [3:0] minute_o ,
input [3:0] minute_t ,
input [3:0] hour_o ,
input [3:0] hour_t ,
input mclk ,
input rst_n ,
output reg [6:0] a_to_g , //段选
output reg [3:0] an , //位选
output dp //小数点
);
reg [1:0] s ;
wire [3:0] aen ;
reg clk190;
reg [17:0] cnt ;
reg [3:0] digit ;
assign dp = 1;
assign aen = 4'b1111;
//分频190hz
parameter T =18'd263157; // 50_000_000除以190
always@(posedge mclk or negedge rst_n)
begin
if(!rst_n)
cnt<=0;
else if(cnt == T-1)
cnt<=0;
else
cnt<=cnt+1;
end
always @(posedge mclk or negedge rst_n)
begin
if(!rst_n)
clk190<=0;
else if(cnt == T-1)
clk190<=1;
else
clk190<=0;
end
//计数
always@(posedge clk190 or negedge rst_n)
begin
if(!rst_n) s<=0;
else s<=s+1;
end
//数字选择
always @(*)
begin
an <= 4'b1111; //全部灭
if(aen[s] == 1) an[s]<=0; //动态扫描亮,在一个clk190时钟为周期
end
//4选一
always @(*)
case(s)
0:digit <= hour_t[3:0];
1:digit <= hour_o[3:0];
2:digit <= minute_t[3:0];
3:digit <= minute_o[3:0];
default:digit <= 4'b0000;
endcase
//7段数码显示管
always @(*)
case (digit)
0:a_to_g<=7'b0000001;
1:a_to_g<=7'b1001111;
2:a_to_g<=7'b0010010;
3:a_to_g<=7'b0000110;
4:a_to_g<=7'b1001100;
5:a_to_g<=7'b0100100;
6:a_to_g<=7'b0100000;
7:a_to_g<=7'b0001111;
8:a_to_g<=7'b0000000;
9:a_to_g<=7'b0000100;
default:a_to_g<=7'b0000001;
endcase
endmodule
这里就不给仿真了,不过资源利用还是贴出来,大家可以互相学习。
PS: 一如年轻时模样。