字符发生器.docx
《字符发生器.docx》由会员分享,可在线阅读,更多相关《字符发生器.docx(19页珍藏版)》请在冰豆网上搜索。
字符发生器
第一章设计任务及要求
1.1课设任务
利用EX-III试验系统提供的字符矩阵显示、时钟等硬件支持,设计一个共阴极16×16点阵控制接口,在时钟信号控制下,将一串16×16点阵字符扫描显示输出。
显示方式一:
字符串的每一个字符为一页,在EX_III实验系统提供的字符矩阵用换页的方式显示。
显示方式二:
字符串在EX_III实验系统提供的字符矩阵从右向左滚动显示。
1.2课设要求
1.要求独立完成设计任务。
2.课程设计说明书封面格式要求见《天津城市建设学院课程设计教学工作规范》附表1
3.课程设计的说明书要求简洁、通顺,计算正确,图纸表达内容完整、清楚、规范。
4.测试要求:
根据题目的特点,采用相应的时序仿真或者在实验系统上观察结果。
5.课设说明书要求:
1)说明题目的设计原理和思路、采用方法及设计流程。
2)系统框图、VHDL语言设计清单或原理图。
3)对各子模块的功能以及各子模块之间的关系作较详细的描述。
4)详细说明调试方法和调试过程。
第二章设计思路
2.1系统框图
本系统主要包括地址计数器、汉字列计数器、只读存储器、分频器、16×16LED点阵模块,其系统结构框图如下:
图1系统框图
2.2设计原理
此电路由八进制计数器、十六进制计数器、EEPROM、分频器、16×16LED点阵电路这几个主要部分构成,另外还可以加上译码器和若干个LED七段数码管对其进行扩展。
1.读取字符地址电路由八进制和十六进制的计数器还有EEPROM组成,八进制计数器的作用是在时钟clk的作用下将从EEPROM中读出的信号(要输出的字符)对应正确的写在16×16的点阵上。
Reset是复位端,起复位作用。
输出d[2..0]选中16X16LED点阵的对应列,随着AD[2..0]值得增加,从左往右依次选中点阵的各列AD[0]则决定输出是在高位还是在低位。
2.十六制计数器是在AD[3..0]输出0-15的循环计数,这个输出与八进制计数器AD[2..0]的输出AD[2]、AD[1]、AD[0]共同作为EEPROM的输入地址,以此决定L[15..0]的输出。
3.分频器主要作用是使八进制计数器的时钟和十六进制的时钟相差一定倍出。
因为八进制计数器选择一个字符,十六进制计数器要经过十六次扫描,所以十六进制计数器的时钟至少是八进制计数器时钟的16倍。
为了效果明显,这里选择256倍。
4.4.2864EEPROM存储器是一个电可擦除、编程的只读存储器,容量为8K×8BIT,由13位并行地址线和8位并行数据线,而一个完整的字符所需的存储空间为32字节即32×8BIT,也就是说2864最多可连续存256个16×16点阵字形,存储方式可事先约定好。
在此电路中的作用是存储“天津城市建设学院”八个字.在AD[6..0]输入相应的地址时读取EEPROM中的相应的数据,然后在输出端L[15..0]输出。
在时钟脉冲的作用下,地址计数器计数,EEPROM相对应的地址单元中的代码输出,以驱动列选通线产生电路。
地址计数器同时又为行选通线产生电路,地址随着地址计数器计数值的变化,显示屏上显示出字符或图案。
由于我们所编的程序是包含八个汉字的字库,所以当全速运行时LED点阵模块上会显示对应的汉字。
第三章模块介绍
3.1八进制计数器
地址计数器是用来实现汉字翻页功能的,因为有八个要输出的汉字,因此用一个八进制的计数器进行计数,八个状态,采用三根地址线。
八进制计数器的输入一个是汉字选择时钟频率,另一个则是rst即置零端,输出为AD[2]、AD[1]、AD[0],输出的地址范围为000~111共八个地址以便进行汉字的翻页。
八进制计数器模块:
图2AND1
图2八进制计数器
图3八进制计数器仿真波形
仿真分析:
由仿真图分析可知,输出d[2],d[1],d[0]当遇到下降沿时触发,将从"000"一直变化到"111",即一个脉冲周期结束返回,由此可证明此模块正确为八进制计数器.
调试方法:
观察触发沿改变后d[2]~d[0]的输出是否从000加到111,若不是这样证明八进制计数器做的有错误。
表1八进制计数器真值表
clk
d2
d1
d3
rst
0
0
0
0
0
1
0
0
1
0
2
0
1
0
0
3
0
1
1
0
4
1
0
0
0
5
1
0
1
0
6
1
1
0
0
7
1
1
1
0
3.2十六进制计数器
每个汉字是由16行和16列组成,每次程序执行都是从左往右点亮一列LED点阵,一个汉字要执行16次这样的程序才能完整的显示出来,所以我们就需要一个16进制的计数器。
十六进制计数器的原理与八进制的相似,输入为扫描频率clk和rst,输出为到d3-d0,四位地址线可以选择16个地址输入到ROM中,并且这个十六进制计数器的输出还要与16×16LED点阵的片选端相连,即SEL3~SEL0,实现对LED点阵的扫描。
十六进制计数模块:
图4十六进制计数器
表2十六进制计数器真值表
Clk
d3
d2
d1
d0
0
0
0
0
0
1
0
0
0
1
2
0
0
1
0
3
0
0
1
1
4
0
1
0
0
5
0
1
0
1
6
0
1
1
0
7
0
1
1
1
8
1
0
0
0
9
1
0
0
1
10
1
0
1
0
11
1
0
1
1
12
1
1
0
0
13
1
1
0
1
14
1
1
1
0
15
1
1
1
1
图5十六进制计数器仿真波形
仿真分析:
由仿真图分析可知,输出d[3]~d[0]当遇到上升沿时触发,将从"0000"一直变化到"1111",即一个脉冲周期结束返回,由此可证明此模块正确为十六进制计数器.
调试方法:
观察触发沿改变后d[3]~d[0]的输出是否从0000加到1111,若不是这样证明十六进制计数器做的有错误。
3.3分频器
分频器主要作用是使八进制计数器的时钟和十六进制的时钟相差一定倍出。
因为八进制计数器选择一个字符,十六进制计数器要经过十六次扫描,所以十六进制计数器的时钟至少是八进制计数器时钟的16倍。
为了效果明显,这里选择256倍。
分频器模块:
图6分频器
波形分析:
clk输入十六个时钟,clk1输入一个时钟
图7分频器仿真波形
3.4存储器
存储器在本系统中有很重要的作用,字符发生器所显示的所有字符都是事先存在ROM中已建立的字符库中,并且它还是联接计数器与LED点阵模块的桥梁。
八进制计数器输出的高三位地址和十六进制计数器输出地低四位地址共同构成存储器ROM的输入地址,根据输入地址和ROM中字库代码的对应关系,最后输出一列16位的LED驱动代码,通过毎十六次输出就显示一个汉字。
在设计ROM时,根据ROM的大小,我们可以采用不同的设计方法进行设计,比如4x8,8x8或256x8的ROM可以采用数组描述或WHEN-ELSE.然而数组描述ROM在面积上是最有效的,在用数组描述时,常把数组常量的ROM放在一个程序包中,这种方法可以提供ROM的重用,在程序包中应当用常量定义ROM的大小.而用WHEN-ELSE描述一个ROM,它确实是最直观的,它是类似查表的方法来设计的,本次设计就是一个用WHEN-ELSE设计的256x8的ROM.
存储器模块:
图8ROM
第四章调试与仿真
3.1顶层文件原理图
顶层文件原理图:
图9顶层文件原理图
3.2仿真波形
为了确保便于观察,系统仿真时采用的总时长是500ms,时钟周期为2ms。
系统仿真波形:
图10系统仿真波形
仿真分析:
1.由仿真图分析可知,输出d[3]~d[0]当遇到上升沿时触发,将从"0000"一直变化到"1111",即一个脉冲周期结束返回,由此可证明此模块正确为十六进制计数器.
调试方法:
观察触发沿改变后d[3]~d[0]的输出是否从0000加到1111,若不是这样证明十六进制计数器做的有错误。
1.有图可观察出CR端给低电平时,输入地址d[6]~d[0]给的是“0010000”时对应输出的L15~L0为“1110000001000010”,这与ROM中程序完全一致,可以得出ROM模块也是正确的。
调试方法:
若输出L15~L0不是字库中对应的代码,则证明ROM设计有错误。
第五章心得体会
今年我们学习了EDA,每一次上课,每一次实验我都会学到很多知识。
通过实验也实际操作了EDA的Quartus软件,对于EDA有了更深的认识和自己的理解。
最后一周的这个EDA课程设计是对我们的知识的掌握和软件应用的一次检阅和练兵。
通过这次试验我充分的认识到我的EDA知识还没有储备的很充足,只掌握了最最基本的,而且对于软件的使用上还有很多不熟悉和不明白的地方。
在做课设期间,我和同学一起研究,最后在同学和老师的帮助下完成了我的课题——字符发生器。
我觉得这是一个很美妙的事情,看到点阵上出现一个接一个的字符,我心情无比激动。
世界上还有什么事情比看到这个景象还要让我开心的呢?
在做字符发生器的课设的时候,我遇到了很多困难。
程序的设计,设计思路还有具体的器件调用上都存在着很多问题,但是在同学的帮助下终于将这些问题一一克服掉了。
不论可设的最后结果如何,我是由衷的享受这个过程,因为我的确是学到了知识。
最后在这里要感谢老师,因为在你的课上我不仅学到了知识,也学习了做人的大道理。
同样要感谢那些帮助过我的同学,没有你们,我可能就做不出来我的字符发生器。
谢谢你们。
实际效果图
附录
生成八进制计数器件程序:
modulecounter8(clk8,d0,d1,d2,rst8);
inputclk8,rst8;
outputd0,d1,d2;
reg[2:
0]counter;
always@(posedgeclk8ornegedgerst8)
begin
if(!
rst8)
counter<=0;
elsecounter<=counter+1;
end
assignd2=counter[2];
assignd1=counter[1];
assignd0=counter[0];
endmodule
生成十六进制器件程序:
modulecounter16(clk8,d0,d1,d2,d3,rst8);
inputclk8,rst8;
outputd0,d1,d2,d3;
reg[3:
0]counter;
always@(posedgeclk8ornegedgerst8)
begin
if(!
rst8)
counter<=0;
elsecounter<=counter+1;
end
assignd3=counter[3];
assignd2=counter[2];
assignd1=counter[1];
assignd0=counter[0];
endmodule
十六分频器设计程序:
modulecount1(clk,clk1);
inputclk;
outputclk1;
reg[4:
0]count;
always@(posedgeclk)
count<=count+1;
assignclk1=count[4];
endmodule
ROM程序:
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entityROMisport
(CR,A6,A5,A4,A3,A2,A1,A0:
instd_logic;
L15,L14,L13,L12,L11,L10,L9,L8,L7,L6,L5,L4,L3,L2,L1,L0:
outstd_logic);
end;
architecturearc_ROMofROMis
signaldin:
std_logic_vector(6downto0);
signaldout:
std_logic_vector(15downto0);
begin
din<=A6&A5&A4&A3&A2&A1&A0;
process(din)
begin
if(CR='0')then
casedinis
when"0000000"=>dout<="0000000000100001";--1
when"0000001"=>dout<="0110000000100010";--2
when"0000010"=>dout<="0001000000100010";--3
when"0000011"=>dout<="0000100000100010";--4
when"0000100"=>dout<="0000010000100010";--5
when"0000101"=>dout<="0000001000100010";--6
when"0000110"=>dout<="0000000100100010";--7
when"0000111"=>dout<="0000000010100010";--8天
when"0001000"=>dout<="0000000001111110";--9
when"0001001"=>dout<="0000000010100010";--10
when"0001010"=>dout<="0000000101100010";--11
when"0001011"=>dout<="0000001000100010";--12
when"0001100"=>dout<="0000010000100010";--13
when"0001101"=>dout<="0001100000100010";--14
when"0001110"=>dout<="0011000000100010";--15
when"0001111"=>dout<="0111000000100000";--16
when"0010000"=>dout<="1110000001000010";--1
when"0010001"=>dout<="0110000110001100";--2
when"0010010"=>dout<="0010000000000000";--3
when"0010011"=>dout<="0010000000100000";--4
when"0010100"=>dout<="0010010100100100";--5
when"0010101"=>dout<="0010010100100100";--6
when"0010110"=>dout<="0010010100100100";--7
when"0010111"=>dout<="1111111111111111";--8津
when"0011000"=>dout<="0010010100100100";--9
when"0011001"=>dout<="0010010100100100";--10
when"0011010"=>dout<="0010010100100100";--11
when"0011011"=>dout<="0010010100100100";--12
when"0011100"=>dout<="0010010100100100";--13
when"0011101"=>dout<="0010010100100100";--14
when"0011110"=>dout<="0010010111111110";--15
when"0011111"=>dout<="0010000000100000";--16
when"0100000"=>dout<="0000000000000000";--1
when"0100001"=>dout<="0100000001000000";--2
when"0100010"=>dout<="0010000010000000";--3
when"0100011"=>dout<="0011111111110000";--4
when"0100100"=>dout<="0010000010000000";--5
when"0100101"=>dout<="0001000000000000";--6
when"0100110"=>dout<="0111111111110000";--7
when"0100111"=>dout<="0010000010001000";--8
when"0101000"=>dout<="0000100010001000";--9城
when"0101001"=>dout<="0001111110011110";--10
when"0101010"=>dout<="0000001001101000";--11
when"0101011"=>dout<="0000000110001000";--12
when"0101100"=>dout<="0000011000100100";--13
when"0101101"=>dout<="0001000000000000";--14
when"0101110"=>dout<="0000100000000000";--15
when"0101111"=>dout<="0000000000000000";--16
when"0110000"=>dout<="0000000000000000";--1
when"0110001"=>dout<="0000000000000000";--2
when"0110010"=>dout<="0000000000000000";--3
when"0110011"=>dout<="0001111111110000";--4
when"0110100"=>dout<="0000000000001000";--5
when"0110101"=>dout<="0000000000001000";--6
when"0110110"=>dout<="0000000000001001";--7
when"0110111"=>dout<="1111111111111110";--8
when"0111000"=>dout<="0000000000001000";--9市
when"0111001"=>dout<="0000100000001000";--10
when"0111010"=>dout<="0001111111110000";--11
when"0111011"=>dout<="0000000000000000";--12
when"0111100"=>dout<="0000000000000000";--13
when"0111101"=>dout<="0000000000000000";--14
when"0111110"=>dout<="0000000000000000";--15
when"0111111"=>dout<="0000000000000000";--16
when"1000000"=>dout<="0000000000000000";--1
when"1000001"=>dout<="0000010000001000";--2
when"1000010"=>dout<="0100100100001111";--3
when"1000011"=>dout<="0011111011111000";--4
when"1000100"=>dout<="0010000000100010";--5
when"1000101"=>dout<="0100010100100100";--6
when"1000110"=>dout<="0101010100100100";--7
when"1000111"=>dout<="0101010100100100";--8
when"1001000"=>dout<="0111111111111111";--9建
when"1001001"=>dout<="0101010100100100";--10
when"1001010"=>dout<="0100010100100100";--11
when"1001011"=>dout<="0100000011111000";--12
when"1001100"=>dout<="0100000000100000";--13
when"1001101"=>dout<="0100000000100000";--14
when"1001110"=>dout<="1000000000000000";--15
when"1001111"=>dout<="0000000000000000";--16
when"1010000"=>dout<="0000000000000000";--1
when"1010001"=>dout<="0000000000010001";--2
when"1010010"=>dout<="0000000000011110";--3
when"1010011"=>dout<="0111111111110000";--4
when"1010100"=>dout<="0010000000000000";--5
when"1010101"=>dout<="0100000000010000";--6
when"1010110"=>dout<="0100000111011111";--7
when"1010111"=>dout<="0010110001000001";--8
when"1011000"=>dout<="0001110001000001";--9设
when"1011001"=>dout<="0010000111011111";--10
when"1011010"=>dout<="0100000000010000";--11
when"1011011"=>dout<="0100000000000000";--12
when"1011100"=>dout<="0000000000000000";--13
when"1011101"=>dout<=