声明:本文为原创作品,版权归akuei2及黑金动力社区(http://www.heijin.org)共同所有,如需转载,请注明出处http://www.cnblogs.com/kingst/
5.7 实验二十:LCD(12864)封装
在这里笔者先提及一些重点。从5.1章开始,读者是否已经发觉到,笔者对封装建模,使用了许多第二章至第四章的建模基础。与其说,封建建模涉及了许多基础建模,还不如说建模基础是为了后期建模才存在。这一点笔者一开始就一直强调“低级建模”是为了后期的建模做好准备。当然“封装建模”也不是最后的建模。实际上“封装建模”也是“低级建模”的一环而已。因为“封装建模”一样也是为后期的建模在做准备。
(那么下一个“后期”又是什么?读者先猜猜吧 ... )
继5.6章后(VGA接口),这一篇同样是有关显示的封装。无论是 VGA接口 还是 LCD接口(LCD封装),原理上都是一样,不同的只是驱动上的方法而已。
上图是 lcd_interface.v 的组合模块。它包含了液晶控制模块,RAM模块,和SPI写模块。和VGA接口一样,RAM模块包含了图像信息,而且RAM模块也添加了访问优先级的逻辑。SPI写模块和实验12是一模一样。至于液晶控制模块就有点特殊了。
液晶控制模块包含了对液晶的“初始化控制”和“绘图控制”的功能以外,还能自动的从RAM模块读取图像信息。乍看lcd_interface.v 和 vga_interface.v 都是一样,它们皆能执行“读取图片信息的操作”以外,还能执行“显示驱动的操作”。此外, 对于 lcd_interface.v 的调用,我们只要针对 lcd_interface.v 的 RAM模块 写入图像信息即可。
lcd_interface.v 的功能大致如下:
(一)初起的时候,液晶控制模块对液晶初始化。RAM模块本身也自行初始化。
(二)每隔一段时间,液晶控制模块就会从RAM模块读取图像信息,然后利用这些信息来驱动液晶的显示。
在封装之前,需要考虑几个参数的配置:
液晶扫描频率 | 40Hz |
图像分辨率 | 64 x 128 |
液晶的扫描频率40Hz,亦即每25ms为液晶写入一副 64 x 128 大小分辨率的图像。
lcd_ram_module.v
在16行,声明了该 8 Bits x 1024 Words 的储存空间,是由m4k资源组成。而且还提示 Quartus II 的综合器无视“写时读”的问题。该储存器是由 pika_ani.mif 该文件爱你初始化。
spi_write_module.v
基本上和实验十二的 spi_write_module.v 是完全一样。
lcd_control_module.v
( ⊙o⊙ )哇!代码那么长!不要被吓到!只要简单的分析,读者会发现,其实上述的内容,读者从实验一到实验二十的经过,它们只是重复出现而已。
在16行定义了25ms的常量。20~28行是25ms的定时器。
我们知道“仿顺序操作”的模块都有一个特征,就是“不被使能不工作”,“完成工作就报告”。但是为了使液晶控制模块有独立性的能力,结果就添加一个“定时使能”的功能。在32~40行,就是充当这样的角色。isStart寄存器(32行)的位宽是2位,亦即该液晶控制模块拥有2个功能。在初始状态 isStart 被复位为 2'b10 。
在51~145行就是液晶控制模块的核心部分,故放映除出了“命令式仿顺序操作”的影子。61~114行是 initial_module.v 的部分,然而该功能被使能是在 isStart[1] ,亦即isStart寄存器最高位被拉高的时候才发生。
也就是说,lcd_interface.v 初始化的时候,51~145的“initial function”(液晶初始化功能)就被执行。在同一个时间20~28行的定时器也开始计数。但是在定时器完成计数之前,在109行,产生了“完成反馈”,亦即“initial fucntion”已经执行完毕。此时在39行,if条件成立 isStart 被清理。
115~145行是“draw function”(液晶绘图功能)。该功能会发生在,当isStart[0],isStart寄存器的最低位被拉高的时候。每隔25ms的时间在20~28行的定时器都会产生定时,isStart的最低位都会被拉高。换句话说,每隔25ms“draw function”就会被执行。
当“draw function”完成后(140行),就会产生一个“完成反馈”。在同一个时间39行的if条件就会成立,isStart会被清零。
在148行的 Read_Addr_Sig 信号是作为“RAM模块”读取操作的寻址信号。
在前面,笔者显示了该lcd_interface.v 的扫描频率是 40Hz。如果换做公式来表达的话:
T = 1 / F
= 1 / 40Hz
= 25 ms
这也是20~28行的定时器要每隔25ms产生一次定时的原因。因为每隔25ms,isStart寄存器的最低位就会被拉低,然后“draw function”就会被执行。换句话来说,定时器的存在是为了充当“仿顺序操作”模块的“Start_Sig”信号。当然也可以这样说“Start_Sig 和 Done_Sig 都是发生在液晶控制模块的内部”
lcd_interface.v
该组合模块和 "图形" 基本上都是相似的,自己看着办吧。
实验二十说明:
如果实验十二和实验二十相比较,实验二十的RAM模块替代了实验十二的ROM模块作为图像信息的储存器。SPI写模块没有任何改变。实验二十的液晶控制模块使用了类似“命令仿顺序操作”的方法,整合了实验十二的 initial_module.v 和 draw_module.v。
此外液晶控制模块在初始化的时候,会对液晶资源执行初始化的操作。然后每个25ms,液晶控制模块都会从RAM模块读取图像信息,用于液晶的显示驱动。
所以说 vga_interface.v 和 lcd_interface.v 有许多相同的地方。基本上它们都是使用同一个工作原理,就是提高扫描频率,利用肉眼的弱点,时而产生动态扫描的效果。如果笔者明白了 vga_interface.v 的工作原理,自然而然就会明白 lcd_interface.v 的工作原理。
完成的扩展图:
实验二十结论:
调用 lcd_interface.v 模块如同对 RAM模块写入信息。
实验二十演示:
这一章主要是演示 lcd_interface.v 如何调用。
在组合模块 lcd_interface_demo.v 中 ROM模块的储存空间是 8 Bits x 2048 Words,我们知道一副分辨率 64 x 128 的图像所占的储存空间是 8 Bits x 1024 Words , 该ROM模块亦即包含两副图像信息。
皮卡丘动作1 | 比卡丘动作2 |
就是以上这只小可爱的两幅图像信息。换句话说,该演示是要实现动画。
该 lcd_interface_demo.v 的大致操作如下:
(一)从ROM模块读第一副图像信息,然后写入 lcd_interface.v 的RAM模块里。
(二)延迟大约500ms
(三)从ROM模块读第一副图像信息,然后写入 lcd_interface.v 的RAM模块里。
(四)延迟大约500ms
(五)重复步骤1~4。
lcd_interface_demo.v
在11行声明了 1ms的常量。15~25行是1ms的定时器,然而29~37行是秒级的计数器。
在94~101行实例化了 ROM模块,而且在105~113行实例化了 lcd_interface.v 。
64~90行是该模块的控制程序。X寄存器计数列填充(61行),Y寄存器计数行切换(62行),Z寄存器控制图像切换(41行)。那么图像寻址地址的表达式是 X + ( Y << 7 ) + ( Z << 10 )。X << 7 表示了一行有128长度,Z << 10 表示了一副图像有 1024的长度。
在79~81行表示了,从 ROM模块 读取图像信息至 lcd_interface.v 的RAM模块的操作。84~85行是延迟500ms的操作。
当步骤0的时候(78行),Z的值是0(49行),也就是第一副图像信息被选择,然后在79~81行,会将ROM模块 0~1023 的图像信息写入 lcd_interface.v 的 RAM模块。当完成 8 次的 128次列填充,79行的if条件就会成立,i会递增以示下一个步骤。(注意,在79~81行的操作的期间 isWrite 一直被拉高,也就说 lcd_interface.v 的 Write_En_Sig 也是一直被拉高 - 81行。)
当步骤等于1的时候(83行),会产生500ms的延迟效果。然后i会递增,以示下一个步骤。
当步骤2的时候(78行),Z的值是1(50行),也就是说第二幅图像信息被选中。接下来的动作,和步骤0一样,只是图像信息不同而已。
当步骤等于3的时候(83行),同样也会产生500ms的延迟效果。i递增 ...
步骤4(87行)将i清理,以示重复执行步骤0~3。
在这里有一个重点,就是在110行,Write_Addr_Sig 信号是由 rAddr[9..0] 驱动。因为有关图像切换仅是影响 rAddr[10] 的位而已。
实验二十演示说明:
没有什么特别的。对lcd_interface.v 的调用如同对 RAM模块写入信息而已。
实验二十结论说明:
嗯!封装以后的 lcd_interface.v ,调用的工作都非常方便了。