打印

LINE函数的实现

[复制链接]
2472|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lfzhou1006|  楼主 | 2011-10-10 14:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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] = 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]=0xff;
  }
  else
  {
   Display_Buf[y][ByteX1] &= (~TempColor1);
   Display_Buf[y][ByteX2] &= (~TempColor2);
   for(i=ByteX1+1;i<ByteX2;i++) Display_Buf[y]=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[ByteX]&=Data_Mask[HarfByte];
  Display_Buf[ByteX]|=color;
  RITWriteData(&Display_Buf[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[ByteX]|=TempColor;
  else Display_Buf[ByteX]&=(~TempColor);
  pucCommand[0]=Display_Buf[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)
OLED12896_GR_Lib.rar (97.65 KB)
下载次数: 4

2011-5-8 00:45



程序运行效果

OLED12896_GR_Lib.rar

97.65 KB

相关帖子

沙发
tianm| | 2011-10-11 11:34 | 只看该作者
附件最好上传到21IC的服务器上  不要做外链

使用特权

评论回复
板凳
sqcumt123| | 2011-10-11 15:10 | 只看该作者
好复杂,看了半天也没有看懂,晕乎乎

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

340

帖子

1

粉丝