搜索
bottom↓
回复: 28

看了怎样在点阵屏上绘图——基于LCD12864,想请教 傻孩子一些问题。

[复制链接]

出0入0汤圆

发表于 2009-3-2 22:05:52 | 显示全部楼层 |阅读模式
我用的是ST7920控制的液晶,是用串行方式控制的,由于需要显示波形,需要编写一个任意画点的函数,但是几乎已经确定串行数据是不能读回数据的,(用并行需要占用多出8个I0口),因为这款液晶需要连续写入两次数据,如果不能读回数据的画,那所谓的任意画点函数是基本不能实现了,会出现点亮一个点的同时,清楚其他数据的问题。用傻孩子的画说-----不能在任意位置点亮一个点的画,就不能说掌握一快液晶。


看到了傻孩子的文章里有这样一段话


事实上,LCD本身存在一块显示存储器,也可以被认为是一个显示缓存,直接写在这个存储器的数据并非直接显示出来,而多半需要一个显示指令来影射一下。我们有时候也通过这种类似的技术来实现很大的图片的显示——先画好,再拿给大家看,让人以为你是一下就画好的,当然如果你刻意需要那种图片被“画”出来的效果,则不在讨论之列。问题就在于,LCD是片外资源,对其存储器的访问可以被认为是对片外存储器的访问,其速度显然没有对片内SRAM的操作速度要快。如果我们使用那种常用的串行方式来作图(所谓串行方式作图,就是绘图指令的执行和系统的其他操作时串行的,指令不完成,其它操作就不回被执行),那么对于一些实时性要求高的系统来说就会造成重大隐患——甚至是不符合要求的;如果开辟一段片内存储空间和LCD的存储器一一对应,在相同的时间段内,花费相同的资源来保持着两个存储空间的一致性,那么就可以保证实时系统的稳定和可靠,保证画面显示的正常(因为允许跳帧嘛^_^)。这就是我们为什么需要另外在片内选取一个显示缓冲区的原因。

   以后,我们的操作都是针对显示缓冲区的。显示缓冲区将成为一个概念,无论这个缓冲区位于SRAM内还是LCD内部。比方说,我们需要一个低成本的游戏机——如做一个贪食蛇游戏机送给老师作为课程设计,或者送给小侄子,那么,M8甚至是M48成为首选,问题是,M8绝对无法开辟出一个8 * 128 = 1K大小的数组,所以,这个时候,认定LCD的片内存储器作为显示缓冲区就是不二的选择——好在贪食蛇速度太快了也没有办法玩哈。



   绕了这么多的弯子,究竟如何画点呢?我还想多补充一个原因,关于,为什么需要显示缓冲区,由于点阵屏幕使用的是1个字节来表示8个点的,如果你想使得一个字节中的某一个点被操作而不影响别的点,你起码要知道原来这个位置是什么内容,对于有些使用595级联的LCD设备来说,无法直接从LCD读取现存数据,所以开辟一个缓冲区,从中获得信息加以加工以后再放回去,是这种设备处理显示图形的唯一方法——当然我们没有那么惨,但是从LCD中获取所需点所在字节的内容还是必须的,不然你画一个点就会破坏一条线上所有的数据。

我看的不是很明白,可不可以不用读回数据,用串行方式,实现任意位置的画点函数呢。

出0入0汤圆

发表于 2009-3-2 22:22:53 | 显示全部楼层
意思就是在单片机的RAM中开辟一块区域(片内显示缓冲存储区)保存屏上每个点的亮、暗信息,需要改变屏幕显示内容的时候,首先修改片内显存的内容,然后刷新整屏(程序简单无算法、响应速度慢)或者刷新有更改的区域(程序复杂需算法支撑、响应速度快)。

出0入296汤圆

发表于 2009-3-3 10:36:57 | 显示全部楼层
to 【1楼】 eduhf_123 经历
    谢谢楼上的回答,我也是这么想的。

出0入0汤圆

 楼主| 发表于 2009-3-3 18:38:39 | 显示全部楼层
谢谢我大概的知道是怎么回事了。
就是说要建立一个和屏幕一一对应的1K的数组。
然后像LCD送指令的话,先修改这个数组的数据,然后整屏的刷新数据

