eda课程设计LED点阵显示控制.docx
《eda课程设计LED点阵显示控制.docx》由会员分享,可在线阅读,更多相关《eda课程设计LED点阵显示控制.docx(58页珍藏版)》请在冰豆网上搜索。
eda课程设计LED点阵显示控制
绍兴文理学院
数理信息学院
EDA技术
课程设计报告
课题LED点阵显示控制设计
姓名
学号
专业班级
指导教师
时间
课程设计任务书
班级
姓名
题目
LED点阵显示控制设计
技术参数、设计要求、
检测数据等
在EDA实验箱上利用FPGA和16*16点阵实现如下功能:
实现基本的字符显示(譬如绍大)
字符的显示时间可调整(譬如1秒、5秒、10秒等)
字符可实现闪烁显示(譬如0.5s)
字符可实现移位显示,且移位方向可控(左移、右移等)
设计进度安排或工作计划
2013.1.4—2013.1.4任务分配,熟悉课题,查询相关资料,出方案初稿。
2013.1.5—2013.1.5方案交流并定稿,划分设计模式,课程设计开展。
2013.1.6—2013.1.7各模块设计实现及调试验证。
2013.1.10—2013.1.13设计整体实现、调试及验证,并开始撰写报告。
2013.1.14—2103.1.15设计完成,课程设计报告撰写并定稿,上交。
其它
基于任务书,我们小组对设计增加了一些功能如下:
①通过键控可以改变字幕滚动速度。
②通过键控可以使字幕横向或纵向滚动。
③通过键控可以使字闪烁出现。
LED点阵显示控制
摘要
本文对基于FPGA控制的LED汉字滚动显示器的设计方法进行了探讨。
提出了两个实现方案。
并对其中一个方案作了详细说明。
文中首先介绍了完成本设计所需的原理、技术、以及所要实现的功能;然后研究了滚动显示汉字的方法及键控模式改变滚动的方式;最后,用VHDL语言程序设计了一个完整的LED汉字滚动显示器。
本系统在FPGA试验箱上完成,由扫描控制模块、只读存储器ROM和16*16LED点阵显示模块、一个4-16译码器构成。
其中:
扫描控制模块和只读存储器ROM集成在FPGA芯片内部。
一个4-16译码器(74LS154)输入完成FPGA中16×16点阵显示模块的列扫描模式。
FPGA定义的只读存储器ROM中保存了要显示的汉字的数模,并以16位的数据宽度输出到LED阵显示模块的行端,配合列扫描控制共同完成汉字的滚动显示。
同时通过键控模式,对字幕滚动速度、方式、形式可调。
本系统利用数字系统设计自动化(EDA)技术实现了全硬件方式的LED点阵显示。
利用FPGA内部的物理资源,将只读存储器ROM和主要功能模块设计在FPGA内部。
充分显示了EDA技术设计的灵活性,同时也大大提高了系统的集成度和稳定性
关键词FPGA;LED;EDA;动态扫描
1.设计概述
1.1LED点阵原理
以下为8×8点阵LED外观及引脚图及其等效电路,只要其对应的X、Y轴顺向偏压,即可使LED发亮。
例如如果想使左上角LED点亮,则Y0=1,X0=0即可。
应用时限流电阻可以放在X轴或Y轴。
图118×8点阵LED外观图[5]
图128×8点阵LED等效图[5]
1.2点阵LED扫描法介绍
点阵LED一般采用扫描式显示,实际运用分为三种方式:
(1)点扫描
(2)行扫描
(3)列扫描
若使用第一种方式,其扫描频率必须大于16×64=1024Hz,周期小于1ms即可。
若使用第二和第三种方式,则频率必须大于16×8=128Hz,周期小于7.8ms即可符合视觉暂留要求。
此外一次驱动一列或一行(8颗LED)时需外加驱动电路提高电流,否则LED亮度会不足
1.3汉字显示原理
要实现汉字的显示,首先是获得数模并保存,即在存贮器中建立汉字数据库。
这里,直接运用取字模软件,输入要取模的字,自动生成字形码。
然后是在扫描模块的控制下,从低往高列扫描的次序正确地输出这些数据,由于人视觉暂留效果,即呈现完整字形。
某一时刻能在显示数据序列中定位待显示数据的地址指针可用下式计算:
addr=n+m
图13滚动显示多汉字信息的原理示意图[5]
1.4设计的主要功能
基本功能:
①实现基本的字符显示(譬如绍大)
②字符的显示时间可调整(譬如1秒、5秒、10秒等)
③字符可实现闪烁显示(譬如0.5s)
④字符可实现移位显示,且移位方向可控(左移、右移等)
附加功能:
①通过键控可以改变字幕滚动速度。
②通过键控可以使字幕横向或纵向滚动。
③通过键控可以使字闪烁出现。
1.5设计的主要工作
本设计需要利用EDA工具软件QuartusII编写并调试系统的VHDL程序。
并且每一个模块都在这个软件下进行了仿真。
系统的VHDL程序编好过后先在实验室的EDA实验箱上下载调试、验证。
2.设计方案
2.1方案一
本文系统的LED点阵模块,共由16×16=256个LED发光二极管组成。
如何在该点阵模块上显示汉字是本文设计的关键技术。
本文系统设计是采用一种16路动态分时扫描技术来实现的。
具体方法是,将4个8×8数组的显示模块组合成两个16行16列的扫描结构。
其行输入端与FPGA内的只读存储器ROM的16位数据输出端口相连;16个列控制端与一个4-16译码器的输出相连;而译码器的输入端和片选信号又与FPGA内的列扫描控制模块的输出端口相连。
图2-1系统结构框图
2.2方案二
VHDL程序设计的是硬件,可以“并发执行”。
本设计可以将LED显示屏要的显示内容抽象成一个二维数组(数组中的‘1’对映点阵显示屏上面的亮点),用VHDL语言设计一个进程将这个数组动态显示在LED显示屏上,再利用另一个进程对这个数组按一定频率进行数据更新,更新的方式可以有多种。
因为两个进程是同时进行的(并发执行),如果对数组中的汉字数据按滚动的方式更新,则可实现汉字的滚动显示。
该方案的原理图。
2.3方案比较
方案一很容易实现,而且占用FPGA的资源较少。
但是由于其实现方式的局限性,该方案只能实现汉字的滚动显示。
方案二中将LED点阵抽象成了一个二维数组。
可以设计一些比较复杂的算法来控制这个数组,使设计的系统不但可以滚动显示汉字,还可以扩展一些其它的显示效果。
但是方案二中对数组的处理部分对FPGA芯片的资源消耗太大,所以最终选择方案一。
3.设计实现
3.1分频程序
该电路主要包含有一个计数器模块和一个译码输出模块,该电路是通过计数器模块实现分频的。
比如要从12MHz的全局时钟得到100Hz的时钟,必须进行120000倍分频。
但是这么大的分频需要仿真时间很久。
仿真是一般采用小的分频来替代,真正下载到电路上时,就需要采用120000分频了。
译码器的输入采用了寄存器锁存输出,这是为了消除毛刺。
多输入的组合逻辑电路中,默写输入信号在理想情况下应该同时发生变化,但由于延迟路径不同造成这些输入信号发生变化的时间有微小差别(门延迟时间量级),这是得到的是输出信号就会有毛刺,这些毛刺有可能会给下一级电路带来,使得整个系统运行不稳定。
因此,为保证系统的稳健性,一般情况下,都应该给输出信号去毛刺,使之变得干净。
在设计中,译码的输入是计数器的输出,计数器各级输出延迟是不一样的,因此译码器输出clk_scan信号波形就会有毛刺。
if(reset_n='0')then--clk输入的500KHz信号
cnt_scan:
=0;--clk_scan1.25khz的点阵动态扫描信号
cnt_key:
=0;
elsif(rising_edge(clk))then--clk_key1KHz的键盘扫描信号
if(cnt_scan=cnt_scan'high)then
cnt_scan:
=0;
else
cnt_scan:
=cnt_scan+1;
endif;
if(cnt_key=cnt_key'high)then
cnt_key:
=0;
else
cnt_key:
=cnt_key+1;
endif;
if(cnt_scan>(cnt_scan'high/2))then
clk_scan<='1';
else
clk_scan<='0';
endif;
if(cnt_key>(cnt_key'high/2))then
clk_key<='1';
else
clk_key<='0';
endif;
endif;
把有毛刺的信号通过时钟采样,即通过一个D触发器也可以消除毛刺。
本设计就是使用这种方法。
这种方法的缺点是信号通过一个D触发器后,就延迟了一个时钟周期。
对于本设计这种延迟是允许的。
process(reset_n,clk_key,key1_in)
variabletemp1:
std_logic;
variablecnt1:
integerrange0to15;
begin
if(reset_n='0')then
key1_out<='1';--高电平表示没有按下
elsif(rising_edge(clk_key))then
if(temp1=key1_in)then
if(cnt1=cnt1'high)then
cnt1:
=0;
key1_out<=temp1;
else
cnt1:
=cnt1+1;
endif;
else
temp1:
=key1_in;
cnt1:
=0;
endif;
endif;
endprocess;
3.2移动速度控制程序
在用VHDL编程的时候,可以定义一个变量x作为“滑窗”在ROM上的起始地址,设计一个进程按一定的频率对x进行累加,再设计一个进程将以x为起始地址的长度为16的ROM中的区域动态显示在LED点阵中。
显然x累加的速度决定了汉字的滚动速度。
if(reset_n='0')then
n<=1;--初始化n为1最快速度
flag_key:
='0';
elsif(rising_edge(clk_scan))then
if(key1='0')then--key1的优先级比key2高,key1=0表示按下
if(flag_key='0')then--flag_key=0表示上次扫描键盘的时候无按键按下
flag_key:
='1';
if(n>=n'high)then
n<=n;
else
n<=n+1;
endif;
endif;
elsif(key2='0')then
if(flag_key='0')then
flag_key:
='1';
if(n=1)then
n<=n;
else
n<=n-1;
endif;
endif;
else
flag_key:
='0';
endif;
endif;
if(reset_n='0')then--x的控制进程
cntx:
=0;
x<=0;
elsif(rising_edge(clk_scan))then
if(flag_scan='1')then
if(cntx=n*10orcntx=cntx'high)then
cntx:
=0;
else
cntx:
=cntx+1;
endif;
if(cntx=n*10)then
if(x=x'high)then
x<=0;
else
x<=x+1;
endif;
endif;
endif;
endif;
此进程根据定义的信号n来控制x递增的速度,n由外部的按键控制。
n的范围为1~5代表了汉字的不同的滚动速度。
当n为1时汉字滚动的速度最快,n为5时LED点阵上显示的汉字滚动速度最慢。
3.3按键扫描
本系统用到的按键只有5个:
复位按键,控制n增大和减小的两个按键,控制闪烁的一个按键,控制横向纵向的一个按键。
3.4汉字显示程序
if(reset_n='0')then--显示各种模式转换
data<="0000000000000000";
elsif(rising_edge(clk_scan))then
if(key4='1')then
if(shanshuo='1')then
if(key3='1')then
index:
=((cnt-x)modL_SZ);--左移
if(key5='1')then--显示模式转换上下或左右
data<=ledsj(index);
else
data<=ledsj1(index);
endif;
endif;
if(key3='0')then
index:
=((cnt+x)modL_SZ);--右移
if(key5='1')then
data<=ledsj(index);
else
data<=ledsj1(index);
endif;
endif;
elsif(shanshuo='0')then
data<=x"0000";
endif;
elsif(key4='0')then
if(key3='1')then
index:
=((cnt-x)modL_SZ);
if(key5='1')then
data<=ledsj(index);
else
data<=ledsj1(index);
endif;
endif;
if(key3='0')then
index:
=((cnt+x)modL_SZ);
if(key5='1')then
data<=ledsj(index);
else
data<=ledsj1(index);
endif;
endif;
endif;
endif;
endprocess;
4.设计验证
(1)分频仿真图
图41分频仿真图
(2)按键扫描去抖仿真图
图42按键去抖动仿真图
(3)汉字显示仿真图
图43汉字显示仿真图
图44汉字显示仿真图
(4)FPGA实验箱结果
图45FPGA实验箱结果
每次来一个时钟脉冲,会对应产生一个列扫描信号,同时会输出一个16位的列段码,当完成16列的扫描之后就呈现一个完整的字码。
下一轮的输出会根据N值的不同改变初始的列段码,从而实现左右平移。
5.总结
本次设计是基于FPGA的LED16*16点阵控制设计,是通过VHDL语言编辑实现汉字的可动可控效果。
经过为期两周的课程设计,使得我对VHDL语言有了更多的认识,此次设计开始时,我和队友开始方案讨论,最后确定从两个方向入手,先是配合王杰同学用数组的方法写,经过几天的不断摸索,讨论,修改,最后写完了设计要求的基本部分,通过仿真,调试和下载到试验箱进行验证,证明它的可行性,期间有张敏和郑士港两位同学帮助王杰同学完成。
接着就是发挥部分,发挥部分由我提供一点思路后,暂由王杰同学去完成。
而我开始转向我们的第二个方向——通过状态机的方法写,最后也在完成了设计的基本要求的前提下,加了汉字静态显示时间可控,且有暂停功能。
当然,期间王杰同学也增加了汉字移动速度可调,以及汉字移动转向可控等功能。
此过程中金老师让我们试图添加的汉字上移下移功能由于用状态机方法太过繁琐,所以,没有写此部分代码。
当然,此后的设计报告交由张敏等人完成,王杰负责答疑报告中的设计思路和功能解释,郑士港负责报告排版,我和王杰负责设计报告初审。
最后交由金老师进行终审。
对于本次设计,使我明白团队的重要性,以及平时实验的必要性。
当然,感谢金老师和潘老师这两周的悉心教导和谆谆教诲,辛苦了。
参考文献
[1]黄任..VHDL入门·解惑·经典实例·经验总结.[M].北京:
北京航空航天大学出版社,2005
[2]王彦主.基于FPGA的工程设计与应用[M].西安:
西安电子科技大学出版社,2007
[3]游达章.简易LED点阵汉字显示控制模块设计[J].中国光学期刊网.2007/11/2019(5):
P42-P45
[4]贾德旺.基于FPGA的LED点阵书写显示屏的实现[J].电子世界.2011年8:
P24-P25
[5]任雪宾.用VHDL设计LED汉字滚动显示器[EB/OL].
2014年1月11日
附录
方向一——数组
1、分频模块代码
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_arith.all;
useieee.std_logic_unsigned.all;
entityfenpinis
port(
clk:
instd_logic;--输入的500KHz信号
clk_scan:
outstd_logic;--1.25khz的点阵动态扫描信号
clk_key:
outstd_logic;--1KHz的键盘扫描信号
reset_n:
instd_logic
);
endfenpin;
architectureabcoffenpinis
begin
process(reset_n,clk)--产生clk_scan和clk_key信号
--下载用下面这两条语句
variablecnt_scan:
integerrange0to400;
variablecnt_key:
integerrange0to500;
--仿真用下面这两条语句
--variablecnt_scan:
integerrange0to30;
--variablecnt_key:
integerrange0to24;
begin
if(reset_n='0')then
cnt_scan:
=0;
cnt_key:
=0;
elsif(rising_edge(clk))then
if(cnt_scan=cnt_scan'high)then
cnt_scan:
=0;
else
cnt_scan:
=cnt_scan+1;
endif;
if(cnt_key=cnt_key'high)then
cnt_key:
=0;
else
cnt_key:
=cnt_key+1;
endif;
if(cnt_scan>(cnt_scan'high/2))then
clk_scan<='1';
else
clk_scan<='0';
endif;
if(cnt_key>(cnt_key'high/2))then
clk_key<='1';
else
clk_key<='0';
endif;
endif;
endprocess;
endabc;
2、键盘扫描字幕显示控制模块程序
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_arith.all;
useieee.std_logic_unsigned.all;
entitymnscanis
port(
clk_scan:
instd_logic;--分频时钟
scan:
outstd_logic_vector(3downto0);--列扫描
data:
outstd_logic_vector(15downto0);--列段码输出
dis_n:
outstd_logic_vector(6downto0);--不需要小数点(7位)
key1,key2,key3,key4,key5:
instd_logic;
--key1(加速)key2(减速)key3=1左移key3=0右移
--key4(闪烁控制)key5(输出形式)
reset_n:
instd_logic--复位
);
endmnscan;
architectureabcofmnscanis
constantL_SZ:
integer:
=223;
constantL_DZ:
integer:
=15;
signalcnt:
integerrange0toL_DZ;--和点阵屏的列一样大
signaln:
integerrange1to5;--控制速度
signalflag_scan:
std_logic;
signalx:
integerrange0toL_SZ;
signalshanshuo:
std_logic;--闪烁
signalshanshuo_cnt:
integerrange0to60;
--创建一个可以存储2唯数据的数据类型array_1array_2
typearray_2isarray(0to31)ofstd_logic_vector(15downto0);
constantledsj:
array_2:
=(
(x"0008"),(x"3f88"),(x"2204"),(x"2204"),(x"2112"),(x"210f"),(x"2888"),(x"1044"),
(x"3f82"),(x"209f"),(x"2080"),(x"2080"),(x"2098"),(x"3f87"),(x"2080"),(x"0000"),
--绍上下
(x"0000"),(x"0080"),(x"0080"),(x"0080"),(x"0080"),(x"7fff"),(x"0080"),(x"0140"),
(x"0140"),(x"0240"),(x"0220"),(x"0420"),(x"0810"),(x"1808"),(x"7004"),(x"2002")
--大
);
typearray_1isarray(0to31)ofstd_logic_vector(15downto0);
constantledsj1:
array_1:
=(
(x"0000"),(x"0000"),(x"7f7e"),(x"2182"