[文章]

【HarmonyOS HiSpark Wi-Fi IoT 套件试用连载】基于HiSpark Wi-Fi IoT套件_5-OLED中文显示

2020-11-25 10:53:15  376 HarmonyOS wifi 鸿蒙系统
分享
3
上一篇报告已经过去一个月了,主要是公司项目太急,耽搁太长时间。上一次的报告主要主要介绍了HI3861的IIC操作,控制OLED显示英文“hello world”,当时调试的时候其实是想显示中文的,但是因为原先IAR开发环境下的中文显示程序移植到鸿蒙里面后居然一堆错误,编译器差异文中对应细节会详述,所以只显示了英文。
那之后总归觉得OLED怎么也得能显示中文吧,所以本篇主要介绍怎么在OLED上显示中文,当然是基于上次报告的代码,最终代码会在文末附件里。主要内容有如下几点:
1、 汉字取模
2、 代码编写修改
3、 烧录测试
一、  汉字取模
上次报告已经介绍过,套件使用的OLED显示cache如下图所示,显示点阵对应cache每个字节的顺序是从左到右从上倒下,而显示的每个字节的bit是高位在下。
1.png
                              
通过显存与点阵对应关系,那汉字取模要遵循字节从左到右从上到下,字节内为纵向8点(一个字节位数)下高位取模方式,使用的取模软件是“LcmZimoLCD字模提取工具软件”,报告后边会在附件中体现。因此,最终软件设置界面设置内容如下图所示:
2.png
   设置完成后点击“参数确认“并在下方文字框中输入”你好“并点击输入字串进入下一界面,下一界面如下图所示:
3.png
  由图中可以看出汉字取模已经完成,并直接生成c语言代码。形式如下:
  1. // ------------------  汉字字模的数据结构定义------------------------ //
  2. typedef struct typFNT_GB16                 // 汉字字模数据结构
  3. {
  4.       signed char Index[2];              // 汉字内码索引
  5.       char Msk[32];                      // 点阵码数据
  6. };
复制代码

  1. /////////////////////////////////////////////////////////////////////////
  2. // 汉字字模表                                                         //
  3. // 汉字库: 宋体16.dot 纵向取模下高位,数据排列:从左到右从上到下         //
  4. /////////////////////////////////////////////////////////////////////////
  5. struct typFNT_GB16 code GB_16[] =          // 数据表
  6. {
  7. "你",0x40,0x20,0xF8,0x07,0x40,0x20,0x18,0x0F,
  8.      0x08,0xC8,0x08,0x08,0x28,0x18,0x00,0x00,
  9.      0x00,0x00,0xFF,0x00,0x00,0x08,0x04,0x43,
  10.      0x80,0x7F,0x00,0x01,0x06,0x0C,0x00,0x00,
  11. "好",0x10,0x10,0xF0,0x1F,0x10,0xF0,0x80,0x82,
  12.      0x82,0x82,0xE2,0x92,0x8A,0xC6,0x80,0x00,
  13.      0x40,0x22,0x15,0x08,0x14,0x63,0x00,0x00,
  14.      0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00
  15. };
  16. // 汉字表:
  17. // 你好
复制代码

此处生成的代码需要做进一步修改方可使用鸿蒙系统使用的GCc编译器,具体修改内容会在代码修改中做详述。
二、  代码编写与修改
代码修改主要有如下几点。
1、 单个汉字字符机构体修改:
修改汉字取模软件生成的代码,能够通过鸿蒙交叉编译器,其中结构体 struct typFNT_GB16 内的signed char Index[2];   索引值由2更改为3,因为单个汉字在双引号内时还需要一个字节存储字符串结束字符“\0”。最终更改后的结构体如下:
  1. struct typFNT_GB16                 // 汉字字模数据结构
  2. {
  3.     unsigned charindex[3];        // 汉字内码索引
  4.     charmask[32];                 // 点阵码数据
  5. };
复制代码

2、 汉字码表:
查看上文中生成的汉字码表struct typFNT_GB16 code GB_16[],可以看出字模软件将所有数据都以字节数组的方式存放的,这种存放方式在IAR中可以直接编译通过,也就是IAR会将字符数组映射到struct typFNT_GB16内容中,而鸿蒙使用的GCC编译器不支持此类操作,所以上次报告未能实现中文显示。根据编译器报错提示,需要将生成的汉字码表更改为如下:
  1. const structtypFNT_GB16  ST_GB_16[] =   
  2. {
  3.     {
  4.         {"你",},
  5.         {
  6.            0x40,0x20,0xF8,0x07,0x40,0x20,0x18,0x0F,
  7.            0x08,0xC8,0x08,0x08,0x28,0x18,0x00,0x00,
  8.            0x00,0x00,0xFF,0x00,0x00,0x08,0x04,0x43,
  9.             0x80,0x7F,0x00,0x01,0x06,0x0C,0x00,0x00,
  10.         }
  11.     },
  12.     {
  13.         {"好",},
  14.         {
  15.            0x10,0x10,0xF0,0x1F,0x10,0xF0,0x80,0x82,
  16.            0x82,0x82,0xE2,0x92,0x8A,0xC6,0x80,0x00,
  17.            0x40,0x22,0x15,0x08,0x14,0x63,0x00,0x00,
  18.            0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,
  19.         }
  20.     },
  21. };