在单片机的内部建立起一个IK的空间,那自然就可以读出里面的数据,那画点函数的问题也就可以解决了

但我对这个方法还是很模糊
第一种还可以理解
刷新有更改的区域(程序复杂需算法支撑、响应速度快)。
但对第二种说法就没有什么思路了。
傻孩子, eduhf_123 经历,可以具体的说说吗,有没有程序可以参考一下

还有我用的是M16,如果真的要实的话是不是还要扩充个外部的FLASH


还有为了解决串口驱动液晶能画点的问题,我是这样想的用 M16+一个外部的FLASH(选择个大的,以后不仅可以放LCD的数据,还可以放其他的数据),但是有个问题~`~~~如果用外部FLASH的话,那么肯定选择用串口的,那这样每次都要把1K的数据读回来在显示到液晶上,那么速度是不是就太慢了。

不知道有没有给好的方案呢?

出0入0汤圆

发表于 2009-3-3 21:00:50 | 显示全部楼层
to 【2楼】 Gorgon Meducer 傻孩子
  呵呵,你没有嫌我抢答问你的问题、没有觉得我是在误人子弟,我就已经很开心了。



to 【3楼】 zbh-avr
  首先说说“刷新有更改的区域”的实现方法,我个人的思路是这样的:
  1、简单矩形区域刷新法:在液晶屏驱动模块中维护4个静态全局变量(本模块所有函数均可访问,而对外部函数不可见),用以存储需要刷新区域的左(L)、右(R)、上(T)、下(B)4个边界的坐标。一般以液晶屏左上角为原点建立坐标系,x轴水平向右、y轴竖直向下。初始的时候将L和T设置为所属数据类型的最大值、而将R和B设置为0;然后在每次写显存的时候,用所写区域的左上角的横、纵坐标分别与L和T比较,用小值更新L和/或T,用所写区域的右下角的横、纵坐标分别与R和B比较,用大值更新R和/或B;写显存完成后,刷新显示的函数就可以只刷新这4个变量所限定的一个矩形区域(因为这个矩形区域以外的显示内容自上一次刷新后没有发生变化,维持原状就好,没有必要重复刷新,所以可以节省大量运行时间),然后再将L和T置为最大、将R和B置为0,以便下一次标记需要刷新的矩形区域。
  2、“逻辑行”刷新法:通常来说,在图形模式下,单色液晶屏显存中一个字节的数据对应屏上纵向一列上8个像素点的亮灭信息,所以屏幕上的行分两种情况:“物理行”,行高1个像素;“逻辑行”,行高8个像素。第一种实现方法,可能仍有很大的运行时间浪费(比如需刷新区域中有的行根本没有变化),所以自然地想到,给每个“逻辑行”设置一个“需要刷新”的标志位,刷新时只刷新“需要刷新”标志位被置位的行。本方法的扩展:给每个“逻辑行”设置一个左右边界用以标记该行需要刷新部分的边界,刷新时,每个“逻辑行”只刷新各自左右边界以内的部分。
  3、“逻辑行”内分块刷新法:在液晶屏比较宽(即“逻辑行”比较长)的时候,如果某一行只有行首和行尾有变化,使用第二种方法(包括其扩展方法)需要刷新该行整行,效率依然不高,所以想到在“逻辑行”内再分块。“逻辑行”内分块的方式,我暂时有两个思路:①位图映射刷新区域法(一个“逻辑行”分为8/16/…个均匀/不均匀的块,每行配备一个8/16/…位的数据,每位对应一个块),②链表对应刷新区域法(使用一个单链表来标记整个屏上所有“逻辑行”中需要刷新的区域,链表节点有3个数据:该区域所在行、左边界、右边界)。
  4、多矩形区域刷新法:不适合低分辨率的屏,就不做详细讨论了。

  其次,显存存储介质的选择:
  首先不建议使用Flash/EEPROM,因为速度太慢;其次不建议使用DRAM,因为外围电路复杂;其实显示缓存有个32KB足矣,完全可以使用SRAM;最后强烈建议使用串行接口存储介质,原因很简单,速度。
  至于你说的Flash放LCD的数据,是指屏上显示的、不怎么变化的框架性内容吗?如果是,那么可以将它放在Flash中,上电初始化的时候将其复制到SRAM的显存中,之后都在显存中操作即可。

出0入0汤圆

 楼主| 发表于 2009-3-4 18:42:57 | 显示全部楼层
谢谢  eduhf_123 经历的耐心解答

我在看第一种方法
一般以液晶屏左上角为原点建立坐标系,x轴水平向右、y轴竖直向下。初始的时候将L和T设置为所属数据类型的最大值、而将R和B设置为0;
L和T所属数据类型的最大值,是不是说如果我用的是UCHAR类型的,那就给L和T附上0XFF?
为什么要这样子做呢?

出0入0汤圆

 楼主| 发表于 2009-3-4 19:08:32 | 显示全部楼层
TO eduhf_123
我刚刚有了个想法
前面说了因为串行方式液晶是不能读回数据的
但是现在既然我们在单片机的内部键立了一个缓存区,那缓存区的数据我们是可以读的

在我们要向缓存区那个单元写数据的时候,先把刚单元的数据给读回来,然后在和新的数据进行与或操作,保有原来的数据的同时又写进了新的数据,然后在把数据附给液晶让他显示出来。

最好能编写一个子函数,能和液晶的坐标对应起来,我写入缓存区的地址和液晶的坐标对应起来,缓存区写入的数据,只写更改了的部分。

不知道这样子行不行。

出0入0汤圆

发表于 2009-3-4 19:34:25 | 显示全部楼层
我也玩过串行驱动12864

只能显示字符,屏幕狂闪,看得见扫描线一行行晃动,晕

出0入0汤圆

发表于 2009-3-5 15:45:43 | 显示全部楼层
【5楼】 zbh-avr
积分:32
派别:
等级:------
来自:
我在看第一种方法
一般以液晶屏左上角为原点建立坐标系,x轴水平向右、y轴竖直向下。初始的时候将L和T设置为所属数据类型的最大值、而将R和B设置为0;
L和T所属数据类型的最大值,是不是说如果我用的是UCHAR类型的,那就给L和T附上0XFF?
为什么要这样子做呢?

  在不涉及显示区域扩展的时候,屏幕上的点所对应的坐标,最小不会小于0,最大不会超过屏幕宽度和高度,所以我们所更改区域的边界坐标肯定是大于等于0、小于屏幕宽度/高度的。当我们把R和B设置为0的时候,不管我们第一次显示的内容在屏幕上的什么位置,R和B一定会被替换;对L和T是同样的道理。对特定的屏,L和T的初值只要分别超过屏幕的宽度和高度就可以了,但是如果随便写一个超过当前屏幕宽度和高度的值,下次换一个更大的屏可能就不满足要求了,所以当时我的第一想法就是设成最大值,但现在想来有些不妥:在不涉及显示区域扩展的时候,L和T的初值应当分别设置为LCD_HORIZONTAL_MAX和LCD_VERTICAL_MAX,R和B的初值则应当设置为LCD_HORIZONTAL_MIN和LCD_VERTICAL_MIN;而在支持显示区域扩展的时候,L和T的初值就应当设置为LCD_HORIZONTAL_MAX_EX和LCD_VERTICAL_MAX_EX,R和B的初值则应当设置为LCD_HORIZONTAL_MIN_EX和LCD_VERTICAL_MIN_EX;这8个宏应当在显示模块的头文件中进行定义,以满足移植要求。
  至于为什么这么做,上面其实已经讲到了,初值设为一个“不可能值”,那么我们就可以在“写显存”操作后,得到一个“最小的”需要刷新的矩形区域,其实就是为了满足“性能最优”的目标。

出0入0汤圆

发表于 2009-3-5 16:27:40 | 显示全部楼层
【6楼】 zbh-avr
积分:32
派别:
等级:------
来自:

我刚刚有了个想法
前面说了因为串行方式液晶是不能读回数据的
但是现在既然我们在单片机的内部键立了一个缓存区,那缓存区的数据我们是可以读的

在我们要向缓存区那个单元写数据的时候,先把刚单元的数据给读回来,然后在和新的数据进行与或操作,保有原来的数据的同时又写进了新的数据,然后在把数据附给液晶让他显示出来。

最好能编写一个子函数,能和液晶的坐标对应起来,我写入缓存区的地址和液晶的坐标对应起来,缓存区写入的数据,只写更改了的部分。

不知道这样子行不行。

  我在4楼提出的4种想法,目的就是想要达到你说的“只写更改了的部分”的效果。
  从系统的角度出发,有显示需要的子程序(任务、进程、甚至是线程),应该不去关心屏幕显示的技术细节(比如是并行接口还是串行接口、多长时间刷新一次等),直接把要显示的内容写进显存、标记好“需要刷新”的矩形区域范围就可以了。而将有更改的数据送显的工作由一个刷新任务来完成,这样做的好处有以下几点:
  1、使用LCD屏的情况。显示内容长时间不发生变化的时候,刷新任务就可以也长时间不运行,降低CPU占用率的同时可以降低功耗(如果其他任务也没有运行,可以让CPU进入节能状态);显示内容过于频繁地发生变化时,刷新任务可以不跟随数据的变化去频繁刷新显示,因为显示内容的频繁刷新对我们人眼的观察并不具有现实意义,而且频繁刷新会过多占用CPU时间,另外,刷新过快时,屏的响应速度能否跟上也是个问题。
  2、使用LED动态扫描显示的情况。使用动态扫描驱动法而数据长时间不变的情况下,将“写显存”和“刷新显示”分开可以避免数码管不亮的问题。需要注意的是,如果是CPU自己负责显示内容的刷新(即没有“GPU”的情况),则不需要设置“需要刷新的区域”,每次均需刷新整屏内容。
  3、使用LED静态显示的情况。显示内容频繁变化时,与第一点中的第二种情况类似,可以实现“不同步刷新”。
  4、方便实现“屏幕保护”。设置一个软件定时器,每次有用户操作时,该定时器被清零;用户长时间无操作,定时器溢出,则刷新任务就可以关掉显示(或者显示屏保动画、公司LOGO等)。
  最后,这个刷新任务要将“显存”中的数据送显,它自然是必须知道“显存”中的数据和屏上的显示内容如何对应的,这个是毫无疑问的。

出0入0汤圆

发表于 2009-3-5 16:49:37 | 显示全部楼层
  友情提醒楼主:以上内容是我在看到你的疑问后,很直接的想法,全然未经验证。帖出来只是给个思路供你参考,暂时不要当成金科玉律。关于嵌入式GUI方面的内容,你最好还是请教一下傻孩子,他在这方面应该很有研究。

  在此也呼唤傻孩子来拍砖,诚心求砖。

出0入296汤圆

发表于 2009-3-5 17:12:33 | 显示全部楼层
非常感谢楼主积极参与讨论。
您所说的技术,其实在游戏领域颇为常见,被称为:脏矩阵技术:即把显示
区域分为若干个矩形,只要这个矩形被重写了,也就是被弄脏了,就在刷新
的时候单独将这一区域写回显示区。您可以给显示缓冲区建立这一机制。具
体实现方法则根据LCD的结构不同而有所差别。但总体原理就如上面所说的。

出0入0汤圆

 楼主| 发表于 2009-3-5 21:41:22 | 显示全部楼层
对于那个矩阵的实现方法

eduhf_123 经历,我是这样理解的
对于那个缩下范围我始终是不能理解

我不明白矩形的缩小是怎么实现的,而且缩下到只有显示的部分的矩形

你是先计算机专业的吗?
感觉你对这方面的东西很精通

出0入0汤圆

发表于 2009-3-5 22:37:20 | 显示全部楼层
  不是“缩小”,而是开始设置了一个“不存在的”矩形区域(左边界在右边界的右边、上边界在下边界的下边,注意L、R、T、B的初值),然后每一次写显存,在需要的时候将其范围扩大,且只扩大一点(这一点恰好能包含本次改变的内容中在上次的矩形之外的部分),使得最后被刷新的区域最小(相对最小,再大就浪费,再小就有改变的内容显示不出来)。
  你可以设想那4个变量的初值,然后自己“假装”写几次显存,每次记得同步更新那4个变量,最后看它们标记出来的区域是否最小。自己走一、两步就很清楚了,并不是很复杂的算法,简单的比较、替换而已。

出0入296汤圆

发表于 2009-3-6 20:54:37 | 显示全部楼层
楼上可以画一个示意图。^_^这是一种动态脏矩阵。我在前面说的是静态脏矩阵算法。
对于绘图量较小的系统来说,动态脏矩阵算法的效率可能较静态要高一些,但对于需
要经常绘图的系统来说,静态脏矩阵算法要更实际一些。

出0入0汤圆

发表于 2009-3-11 23:02:31 | 显示全部楼层
学习!

出0入0汤圆

发表于 2010-12-2 15:34:11 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-19 09:31:49 | 显示全部楼层
学习!

出0入0汤圆

发表于 2011-8-23 15:51:48 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-10-9 22:25:00 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-10-9 23:09:17 | 显示全部楼层
不能对lcd的显存就在单片机内存中划出一段来充当显存,我的方法是定一个二维数组,要写入lcd的数据与二维数组的对应元素与一下再写入lcd,这样就不会显示新点的同时清除已经存在的点了,用这种已经可以在淘宝超值推荐坛子上的128*128液晶上画任一点了,缺点是太太太太占内存,51单片机肯定是不行的,我用的是atmega128,4k的sram

出0入0汤圆

发表于 2011-10-11 16:00:22 | 显示全部楼层
我有个 7565 控制器的 12864 也是 串口方式........也想玩下绘图  但是无法读回  所以...也构思了 在单片机内部RAM映射一块和液晶一样的区域  刷新的时候只刷新改动过的 单元 ...........由于能力不够  目前还没能达成所想效果  

不知道时隔一年 LZ 有没有搞定啊??

出0入0汤圆

发表于 2011-10-12 16:03:17 | 显示全部楼层
mark

出0入4汤圆

发表于 2012-6-11 16:19:43 | 显示全部楼层
太高深了   

出0入0汤圆

发表于 2012-6-17 17:54:23 | 显示全部楼层
对头,但是能不能在楼上说的脏矩阵方法的基础上实现对一个字节操作呢。我们都知道12864屏的点阵是每八个写在一个字节里面的,我们每次要改其中的一个点的时候,只改这个点所在的字节,然后重新写入,这样一来处理速度会不会快一点呢。我之前也试着写过单独的一个点的屏,但是会出现在一条线上出现断断续续的情况。

出0入0汤圆

发表于 2013-1-29 21:48:05 | 显示全部楼层
eduhf_123 发表于 2009-3-2 22:22
意思就是在单片机的RAM中开辟一块区域(片内显示缓冲存储区)保存屏上每个点的亮、暗信息,需要改变屏幕显 ...

请教下,你的意思是不是这样的
比如12864的屏,8页,一页128个字节
我在FLASH中建个数组aa[8][128]来与屏对应
在画点函数中比如画点最做上角(0,0)的时候
就aa[0][0]&=0x01;
让后在用指定位置写数据的函数写到屏上去?

出0入264汤圆

发表于 2013-1-29 22:25:30 来自手机 | 显示全部楼层
kingsor120 发表于 2013-1-29 21:48
请教下,你的意思是不是这样的
比如12864的屏,8页,一页128个字节
我在FLASH中建个数组aa[8][128]来与屏 ...

你的理解是对的,不过注意绘点操作是对相应位置1。

出0入0汤圆

发表于 2013-1-29 23:08:21 | 显示全部楼层
最近也正在玩12864的屏幕,也是SPi接口的。

打算已行作为单位进行读写,8行*128位。

正在读商家给我的示例代码。。。由于示例是C语言写的,而我只懂Basicom……

出0入0汤圆

发表于 2013-1-31 19:04:15 | 显示全部楼层
mcu_lover 发表于 2013-1-29 22:25
你的理解是对的,不过注意绘点操作是对相应位置1。

感觉这样的话全是滑图还好
要是还有汉字呢不是很麻烦
比如同时显示数字和表盘的时钟
那不是还得把数字的部分转换到数组中去?
固定显示位置还好
如果显示位置变化更麻烦
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-2 17:00

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表