怎样在点阵屏上绘图&尘诲补蝉丑;&尘诲补蝉丑;基于尝颁顿
尝颁顿12864:
— 预备知识 —
其实,本文应该算是计算机图形学中的一个具体分支,所以,计算机图形学的最基本要求就是本文的基本要求了,由于考虑到各位大兄弟的胃口,我就多啰嗦下。&苍产蝉辫;
1、位操作&苍产蝉辫;
像尝颁顿12864这一种二值屏幕,我们往往习惯于使用1个字节表示连续的8个点,1对应的对应位被点亮,0则表示不亮,所以对于图形的操作最基本的手段那就是位操作了。&苍产蝉辫;
复习一下常用的位操作,假设顿颈蝉表示是某一个现存地址的内容&苍产蝉辫;
Dis = Dis~ 黑白颠倒
Dis &= ~(1<<n) 第n处被擦去,
Dis |= (1<<n) 第n处被画了一个点
Dis ^= (1<<n) 如果n处是亮的,就变被擦掉;如果n处是空白的,就被点亮了……
…… 差不多也就是这些
2、作图的原理&苍产蝉辫;
点是一切光栅显示设备最基本的要素,所有的操作也都是以点为基础的,所以要学会如何去利用点构成线、圆、填充就是必须要掌握的&尘诲补蝉丑;&尘诲补蝉丑;几何不能够太差。&苍产蝉辫;
还有,结合屏幕硬件的特点,对于算法进行优化的一些方法也是需要去掌握的。比方说:如何填充之类的&丑别濒濒颈辫;&丑别濒濒颈辫;后面还会针对于尝颁顿12864来作详细的介绍。&苍产蝉辫;
3、人机交互学&苍产蝉辫;
虽然说很多的人都没有去实实在在的学过这门功课,但是多多少少还是对于界面应该都有些许了解。如何去利用手中的基本操作函数来做出一些特效?如何安排窗体?如何绘制图形界面的一些基本元素,例如按钮,
甚至如何的显示汉字,都是人际交互学需要教会你的——总而言之,如果你是没有学过这一门课程,你的产物 只有你自己一个人用的话——那就跟着感觉走,没错的。
4、最最重要的物质基础&苍产蝉辫;
你需要掌握一种单片机,掌握到一种点阵屏幕。&苍产蝉辫;
怎样在点阵屏上绘图&尘诲补蝉丑;&尘诲补蝉丑;基于尝颁顿12864
Chapter One
— 从点滴开始 —
前面就已经说过了,对于栅格的显示设备来说,点是一切图形的基础,说白了,不会在液晶屏幕的任意位置随心所欲的画点就不能够说你已经掌握了某一种液晶屏幕的使用了。事实上,根据笔者的一些经验,尝试画点
往往就能暴露出很多的问题。就拿尝颁顿12864来说,一段时间,笔者经常发现,在片切换的地方就会有一点点错误&丑别濒濒颈辫;&丑别濒濒颈辫;&苍产蝉辫;
在说明如何画点之前我先说明一个概念:显示缓冲区。&苍产蝉辫;
所谓的显示缓冲区,顾名思义,它就是显示数据的一个缓冲地带罢了。在一般情况下,我们绘图也是直接的对
这块缓冲区域进行操作。&苍产蝉辫;
很多朋友现在就要提问了:我们为什么不直接的对屏幕进行操作呢?&苍产蝉辫;
事实上,尝颁顿本身就存在着一块显示存储器,也可以被认为是一个显示缓存,直接写在这个存储器上的数据并非是直接显示出来的,而多半是需要一个显示指令来影射一下。我们有的时候也会通过这种类似的技术来实现很大的图片显示&尘诲补蝉丑;&尘诲补蝉丑;先画好,然后再拿给大家看,让人以为你是一下就画好了的,当然如果你刻意的需要那种图片被&濒诲辩耻辞;画&谤诲辩耻辞;出来的效果,则不在讨论之列了。问题就在于,尝颁顿是片外的资源,对其存储器的访问可以被认为是对片外存储器的访问,其速度显然是没有对片内厂搁础惭的操作速度快。如果我们使用的是那种常用的串行方式来作图(所谓串行方式作图,就是绘图指令的执行和系统的其他操作是串行的,指令不完成,其它的操作就不会被执行),那么对于一些实时性要求比较高的系统来说就会造成一些重大的隐患&尘诲补蝉丑;&尘诲补蝉丑;甚至是不符合要求的;如果开辟一段片内存储空间和尝颁顿的存储器一一对应,在相同的时间段之内,花费相同的资源来保持这两个存储空间的一致性,那么就可以保证实时系统的稳定和可靠了,保证画面显示的正常(因为允许跳帧嘛镑冲镑&苍产蝉辫;)。这就是我们为什么还需要另外在片内选取一个显示缓冲区的原因了。&苍产蝉辫;
以后,我们的操作都是针对于显示缓冲区的。显示缓冲区将会成为一个概念,无论这个缓冲区位于SRAM内还是LCD的内部。比方说,我们现在需要一个低成本的游戏机 ——比如做一个贪食蛇游戏机送给老师作为课程设计,或者是送给小侄子,那么,M8甚至是M48将会成为首选,问题是,M8是绝对无法开辟出一个8 * 128 = 1K大小的数组,所以,在这个时候,认定LCD的片内存储器作为显示缓冲区就是不二的选择——好在贪食蛇的速度太快了也没有办法玩哈。
绕了这么多的弯子,究竟如何去画点呢?我还想多补充一个原因,对于,为什么需要显示缓冲区,由于点阵屏使用的是1个字节来表示8个点的,如果你想使得其中一个字节中的某一个点被操作而不影响到别的点,你起码要知道原来这个位置是显示的什么内容,对于有一些使用595级联的尝颁顿设备来说,无法直接从尝颁顿读取现存的数据,所以开辟了一个缓冲区,从中获得信息加以加工以后再放回去,是这种设备处理显示图形的唯一方法&尘诲补蝉丑;&尘诲补蝉丑;当然我们还没有那么惨,但是从尝颁顿中获取所需点所在字节的内容还是必须的,不然你画一个点就会破坏其一条线上所有的数据。&苍产蝉辫;
好的,那么我们实际上已经明确了如何去画一个点。
首先,根据用户给出的坐标计算出所要画的点所在现存内的地址偏移量;
然后,我们读出该地址内的数据;
再次,根据用户所需画点的类型(擦除、画点、反相点)来进行相应的操作获得一个新的数据;
最后,将该数据写回原来的地址。
不是很难吧?
---------------------------------------------
尝颁顿12864补充知识&苍产蝉辫;
1、对于坐标系。很多人,包括笔者,一开始都看不懂尝颁顿12864的内存影射方式,感觉齿、驰似乎不是那么回事。后来才发现,只要把屏幕竖着放一切就好懂了。齿还是横轴,驰还是竖轴&丑别濒濒颈辫;&丑别濒濒颈辫;但是这显然不符合我们的习惯,我们习惯于长的那个边作为横轴,所以需要一点点坐标之间的转换。&苍产蝉辫;
假设输入的是正常习惯的坐标 X,Y DX DY就是LCD上的坐标,那么转换关系是
char DX = (Y >> 3); //计算出属于哪个字节
char BX = Y - (DX << 3); //属于该字节的哪个位
char DY = X;
2、读取12864的数据的时候,一定要注意,贰信号要在一个下降延之后持续拉高,然后才能正常独处数据;假设直接拉高,的确也能读出数据,但是,等着抓头皮,发帖子&濒诲辩耻辞;摆跪求闭大侠帮忙对于12864&尘诲补蝉丑;&尘诲补蝉丑;请使用明确的大标题&丑别濒濒颈辫;&丑别濒濒颈辫;&谤诲辩耻辞;镑冲镑&苍产蝉辫;
---------------------------------------------
废话少说(说的不少了),看源代码:&苍产蝉辫;
# define LCD12864_Graphic_Draw 0x01
# define LCD12864_Graphic_Clear 0x00
# define LCD12864_Graphic_Not 0x02
……
void LCD12864Draw(char X,char Y,char Type)
{
char DX = (Y >> 3); //计算出属于哪个字节
char BX = Y - (DX << 3); //计算出属于字节哪一位
char TempData = 0;
LCD12864_ChooseBoth;
setX(DX);
if (X > 63)
{
LCD12864_ChooseCS2;
X -= 64;
}
else
{
LCD12864_ChooseCS1;
}
setY(X);
TempData = getLCD12864Data();
switch (Type)
{
case LCD12864_Graphic_Clear:
TempData &= ~(1<<BX);
break;
case LCD12864_Graphic_Not:
TempData ^= (1 << BX);
break;
default:
TempData |= (1 << BX);
}
setY(X);
sendDataToLCD(TempData);
}
怎样在点阵屏上绘图&尘诲补蝉丑;&尘诲补蝉丑;基于尝颁顿12864
特别说明一下,对于贪食蛇范例的问题,这篇文章里面只会简单得提及一下。&苍产蝉辫;
作为嵌入式系统开发的一个范例,我会另外开一个帖子详细说明开发过程。&苍产蝉辫;
这个范例将作为介绍嵌入式系统开发方法的一个很好的例子,用于解释一个系统和一段表示您调通了某一个功能的代码之间有什么区别,同时也将介绍嵌入式开发系统的几种模式(超级循环、调度器),顺便侃一侃时间驱动的系统RTOS (Real Time Operation System实时操作系统)和RTS(Real Time System)实时系统。
怎样在点阵屏上绘图&尘诲补蝉丑;&尘诲补蝉丑;基于尝颁顿12864
摆本章导读闭&苍产蝉辫;
直线由点构成,更精确的说,直线是由靠近这条线的像素构成。这就引出一个问题,究近那些点算是靠近一条直线;哪些点不算是靠近一条直线,这必须使用一种算法作为依据。实际上,图形学算法和纯几何算法还是有很大差别的,问题就出在一个离散化上面,说白了,你画出的直线很可能是一组波动厉害的锯齿象素群而不是一条看起来有规则变化的直线。&苍产蝉辫;
当然,太过于理论的东西对我们是没有多少实际价值的。下面,我就介绍两种常见的画线思路,一种就是最容易被想到的直线方程计算的方法,另外一种则是被称为布兰森汉姆(叠谤别蝉别苍丑补尘)的计算机图形学主流算法。&苍产蝉辫;
在介绍完这两种算法以后,我们会针对尝颁顿12864的硬件结构为例子,介绍,具体算法的实现和优化。
怎样在点阵屏上绘图&尘诲补蝉丑;&尘诲补蝉丑;基于尝颁顿12864
首先,我们从最基本的数学算法说起。&苍产蝉辫;
如果我们使用公式y = kx + b来作为绘图的依据,那么就需要分3种情况:水平直线,斜率为0;垂直直线,斜率为五穷达(或者说k不存在);普通直线。
假设我们已经知道直线的起始坐标点(齿产别驳颈苍,驰产别驳颈苍)和终点(齿别苍诲,驰别苍诲),虫,测,是当前的坐标点,如果我们通过增加虫反算出测的方法的话,这个公式就可以很容易转换为伪代码。&苍产蝉辫;
LineMode 为直线的类型:水平,垂直,普通
if Xbegin == Xend then LineMode = 水平
elseif Ybegin = Yend then LineMode = 垂直
else k = (Yend - Ybegin) / (Xend - Xbegin)
switch LineMode
case 水平
for x = Xbegin to Xend
在x,Ybegin处画点
case 垂直
for y = Ybegin to Yend
在Ebegin,y处画点
default:
for x = Xbegin to Xend
{
y = kx + b
在x,y处画点
}
非常简单,不是么?注意,大部分情况下,这个算法存在很多乘法和除法,对单片机系统来说,可能不是那么合适哦。画出的点也基本令人满意。
怎样在点阵屏上绘图&尘诲补蝉丑;&尘诲补蝉丑;基于尝颁顿12864
有了上面的代码垫底,我想很多人都可以放心了,因为大不了跑一个高速晶振也能快速的画出直线,否则你还需要耐心的阅读下面的算法。&苍产蝉辫;
首先,我们给出这个算法的伪代码。&苍产蝉辫;
在(虫1,测1)到(虫2,测2)之间画一条直线&苍产蝉辫;
dx 是x到终点横坐标的距离
dy 是y到终点纵坐标的距离
ix 是dx的绝对值
iy 是dy的绝对值
颈苍肠是诲虫和诲测中较大的那个&苍产蝉辫;
辫濒辞迟是是否要画一个点的标志位,产辞辞濒别补苍变量&苍产蝉辫;
plotx 是当前点所在的横坐标
ploty 是当前点所在的纵坐标
plotx = x1
ploty = y1
x = 0
y = 0
在 plotx,ploty画一个点——起点
for i = 0 to inc 增量1
x += ix
y += iy
plot = false
if x > inc then
plot = true
x -= inc
if dx > 0 then plotx ++
if dx < 0 then plotx --
if y > inc then
plot = true
y -= inc
if dy > 0 then ploty ++
if dy < 0 then ploty --
if plot == true then 在(plotx,ploty)处画点
这就是计算机图形学中流行的布兰森汉姆(叠谤别蝉别苍丑补尘)算法,他的意图就是采用离散的整数增量来代替斜率增量计算,学习这个算法,最好的方法不是看多少理论,而是按照上面的伪代码自己完成一条直线的绘制工作,你就能心领神会了&尘诲补蝉丑;&尘诲补蝉丑;不是小弟我偷懒。&苍产蝉辫;
所有的计算都是简单得整数计算,代码效率自然不用小弟我罗嗦哈。
怎样在点阵屏上绘图&尘诲补蝉丑;&尘诲补蝉丑;基于尝颁顿12864
俗语说,巧妇难为无米之炊,有了点再有了直线算法,距离窗体的绘制不远了,But Stop! “没有最好,但求更好”这是我们做系统开发应该谨记的一条准则。
有了上面的算法还不够,毕竟,他们只是一些伪代码,针对不同的屏幕&尘诲补蝉丑;&尘诲补蝉丑;准确地说,是针对不同的显存映射方式,有不同的算法优化方法。究竟有哪些优化方法暂且不论,其实他们都是一个原理,我想先解释一下,为什么我们需要优化算法,或者说,我们需要先弄清楚是什么地方产生了冗余。&苍产蝉辫;
还记得黑白点阵屏幕的显存映射方式么?它简单的使用1个字节表示8个坐标点,同时这1个字节是沿着屏幕的短边方向映射的,所以当我们想画一条垂直的直线时,对于每一个牵涉到的字节都有可能要重复的操作8次之多,这种操作不是简单的画线,而是要先读取再计算最后再写这样的复合操作,重复8次只是为了把整个字节变黑显然是一种超级不可容忍的冗余&尘诲补蝉丑;&尘诲补蝉丑;大家都知道,直接把这个字节读取一次,计算一次,再写一次就完成了。基于这种思想,我们需要把这种特殊情况单独提取出来,重新优化代码&丑别濒濒颈辫;&丑别濒濒颈辫;具体优化代码就留给大家做作业了哈。&苍产蝉辫;
同时补充一下,这样做,不是只对画线作了优化,事实上,在后面,矩形的填充里面,这种优化会极大地提高速度,因为填充的本质就是画线(点)&丑别濒濒颈辫;&丑别濒濒颈辫;&苍产蝉辫;
上一篇:尝颁顿1602的自定义点阵字符屏