
一、总体设计思路
1.1 基本原理
LED 就是Light Emitting Diode(发光二极管)的缩写。在某些半导体材料的PN结中,注入的少数载流子与多数载流子复合时会把多余的能量以光的形式释放出来,从而把电能直接转换为光能。PN结加反向电压,少数载流子难以注入,故不发光。这种利用注入式电致发光原理制作的二极管叫发光二极管,通称LED。LED显示屏是一种通过控制半导体发光二极管的显示方式,用来显示文字、图形、图像、动画、行情、视频、录像信号等各种信息的显示屏幕。
中小规模的LED点阵显示使用非常广泛,采用单片机控制时,需要扩展大量的外围资源,并且不便于进行扩展、修改和维护。在系统可编程逻辑器件具有丰富的I/O口及内部资源,器件的编程和修改也极为方便。本设计是以Altera公司可编程逻辑芯片EP1K30TC144-3为控制核心、附加一定外围电路组成的一个16×16点阵,此点阵系统使用逐列循环扫描的方式来显示自己姓名的英文大写字母。这样不但简化了外围电路、而且易于修改、扩展和维护。
16×16扫描LED点阵的工作原理同8位扫描数码管类似。它有16个共阴极输出端口,每个共阴极对应有16个LED显示灯,所以其扫描译码地址需4位信号线(SEL0-SEL3),其汉字扫描码由16位段地址(0-15)输入。 通过时钟的每列扫描显示完整汉字。
点阵LED一般采用扫描式显示,实际运用分为三种方式:
(1)点扫描
(2)行扫描
(3)列扫描
若使用第一种方式,其扫描频率必须大于16×=1024Hz,周期小于1ms即可。若使用第二和第三种方式,则频率必须大于16×8=128Hz,周期小于7.8ms即可符合视觉暂留要求。此外一次驱动一列或一行(8颗LED)时需外加驱动电路提高电流,否则LED亮度会不足。
实验箱上为我们提供了16*16的点阵显示模块。通过观察,我们可以看到,此点阵显示屏即为16行、16列的LED显示灯。那么控制这些灯的亮暗分布,就能达到字符显示的目的。首先我们设计要正确显示自己名字的英文大写字母(T,A,N,G,J,I,N,G),显示屏上的灯的亮暗情况具体应如何。
如第一个字母‘T’:
0000000000000000
111111*********1
111111*********1
0000000111000000
0000000111000000
0000000111000000
0000000111000000
0000000111000000
0000000111000000
0000000111000000
0000000111000000
0000000111000000
0000000111000000
0000000111000000
0000000111000000
0000000000000000
如果高电平‘1 时表示灯是亮的,低电平‘0’时灯是暗的,这样上面的灯呈现在我们眼前的就是‘T’字了。依次类推,我们就可以设计出所有要显示的字母了。这样这些字母就好象是被我们当作了固定模型了。但如何点亮这些灯呢,这就要求有一个脉冲循环扫描的电路,我们采用列扫描,当扫描的和我们先设计好的字母模型的高电平相匹配时,灯就相应的点亮。由于扫描的速度很快,我们人的眼睛并不会感到灯的闪烁,所以每扫描完16列就会显示在我们眼中一个字母了。但要所有的字母就可以依次的显示出来并不停的循环显示,就还要再有一个时序控制电路来控制。此时序控制电路象一个计数器,有自动清零的功能,这样就可以实现循环的效果了。
1.2总体设计图框图
图1.2总体设计框图
1.3顶层文件设计
顶层文件来实现循环显示各个字母的功能。它由时序控制模块,扫描模块和字母显示控制模块组成。时序控制模块利用脉冲来控制每个字母的显示时间。扫描控制模块利用列扫描脉冲产生列扫描信号。而字母显示控制模块用时序控制模块和扫描控制模块所提供的脉冲信号来点亮各个字母模型中相应的灯。在时序模块的控制下(此设计中每八个字母为一个循环)实现了各个字母循环显示的功能。
要实现显示自己的英文名字大写字母。结合实际,模块chw,cnta, cora分别实现时序控制模块,扫描模块和字母显示控制模块。具体电路的 顶层文件设计如下图
图1.3 顶层文件设计
二、单元电路设计
2.1时序控制模块
此模块用来控制每个字母的显示时间,当计满四个脉冲时cnt自动清零,即每个字母显示四个脉冲的时间。一共有八个字母(T,A,N,G,J,I,N,G)。当tmp=1000时,tmp自动清零,此后是这些字母显示的下一个循环。如此不停的循环显示各个字母。
为使字母不断地循环显示,并且使每个字母之间有停顿,就需要在中间加一定的延时和循环环节。在这一环节中,可以通过修改其数值来控制每个字母的显示时间。
图2.1 时序控制模块
程序如下:
Library ieee;
use ieee.std_logic_11.all;
use ieee.std_logic_unsigned.all;
Entity chw is
Port(clk:in std_logic;
q:out std_logic_vector(3 downto 0));
End chw;
Architecture chw_arc of chw is
Begin
Process(clk)
variable cnt:integer range 0 to 1000;
variable tmp:std_logic_vector(3 downto 0);
begin
If clk'event and clk='1'then
If cnt<1000 then
cnt:=cnt+1;
Else
cnt:=0;
If tmp="1111" then
tmp:="0000";
Else
tmp:=tmp+1;
End if;
End if;
End if;
q<=tmp;
End process;
End chw_arc;
2.2扫描控制模块
此模块用来实现列扫描控制,通过对每一列的扫描来完成对字母的现实,每扫描完16列,tmp自动清零,这样就提供了一个列循环扫描的功能,这样就可以循环的是各个字母。
只要扫描的频率足够快,就能给人以连续的感觉。因此要控制扫描的频率,不能太低,否则,就会造成视觉上的不连续。
图2.2 扫描控制模块
扫描程序如下
Library ieee;
use ieee.std_logic_11.all;
use ieee.std_logic_unsigned.all;
Entity cnta is
Port(clk:in std_logic; --端口定义 输入信号
q:out std_logic_vector(3 downto 0)); --端口定义 输出信号
End cnta;
Architecture count of cnta is
Signal lie:std_logic_vector(3 downto 0);
Begin
Process(clk)
begin
If clk'event and clk='1'then
If lie="1111" then
Lie<="0000";
Else
Lie<=lie+1;
End if;
End if;
q<=lie-1;
End process;
End count;
2.3显示控制模块
此模块为列驱动控制器sel控制的是所显示的字,用来实现显示出相应的字母。ch控制字母的个数,sel控制扫描的行数。使对应列选择信号输出每一列对应的数据,点量相应的灯。
例如当ch为0000B时,表示输出字的第一列文字信息,sel为0001B时,表示输出字的第二列文字信息,依次类推。
图2.3 显示控制模块
显示程序如下:
LIBRARY IEEE;
USE IEEE. STD_LOGIC_11.ALL;
ENTITY cora IS
PORT(ch : IN STD_LOGIC_VECTOR(3 downto 0);
sel : IN STD_LOGIC_VECTOR(3 downto 0);
q : OUT STD_LOGIC_VECTOR(15 downto 0));
END cora;
ARCHITECTURE cora_arc OF cora IS
BEGIN
PROCESS(ch,sel)
BEGIN
CASE ch IS
When "0000"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="1111111111111111";
when "0010" =>q<="1111111111111111";
when "0011" =>q<="0000000111000000";
when "0100" =>q<="0000000111000000";
when "0101" =>q<="0000000111000000";
when "0110" =>q<="0000000111000000";
when "0111" =>q<="0000000111000000";
when "1000" =>q<="0000000111000000";
when "1001" =>q<="0000000111000000";
when "1010" =>q<="0000000111000000";
when "1011" =>q<="0000000111000000";
when "1100" =>q<="0000000111000000";
when "1101" =>q<="0000000111000000";
when "1110" =>q<="0000000111000000";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0001"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="0000001111000000";
when "0010" =>q<="0000011001100000";
when "0011" =>q<="0000110000110000";
when "0100" =>q<="0000110000110000";
when "0101" =>q<="0001110000111000";
when "0110" =>q<="0001110000111000";
when "0111" =>q<="0011110000111100";
when "1000" =>q<="0011111111111100";
when "1001" =>q<="0011111111111100";
when "1010" =>q<="0011100000111100";
when "1011" =>q<="0011100000011100";
when "1100" =>q<="0011100000011100";
when "1101" =>q<="0011100000011100";
when "1110" =>q<="0011100000011100";
when "1111" =>q<="0011100000011100";
when others=>null; end case;
When "0010"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="1111100000001111";
when "0010" =>q<="1111110000001111";
when "0011" =>q<="1111011100001111";
when "0100" =>q<="1111011100001111";
when "0101" =>q<="1111001110001111";
when "0110" =>q<="1111001110001111";
when "0111" =>q<="1111000111001111";
when "1000" =>q<="1111000111001111";
when "1001" =>q<="1111000111001111";
when "1010" =>q<="1111000011101111";
when "1011" =>q<="1111000011101111";
when "1100" =>q<="1111000011101111";
when "1101" =>q<="1111000001111111";
when "1110" =>q<="1111000000111111";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0011"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="1111111111111111";
when "0010" =>q<="1111111111111111";
when "0011" =>q<="1110000000000000";
when "0100" =>q<="1110000000000000";
when "0101" =>q<="1110000000000000";
when "0110" =>q<="1110000000000000";
when "0111" =>q<="1110000000000000";
when "1000" =>q<="1110000000000000";
when "1001" =>q<="1110000011111111";
when "1010" =>q<="1110000011111111";
when "1011" =>q<="1110000000000111";
when "1100" =>q<="1110000000000111";
when "1101" =>q<="111111*********11";
when "1110" =>q<="1111111111111111";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0100"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="0111111111111111";
when "0010" =>q<="0111111111111111";
when "0011" =>q<="0000000111000000";
when "0100" =>q<="0000000111000000";
when "0101" =>q<="0000000111000000";
when "0110" =>q<="0000000111000000";
when "0111" =>q<="0000000111000000";
when "1000" =>q<="0000000111000000";
when "1001" =>q<="0000000111000000";
when "1010" =>q<="0000000111000000";
when "1011" =>q<="0000000111000000";
when "1100" =>q<="0111100111000000";
when "1101" =>q<="0011110111000000";
when "1110" =>q<="0001111111000000";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0101"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="0000000000000000";
when "0010" =>q<="0111111111111100";
when "0011" =>q<="0000000110000000";
when "0100" =>q<="0000000110000000";
when "0101" =>q<="0000000110000000";
when "0110" =>q<="0000000110000000";
when "0111" =>q<="0000000110000000";
when "1000" =>q<="0000000110000000";
when "1001" =>q<="0000000110000000";
when "1010" =>q<="0000000110000000";
when "1011" =>q<="0000000110000000";
when "1100" =>q<="0000000110000100";
when "1101" =>q<="1111111111111110";
when "1110" =>q<="0000000000000000";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0110"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="1111100000001111";
when "0010" =>q<="1111110000001111";
when "0011" =>q<="1111011100001111";
when "0100" =>q<="1111011100001111";
when "0101" =>q<="1111001110001111";
when "0110" =>q<="1111001110001111";
when "0111" =>q<="1111000111001111";
when "1000" =>q<="1111000111001111";
when "1001" =>q<="1111000111001111";
when "1010" =>q<="1111000011101111";
when "1011" =>q<="1111000011101111";
when "1100" =>q<="1111000011101111";
when "1101" =>q<="1111000001111111";
when "1110" =>q<="1111000000111111";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0111"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="1111111111111111";
when "0010" =>q<="1111111111111111";
when "0011" =>q<="1110000000000000";
when "0100" =>q<="1110000000000000";
when "0101" =>q<="1110000000000000";
when "0110" =>q<="1110000000000000";
when "0111" =>q<="1110000000000000";
when "1000" =>q<="1110000000000000";
when "1001" =>q<="1110000011111111";
when "1010" =>q<="1110000011111111";
when "1011" =>q<="1110000000000111";
when "1100" =>q<="1110000000000111";
when "1101" =>q<="111111*********11";
when "1110" =>q<="111111*********11";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
when others=>null; end case;
END PROCESS;
END cora_arc;
三、仿真结果
3.1时序控制模块仿真
3.2扫描控制模块仿真
3.3显示控制模块仿真
3.4总体仿真图
四、系统调试
4.1创建工程
在Quartus II 中新建一个VHDL File文件,将VHDL代码输入这个文件,并保存到工作目录,名为cnta.vhd。
4.2全程编译
设置好前面的内容之后,就可以进行编译了。选择Processing菜单中start compilation,在窗口的下方processing栏中显示编译信息。完成后在工程管理窗口左是角显示了工程cnta的层次结构和其中结构模块耗用的逻辑宏单元数。此栏的右边是编译处理流程,包括数据网表建立、逻辑综合、适配、配置文件装配和时序分析等。
4.3管脚绑定
软件仿真实现之后,要进行硬件仿真,即硬件实现。硬件实现简单明了,可以清楚的看到实验的成功与否,而且真实可靠。管脚绑定可以实现硬件和软件的完美结合,使实验清楚明白。图4.3为管脚绑定的大致图形。
图4.3 管脚绑定
4.4 硬件调试
选择tools菜单中programmer,点击左上角的Hardware Setup,选择USB,点击start即可连接硬件,进行调试 。连接成功后,即可在实验箱中LED屏循环显示字母。
如下图字母的显示:
五、心得体会
为期两周的嵌入式课程设计完成了。整过设计过程虽然不是很顺利。不过我认真对待老师给我们的课题,中间虽然也有不少挫折,但不经历挫折怎么见风雨,在我四处查看资料,请教同学下终于完成。
经过这两周的课程设计,我加深了对PLD的认识,学到了很多以前不知道的东西,也明白也PLD在现实生活中的重要应用和它的发展趋势。以前在书本上学到的东西总是不能够很好地运用到现实当中去,现在终于得到了改善,这让我感到非常的高兴。从这次实习中,我体会到,如果将我们在大学里所学的知识与更多的实践结合在一起,用实践来检验真理,使一个本科生具备较强的处理基本实务的能力与比较系统的专业知识,这才是我们学习与实习的真正目的。让我们不再是一个沉睡的孩子,让我们的无知渐渐远去,把我们所学的知识运用到实际中去,为社会出上我们的一份力。
感谢老师给的这次让我们自行设计的机会,通过这次设计通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和思考的能力。在设计的过程中遇到问题,可以说得是困难重重,这毕竟第一次做的,难免会遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固。
总的来说,这次设计的16×16点阵显示控制还是比较成功的,在设计中遇到了很多问题,最后在老师的辛勤的指导下,终于游逆而解,有点小小的成就感,终于觉得平时所学的知识有了实用的价值,达到了理论与实际相结合的目的,不仅学到了不少知识,而且锻炼了自己的能力,使自己对以后的路有了更加清楚的认识,同时,对未来有了更多的信心。最后,对给过我帮助的所有同学和指导老师再次表示忠心的感谢
六、附录
6.1总电路图
6.2参考程序:
时序控制模块
Library ieee;
use ieee.std_logic_11.all;
use ieee.std_logic_unsigned.all;
Entity chw is
Port(clk:in std_logic;
q:out std_logic_vector(3 downto 0));
End chw;
Architecture chw_arc of chw is
Begin
Process(clk)
variable cnt:integer range 0 to 1000;
variable tmp:std_logic_vector(3 downto 0);
begin
If clk'event and clk='1'then
If cnt<1000 then
cnt:=cnt+1;
Else
cnt:=0;
If tmp="1111" then
tmp:="0000";
Else
tmp:=tmp+1;
End if;
End if;
End if;
q<=tmp;
End process;
End chw_arc;
扫描控制模块
Library ieee;
use ieee.std_logic_11.all;
use ieee.std_logic_unsigned.all;
Entity cnta is
Port(clk:in std_logic; --端口定义 输入信号
q:out std_logic_vector(3 downto 0)); --端口定义 输出信号
End cnta;
Architecture count of cnta is
Signal lie:std_logic_vector(3 downto 0);
Begin
Process(clk)
begin
If clk'event and clk='1'then
If lie="1111" then
Lie<="0000";
Else
Lie<=lie+1;
End if;
End if;
q<=lie-1;
End process;
End count;
显示控制模块
LIBRARY IEEE;
USE IEEE. STD_LOGIC_11.ALL;
ENTITY cora IS
PORT(ch : IN STD_LOGIC_VECTOR(3 downto 0);
sel : IN STD_LOGIC_VECTOR(3 downto 0);
q : OUT STD_LOGIC_VECTOR(15 downto 0));
END cora;
ARCHITECTURE cora_arc OF cora IS
BEGIN
PROCESS(ch,sel)
BEGIN
CASE ch IS
When "0000"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="1111111111111111";
when "0010" =>q<="1111111111111111";
when "0011" =>q<="0000000111000000";
when "0100" =>q<="0000000111000000";
when "0101" =>q<="0000000111000000";
when "0110" =>q<="0000000111000000";
when "0111" =>q<="0000000111000000";
when "1000" =>q<="0000000111000000";
when "1001" =>q<="0000000111000000";
when "1010" =>q<="0000000111000000";
when "1011" =>q<="0000000111000000";
when "1100" =>q<="0000000111000000";
when "1101" =>q<="0000000111000000";
when "1110" =>q<="0000000111000000";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0001"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="0000001111000000";
when "0010" =>q<="0000011001100000";
when "0011" =>q<="0000110000110000";
when "0100" =>q<="0000110000110000";
when "0101" =>q<="0001110000111000";
when "0110" =>q<="0001110000111000";
when "0111" =>q<="0011110000111100";
when "1000" =>q<="0011111111111100";
when "1001" =>q<="0011111111111100";
when "1010" =>q<="0011100000111100";
when "1011" =>q<="0011100000011100";
when "1100" =>q<="0011100000011100";
when "1101" =>q<="0011100000011100";
when "1110" =>q<="0011100000011100";
when "1111" =>q<="0011100000011100";
when others=>null; end case;
When "0010"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="1111100000001111";
when "0010" =>q<="1111110000001111";
when "0011" =>q<="1111011100001111";
when "0100" =>q<="1111011100001111";
when "0101" =>q<="1111001110001111";
when "0110" =>q<="1111001110001111";
when "0111" =>q<="1111000111001111";
when "1000" =>q<="1111000111001111";
when "1001" =>q<="1111000111001111";
when "1010" =>q<="1111000011101111";
when "1011" =>q<="1111000011101111";
when "1100" =>q<="1111000011101111";
when "1101" =>q<="1111000001111111";
when "1110" =>q<="1111000000111111";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0011"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="1111111111111111";
when "0010" =>q<="1111111111111111";
when "0011" =>q<="1110000000000000";
when "0100" =>q<="1110000000000000";
when "0101" =>q<="1110000000000000";
when "0110" =>q<="1110000000000000";
when "0111" =>q<="1110000000000000";
when "1000" =>q<="1110000000000000";
when "1001" =>q<="1110000011111111";
when "1010" =>q<="1110000011111111";
when "1011" =>q<="1110000000000111";
when "1100" =>q<="1110000000000111";
when "1101" =>q<="1111111111111111";
when "1110" =>q<="1111111111111111";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0100"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="0111111111111111";
when "0010" =>q<="0111111111111111";
when "0011" =>q<="0000000111000000";
when "0100" =>q<="0000000111000000";
when "0101" =>q<="0000000111000000";
when "0110" =>q<="0000000111000000";
when "0111" =>q<="0000000111000000";
when "1000" =>q<="0000000111000000";
when "1001" =>q<="0000000111000000";
when "1010" =>q<="0000000111000000";
when "1011" =>q<="0000000111000000";
when "1100" =>q<="0111100111000000";
when "1101" =>q<="0011110111000000";
when "1110" =>q<="0001111111000000";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0101"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="0000000000001000";
when "0010" =>q<="0111111111111100";
when "0011" =>q<="0000000110000000";
when "0100" =>q<="0000000110000000";
when "0101" =>q<="0000000110000000";
when "0110" =>q<="0000000110000000";
when "0111" =>q<="0000000110000000";
when "1000" =>q<="0000000110000000";
when "1001" =>q<="0000000110000000";
when "1010" =>q<="0000000110000000";
when "1011" =>q<="0000000110000000";
when "1100" =>q<="0000000110000100";
when "1101" =>q<="1111111111111110";
when "1110" =>q<="0000000000000000";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0110"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="1111100000001111";
when "0010" =>q<="1111110000001111";
when "0011" =>q<="1111011100001111";
when "0100" =>q<="1111011100001111";
when "0101" =>q<="1111001110001111";
when "0110" =>q<="1111001110001111";
when "0111" =>q<="1111000111001111";
when "1000" =>q<="1111000111001111";
when "1001" =>q<="1111000111001111";
when "1010" =>q<="1111000011101111";
when "1011" =>q<="1111000011101111";
when "1100" =>q<="1111000011101111";
when "1101" =>q<="1111000001111111";
when "1110" =>q<="1111000000111111";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
When "0111"=>
case sel is
when "0000" =>q<="0000000000000000";
when "0001" =>q<="1111111111111111";
when "0010" =>q<="1111111111111111";
when "0011" =>q<="1110000000000000";
when "0100" =>q<="1110000000000000";
when "0101" =>q<="1110000000000000";
when "0110" =>q<="1110000000000000";
when "0111" =>q<="1110000000000000";
when "1000" =>q<="1110000000000000";
when "1001" =>q<="1110000011111111";
when "1010" =>q<="1110000011111111";
when "1011" =>q<="1110000000000111";
when "1100" =>q<="1110000000000111";
when "1101" =>q<="1111111111111111";
when "1110" =>q<="1111111111111111";
when "1111" =>q<="0000000000000000";
when others=>null; end case;
when others=>null; end case;
END PROCESS;
END cora_arc;
七、参考文献
1. 康华光主编.电子技术基础(数字部分),高等教育出版社。
2. 阎石主编. 电子技术基础(数字部分),清华大学出版社。
3. 陈大钦主编,电子技术基础实验,高等教育出版社。
4. 彭介华主编,电子技术课程设计指导,高等教育出版社。
5. 张 原编著,可编程逻辑器件设计及应用,机械工业出版社。
6.荀殿栋,徐志军编著,数字电路设计实用手册,电子工业出版社。
7刘洪喜,陆颖编著. VHDL电路设计实用教程 清华大学出版社
