–作者:肖肖肖
本文为明德扬原创及录用文章,转载请注明出处!
1.1 总体设计
1.1.1 概述
LED数码管以发光二极管作为发光单元,颜色有单红,黄,蓝,绿,白,黄绿等效果,并且可以构造成“8”字形。数码管根据LED的接法不同分为共阴和共阳两类,它们的发光原理是一样的,只是它们的电源极性不同而已。
数码管可以通过驱动电路来驱动内部的各个段码,从而显示出需要的数字。根据数码管驱动方式的不同,可以将其分为静态式和动态式两类。
1.1.2 设计目标
完成数码管的显示,具体功能要求如下:
-
间隔1s切换数码管位选,做到数码管从左到右流动显示的效果;
-
数码管显示的数值从0开始,每切换一位位选数值加一;
1.1.3信号列表
信号名 | I/O | 位宽 | 定义 |
---|---|---|---|
clk | I | 1 | 系统工作时钟 50M |
rst_n | I | 1 | 系统复位信号,低电平有效 |
segment | O | 8 | 8位数码管段选信号。 由低到高,分别表示数码管的a,b,c,d,e,f,g,dp,低电平时,点亮对应段位。 |
seg_sel | O | 8 | 8位数码管位选信号,低电平时,对应位置数码管点亮。 |
1.1.4设计思路
Ø 数码管显示原理
数码管的8个显示字段”a、b、c、d、e、f、g、h”对应显示面板的位置如下图所示。
数码管显示数字0到9对应的gfedcba值如下表所示。
表5- 1 数码管显示数字与字段值的对应关系
显示 数字 | 共阳gfedcba 2进制 | 共阳gfedcba 16进制 | 共阴gfedcba 2进制 | 共阴gfedcba 16进制 |
---|---|---|---|---|
0 | 7’b1000000 | 7’h40 | 7’b 0111111 | 7’h3f |
1 | 7’b 1111001 | 7’h79 | 7’b 0000110 | 7’h06 |
2 | 7’b 0100100 | 7’h42 | 7’b 1011011 | 7’h5b |
3 | 7’b 0110000 | 7’h30 | 7’b 1001111 | 7’h4f |
4 | 7’b 0011001 | 7’h19 | 7’b 1100110 | 7’h66 |
5 | 7’b 0010010 | 7’h12 | 7’b 1101101 | 7’h6d |
6 | 7’b 0000010 | 7’h02 | 7’b 1111101 | 7’h7d |
7 | 7’b 1111000 | 7’h78 | 7’b 0000111 | 7’h07 |
8 | 7’b 0000000 | 7’h00 | 7’b 1111111 | 7’h7f |
9 | 7’b 0010000 | 7’h10 | 7’b 1101111 | 7’h6f |
数码管静态驱动是指每个数码管的每一个段码都通过一个I/O端口进行驱动,或使用如BCD码二-十进制译码器译码进行驱动,也称直流驱动。静态驱动编程简单,显示亮度高,但占用的I/O端口多,这里不使用这种方法。
数码管动态驱动是将所有数码管的8个显示字段"a、b、c、d、e、f、g、h"的同名端连接在一起,此外每个数码管的公共极COM需增加由各自独立I/O线控制的位选通控制电路。当要输出某一字形码时,所有数码管都会接收到相同的字形码,但究竟是哪个数码管会显示出字形取决于单片机对位选通COM端电路的控制。只需将显示数码管的选通控制打开,该位就会显示出字形,而没有选通的数码管并不会点亮。数码管特定的发光二极管段加上电压后,这些特定的段就会发亮,并且当每位元数码管的点亮时间为1~20ms,由于人的视觉暂留现象及发光二极体的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示资料,不会有闪烁感,使得动态显示的效果和静态显示是一样的,这样能够节省大量的I/O口,而且功耗更低。
以下是mp801开发板对应的数码管原理图,并且是共阳极的数码管:
Ø 工程架构
根据设计目标将现象翻译成信号表示如下:
第1秒,数码管0显示数字“0”,即seg_sel的值为8’b1111_1110,seg_ment的值为8’b1100_0000;
第2秒,数码管1显示数字“1”,即seg_sel的值为8’b1111_1101,seg_ment的值为8’b1111_1001;
第3秒,数码管2显示数字“2”,即seg_sel的值为8’b1111_1011,seg_ment的值为8’b1010_0100;
第4秒,数码管3显示数字“3”,即seg_sel的值为8’b1111_0111,seg_ment的值为8’b1011_0000;
第5秒,数码管4显示数字“4”,即seg_sel的值为8’b1110_1111,seg_ment的值为8’b1001_1001;
第6秒,数码管5显示数字“5”,即seg_sel的值为8’b1101_1111,seg_ment的值为8’b1001_0010;
第7秒,数码管6显示数字“6”,即seg_sel的值为8’b1011_1111,seg_ment的值为8’b1000_0010;
第8秒,数码管7显示数字“7”,即seg_sel的值为8’b0111_1111,seg_ment的值为8’b1111_1000;
第九秒,回到数码管0显示数字“0”,以此进行循环。
总结发现,数码管每隔1秒进行变化,且8个数码管轮流显示。
因此本工程用到了三个计数器的架构,具体架构如下图所示:
1秒计数器cnt_1s:用于计算1s的时间,加一条件为1,表示一直在计数;数到50,000,000下,表示数到1s就结束。
位选计数器sel_cnt:用于区分选通的数码管,加一条件为end_cnt_1s,表示每间隔1秒的时间后,切换选通下一个数码管;数到8下,表示8个数码管都选通过一轮了。
1.1.5参考代码
module seg_disp(
rst_n ,
clk ,
seg_sel ,
segment
);
parameterTIME_1S = 50_000_000 ;
parameterSEG_WID = 8 ;
parameterSEG_NUM = 8 ;
parameterCNT_WID = 10 ;
parameterTIME_20US = 10’d1000 ;
parameterNUM_0 = 8’b1100_0000;
parameterNUM_1 = 8’b1111_1001;
parameterNUM_2 = 8’b1010_0100;
parameterNUM_3 = 8’b1011_0000;
parameterNUM_4 = 8’b1001_1001;
parameterNUM_5 = 8’b1001_0010;
parameterNUM_6 = 8’b1000_0010;
parameterNUM_7 = 8’b1111_1000;
parameterNUM_8 = 8’b1000_0000;
parameterNUM_9 = 8’b1001_0000;
parameterNUM_ERR = 8’b1111_1111;
input clk ;
input rst_n ;
output [SEG_WID - 1:0] seg_sel ;
output [SEG_WID - 1:0] segment ;
reg[SEG_WID - 1:0]seg_sel ;
reg[SEG_WID - 1:0]segment ;
reg[ 31 : 0] cnt_1s ;
reg [SEG_NUM1:0] sel_cnt ;
reg[ 4 - 1 : 0] seg_tmp ;
wire add_cnt_1s ;
wire end_cnt_1s ;
wire add_sel_cnt ;
wire end_sel_cnt ;
always @(posedge clk or negedge rst_n) begin
if(rst_n==0) begin
cnt_1s <= 0;
end
else if(add_cnt_1s) begin
if(end_cnt_1s)
cnt_1s <= 0;
else
cnt_1s <= cnt_1s+1 ;
end
end
assign add_cnt_1s = 1;
assign end_cnt_1s = add_cnt_1s && cnt_1s == TIME_1S-1 ;
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sel_cnt <= 0;
end
else if(add_sel_cnt)begin
if(end_sel_cnt)
sel_cnt <= 0;
else
sel_cnt <= sel_cnt + 1;
end
end
assign add_sel_cnt = end_cnt_1s;
assign end_sel_cnt = add_sel_cnt &&sel_cnt == SEG_NUM-1;
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
seg_sel <= {SEG_NUM{1'b1}};
end
else begin
seg_sel <= ~(1'b1 << sel_cnt);
end
end
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
seg_tmp = 0;
else
seg_tmp = sel_cnt ;
end
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
segment<=NUM_0;
end
else begin
case (seg_tmp)
0 : segment <= NUM_0;
1 : segment <= NUM_1;
2 : segment <= NUM_2;
3 : segment <= NUM_3;
4 : segment <= NUM_4;
5 : segment <= NUM_5;
6 : segment <= NUM_6;
7 : segment <= NUM_7;
8 : segment <= NUM_8;
9 : segment <= NUM_9;
default : segment <= NUM_ERR;
endcase
end
end
endmodule
1.2 效果和总结
Ø 下图是该工程在db603开发板上的现象
Ø 下图是该工程在mp801开发板上的现象
Ø 下图是该工程在ms980试验箱上的现象
由于该项目的上板现象是上电数码管从左到右流动显示对应的数值,想观看完整现象的朋友可以看一下现象演示的视频。
感兴趣的朋友也可以访问论坛进行FPGA相关工程设计学习,也可以看一下我们往期的文章。