|
OLED_12896_GR_Lib函数(三) ——LINE函数的实现
[复制链接]
首先向大家说声抱歉,因为自己的不小心,上次的PSET函数中出现了一些失误,且在测试程序中也没有测试出来,这次在编写LINE函数时发现并修改过来了。现把修改的地方罗列如下: 1、 缓冲数组的定义,这是一个非常低级的失误,在定义数组的时候,我习惯性的按照先写横坐标,后写纵坐标的方式来定义数组下标。但我的本意是让数组横向连续,因为在OLED显示器中,一个字节表示两个横向相邻的像素。如果数组横向连续,则在进行横向画线的时候就可以进行连续填充,可以节省许多的运算。而纵向连续的时候这种优势就不明显了。所以,这次将数组的两个下标交换了一下位置,所有引用该数组的位置都要做此处理。 2、 半字节交换选项设置。数组数据对应像素顺序本来设置为,从低到高,从低位到高位依次排列,但是TI的函数中对OLED半字节交换选项做了设置,则函数从低到高依次对应每对像素,而在每对像素中,高四位对应低位像素,低四位对应高位像素。而卧在PSET函数中对位的运算也是出了一个问题,导致我的数据设置跟TI的设置相符,问题没有显现出来,但是在编写LINE函数时出现了与PSET不一致的地方。所修改的地方为:在TI的rit128x96x4.c中,将所有0xA0,0x52命令改为0xA0,0x50;将0xA0,0x56命令改为0xA0,0x54。当然,大家也可以使用我在函数工程包里的OLED驱动文件,这个文件中的命令已经改好。 3、 又是一个低级错误,将表达式(ByteX<<2)+(HarfByte>>1)写成了(ByteX<<2)+(HarfByte>1)。 好了,前面的错误已经修改完成了,下面就开始新的LINE函数编写吧。 _LINEH函数 这个是绘制横线的函数,函数原型为:__inline static void _LINEH(unsigned char x1,unsigned char x2,unsigned char y,unsigned char color) 这个函数有四个参数,用来在显示器上绘制一条从x1,y到x2,y点的线,灰度为color。 该函数的实现算法总共包含以下几个部分: 对参数的预处理。 这部分的代码如下:
- unsigned char HarfByte1,ByteX1,HarfByte2,ByteX2,i,pucCommand[4];
if (x1>x2) { i=x1; x1=x2; x2=i; }
复制代码
变量HarfByte和ByteX的作用在PSET函数中已经说过,在这里由于有两个横坐标x1和x2,相应的HarfByte和ByteX变量也分别需要两个。 同时,由于对OLED自动增量设置的方向为单一方向,因此,在这里要保证x1<x2,线段从x1向x2绘制。 缓冲区数据处理 对于缓冲区数据,需要考虑进行保护的只有两端的两个字节,中间全部填充为所设置的灰度数据即可。 在灰度模式下: 对于起始坐标位置的字节,假如该坐标为偶数,则表示从该字节的低位开始绘制,则直接对该字节填充即可。假如该坐标为奇数,则只能修改其字节高位。 而对于终点坐标则正好相反,假如该坐标为偶数,则只修改字节低位,假如该坐标为奇数,则填充整个字节。 为什么呢?大家画一串字节框来模拟一下即可知晓。 灰度模式下绘制横线的代码如下: - HarfByte1=x1 & 0x01;
ByteX1=x1>>1; HarfByte2=x2 & 0x01; ByteX2=x2>>1; if(HarfByte1) { Display_Buf[y][ByteX1] &= 0x0f; Display_Buf[y][ByteX1] |= (color & 0xf0); } else { Display_Buf[y][ByteX1] = color; } if(HarfByte2) { Display_Buf[y][ByteX2] = color; } else { Display_Buf[y][ByteX2] &= 0xf0; Display_Buf[y][ByteX2] |= (color & 0x0f); } for(i=ByteX1+1;i<ByteX2;i++) Display_Buf[y][i] = color; pucCommand[0]=0x15; pucCommand[1]=ByteX1; pucCommand[2]=63; RITWriteCommand(pucCommand, 3); pucCommand[0]=0x75; pucCommand[1]=y; pucCommand[2]=95; RITWriteCommand(pucCommand, 3); pucCommand[0]=0xA0; pucCommand[1]=0x50; RITWriteCommand(pucCommand, 2); RITWriteData(&Display_Buf[y][ByteX1], ByteX2-ByteX1+1);
复制代码
在单色模式下,与灰度模式的区别于PSET函数中二者区别类似,只是在该函数中,还需要考虑两个坐标在同一个字节中的情况(这个函数绘制的最短线段为2个像素,而一个字节可以表示8个像素)。 最后在将缓冲区数据写入OLED的转换过程中,只有首尾两个字节需要按照PSET函数中那样的算法进行移位转换,其他字节则统一写入0xffffffff或者0。这也是这个函数中将pucCommand数组元素定义为四个的原因。单色模式下代码如下: -
unsigned char TempColor1,TempColor2; HarfByte1=x1 & 0x07; ByteX1=x1>>3; HarfByte2=x2 & 0x07; ByteX2=x2>>3; TempColor1=0xff<<HarfByte1; TempColor2=0xff>>(7-HarfByte2);
pucCommand[0]=0x15; pucCommand[1]=(ByteX1<<2)+(HarfByte1>>1); pucCommand[2]=63; RITWriteCommand(pucCommand, 3); pucCommand[0]=0x75; pucCommand[1]=y; pucCommand[2]=95; RITWriteCommand(pucCommand, 3); pucCommand[0]=0xA0; pucCommand[1]=0x50; RITWriteCommand(pucCommand, 2);
if(ByteX1==ByteX2) { TempColor1 &= TempColor2; if(color) Display_Buf[y][ByteX1] |= TempColor1; else Display_Buf[y][ByteX1] &= (~TempColor1); TempColor1=Display_Buf[y][ByteX1]; HarfByte1 &= 0x06; HarfByte2 &= 0x06; for(TempColor1>>=HarfByte1;HarfByte1<=HarfByte2;HarfByte1+=2) { i=((TempColor1>>1)&0x01)*0xf0+(TempColor1 & 0x01)*0x0f; RITWriteData(&i, 1); TempColor1 >>= 2; } } else { if(color) { Display_Buf[y][ByteX1] |= TempColor1; Display_Buf[y][ByteX2] |= TempColor2; for(i=ByteX1+1;i<ByteX2;i++) Display_Buf[y][i]=0xff; } else { Display_Buf[y][ByteX1] &= (~TempColor1); Display_Buf[y][ByteX2] &= (~TempColor2); for(i=ByteX1+1;i<ByteX2;i++) Display_Buf[y][i]=0x00; } TempColor1=Display_Buf[y][ByteX1]; TempColor2=Display_Buf[y][ByteX2]; HarfByte1 &= 0x06; HarfByte2 &= 0x06; for(TempColor1>>=HarfByte1;HarfByte1<=6;HarfByte1+=2) { i=((TempColor1>>1)&0x01)*0xf0+(TempColor1 & 0x01)*0x0f; RITWriteData(&i, 1); TempColor1 >>= 2; } if(ByteX1+1<ByteX2) { if(color) *(unsigned long *)&pucCommand[0] = 0xffffffff; else *(unsigned long *)&pucCommand[0] = 0; for(i=ByteX1+1;i<ByteX2;i++) RITWriteData(pucCommand, 4); } for(HarfByte1=0;HarfByte1<=HarfByte2;HarfByte1+=2) { i=((TempColor2>>1)&0x01)*0xf0+(TempColor2 & 0x01)*0x0f; RITWriteData(&i, 1); TempColor2 >>= 2; } }
复制代码
_LINEV函数 这个是绘制竖线的函数,原型为:__inline static void _LINEV(unsigned char x,unsigned char y1,unsigned char y2,unsigned char color) 其功能为在x,y1点和x,y2点之间绘制一条竖线。 绘制竖线的算法就比较简单了,因为纵向所有数据的性质都是一样的,所影响的位都是一致的,所以只需要用循环的方式按照_PSET中的算法对所有数据中的响应位进行修改即可(所影响位由HarfByte变量决定),具体算法请参考_PSET函数。该函数完整代码如下:
-
__inline static void _LINEV(unsigned char x,unsigned char y1,unsigned char y2,unsigned char color) { unsigned char HarfByte,ByteX,i,pucCommand[4]; if (y1>y2) { i=y1; y1=y2; y2=i; } #if Color_Mode HarfByte=x & 0x01; ByteX=x>>1; color =color & (~Data_Mask[HarfByte]); pucCommand[0]=0x15; pucCommand[1]=ByteX; pucCommand[2]=63; RITWriteCommand(pucCommand, 3); pucCommand[0]=0x75; pucCommand[1]=y1; pucCommand[2]=95; RITWriteCommand(pucCommand, 3); pucCommand[0]=0xA0; pucCommand[1]=0x54; RITWriteCommand(pucCommand, 2);
for(i=y1;i<=y2;i++) { Display_Buf[i][ByteX]&=Data_Mask[HarfByte]; Display_Buf[i][ByteX]|=color; RITWriteData(&Display_Buf[i][ByteX], 1); } #else unsigned char TempColor; HarfByte=x & 0x07; ByteX=x>>3; TempColor=1<<HarfByte; pucCommand[0]=0x15; pucCommand[1]=(ByteX<<2)+(HarfByte>>1); pucCommand[2]=63; RITWriteCommand(pucCommand, 3); pucCommand[0]=0x75; pucCommand[1]=y1; pucCommand[2]=95; RITWriteCommand(pucCommand, 3); pucCommand[0]=0xA0; pucCommand[1]=0x54; RITWriteCommand(pucCommand, 2); HarfByte &=0x06; for(i=y1;i<=y2;i++) { if (color) Display_Buf[i][ByteX]|=TempColor; else Display_Buf[i][ByteX]&=(~TempColor); pucCommand[0]=Display_Buf[i][ByteX]>>HarfByte; pucCommand[0]&=0x03; pucCommand[0]=(pucCommand[0]>>1)*0xf0+(pucCommand[0]&0x01)*0x0f; RITWriteData(pucCommand, 1); } #endif
}
复制代码
LINE函数
这个函数就是我们要在应用中面对的最终函数,其函数原型为: void LINE(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char color) 该功能为绘制一条从x1,y1到x2,y2的线,其长度最小可为1个像素,即一个点。 实现方法: 如果x1=x2,y1=y2,则表示为一个点,调用_PSET函数来完成。 如果仅y1=y2,则调用_LINEH函数来绘制。 如果仅x1=x2,则调用_LINEV函数来绘制。 其他情况,则即使dx,dy后根据斜率来调用_PSET逐点绘制。这里采用dx和dy两个变量而不采用最终比例是为了避免出现浮点数运算。 LINE函数代码如下:
- void LINE(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char color)
{ unsigned char i; signed char dx,dy; if((x1>127)||(x2>127)||(y1>95)||(y2>95)) return; dx=x2-x1; dy=y2-y1; P_Cursor_X=x2,P_Cursor_Y=y2; color &=0x0f; #if Color_Mode color = (color<<4) + color; #else color >>=3; #endif if (y1==y2) { if(x1==x2) _PSET(x1,y1,color); else _LINEH(x1,x2,y1,color); return; } if (x1==x2) { if(y1==y2) _PSET(x1,y1,color); else _LINEV(x1,y1,y2,color); return; } for(i=x1;i<=x2;i++) { _PSET(i,y1+((i-x1)*dy)/dx,color); } }
复制代码
测试例程,在最后依然给出一个应用了LINE函数的例程来测试其功能,该例程的实现的效果是在OLED显示器上绘制了一个课程表的表格。 工程包可以从这里下载。
OLED12896_GR_Lib.rar
(97.65 KB, 下载次数: 16)
程序运行效果
[ 本帖最后由 柳叶舟 于 2011-5-10 00:26 编辑 ]
|
|