复制代码

3、 显示函数添加中文显示代码:
需要在OLED驱动中添加汉字处理部分,本报告依据上一个报告主要是修改OLED_DrawString16函数。其中有几个需要特别注意的在代码中有注释。修改后代码如下:
i
  1. ntOLED_DrawString16(int x  , int y ,const  char* p_str  , int color)
  2. {
  3.     int i , j , m ;
  4.     const unsigned char *p_asc  = 0;
  5.     const char* p_cn  = 0;
  6.     const struct typFNT_GB16* p_cn_lib ;
  7.     if((x >= 120) || (y >= 7))
  8.         return -1;
  9.     while(*p_str != '\0')
  10.     {
  11.        // 判断当前字节是不是汉字字符,
  12. // 汉字编码用两个字节表示一个汉字,并且起始自己大余0x7f
  13.         // 本来使用(*p_str)<0X80,但是编译器编译有Warning提示
  14.         // 提示为此条指令永远为true,编译中不允许有告警故更改为
  15.         //  (*p_str)&0X80)==0
  16.         if(((*p_str)&0X80)==0)   
  17.         {
  18.             p_asc = nAsciiDot16X8 + ((*p_str -32)<< 4) ;
  19.             for(j = 0 ; j < 2 ;  j++)
  20.             {
  21.                 for(i = 0 ; i < 8 ; i++)
  22.                 {
  23.                     if(color)
  24.                     {
  25.                         OLEDBuffer[(y + j)][x +i]= * p_asc ++  ;
  26.                     }
  27.                     else
  28.                     {
  29.                         OLEDBuffer[(y + j)][x +i] = ~(* p_asc ++) ;
  30.                     }
  31.                 }
  32.             }
  33.             x += 8 ;
  34.             p_str ++ ;
  35.         }
  36.         Else
  37.         {
  38.             printf("[xxxxx]hanzi.\r\n");
  39.             p_cn = (char*)-1  ;
  40.             p_cn_lib = ST_GB_16 ;
  41.             m = GetSTLiberayNum();
  42.             for(i = 0 ; i < m ; i++)
  43.             {
  44.                 printf("[xxxxx] *p_str =%x.\r\n",*p_str);
  45.                // 此处多一个char型指针取值与0xff解释在代码末尾
  46.                 if(((*p_str)&0xff) ==p_cn_lib->index[0])
  47.                 {
  48.                     printf("[xxxxx]bingo1.\r\n");
  49.                     if(((*(p_str+1))&0xff)== p_cn_lib->index[1])
  50.                     {
  51.                         p_cn = p_cn_lib->mask ;
  52.                                           printf("[xxxxx]bingo2.\r\n");
  53.                         break ;
  54.                     }
  55.                 }
  56.                 p_cn_lib++;
  57.             }
  58.             if(p_cn != (char*)-1)
  59.             {
  60.                 for(j = 0 ; j < 2 ;  j++)
  61.                 {
  62.                     for(i = 0 ; i < 16 ;i++)
  63.                     {
  64.                         if(color)
  65.                         {
  66.                             OLEDBuffer[(y +j)][x + i]= * p_cn ++  ;
  67.                         }
  68.                         else
  69.                         {
  70.                             OLEDBuffer[(y +j)][x + i] = ~(* p_cn ++) ;
  71.                         }
  72.                     }
  73.                 }
  74.             }
  75.             x += 16 ;
  76.             p_str += 2;
  77.         }
  78.     }
  79.     return x;
  80. }
复制代码

以上代码修改过程中从注释可以看出有两个地方编译器有特别之处,第一个在代码注释中已经解释,而第二个贴别解释一下,因为本人也很困惑。
其中((*p_str)&0xff) == p_cn_lib->index[0]这一条,p_str按照定义类型是“const  char*”,对其取值应该是char类型,而实际取值后是一个4字节数值。可能所使用的gcc中char为4字节的类型,使用printf("[xxxxx] *p_str =%x.\r\n",*p_str);语句串口打印居然在字符值前面添加了0xffffff--。所以才有了((*p_str)&0xff)的处理。此处问题折腾了半个下午才找到原因,一方面对gcc使用不多,不是很熟悉,另一方面可能是自己编程方式有问题。
4、 显示代码添加:
在OLED显示驱动中添加OLED_DrawString16(8,4,"你好",1);语句,并修改BUILD.gn文件添加字库代码文件,编译生成bin文件。
三、  编译测试
   编译测试不多说了,下载后按RESET按键重启,OLED显示内容如下图:
4.png
app20201125.rar (2.87 MB, 下载次数: 2)
dianzi 2020-11-26 09:56:09
感谢分享!
回复

举报

绿波电龙 2020-11-26 10:18:41
好文章
回复

举报

张帅 2020-11-26 13:52:53
好文章,谢谢分享啊
回复

举报

评论

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

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发文章