4663|4

167

帖子

0

TA的资源

纯净的硅(高级)

楼主
 

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。
该函数的实现算法总共包含以下几个部分:
对参数的预处理。
这部分的代码如下:

  1. 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绘制。
缓冲区数据处理
对于缓冲区数据,需要考虑进行保护的只有两端的两个字节,中间全部填充为所设置的灰度数据即可。
在灰度模式下:
对于起始坐标位置的字节,假如该坐标为偶数,则表示从该字节的低位开始绘制,则直接对该字节填充即可。假如该坐标为奇数,则只能修改其字节高位。
而对于终点坐标则正好相反,假如该坐标为偶数,则只修改字节低位,假如该坐标为奇数,则填充整个字节。
为什么呢?大家画一串字节框来模拟一下即可知晓。
灰度模式下绘制横线的代码如下:
 

  1. 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数组元素定义为四个的原因。单色模式下代码如下:
 

  1. unsigned char TempColor1,TempColor2;
     HarfByte1=x1 & 0x07;
     ByteX1=x1>>3;
     HarfByte2=x2 & 0x07;
     ByteX2=x2>>3;
     TempColor1=0xff<<HarfByte1;
     TempColor2=0xff>>(7-HarfByte2);

  2.  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);

  3.  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函数。该函数完整代码如下:

  1. __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);

  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

  3. }

复制代码

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函数代码如下:

  1. 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 编辑 ]

最新回复

太酷了,顶。  详情 回复 发表于 2011-5-8 12:27
 
点赞 关注

回复
举报

167

帖子

0

TA的资源

纯净的硅(高级)

沙发
 
又出现了[i]的问题,这个问题很影响发布代码啊
 
 

回复

2万

帖子

71

TA的资源

管理员

板凳
 

回复 沙发 柳叶舟 的帖子

我们再和技术沟通下
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复

2751

帖子

0

TA的资源

裸片初长成(初级)

4
 
 
 
 

回复

918

帖子

0

TA的资源

纯净的硅(中级)

5
 

回复 楼主 柳叶舟 的帖子

太酷了,顶。
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表