硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2827|回复: 8
收起左侧

[emWin教程入门篇] 【emWin实战教程V2.0】第28章  矢量字体(支持汉字全字库,Unicode编码)

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2017-2-6 16:43:50 | 显示全部楼层 |阅读模式
完整65章+12章附件教程下载地址:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=19834



第28章     矢量字体(支持汉字全字库,Unicode编码)


    本期教程跟大家讲解矢量字体的相关知识,矢量字体最大的好处就是可以任意放大或者缩小字体,而且字体的显示效果不失真。矢量字体也有缺点,即非常消耗内存。但是本教程配套开发板的STM32F429是支持外接SDRAM,这样就有大容量的空间供矢量字体使用了。
28.1 初学者重要提示
28.2 矢量字体介绍
28.3 STemWin对矢量字体的支持
28.4 矢量字体库的移植方法
28.5 矢量字体库的使用方法
28.6 实验例程说明(RTOS)
28.7 实验例程说明(裸机)
28.8 总结
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-2-6 16:45:53 | 显示全部楼层
28.1  初学者重要提示

1、使用STM32F429+大容量的SDRAM来实现矢量字体具有一定的实战意义,可用于实际项目。
2、实验中发现了以下三个问题,给大家分享下:
    (1)、不是所有电脑端的矢量字体都可以显示,测试发现有些无法正常显示,估计是emWin库不支持。
    (2)、不能显示太大的字体,测试发现130点阵之后就无法显示了,不知道是不是动态内存和系统堆空间分配小了,以后换了超大容量SDRAM再测试。
    (3)、显示比较大的字体,STM32F429的图形性能完全跟的上,但CPU的计算性能有些吃紧,表现在800*480界面显示满屏字符的时候,整体拖动窗口反应不够流畅。
3、矢量字体也是用的Unicode编码,这点要特别注意。
4、矢量字体所有API函数在emWin手册中都有讲解,下图是中文版手册里面API函数的位置
28.1.png


下图是英文版手册里面API函数的位置:
28.2.png
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-2-6 16:48:44 | 显示全部楼层
28.2矢量字体介绍

    下面的内容来中文版wiki百科,讲的非常好,特此转载过来:https://zh.wikipedia.org/wiki/%E ... F%E5%AD%97%E4%BD%93

    目前主流的矢量字体格式有3种:Type1,TrueType和OpenType,这三种格式都是与平台无关的。
        Type1全称PostScript Type1,是1985年由Adobe公司提出的一套矢量字体标准,由于这个标准是基于PostScriptDescription Language(PDL),而PDL又是高端打印机首选的打印描述语言,所以Type1迅速流行起来。但是Type1是非开放字体,Adobe对使用Type1的公司征收高额的使用费。
    TrueType是1991年由Apple公司与Microsoft公司联合提出另一套矢量字标准。
   
     Type1使用三次贝塞尔曲线来描述字形,TrueType则使用二次贝塞尔曲线来描述字形。所以Type1的字体比TrueType字体更加精确美观。一个误解是,Type1字体比TrueType字体占用空间多。这是因为同样描述一个圆形,二次贝塞尔曲线只需要8个关键点和7段二次曲线;而三次贝塞尔曲线则需要12个关键点和11段三次曲线。然而实际情况是一般来说 Type1比TrueType要小10%左右。这是因为对于稍微复杂的字形,为了保持平滑,TrueType必须使用更多的关键点。由于现代大部分打印机都是使用PDL作为打印描述语言,所以Type1字体打印的时候不会产生形变,速度快;而TrueType则需要翻译成PDL,由于曲线方程的变化,还会产生一定的形变,不如Type1美观。
    这么说来,Type1应该比TrueType更具有优势,为什么如今的计算机上TrueType反而比Type1使用更广泛呢?这是因为第一:Type1由于字体方程的复杂,所以在屏幕上渲染的时候,花费的时间多,解决方案是大部分Type1字体嵌入了点阵字体,这样渲染快,但是边缘不光滑,比较难看。很多ps文档和ps转换的pdf文档都是这样,在计算机上浏览的时候字体很难看,但是打印出来很美观。TrueType则渲染比较快,可以平滑的显示在屏幕上,看上去很美观。
    第二个原因是Type1的高额使用费,使得Type1没有被所有的操作系统所支持。Windows家族只有OS/2和windows2000及之后的版本从操作系统级别开始支持Type1。由于这个问题,Adobe只好在其所有的产品中嵌入Adobe Type Manager(ATM)作为渲染引擎。
   
    OpenType则是Type1与TrueType之争的最终产物。1995年,Adobe公司和Microsoft公司开始联手开发一种兼容Type1和TrueType,并且真正支持Unicode的字体,后来在发布的时候,正式命名为OpenType。OpenType可以嵌入Type1和TrueType,这样就兼有了二者的特点,无论是在屏幕上察看还是打印,质量都非常优秀。可以说OpenType是一个三赢的结局,无论是Adobe、Microsoft还是最终用户,都从OpenType中得到了好处。Windows家族从Windows 2000开始,正式支持OpenType。打开系统的字体目录(一般是C:\\Windows\\Fonts\\或C:\\Winnt\\Fonts),可以看到:一个红色A的图标的是点阵字体,两个重叠的T的图标是TrueType字体,一个O的图标就是OpenType字体。
    下面是XP系统中字体的部分截图,其中矢量字体扩展名ttf,点阵字体的扩展名是fon。
28.3.png

Win7系统中已经变成如下这种样子:
28.4.png
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-2-6 16:49:35 | 显示全部楼层
28.3 STemWin对矢量字体的支持

    emWin对矢量字体库的支持是基于David Turner、Robert Wilhelm和Werner Lembergr的FreeType字体库,该库可在www.freetype.org下免费获得。emWin对该库的使用符GUI\\TrueType\\FTL. txt下的FreeType授权许可。emWin对该库进行了少许改编,添加了带有GUI函数的应用层。emWin软件包中也是没有矢量字体库的,需要大家在SEGEER官网地址www.segger.com/link/emwin_freetype.zip下载。

    矢量字体基于矢量图形,矢量的优势在于可以无损的放缩。而点阵字体虽然也可以放缩,但不是矢量的,放缩后锯齿很明显。并且项目中需要多种字体大小支持的话,需要几种字体支持,就需要生成几种点阵字库,非常占空间,而矢量字体仅需要一个字体库就可以了。特别是显示大字体,矢量字体库的优势更明显。
    通过矢量字体带来无损放缩的同时,也是有缺点的。使用矢量字体的话,每个字符在绘制前需要光栅化为位图,为避免每次绘制字符时都进行光栅化,通常用字体引擎缓存点阵数据。这要求CPU速度快、RAM足够。当前emWin对矢量字体的支持是以总线方式寻址的,与第24章讲解的SIF格式字体是类似的。现在使用STM32F103和STM32F407配合外部SRAM来显示字符还可以,但是显示十几MB的矢量汉字就无法实现了,因为当前使用的静态SRAM最大也就2MB,完全放不下一个矢量汉字库,即使放到容量比较大且可以总线方式寻址的NOR Flash里面,并将2MB的SRAM空间分配给系统堆和emWin动态内存,也无法成功。但使用STM32F429配合外部大容量的SDRAM是可以的,效果也不错。本章节配套的例子就是采用这种方式。
    TrueType矢量字体的硬件要求如下:
28.5.png
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-2-6 16:55:46 | 显示全部楼层
28.4  矢量字体库的移植方法


    跟第19章讲解的PNG库一样,emWin的库中也是不含有矢量库的,需要用户自行添加,添加也比较简单,只需用户把源码文件添加到工程里面就可以使用了。
    矢量库的下载地址:www.segger.com/link/emwin_freetype.zip。下载软件包后进行解压,官方压缩了两次,解压两次后的部分文件截图(早期的时候里面包含了多个版本,现在官方将其修改为仅包含一个版本,当前 2016-09-13,里面仅有一个5.36版本的库,以后的emWin版本是否还会做其它修改就不得而知了),当前这个版本的库已经被存到本章节配套例子的Doc文件夹:
28.6.png
    MDK编译和IAR编译在移植上是有所不同的,分别进行说明。


28.4.1   MDK版本移植说明


第1步:在 emWin工程-->emWin文件夹-->新建一个TrueType文件夹,将矢量字体库里面的源码文件全部复制到此文件夹里面(其它任意文件夹都是可以的,不限制)。
28.7.png

第2步:将矢量库的所有.C格式的源码文件添加到MDK工程里面,下面是部分源码文件的截图。
28.8.png

第3步:添加矢量库的头文件路径,添加完毕后别忘了点击OK
28.9.png

第4步:修改系统堆(heap)大小,这一步非常关键。因为矢量库要用到函数malloc和free,而这种函数是从系统堆空间里面申请内存的,鉴于矢量库非常的消耗动态内存,这里将16MB SDRAM的最后1MB空间给系统堆使用,设置如下:
28.10.png


      Heap_Size:表示堆大小设置为1MB。
      _heap_base:表示堆起始地址为0xC0F00000,即16MB SDRAM最后1MB空间的起始地址。
      _heap_linmit:表示堆结束地址0xC0FFFFFF,即16MBSDRAM最后1MB空间的结束地址。
    除了malloc和free要用到堆空间,部分C标准库的其它函数也要用到堆空间,所以一定要及时初始化SDRAM,防止用到堆空间的时候,SDRAM还没有初始化,将导致系统崩溃。当前是将SDRAM的初始化放在了bsp.c文件的bsp_Init函数开始的地方,之前执行的程序都没有用到C标准库,所以可以放在这里。
    讲解完这些,还有一点知识要补充的,矢量汉字库是非常大的,稍小点的都得10MB,大点的得20MB,教程配套板子的SDRAM只有16MB,有点捉襟见肘,所以要重新划分下,当前是把前3MB的空间给LCD的显存使用,相关代码不用做任何修改,因为默认的800*480分辨率,RGB565格式的三缓冲大小800*480*2*3 大概是2.19MB(乘以2是因为RGB565格式需要2字节来表示一个像素),小于3MB。中间的12MB用于emWin动态内存,最后1MB用于系统堆空间,这里有两个地方要修改一下,一个是bsp_fmc_sdram.h文件,修改emWin动态内存的起始地址
  1. /*
  2. **********************************************************************************************************
  3.                                           emWin使用
  4. **********************************************************************************************************
  5. */
  6. /* emWin动态内存首地址 */
  7. #define SDRAM_APP_BUF  (EXT_SDRAM_ADDR + 3 * 1024 * 1024)
复制代码
另一个是GUIConf.c文件,将emWin的动态内存大小设置为12MB,即下面置红的字体。
  1. //
  2. // Define the available number of bytes available for the GUI
  3. //
  4. #define EX_SRAM   1/*1 used extern sram, 0 used internal sram */
  5. #if EX_SRAM
  6. #define GUI_NUMBYTES  (1024*1024*12)
  7. #else
  8. #define GUI_NUMBYTES  (100*1024)
  9. #endif
  10. /* Define the average block size */
  11. #define GUI_BLOCKSIZE 0x80
复制代码
修改完毕这几个地方后,就没有问题了,使用的时候选取了仿宋体,大小是10MB,系统上电后将其加载到emWin的动态内存里面,也就是SDRAM里面。
第5步:最后一步,添加好库文件并且修改完毕后,验证是否已经添加成功,可以进行一次全编译,全编译后MDK会有几个警告,这个是矢量库的问题,但都不影响正常使用。
28.11.png

至此,矢量字体库就添加成功了。剩下就可以调用矢量库的API函数了。

28.4.2   IAR版本移植说明


第1步:在 emWin工程-->emWin文件夹-->新建一个TrueType文件夹,将矢量字体库里面的源码文件全部复制到此文件夹里面(其它任意文件夹都是可以的,不限制
28.12.png

第2步:将矢量库的所有.C格式的源码文件添加到IAR工程里面,下面是部分源码文件的截图。
28.13.png

第3步:添加矢量库的头文件路径,添加完毕后别忘了点击OK
28.14.png

第4步:修改系统堆(heap)大小,这一步非常关键。因为矢量库要用到函数malloc和free,而这种函数是从系统堆空间里面申请内存的,鉴于矢量库非常的消耗动态内存,这里将16MB SDRAM的最后1MB空间给系统堆使用,IAR中设置堆使用外部空间比MDK要麻烦些,需要修改本章节配套例程路径\\Project\\EWARMv7里面的文件stm32f4xx_flash.icf,内容如下(红色字体部分是新添加的或者被修改的):
  1. /*###ICF### Section handled by ICF editor, don't touch! ****/
  2. /*-Editor annotation file-*/
  3. /* IcfEditorFile="$TOOLKIT_DIR$\\config\\ide\\IcfEditor\\cortex_v1_0.xml" */
  4. /*-Specials-*/
  5. define symbol __ICFEDIT_intvec_start__ = 0x08000000;
  6. /*-Memory Regions-*/
  7. define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
  8. define symbol __ICFEDIT_region_ROM_end__   = 0x081FFFFF;
  9. define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
  10. define symbol __ICFEDIT_region_RAM_end__   = 0x2002FFFF;
  11. /*-Sizes-*/
  12. define symbol __ICFEDIT_size_cstack__ = 0x0400;
  13. define symbol __ICFEDIT_size_heap__   = 0x100000;
  14. /**** End of ICF editor section. ###ICF###*/
  15. define symbol __region_RAM1_start__ = 0x10000000;
  16. define symbol __region_RAM1_end__   = 0x1000FFFF;
  17. define symbol __region_RAM2_start__ = 0xC0F00000;
  18. define symbol __region_RAM2_end__   = 0xC0FFFFFF;
  19. define memory mem with size = 4G;
  20. define region ROM_region   = mem:[from __ICFEDIT_region_ROM_start__   to __ICFEDIT_region_ROM_end__];
  21. define region RAM_region   = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];
  22. define region RAM1_region  = mem:[from __region_RAM1_start__   to __region_RAM1_end__];
  23. define region RAM2_region  = mem:[from __region_RAM2_start__   to __region_RAM2_end__];
  24. define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };
  25. define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__     { };
  26. initialize by copy { readwrite };
  27. do not initialize  { section .noinit };
  28. place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
  29. place in ROM_region   { readonly };
  30. place in RAM_region   { readwrite, block CSTACK};
  31. place in RAM1_region  { section .sram };
  32. place in RAM2_region  { section .sram, block HEAP };
复制代码
define symbol __ICFEDIT_size_heap__   = 0x100000;
    重新设置堆空间大小是1MB。
define symbol __region_RAM2_start__ =0xC0F00000;
define symbol__region_RAM2_end__  = 0xC0FFFFFF;
    添加的RAM2的起始地址和结束地址定义,
      __region_RAM2_start__:表示堆起始地址为0XC0F00000,即16MB SDRAM最后1MB空间的起始地址。
      __region_RAM2_end__ : 堆结束地址0XC0FFFFFF,即16MBSDRAM最后1MB空间的结束地址。
define regionRAM2_region  = mem:[from__region_RAM2_start__   to__region_RAM2_end__];

    设置新添加RAM2的区间范围。
place in RAM_region { readwrite, block CSTACK};
    表示将栈空间放到RAM区域,可读可写。
place in RAM2_region  { section .sram, block HEAP };
    表示将堆空间放到RAM2区域,可读可写。
--------------------------------------------------------------------------
    通过上面的设置就实现将16MB SDRAM的最后1MB空间给系统堆使用。除了malloc和free要用到堆空间,部分C标准库的其它函数也要用到堆空间,所以一定要及时初始化SDRAM,防止用到堆空间的时候,SDRAM还没有初始化,将导致系统崩溃。当前是将SDRAM的初始化放在了bsp.c件的bsp_Init函数开始的地方,之前执行的程序都没有用到C标准库,所以可以放在这里。
    讲解完这些,还有一点知识要补充的,矢量汉字库是非常大的,稍小点的都得10MB,大点的得20MB,教程配套板子的SDRAM只有16MB,有点捉襟见肘,所以要重新划分下,当前是把前3MB的空间给LCD的显存使用,相关代码不用做任何修改,因为默认的800*480分辨率,RGB565格式的三缓冲大小800*480*2*3 大概是2.19MB(乘以2是因为RGB565格式需要2字节来表示一个像素),小于3MB。中间的12MB用于emWin动态内存,最后1MB用于系统堆空间,这里有两个地方要修改一下,一个是bsp_fmc_sdram.h,修改emWin动态内存的起始地址
  1. /*
  2. **********************************************************************************************************
  3.                                           emWin使用
  4. **********************************************************************************************************
  5. */
  6. /* emWin动态内存首地址 */
  7. #define SDRAM_APP_BUF  (EXT_SDRAM_ADDR + 3 * 1024 * 1024)
复制代码
另一个是GUIConf.c文件,将emWin的动态内存大小设置为12MB,即下面置红的字体。
  1. //
  2. // Define the available number of bytes available for the GUI
  3. //
  4. #define EX_SRAM   1/*1 used extern sram, 0 used internal sram */
  5. #if EX_SRAM
  6. #define GUI_NUMBYTES  (1024*1024*12)
  7. #else
  8. #define GUI_NUMBYTES  (100*1024)
  9. #endif
  10. /* Define the average block size */
  11. #define GUI_BLOCKSIZE 0x80
复制代码
修改完毕这几个地方后,就没有问题了,使用的时候选取了仿宋体,大小是10MB,系统上电后将其加载到emWin的动态内存里面,也就是SDRAM里面。
第5步:最后一步,添加好库文件并且修改完毕后,验证是否已经添加成功,可以进行一次全编译,全编译后IAR会有70多个警告,这个是矢量库的问题,但都不影响正常使用。
28.15.png

至此,矢量字体库就添加成功了。剩下就可以调用矢量库的API函数了。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-2-6 16:58:03 | 显示全部楼层
28.5  矢量字体库的使用方法


    矢量字体的使用通过下面四步就可以实现:
第1步:定义16点阵大小,24点阵大小,32点阵大小,48点阵大小,72点阵大小和120点阵大小的格式字体。
  1. /*
  2. *********************************************************************************************************
  3. *                                      定义矢量字体
  4. *********************************************************************************************************
  5. */
  6. GUI_TTF_CS Cs0, Cs1, Cs2, Cs3, Cs4, Cs5;
  7. GUI_TTF_DATA Data;
  8. GUI_FONT Font16, Font24, Font32, Font48, Font72, Font120;
复制代码
    这里对定义矢量字体用到的两个结构体变量做如下介绍。
    GUI_TTF_CS结构体变量:
28.16.png
   GUI_TTF_DATA结构体变量:
28.17.png

第2步:创建16点阵大小,24点阵大小,32点阵大小,48点阵大小,72点阵大小和120点阵大小的格式字体。
    创建前要先将矢量字体库存到SD卡中,然后将其加载到SDRAM里面,这个矢量字体是来自电脑系统自带,电脑系统是WIN7 64bit,路径:C:\\Windows\\Fonts(已经将这个字体存到本章节配套例子的Doc文件夹下)。
28.18.png

    大小是10MB,由于前面我们设置emWin的动态内存是12MB,所以10MB大小是没问题的。其它类型的矢量字体也是可以的,最好不要超过11MB,给emWin其它应用留一部分动态内存。
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: LoadFontTTF
  4. *    功能说明: 从SD卡中读取矢量字体库到SDRAM中并创建矢量字体
  5. *    形    参: sFilename  要读取的文件名
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void LoadFontTTF(const char *sFilename)
  10. {
  11.      char *_acBuffer;
  12.      GUI_HMEM hMem;
  13.    
  14.      /* 打开文件 */        
  15.      result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
  16.      if (result != FR_OK)
  17.      {
  18.          return;
  19.      }
  20.       
  21.      /* 申请一块内存空间 并且将其清零 */
  22.      hMem = GUI_ALLOC_AllocZero(file.fsize);
  23.    
  24.      /* 将申请到内存的句柄转换成指针类型 */
  25.      _acBuffer = GUI_ALLOC_h2p(hMem);
  26.      /* 读取文件到动态内存 */
  27.      result = f_read(&file, _acBuffer, file.fsize, &bw);
  28.      if (result != FR_OK)
  29.      {
  30.          return;
  31.      }
  32.      /* 设置参数 */
  33.      Data.pData = _acBuffer;
  34.      Data.NumBytes = file.fsize;
  35.      /* 设置第1种字体显示方式 */
  36.      Cs0.pTTF = &Data;       /* 矢量字体数据地址 */
  37.      Cs0.PixelHeight = 16;   /* 字体高度 */
  38.      Cs0.FaceIndex = 0;
  39.    
  40.      /* 设置第2种字体显示方式 */
  41.      Cs1.pTTF = &Data;       /* 矢量字体数据地址 */
  42.      Cs1.PixelHeight = 24;   /* 字体高度 */
  43.      Cs1.FaceIndex = 0;
  44.    
  45.    
  46.      /* 设置第3种字体显示方式 */
  47.      Cs2.pTTF = &Data;       /* 矢量字体数据地址 */
  48.      Cs2.PixelHeight = 32;   /* 字体高度 */
  49.      Cs2.FaceIndex = 0;
  50.    
  51.      /* 设置第4种字体显示方式 */
  52.      Cs3.pTTF = &Data;      /* 矢量字体数据地址 */
  53.      Cs3.PixelHeight = 48;  /* 字体高度 */
  54.      Cs3.FaceIndex = 0;
  55.    
  56.    
  57.      /* 设置第5种字体显示方式 */
  58.      Cs4.pTTF = &Data;      /* 矢量字体数据地址 */
  59.      Cs4.PixelHeight = 72;  /* 字体高度 */
  60.      Cs4.FaceIndex = 0;
  61.    
  62.      /* 设置第6种字体显示方式 */
  63.      Cs5.pTTF = &Data;    /* 矢量字体数据地址 */
  64.      Cs5.PixelHeight = 120; /* 字体高度 */
  65.      Cs5.FaceIndex = 0;
  66.    
  67.      /* 创建6种字体 */
  68.      GUI_TTF_CreateFontAA(&Font16, &Cs0);
  69.      GUI_TTF_CreateFontAA(&Font24, &Cs1);
  70.      GUI_TTF_CreateFontAA(&Font32, &Cs2);
  71.      GUI_TTF_CreateFontAA(&Font48, &Cs3);
  72.      GUI_TTF_CreateFontAA(&Font72, &Cs4);
  73.      GUI_TTF_CreateFontAA(&Font120, &Cs5);
  74.    
  75.      f_close(&file);
  76. }
复制代码
第3步:加载到SDRAM后,使用就比较简单了。
    用户只需调用函数GUI_UC_SetEncodeUTF8()使能UTF-8编码就可以使用矢量字体了,比如设置按钮的字体,调用如下设置函数即可。
      BUTTON_SetFont(hWin,  &Font32); /* hWin是按钮的句柄*/
第4步:最后一步切不可忘记设置汉字显示所在源文件的编码类型,具体MDK和IAR的设置方法请看第22章22.4小节(本章节配套的例子也是设置的MainTask,c文件),这一步绝对不可以省略,因为我们使用的矢量字体库也是Unicode编码。
    通过这4步就实现矢量字体的显示了。另外注意,如果系统运行中不需要矢量字体了,可以通过函数GUI_TTF_DestroyCache释放矢量字体所消耗的内存资源,通过函数GUI_ALLOC_AllocZero申请的空间,可以使用函数GUI_ALLOC_Free来释放。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-2-6 17:02:37 | 显示全部楼层
28.6   实验例程说明(RTOS)


配套例子:
    V6-538_STemWin实验_矢量全字库,支持中文,Unicode编码(RTOS)
实验目的:
    1.     学习emWin矢量字体库的使用方法,Unicode编码。
    2.     emWin功能的实现在MainTask.c文件里面。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2按键按下,实现截图功能,将图片以BMP格式保存到SD卡中。
    3.     各个任务实现的功能如下:
              App Task Start   任务:实现按键和触摸扫描。
              App Task MspPro任务 :实现截图功能,将图片以BMP格式保存到SD卡中。
              App Task UserIF  任务:按键消息处理。
              App Task COM   任务:暂未使用。
             App Task GUI    任务:GUI任务。
矢量字体:
    1.     相比点阵字体,矢量字体可以进行无损放缩,本工程测试了16点阵,24点阵,32点阵,48点阵,72点阵和120点阵的显示效果。
    2.     给emWin分配的动态内存大小是12MB,如果用户想测试其它矢量字体,最好不要超过11MB。emWin本身预留1MB使用。
字库存储方式:
    1.     系统上电后,将矢量字体从SD卡加载到emWin动态内存,即SDRAM里面。
实验步骤如下:
    1.     矢量库文件song.ttf已经放到本工程的Doc文件夹下。用户使用前,务必将此文件放到SD卡根目录中,系统上电后会将其加载到SDRAM里面。
    2.     板子上电后,会等待10秒钟后开始加载矢量字体到SDRAM。
实验注意:
    1.     实验所需的矢量字体库song.ttf已经存储到本工程的Doc文件夹下,使用此例子前,请务必将这个文件存储到SD卡根目录中,并将SD卡插到开发板上面。
μCOS-III任务调试信息(按K1按键,串口打印):
28.19.png

STemWin界面显示效果:
    800*480分辨率界面效果。
28.20.png

STemWin动态内存配置:
    GUIConf.c文件中的配置如下:
  1. #define EX_SRAM   1/*1 used extern sram, 0 used internal sram */
  2. #if EX_SRAM
  3. #define GUI_NUMBYTES  (1024*1024*12)
  4. #else
  5. #define GUI_NUMBYTES  (100*1024)
  6. #endif
复制代码
    通过宏定义来配置使用内部SRAM还是外部的SDRAM做为emWin的动态内存,当配置:
#define EX_SRAM    1 表示使用外部SDRAM作为emWin动态内存,大小12MB。
#define EX_SRAM    0 表示使用内部SRAM作为emWin动态内存,大小100KB。
默认情况下,本教程配套的所有emWin例子都是用外部SDRAM作为emWin动态内存。
STemWin底层接口配置:
    LCDConf_Lin_Template.c文件中共12项emWin配置:
  1. /*
  2. **********************************************************************************************************
  3.                                           用户可以配置的选项
  4. **********************************************************************************************************
  5. */
  6. /* 0. 在官方代码的基础上再做优化,官方的部分函数效率低,耗内存, 0表示优化 */
  7. #define emWin_Optimize   0
  8. /*
  9.   1. 显示屏的物理分辨率,驱动已经做了显示屏自适应,支持4.3寸,5寸和7寸屏
  10.      这里填写自适应显示屏中的最大分辨率。
  11. */
  12. #define XSIZE_PHYS       800
  13. #define YSIZE_PHYS       480
  14. /* 2. 多缓冲 / 虚拟屏,多缓冲和虚拟屏不可同时使用,emWin不支持 */
  15. #define NUM_BUFFERS      3 /* 定义多缓冲个数,仅可以设置1,2和3,也就是最大支持三缓冲 */
  16. #define NUM_VSCREENS     1 /* 定义虚拟屏个数 */
  17. /* 3. 没有图层激活时,背景色设置, 暂时未用到 */
  18. #define BK_COLOR         GUI_DARKBLUE
  19. /*
  20.    4. 重定义图层数,对于STM32F429/439,用户可以选择一个图层或者两个图层,不支持三图层
  21.       (1). 设置GUI_NUM_LAYERS = 1时,即仅使用图层1时,默认触摸值是发送给图层1的。
  22.        (2). 设置GUI_NUM_LAYERS = 2时,即图层1和图层2都已经使能,此时图层2是顶层,
  23.             用户需要根据自己的使用情况设置如下两个地方。
  24.             a. 在bsp_touch.c文件中的函数TOUCH_InitHard里面设置参数State.Layer = 1,1就表示
  25.                给图层2发送触摸值。
  26.             b. 调用GUI_Init函数后,调用函数GUI_SelectLayer(1), 设置当前操作的是图层2。
  27. */
  28. #undef  GUI_NUM_LAYERS
  29. #define GUI_NUM_LAYERS    1
  30. /*
  31.    5. 设置图层1和图层2对应的显存地址
  32.       (1) EXT_SDRAM_ADDR 是SDRAM的首地址。
  33.       (2) LCD_LAYER0_FRAME_BUFFER 是图层1的显存地址。
  34.        (3) LCD_LAYER1_FRAME_BUFFER 是图层2的显存地址。
  35.        (4) 每个图层的显存大小比较考究,这里进行下简单的说明。
  36.            如果用户选择的颜色模式 = 32位色ARGB8888,显存的大小:
  37.            XSIZE_PHYS * YSIZE_PHYS * 4 * NUM_VSCREENS * NUM_BUFFERS
  38.          
  39.            颜色模式 = 24位色RGB888,显存的大小:
  40.            XSIZE_PHYS * YSIZE_PHYS * 3 * NUM_VSCREENS * NUM_BUFFERS
  41.          
  42.            颜色模式 = 16位色RGB566,ARGB1555, ARGB4444,AL88,那么显存的大小就是:
  43.            XSIZE_PHYS * YSIZE_PHYS * 2 * NUM_VSCREENS * NUM_BUFFERS
  44.            颜色模式 = 8位色L8,AL44,那么显存的大小就是:
  45.            XSIZE_PHYS * YSIZE_PHYS * 1 * NUM_VSCREENS * NUM_BUFFERS  
  46.      
  47.       这里为了方便起见,将开发板配套的16MB的SDRAM前8MB分配给LCD显存使用,后8MB用于emWin动态内存。
  48.        对于24位色,16位色,8位色,用户可以对其使能三缓冲,并且使能双图层。但是32位色也使能三缓冲和双
  49.        图层的话会超出8MB,所以用户根据自己的情况做显存和emWin动态内存的分配调整。
  50.          举一个例子,对于800*480分辨率的显示屏,使能32位色,三缓冲,那么最终一个图层需要的大小就是
  51.       800 * 480 * 4 * 3  = 4.394MB的空间,如果是双图层,已经超出8MB的分配范围。
  52.      
  53.       (5)为了方便起见,图层2的宏定义LCD_LAYER1_FRAME_BUFFER中的参数4是按照32位色设置的,如果用户的图层1
  54.          使用的是8位色,这里填数字1,如果是16位色,这里填2,如果是24位色,这里填3。
  55. */
  56. #define LCD_LAYER0_FRAME_BUFFER  EXT_SDRAM_ADDR
  57. #define LCD_LAYER1_FRAME_BUFFER  (LCD_LAYER0_FRAME_BUFFER + XSIZE_PHYS * YSIZE_PHYS * 4 * NUM_VSCREENS *
  58. NUM_BUFFERS)
  59. /*
  60.    6. STM32F429/439支持的颜色模式,所有模式都支持,用户可任意配置。
  61.       特别注意如下两个问题:
  62.        (1) 如果用户选择了ARGB8888或者RGB888模式,LCD闪烁比较厉害的话,
  63.            请降低LTDC的时钟大小,在文件bsp_tft_429.c的函数LCD_ConfigLTDC里面设置。
  64.            a. 一般800*480分辨率的显示屏,ARGB8888或者RGB888模式LTDC时钟选择10-20MHz即可。
  65.            b. 480*272分辨率的可以高些,取20MHz左右即可。
  66.        (2) 16位色或者8位色模式,LTDC的时钟频率一般可以比24位色或者32位色的高一倍。
  67. */
  68. #define _CM_ARGB8888      1
  69. #define _CM_RGB888        2
  70. #define _CM_RGB565        3
  71. #define _CM_ARGB1555      4
  72. #define _CM_ARGB4444      5
  73. #define _CM_L8            6
  74. #define _CM_AL44          7
  75. #define _CM_AL88          8
  76. /* 7. 配置图层1的颜色模式和分辨率大小 */
  77. #define COLOR_MODE_0      _CM_RGB565
  78. #define XSIZE_0           XSIZE_PHYS
  79. #define YSIZE_0           YSIZE_PHYS
  80. /* 8. 配置图层2的的颜色模式和分辨率大小 */
  81. #define COLOR_MODE_1      _CM_RGB565
  82. #define XSIZE_1           XSIZE_PHYS
  83. #define YSIZE_1           YSIZE_PHYS
  84. /* 9. 单图层情况下,根据用户选择的颜色模式可自动选择图层1的emWin的驱动和颜色模式 */
  85. #if   (COLOR_MODE_0 == _CM_ARGB8888)
  86.   #define COLOR_CONVERSION_0 GUICC_M8888I
  87.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_32
  88. #elif (COLOR_MODE_0 == _CM_RGB888)
  89.   #define COLOR_CONVERSION_0 GUICC_M888
  90.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_24
  91. #elif (COLOR_MODE_0 == _CM_RGB565)
  92.   #define COLOR_CONVERSION_0 GUICC_M565
  93.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_16
  94. #elif (COLOR_MODE_0 == _CM_ARGB1555)
  95.   #define COLOR_CONVERSION_0 GUICC_M1555I
  96.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_16
  97. #elif (COLOR_MODE_0 == _CM_ARGB4444)
  98.   #define COLOR_CONVERSION_0 GUICC_M4444I
  99.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_16
  100. #elif (COLOR_MODE_0 == _CM_L8)
  101.   #define COLOR_CONVERSION_0 GUICC_8666
  102.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_8
  103. #elif (COLOR_MODE_0 == _CM_AL44)
  104.   #define COLOR_CONVERSION_0 GUICC_1616I
  105.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_8
  106. #elif (COLOR_MODE_0 == _CM_AL88)
  107.   #define COLOR_CONVERSION_0 GUICC_88666I
  108.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_16
  109. #else
  110.   #error Illegal color mode 0!
  111. #endif
  112. /* 10. 双图层情况下,根据用户选择的颜色模式可自动选择图层2的emWin的驱动和颜色模式 */
  113. #if (GUI_NUM_LAYERS > 1)
  114. #if   (COLOR_MODE_1 == _CM_ARGB8888)
  115.   #define COLOR_CONVERSION_1 GUICC_M8888I
  116.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_32
  117. #elif (COLOR_MODE_1 == _CM_RGB888)
  118.   #define COLOR_CONVERSION_1 GUICC_M888
  119.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_24
  120. #elif (COLOR_MODE_1 == _CM_RGB565)
  121.   #define COLOR_CONVERSION_1 GUICC_M565
  122.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_16
  123. #elif (COLOR_MODE_1 == _CM_ARGB1555)
  124.   #define COLOR_CONVERSION_1 GUICC_M1555I
  125.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_16
  126. #elif (COLOR_MODE_1 == _CM_ARGB4444)
  127.   #define COLOR_CONVERSION_1 GUICC_M4444I
  128.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_16
  129. #elif (COLOR_MODE_1 == _CM_L8)
  130.   #define COLOR_CONVERSION_1 GUICC_8666
  131.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_8
  132. #elif (COLOR_MODE_1 == _CM_AL44)
  133.   #define COLOR_CONVERSION_1 GUICC_1616I
  134.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_8
  135. #elif (COLOR_MODE_1 == _CM_AL88)
  136.   #define COLOR_CONVERSION_1 GUICC_88666I
  137.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_16
  138. #else
  139.   #error Illegal color mode 1!
  140. #endif
  141. #else
  142. #undef XSIZE_0
  143. #undef YSIZE_0
  144. #define XSIZE_0       XSIZE_PHYS
  145. #define YSIZE_0       YSIZE_PHYS
  146. #endif
  147. /*11. 配置选项检测,防止配置错误或者某些选项没有配置 */
  148. #ifndef   XSIZE_PHYS
  149.   #error Physical X size of display is not defined!
  150. #endif
  151. #ifndef   YSIZE_PHYS
  152.   #error Physical Y size of display is not defined!
  153. #endif
  154. #ifndef   NUM_VSCREENS
  155.   #define NUM_VSCREENS 1
  156. #else
  157.   #if (NUM_VSCREENS <= 0)
  158.     #error At least one screeen needs to be defined!
  159.   #endif
  160. #endif
  161. #if (NUM_VSCREENS > 1) && (NUM_BUFFERS > 1)
  162.   #error Virtual screens and multiple buffers are not allowed!
  163. #endif
复制代码
    对于这12个配置选项,注释说明已经比较详细。默认情况下,本教程配套的emWin例子都是用的三缓冲,RGB565格式,且仅使用单图层。
程序设计:
任务栈大小分配:
    μCOS-III任务栈大小在os_cfg.h文件中配置:
#define  APP_CFG_TASK_START_STK_SIZE                     512u
#define  APP_CFG_TASK_MsgPro_STK_SIZE                    512u
#define  APP_CFG_TASK_COM_STK_SIZE                       512u
#define  APP_CFG_TASK_USER_IF_STK_SIZE                    512u
#define  APP_CFG_TASK_GUI_STK_SIZE                        1024u
    任务栈大小的单位是4字节,那么每个任务的栈大小如下:
App Task Start   任务:2048字节。
       App Task MspPro任务 :2048字节。
       App Task UserIF  任务:2048字节。
       App Task COM   任务:2048字节。
App Task GUI    任务:4096字节。
系统栈大小分配:
    μCOS-III的系统栈大小在os_cfg_app.h文件中配置:
        #define  OS_CFG_ISR_STK_SIZE                      512u      
     系统栈大小的单位是4字节,那么这里就是配置系统栈大小为2KB。
μCOS-III初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.     OS_ERR  err;
  12.    
  13.      /* 初始化uC/OS-III 内核 */
  14.     OSInit(&err);
  15.      /* 创建一个启动任务(也就是主任务)。启动任务会创建所有的应用程序任务 */
  16.      OSTaskCreate((OS_TCB       *)&AppTaskStartTCB,  /* 任务控制块地址 */           
  17.                  (CPU_CHAR     *)"App Task Start",  /* 任务名 */
  18.                  (OS_TASK_PTR   )AppTaskStart,      /* 启动任务函数地址 */
  19.                  (void         *)0,                 /* 传递给任务的参数 */
  20.                  (OS_PRIO       )APP_CFG_TASK_START_PRIO, /* 任务优先级 */
  21.                  (CPU_STK      *)&AppTaskStartStk[0],     /* 堆栈基地址 */
  22.                  (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE / 10, /* 堆栈监测区,这里表示后10%作为监测区 */
  23.                  (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE,      /* 堆栈空间大小 */
  24.                  (OS_MSG_QTY    )0,  /* 本任务支持接受的最大消息数 */
  25.                  (OS_TICK       )0,  /* 设置时间片 */
  26.                  (void         *)0,  /* 堆栈空间大小 */
  27.                  (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
  28.         
  29.                     /*  定义如下:
  30.                        OS_OPT_TASK_STK_CHK      使能检测任务栈,统计任务栈已用的和未用的
  31.                        OS_OPT_TASK_STK_CLR      在创建任务时,清零任务栈
  32.                        OS_OPT_TASK_SAVE_FP      如果CPU有浮点寄存器,则在任务切换时保存浮点寄存器的内容
  33.                     */
  34.                  (OS_ERR       *)&err);
  35.      /* 启动多任务系统,控制权交给uC/OS-III */
  36.     OSStart(&err);                                             
  37.    
  38.     (void)&err;
  39.    
  40.     return (0);
  41. }
复制代码
硬件外设初始化
    硬件外设的初始化是在bsp.c文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.      /*
  12.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  15.      */
  16.      /* 使能CRC 因为使用STemWin前必须要使能 */
  17.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
  18.    
  19.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  20.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  21.    
  22.      SystemCoreClockUpdate();    /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */
  23.      bsp_InitUart();        /* 初始化串口 */
  24.      bsp_InitKey();         /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */
  25.    
  26.      bsp_InitExtIO();       /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */
  27.      bsp_InitLed();         /* 初始LED指示灯端口 */
  28.    
  29.      bsp_InitI2C();         /* 配置I2C总线 */
  30.    
  31.      bsp_InitExtSDRAM();   /* 初始化SDRAM */
  32.      bsp_DetectLcdType();  /* 检测触摸板和LCD面板型号, 结果存在全局变量 g_TouchType, g_LcdType */
  33.    
  34.      TOUCH_InitHard();    /* 初始化配置触摸芯片 */
  35.      LCD_ConfigLTDC();     /* 初始化配置LTDC */
  36.    
  37.      result = f_mount(&fs, "0:/", 0);     /* 挂载文件系统 */
  38. }
复制代码
五个μCOS-III任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskStart
  4. *    功能说明: 这是一个启动任务,在多任务系统启动后,必须初始化滴答计数器。本任务主要实现按键和触摸检测。
  5. *    形    参: p_arg 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7.      优 先 级: 2
  8. *********************************************************************************************************
  9. */
  10. static  void  AppTaskStart (void *p_arg)
  11. {
  12.      OS_ERR      err;
  13.      uint8_t  ucCount = 0;
  14.      uint8_t  ucCount1 = 0;
  15.    
  16.     /* 仅用于避免编译器告警,编译器不会产生任何目标代码 */  
  17.     (void)p_arg;
  18.    
  19.      /* BSP 初始化。 BSP = Board Support Package 板级支持包,可以理解为底层驱动。*/
  20.      CPU_Init();  /* 此函数要优先调用,因为外设驱动中使用的us和ms延迟是基于此函数的 */
  21.      bsp_Init();      
  22.      BSP_Tick_Init();
  23.    
  24. #if OS_CFG_STAT_TASK_EN > 0u
  25.      OSStatTaskCPUUsageInit(&err);  
  26. #endif
  27. #ifdef CPU_CFG_INT_DIS_MEAS_EN
  28.     CPU_IntDisMeasMaxCurReset();
  29. #endif
  30.         
  31.      /* 创建应用程序的任务 */
  32.      AppTaskCreate();
  33.    
  34.      /* 创建任务通信 */
  35.      AppObjCreate();
  36.    
  37.     while(1)
  38.     {
  39.          /* 1ms一次触摸扫描,电阻触摸屏 */
  40.          if(g_tTP.Enable == 1)
  41.          {
  42.               TOUCH_Scan();
  43.             
  44.               /* 按键扫描 */
  45.               ucCount++;
  46.               if(ucCount == 10)
  47.               {
  48.                    ucCount = 0;
  49.                    bsp_KeyScan();
  50.               }
  51.              OSTimeDly(1, OS_OPT_TIME_DLY, &err);         
  52.          }
  53.         
  54.          /* 20ms一次触摸扫描,电容触摸屏GT811
  55.             GT811取20ms比较稳定,取10ms偶尔会有跳动。
  56.          */
  57.          if(g_GT811.Enable == 1)
  58.          {
  59.               bsp_KeyScan();
  60.               ucCount1++;
  61.               if(ucCount1 == 2)
  62.               {
  63.                    ucCount1 = 0;
  64.                    GT811_OnePiontScan();
  65.               }
  66.              OSTimeDly(10, OS_OPT_TIME_DLY, &err);     
  67.          }
  68.         
  69.          /* 10ms一次触摸扫描,电容触摸屏FT5X06 */
  70.          if(g_tFT5X06.Enable == 1)
  71.          {
  72.               bsp_KeyScan();
  73.               FT5X06_OnePiontScan();
  74.              OSTimeDly(10, OS_OPT_TIME_DLY, &err);
  75.          }
  76.     }   
  77. }
  78. /*
  79. *********************************************************************************************************
  80. *    函 数 名: AppTaskMsgPro
  81. *    功能说明: 实现截图功能,将图片以BMP格式保存到SD卡中
  82. *    形    参: p_arg 是在创建该任务时传递的形参
  83. *    返 回 值: 无
  84.      优 先 级: 3
  85. *********************************************************************************************************
  86. */
  87. static void AppTaskMsgPro(void *p_arg)
  88. {
  89.      uint32_t ulStart, ulEnd;
  90.      OS_ERR      err;
  91.      uint8_t       Pic_Name = 0;
  92.      char buf[20];
  93.      (void)p_arg;
  94.          
  95.      while(1)
  96.      {   
  97.           /* 等待获取信号量同步消息,接收到后执行串口打印 */
  98.          OSSemPend((OS_SEM *)&SEM_SYNCH,
  99.                      (OS_TICK )0,
  100.                      (OS_OPT  )OS_OPT_PEND_BLOCKING,
  101.                      (CPU_TS  )0,
  102.                      (OS_ERR *)&err);
  103.         
  104.          if(err == OS_ERR_NONE)
  105.          {   
  106.               sprintf(buf,"0:/PicSave/%d.bmp",Pic_Name);
  107.             
  108.               /* 记录截图前起始时间 */
  109.               ulStart = OSTimeGet(&err);
  110.             
  111.               /* 开启调度锁 */
  112.               OSSchedLock(&err);
  113.             
  114.               /* 如果SD卡中没有PicSave文件,会进行创建 */
  115.               result = f_mkdir("0:/PicSave");
  116.             
  117.               /* 创建截图 */
  118.               result = f_open(&file,buf, FA_WRITE|FA_CREATE_ALWAYS);
  119.             
  120.               /* 向SD卡绘制BMP图片 */
  121.               GUI_BMP_Serialize(_WriteByte2File, &file);
  122.             
  123.               /* 创建完成后关闭file */
  124.              result = f_close(&file);
  125.             
  126.               /* 开启调度锁 */
  127.               OSSchedUnlock(&err);
  128.             
  129.               /* 记录截图后时间并获取截图过程耗时 */
  130.               ulEnd = OSTimeGet(&err);
  131.               ulEnd -= ulStart;
  132.             
  133.               App_Printf("截图完成,耗时 = %dms\\r\\n", ulEnd);
  134.               Pic_Name++;      
  135.          }                                                                                                                  
  136.      }  
  137. }
  138. /*
  139. *********************************************************************************************************
  140. *    函 数 名: AppTaskUserIF
  141. *    功能说明: 按键消息处理
  142. *    形    参: p_arg 是在创建该任务时传递的形参
  143. *    返 回 值: 无
  144.      优 先 级: 4
  145. *********************************************************************************************************
  146. */
  147. static void AppTaskUserIF(void *p_arg)
  148. {
  149.      OS_ERR      err;
  150.      uint8_t  ucKeyCode;
  151.    
  152.      (void)p_arg;                /* 避免编译器报警 */
  153.    
  154.      while (1)
  155.      {      
  156.          ucKeyCode = bsp_GetKey();
  157.         
  158.          if (ucKeyCode != KEY_NONE)
  159.          {
  160.               switch (ucKeyCode)
  161.               {
  162.                    case KEY_DOWN_K1:             /* K1键按下 打印任务执行情况 */
  163.                        DispTaskInfo();        
  164.                        break;
  165.                   
  166.                    case KEY_DOWN_K2:             /* K2键按下 向消息队列发送数据 */
  167.                        OSSemPost((OS_SEM *)&SEM_SYNCH,
  168.                                   (OS_OPT  )OS_OPT_POST_1,
  169.                                   (OS_ERR *)&err);
  170.                        break;
  171.                   
  172.                    default:                     /* 其他的键值不处理 */
  173.                        break;
  174.               }
  175.          }
  176.         
  177.          OSTimeDly(20, OS_OPT_TIME_DLY, &err);
  178.      }
  179. }
  180. /*
  181. *********************************************************************************************************
  182. *    函 数 名: AppTaskCom
  183. *    功能说明: 暂未使用
  184. *    形    参: p_arg 是在创建该任务时传递的形参
  185. *    返 回 值: 无
  186.      优 先 级: 5
  187. *********************************************************************************************************
  188. */
  189. static void AppTaskCOM(void *p_arg)
  190. {
  191.      OS_ERR  err;      
  192.    
  193.      (void)p_arg;
  194.    
  195.      while(1)
  196.      {   
  197.          OSTimeDly(500, OS_OPT_TIME_DLY, &err);
  198.      }                                                                                                
  199. }
  200. /*
  201. *********************************************************************************************************
  202. *    函 数 名: AppTaskGUI
  203. *    功能说明: GUI任务,最低优先级                        
  204. *    形    参:p_arg 是在创建该任务时传递的形参
  205. *    返 回 值: 无
  206. *   优 先 级:OS_CFG_PRIO_MAX - 4u
  207. *********************************************************************************************************
  208. */
  209. static void AppTaskGUI(void *p_arg)
  210. {
  211.     (void)p_arg;       /* 避免编译器告警 */
  212.         
  213.      while (1)
  214.      {
  215.          MainTask();
  216.      }
  217. }
复制代码
emWin任务的具体实现(在MainTask.c文件里面):
  1. #include "MainTask.h"
  2. #include "includes.h"
  3. /*
  4. *********************************************************************************************************
  5. *                                      定义矢量字体
  6. *********************************************************************************************************
  7. */
  8. GUI_TTF_CS Cs0, Cs1, Cs2, Cs3, Cs4, Cs5;
  9. GUI_TTF_DATA Data;
  10. GUI_FONT Font16, Font24, Font32, Font48, Font72, Font120;
  11. /*
  12. *********************************************************************************************************
  13. *                                                       对话框信息
  14. *********************************************************************************************************
  15. */
  16. static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
  17. { FRAMEWIN_CreateIndirect,  "安富莱电子矢量字体展示,支持抗锯齿",     0,        0,  0,  800, 480,0, 0},
  18. { BUTTON_CreateIndirect,    "安富莱电子",     GUI_ID_BUTTON0,  30, 330, 400, 70, 0, 0},
  19. { TEXT_CreateIndirect,      "安富莱电子AaAa-16点半角全角",   GUI_ID_TEXT0,   0, 0, 800, 16, 0,0},
  20. { TEXT_CreateIndirect,      "安富莱电子AaAa-24点半角全角",   GUI_ID_TEXT1,   0, 16, 800, 24, 0,0},
  21. { TEXT_CreateIndirect,      "安富莱电子AaAa-32点半角全角",   GUI_ID_TEXT2,   0, 40, 800, 32, 0,0},
  22. { TEXT_CreateIndirect,      "安富莱电子AaAa-48点半角全角",   GUI_ID_TEXT3,   0, 72, 800, 48, 0,0},
  23. { TEXT_CreateIndirect,      "安富莱电子AaAa-72点",           GUI_ID_TEXT4,   0, 120, 800, 72, 0,0},
  24. { TEXT_CreateIndirect,      "安富莱电子120点",                 GUI_ID_TEXT5,   0, 192, 800, 120, 0,0},
  25. };
  26. /*
  27. *********************************************************************************************************
  28. *    函 数 名: PaintDialog
  29. *    功能说明: 重绘
  30. *    形    参:pMsg  消息指针
  31. *    返 回 值: 无
  32. *********************************************************************************************************
  33. */
  34. void PaintDialog(WM_MESSAGE * pMsg)
  35. {
  36. }
  37. /*
  38. *********************************************************************************************************
  39. *    函 数 名: InitDialog
  40. *    功能说明: 对话框初始化
  41. *    形    参: pMsg 消息指针
  42. *    返 回 值: 无
  43. *********************************************************************************************************
  44. */
  45. void InitDialog(WM_MESSAGE * pMsg)
  46. {
  47.     WM_HWIN hWin = pMsg->hWin;
  48.    
  49.      //
  50.     // 框架窗口设置
  51.     //  
  52.     FRAMEWIN_SetFont(hWin,&Font32);
  53.     FRAMEWIN_SetTextAlign(hWin,GUI_TA_VCENTER|GUI_TA_CENTER);
  54.     FRAMEWIN_AddCloseButton(hWin, FRAMEWIN_BUTTON_RIGHT, 0);
  55.     FRAMEWIN_AddMaxButton(hWin, FRAMEWIN_BUTTON_RIGHT, 1);
  56.     FRAMEWIN_AddMinButton(hWin, FRAMEWIN_BUTTON_RIGHT, 2);
  57.     FRAMEWIN_SetTitleHeight(hWin,35);
  58.    
  59.      //
  60.     // 按钮控件设置
  61.     //
  62.     BUTTON_SetFont(WM_GetDialogItem(hWin,GUI_ID_BUTTON0),&Font48);
  63.    
  64.     //
  65.     // 文本控件设置
  66.     //
  67.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT0), GUI_BLACK);
  68.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT0), &Font16);
  69.    
  70.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT1), GUI_BLUE);
  71.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT1), &Font24);
  72.    
  73.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT2), GUI_ORANGE);
  74.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT2), &Font32);
  75.    
  76.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT3), GUI_MAGENTA);
  77.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT3), &Font48);
  78.    
  79.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT4), GUI_BLUE);
  80.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT4), &Font72);
  81.    
  82.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT5), GUI_RED);
  83.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT5), &Font120);
  84. }
  85. /*
  86. *********************************************************************************************************
  87. *    函 数 名: _cbCallback
  88. *    功能说明: 对话框回调函数
  89. *    形    参: 无
  90. *    返 回 值: 无
  91. *********************************************************************************************************
  92. */
  93. static void _cbCallback(WM_MESSAGE * pMsg)
  94. {
  95.     int NCode, Id;
  96.     WM_HWIN hWin = pMsg->hWin;
  97.     switch (pMsg->MsgId)
  98.     {
  99.         case WM_PAINT:
  100.             PaintDialog(pMsg);
  101.             break;
  102.         
  103.         case WM_INIT_DIALOG:
  104.             InitDialog(pMsg);
  105.             break;
  106.         
  107.         case WM_KEY:
  108.             switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key)
  109.             {
  110.                 case GUI_KEY_ESCAPE:
  111.                     GUI_EndDialog(hWin, 1);
  112.                     break;
  113.                 case GUI_KEY_ENTER:
  114.                     GUI_EndDialog(hWin, 0);
  115.                     break;
  116.             }
  117.             break;
  118.             
  119.         case WM_NOTIFY_PARENT:
  120.             Id = WM_GetId(pMsg->hWinSrc);
  121.             NCode = pMsg->Data.v;      
  122.             switch (Id)
  123.             {
  124.                 case GUI_ID_OK:
  125.                     if(NCode==WM_NOTIFICATION_RELEASED)
  126.                         GUI_EndDialog(hWin, 0);
  127.                     break;
  128.                      
  129.                 case GUI_ID_CANCEL:
  130.                     if(NCode==WM_NOTIFICATION_RELEASED)
  131.                         GUI_EndDialog(hWin, 0);
  132.                     break;
  133.             }
  134.             break;
  135.             
  136.         default:
  137.             WM_DefaultProc(pMsg);
  138.     }
  139. }
  140. /*
  141. *********************************************************************************************************
  142. *    函 数 名: LoadFontTTF
  143. *    功能说明: 从SD卡中读取矢量字体库到SDRAM中并创建矢量字体
  144. *    形    参: sFilename  要读取的文件名
  145. *    返 回 值: 无
  146. *********************************************************************************************************
  147. */
  148. void LoadFontTTF(const char *sFilename)
  149. {
  150.      char *_acBuffer;
  151.      GUI_HMEM hMem;
  152.    
  153.      /* 打开文件 */        
  154.      result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
  155.      if (result != FR_OK)
  156.      {
  157.          return;
  158.      }
  159.       
  160.      /* 申请一块内存空间 并且将其清零 */
  161.      hMem = GUI_ALLOC_AllocZero(file.fsize);
  162.    
  163.      /* 将申请到内存的句柄转换成指针类型 */
  164.      _acBuffer = GUI_ALLOC_h2p(hMem);
  165.      /* 读取文件到动态内存 */
  166.      result = f_read(&file, _acBuffer, file.fsize, &bw);
  167.      if (result != FR_OK)
  168.      {
  169.          return;
  170.      }
  171.      /* 设置参数 */
  172.      Data.pData = _acBuffer;
  173.      Data.NumBytes = file.fsize;
  174.      /* 设置第1种字体显示方式 */
  175.      Cs0.pTTF = &Data;       /* 矢量字体数据地址 */
  176.      Cs0.PixelHeight = 16;   /* 字体高度 */
  177.      Cs0.FaceIndex = 0;
  178.    
  179.      /* 设置第2种字体显示方式 */
  180.      Cs1.pTTF = &Data;       /* 矢量字体数据地址 */
  181.      Cs1.PixelHeight = 24;   /* 字体高度 */
  182.      Cs1.FaceIndex = 0;
  183.    
  184.    
  185.      /* 设置第3种字体显示方式 */
  186.      Cs2.pTTF = &Data;       /* 矢量字体数据地址 */
  187.      Cs2.PixelHeight = 32;   /* 字体高度 */
  188.      Cs2.FaceIndex = 0;
  189.    
  190.      /* 设置第4种字体显示方式 */
  191.      Cs3.pTTF = &Data;      /* 矢量字体数据地址 */
  192.      Cs3.PixelHeight = 48;  /* 字体高度 */
  193.      Cs3.FaceIndex = 0;
  194.    
  195.    
  196.      /* 设置第5种字体显示方式 */
  197.      Cs4.pTTF = &Data;      /* 矢量字体数据地址 */
  198.      Cs4.PixelHeight = 72;  /* 字体高度 */
  199.      Cs4.FaceIndex = 0;
  200.    
  201.      /* 设置第6种字体显示方式 */
  202.      Cs5.pTTF = &Data;    /* 矢量字体数据地址 */
  203.      Cs5.PixelHeight = 120; /* 字体高度 */
  204.      Cs5.FaceIndex = 0;
  205.    
  206.      /* 创建6种字体 */
  207.      GUI_TTF_CreateFontAA(&Font16, &Cs0);
  208.      GUI_TTF_CreateFontAA(&Font24, &Cs1);
  209.      GUI_TTF_CreateFontAA(&Font32, &Cs2);
  210.      GUI_TTF_CreateFontAA(&Font48, &Cs3);
  211.      GUI_TTF_CreateFontAA(&Font72, &Cs4);
  212.      GUI_TTF_CreateFontAA(&Font120, &Cs5);
  213.    
  214.      f_close(&file);
  215. }
  216. /*
  217. *********************************************************************************************************
  218. *    函 数 名: MainTask
  219. *    功能说明: GUI主函数
  220. *    形    参: 无
  221. *    返 回 值: 无
  222. *********************************************************************************************************
  223. */
  224. void MainTask(void)
  225. {
  226.      uint16_t i;
  227.      char cDispBuf[80];
  228.    
  229.      /* 初始化 */
  230.      GUI_Init();
  231.       
  232.      /*
  233.       关于多缓冲和窗口内存设备的设置说明
  234.         1. 使能多缓冲是调用的如下函数,用户要在LCDConf_Lin_Template.c文件中配置了多缓冲,调用此函数才有效:
  235.            WM_MULTIBUF_Enable(1);
  236.         2. 窗口使能使用内存设备是调用函数:WM_SetCreateFlags(WM_CF_MEMDEV);
  237.         3. 如果emWin的配置多缓冲和窗口内存设备都支持,二选一即可,且务必优先选择使用多缓冲,实际使用
  238.            STM32F429BIT6 + 32位SDRAM + RGB565/RGB888平台测试,多缓冲可以有效的降低窗口移动或者滑动时的撕裂
  239.             感,并有效的提高流畅性,通过使能窗口使用内存设备是做不到的。
  240.         4. 所有emWin例子默认是开启三缓冲。
  241.      */
  242.      WM_MULTIBUF_Enable(1);
  243.    
  244.      /* 清屏 */
  245.      GUI_SetBkColor(GUI_BLUE);
  246.      GUI_Clear();
  247.    
  248.      /* 设置字体 */
  249.      GUI_SetFont(GUI_FONT_20_1);
  250.    
  251.      GUI_DispStringAt("1. Please make sure the song.ttf is saved in SD", 0, 0);
  252.      GUI_DispStringAt("2. if the song.ttf is not saved in SD, this lab will fail", 0, 24);
  253.    
  254.      /* 等待10s后开始进行复制,方便客户看屏幕上的显示信息 */
  255.      for(i = 0; i < 11; i++)
  256.      {
  257.          sprintf(cDispBuf, "3. 10 seconds will start, %ds..  ", 10 - i);
  258.          GUI_DispStringAt(cDispBuf, 0, 48);
  259.          GUI_Delay(1000);
  260.      }
  261.      GUI_DispStringAt("Loading song.ttf file from sdcard, please wait....", 0, 72);
  262.    
  263.      /*
  264.        触摸校准函数默认是注释掉的,电阻屏需要校准,电容屏无需校准。如果用户需要校准电阻屏的话,执行
  265.         此函数即可,会将触摸校准参数保存到EEPROM里面,以后系统上电会自动从EEPROM里面加载。
  266.      */
  267.     //TOUCH_Calibration();
  268.      /* 使能UTF-8编码 */   
  269.      GUI_UC_SetEncodeUTF8();
  270.    
  271.      /* 将字库从SD卡中加载到SP FLASH里面,加载一次即可,以后使用注释掉此函数 */
  272.      LoadFontTTF("song.ttf");
  273.    
  274.      /* 调用此函数会自动的刷新桌面窗口 */
  275.      WM_SetDesktopColor(GUI_BLUE);
  276.      /* 创建对话框 */
  277.      GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), &_cbCallback, 0, 0, 0);
  278.    
  279.      while(1)
  280.      {
  281.          GUI_Delay(10);
  282.      }
  283. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-2-6 17:05:40 | 显示全部楼层
28.7   实验例程说明(裸机)


配套例子:
    V6-539_STemWin实验_矢量全字库,支持中文,Unicode编码(裸机)
实验目的:
    1.     学习emWin矢量字体库的使用方法,Unicode编码。
    2.     emWin功能的实现在MainTask.c文件里面。
矢量字体:
    1.     相比点阵字体,矢量字体可以进行无损放缩,本工程测试了16点阵,24点阵,32点阵,48点阵,72点阵和120点阵的显示效果。
    2.     给emWin分配的动态内存大小是12MB,如果用户想测试其它矢量字体,最好不要超过11MB。emWin本身预留1MB使用。
字库存储方式:
    1.     系统上电后,将矢量字体从SD卡加载到emWin动态内存,即SDRAM里面。
实验步骤如下:
    1.     矢量库文件song.ttf已经放到本工程的Doc文件夹下。用户使用前,务必将此文件放到SD卡根目录中,系统上电后会将其加载到SDRAM里面。
    2.     板子上电后,会等待10秒钟后开始加载矢量字体到SDRAM。
实验注意:
    1.     实验所需的矢量字体库song.ttf已经存储到本工程的Doc文件夹下,使用此例子前,请务必将这个文件存储到SD卡根目录中,并将SD卡插到开发板上面。
STemWin界面显示效果:
    800*480分辨率界面效果。
28.21.png


STemWin动态内存配置:
    GUIConf.c文件中的配置如下:
  1. #define EX_SRAM   1/*1 used extern sram, 0 used internal sram */
  2. #if EX_SRAM
  3. #define GUI_NUMBYTES  (1024*1024*12)
  4. #else
  5. #define GUI_NUMBYTES  (100*1024)
  6. #endif
复制代码
    通过宏定义来配置使用内部SRAM还是外部的SDRAM做为emWin的动态内存,当配置:
#define EX_SRAM    1 表示使用外部SDRAM作为emWin动态内存,大小8MB。
#define EX_SRAM    0 表示使用内部SRAM作为emWin动态内存,大小100KB。
默认情况下,本教程配套的所有emWin例子都是用外部SDRAM作为emWin动态内存。
STemWin底层接口配置:
    LCDConf_Lin_Template.c文件中共12项emWin配置:
  1. /*
  2. **********************************************************************************************************
  3.                                           用户可以配置的选项
  4. **********************************************************************************************************
  5. */
  6. /* 0. 在官方代码的基础上再做优化,官方的部分函数效率低,耗内存, 0表示优化 */
  7. #define emWin_Optimize   0
  8. /*
  9.   1. 显示屏的物理分辨率,驱动已经做了显示屏自适应,支持4.3寸,5寸和7寸屏
  10.      这里填写自适应显示屏中的最大分辨率。
  11. */
  12. #define XSIZE_PHYS       800
  13. #define YSIZE_PHYS       480
  14. /* 2. 多缓冲 / 虚拟屏,多缓冲和虚拟屏不可同时使用,emWin不支持 */
  15. #define NUM_BUFFERS      3 /* 定义多缓冲个数,仅可以设置1,2和3,也就是最大支持三缓冲 */
  16. #define NUM_VSCREENS     1 /* 定义虚拟屏个数 */
  17. /* 3. 没有图层激活时,背景色设置, 暂时未用到 */
  18. #define BK_COLOR         GUI_DARKBLUE
  19. /*
  20.    4. 重定义图层数,对于STM32F429/439,用户可以选择一个图层或者两个图层,不支持三图层
  21.       (1). 设置GUI_NUM_LAYERS = 1时,即仅使用图层1时,默认触摸值是发送给图层1的。
  22.        (2). 设置GUI_NUM_LAYERS = 2时,即图层1和图层2都已经使能,此时图层2是顶层,
  23.             用户需要根据自己的使用情况设置如下两个地方。
  24.             a. 在bsp_touch.c文件中的函数TOUCH_InitHard里面设置参数State.Layer = 1,1就表示
  25.                给图层2发送触摸值。
  26.             b. 调用GUI_Init函数后,调用函数GUI_SelectLayer(1), 设置当前操作的是图层2。
  27. */
  28. #undef  GUI_NUM_LAYERS
  29. #define GUI_NUM_LAYERS    1
  30. /*
  31.    5. 设置图层1和图层2对应的显存地址
  32.       (1) EXT_SDRAM_ADDR 是SDRAM的首地址。
  33.       (2) LCD_LAYER0_FRAME_BUFFER 是图层1的显存地址。
  34.        (3) LCD_LAYER1_FRAME_BUFFER 是图层2的显存地址。
  35.        (4) 每个图层的显存大小比较考究,这里进行下简单的说明。
  36.            如果用户选择的颜色模式 = 32位色ARGB8888,显存的大小:
  37.            XSIZE_PHYS * YSIZE_PHYS * 4 * NUM_VSCREENS * NUM_BUFFERS
  38.          
  39.            颜色模式 = 24位色RGB888,显存的大小:
  40.            XSIZE_PHYS * YSIZE_PHYS * 3 * NUM_VSCREENS * NUM_BUFFERS
  41.          
  42.            颜色模式 = 16位色RGB566,ARGB1555, ARGB4444,AL88,那么显存的大小就是:
  43.            XSIZE_PHYS * YSIZE_PHYS * 2 * NUM_VSCREENS * NUM_BUFFERS
  44.            颜色模式 = 8位色L8,AL44,那么显存的大小就是:
  45.            XSIZE_PHYS * YSIZE_PHYS * 1 * NUM_VSCREENS * NUM_BUFFERS  
  46.      
  47.       这里为了方便起见,将开发板配套的16MB的SDRAM前8MB分配给LCD显存使用,后8MB用于emWin动态内存。
  48.        对于24位色,16位色,8位色,用户可以对其使能三缓冲,并且使能双图层。但是32位色也使能三缓冲和双
  49.        图层的话会超出8MB,所以用户根据自己的情况做显存和emWin动态内存的分配调整。
  50.          举一个例子,对于800*480分辨率的显示屏,使能32位色,三缓冲,那么最终一个图层需要的大小就是
  51.       800 * 480 * 4 * 3  = 4.394MB的空间,如果是双图层,已经超出8MB的分配范围。
  52.      
  53.       (5)为了方便起见,图层2的宏定义LCD_LAYER1_FRAME_BUFFER中的参数4是按照32位色设置的,如果用户的图层1
  54.          使用的是8位色,这里填数字1,如果是16位色,这里填2,如果是24位色,这里填3。
  55. */
  56. #define LCD_LAYER0_FRAME_BUFFER  EXT_SDRAM_ADDR
  57. #define LCD_LAYER1_FRAME_BUFFER  (LCD_LAYER0_FRAME_BUFFER + XSIZE_PHYS * YSIZE_PHYS * 4 * NUM_VSCREENS *
  58. NUM_BUFFERS)
  59. /*
  60.    6. STM32F429/439支持的颜色模式,所有模式都支持,用户可任意配置。
  61.       特别注意如下两个问题:
  62.        (1) 如果用户选择了ARGB8888或者RGB888模式,LCD闪烁比较厉害的话,
  63.            请降低LTDC的时钟大小,在文件bsp_tft_429.c的函数LCD_ConfigLTDC里面设置。
  64.            a. 一般800*480分辨率的显示屏,ARGB8888或者RGB888模式LTDC时钟选择10-20MHz即可。
  65.            b. 480*272分辨率的可以高些,取20MHz左右即可。
  66.        (2) 16位色或者8位色模式,LTDC的时钟频率一般可以比24位色或者32位色的高一倍。
  67. */
  68. #define _CM_ARGB8888      1
  69. #define _CM_RGB888        2
  70. #define _CM_RGB565        3
  71. #define _CM_ARGB1555      4
  72. #define _CM_ARGB4444      5
  73. #define _CM_L8            6
  74. #define _CM_AL44          7
  75. #define _CM_AL88          8
  76. /* 7. 配置图层1的颜色模式和分辨率大小 */
  77. #define COLOR_MODE_0      _CM_RGB565
  78. #define XSIZE_0           XSIZE_PHYS
  79. #define YSIZE_0           YSIZE_PHYS
  80. /* 8. 配置图层2的的颜色模式和分辨率大小 */
  81. #define COLOR_MODE_1      _CM_RGB565
  82. #define XSIZE_1           XSIZE_PHYS
  83. #define YSIZE_1           YSIZE_PHYS
  84. /* 9. 单图层情况下,根据用户选择的颜色模式可自动选择图层1的emWin的驱动和颜色模式 */
  85. #if   (COLOR_MODE_0 == _CM_ARGB8888)
  86.   #define COLOR_CONVERSION_0 GUICC_M8888I
  87.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_32
  88. #elif (COLOR_MODE_0 == _CM_RGB888)
  89.   #define COLOR_CONVERSION_0 GUICC_M888
  90.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_24
  91. #elif (COLOR_MODE_0 == _CM_RGB565)
  92.   #define COLOR_CONVERSION_0 GUICC_M565
  93.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_16
  94. #elif (COLOR_MODE_0 == _CM_ARGB1555)
  95.   #define COLOR_CONVERSION_0 GUICC_M1555I
  96.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_16
  97. #elif (COLOR_MODE_0 == _CM_ARGB4444)
  98.   #define COLOR_CONVERSION_0 GUICC_M4444I
  99.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_16
  100. #elif (COLOR_MODE_0 == _CM_L8)
  101.   #define COLOR_CONVERSION_0 GUICC_8666
  102.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_8
  103. #elif (COLOR_MODE_0 == _CM_AL44)
  104.   #define COLOR_CONVERSION_0 GUICC_1616I
  105.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_8
  106. #elif (COLOR_MODE_0 == _CM_AL88)
  107.   #define COLOR_CONVERSION_0 GUICC_88666I
  108.   #define DISPLAY_DRIVER_0   GUIDRV_LIN_16
  109. #else
  110.   #error Illegal color mode 0!
  111. #endif
  112. /* 10. 双图层情况下,根据用户选择的颜色模式可自动选择图层2的emWin的驱动和颜色模式 */
  113. #if (GUI_NUM_LAYERS > 1)
  114. #if   (COLOR_MODE_1 == _CM_ARGB8888)
  115.   #define COLOR_CONVERSION_1 GUICC_M8888I
  116.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_32
  117. #elif (COLOR_MODE_1 == _CM_RGB888)
  118.   #define COLOR_CONVERSION_1 GUICC_M888
  119.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_24
  120. #elif (COLOR_MODE_1 == _CM_RGB565)
  121.   #define COLOR_CONVERSION_1 GUICC_M565
  122.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_16
  123. #elif (COLOR_MODE_1 == _CM_ARGB1555)
  124.   #define COLOR_CONVERSION_1 GUICC_M1555I
  125.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_16
  126. #elif (COLOR_MODE_1 == _CM_ARGB4444)
  127.   #define COLOR_CONVERSION_1 GUICC_M4444I
  128.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_16
  129. #elif (COLOR_MODE_1 == _CM_L8)
  130.   #define COLOR_CONVERSION_1 GUICC_8666
  131.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_8
  132. #elif (COLOR_MODE_1 == _CM_AL44)
  133.   #define COLOR_CONVERSION_1 GUICC_1616I
  134.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_8
  135. #elif (COLOR_MODE_1 == _CM_AL88)
  136.   #define COLOR_CONVERSION_1 GUICC_88666I
  137.   #define DISPLAY_DRIVER_1   GUIDRV_LIN_16
  138. #else
  139.   #error Illegal color mode 1!
  140. #endif
  141. #else
  142. #undef XSIZE_0
  143. #undef YSIZE_0
  144. #define XSIZE_0       XSIZE_PHYS
  145. #define YSIZE_0       YSIZE_PHYS
  146. #endif
  147. /*11. 配置选项检测,防止配置错误或者某些选项没有配置 */
  148. #ifndef   XSIZE_PHYS
  149.   #error Physical X size of display is not defined!
  150. #endif
  151. #ifndef   YSIZE_PHYS
  152.   #error Physical Y size of display is not defined!
  153. #endif
  154. #ifndef   NUM_VSCREENS
  155.   #define NUM_VSCREENS 1
  156. #else
  157.   #if (NUM_VSCREENS <= 0)
  158.     #error At least one screeen needs to be defined!
  159.   #endif
  160. #endif
  161. #if (NUM_VSCREENS > 1) && (NUM_BUFFERS > 1)
  162.   #error Virtual screens and multiple buffers are not allowed!
  163. #endif
复制代码
    对于这12个配置选项,注释说明已经比较详细。默认情况下,本教程配套的emWin例子都是用的三缓冲,RGB565格式,且仅使用单图层。
程序设计:
栈大小分配:
    系统栈大小在startup_stm32f429_439xx.s文件中配置:
28.22.png

    栈大小的单位是字节,那么这里配置的系统栈大小就是8192字节。
主函数初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main (void)
  10. {   
  11.      /* 初始化外设 */
  12.      bsp_Init();
  13.      /* 进入emWin主函数 */
  14.      MainTask();
  15. }
复制代码
硬件外设初始化
    硬件外设的初始化是在bsp.c文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.      /*
  12.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  15.      */
  16.      /* 使能CRC 因为使用STemWin前必须要使能 */
  17.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
  18.    
  19.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  20.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  21.    
  22.      SystemCoreClockUpdate();    /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */
  23.      bsp_InitUart();        /* 初始化串口 */
  24.      bsp_InitKey();         /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */
  25.    
  26.      bsp_InitExtIO();       /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */
  27.      bsp_InitLed();         /* 初始LED指示灯端口 */
  28.    
  29.      bsp_InitI2C();         /* 配置I2C总线 */
  30.      bsp_InitSPIBus();       /* 配置SPI总线 */
  31.    
  32.      bsp_InitSFlash();       /* 初始化SPI Flash */
  33.    
  34.      bsp_InitExtSDRAM();   /* 初始化SDRAM */
  35.      bsp_DetectLcdType();  /* 检测触摸板和LCD面板型号, 结果存在全局变量 g_TouchType, g_LcdType */
  36.    
  37.      TOUCH_InitHard();    /* 初始化配置触摸芯片 */
  38.      LCD_ConfigLTDC();     /* 初始化配置LTDC */
  39.    
  40.      result = f_mount(&fs, "0:/", 0);     /* 挂载文件系统 */
  41. }
复制代码
emWin功能的具体实现(在MainTask.c文件里面):
  1. #include "MainTask.h"
  2. #include "bsp.h"
  3. /*
  4. *********************************************************************************************************
  5. *                                      定义矢量字体
  6. *********************************************************************************************************
  7. */
  8. GUI_TTF_CS Cs0, Cs1, Cs2, Cs3, Cs4, Cs5;
  9. GUI_TTF_DATA Data;
  10. GUI_FONT Font16, Font24, Font32, Font48, Font72, Font120;
  11. /*
  12. *********************************************************************************************************
  13. *                                                       对话框信息
  14. *********************************************************************************************************
  15. */
  16. static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
  17. { FRAMEWIN_CreateIndirect,  "安富莱电子矢量字体展示,支持抗锯齿",     0,        0,  0,  800, 480,0, 0},
  18. { BUTTON_CreateIndirect,    "安富莱电子",     GUI_ID_BUTTON0,  30, 330, 400, 70, 0, 0},
  19. { TEXT_CreateIndirect,      "安富莱电子AaAa-16点半角全角",   GUI_ID_TEXT0,   0, 0, 800, 16, 0,0},
  20. { TEXT_CreateIndirect,      "安富莱电子AaAa-24点半角全角",   GUI_ID_TEXT1,   0, 16, 800, 24, 0,0},
  21. { TEXT_CreateIndirect,      "安富莱电子AaAa-32点半角全角",   GUI_ID_TEXT2,   0, 40, 800, 32, 0,0},
  22. { TEXT_CreateIndirect,      "安富莱电子AaAa-48点半角全角",   GUI_ID_TEXT3,   0, 72, 800, 48, 0,0},
  23. { TEXT_CreateIndirect,      "安富莱电子AaAa-72点",           GUI_ID_TEXT4,   0, 120, 800, 72, 0,0},
  24. { TEXT_CreateIndirect,      "安富莱电子120点",                 GUI_ID_TEXT5,   0, 192, 800, 120, 0,0},
  25. };
  26. /*
  27. *********************************************************************************************************
  28. *    函 数 名: PaintDialog
  29. *    功能说明: 重绘
  30. *    形    参:pMsg  消息指针
  31. *    返 回 值: 无
  32. *********************************************************************************************************
  33. */
  34. void PaintDialog(WM_MESSAGE * pMsg)
  35. {
  36. }
  37. /*
  38. *********************************************************************************************************
  39. *    函 数 名: InitDialog
  40. *    功能说明: 对话框初始化
  41. *    形    参: pMsg 消息指针
  42. *    返 回 值: 无
  43. *********************************************************************************************************
  44. */
  45. void InitDialog(WM_MESSAGE * pMsg)
  46. {
  47.     WM_HWIN hWin = pMsg->hWin;
  48.    
  49.      //
  50.     // 框架窗口设置
  51.     //  
  52.     FRAMEWIN_SetFont(hWin,&Font32);
  53.     FRAMEWIN_SetTextAlign(hWin,GUI_TA_VCENTER|GUI_TA_CENTER);
  54.     FRAMEWIN_AddCloseButton(hWin, FRAMEWIN_BUTTON_RIGHT, 0);
  55.     FRAMEWIN_AddMaxButton(hWin, FRAMEWIN_BUTTON_RIGHT, 1);
  56.     FRAMEWIN_AddMinButton(hWin, FRAMEWIN_BUTTON_RIGHT, 2);
  57.     FRAMEWIN_SetTitleHeight(hWin,35);
  58.    
  59.      //
  60.     // 按钮控件设置
  61.     //
  62.     BUTTON_SetFont(WM_GetDialogItem(hWin,GUI_ID_BUTTON0),&Font48);
  63.    
  64.     //
  65.     // 文本控件设置
  66.     //
  67.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT0), GUI_BLACK);
  68.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT0), &Font16);
  69.    
  70.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT1), GUI_BLUE);
  71.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT1), &Font24);
  72.    
  73.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT2), GUI_ORANGE);
  74.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT2), &Font32);
  75.    
  76.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT3), GUI_MAGENTA);
  77.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT3), &Font48);
  78.    
  79.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT4), GUI_BLUE);
  80.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT4), &Font72);
  81.    
  82.      TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT5), GUI_RED);
  83.      TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT5), &Font120);
  84. }
  85. /*
  86. *********************************************************************************************************
  87. *    函 数 名: _cbCallback
  88. *    功能说明: 对话框回调函数
  89. *    形    参: 无
  90. *    返 回 值: 无
  91. *********************************************************************************************************
  92. */
  93. static void _cbCallback(WM_MESSAGE * pMsg)
  94. {
  95.     int NCode, Id;
  96.     WM_HWIN hWin = pMsg->hWin;
  97.     switch (pMsg->MsgId)
  98.     {
  99.         case WM_PAINT:
  100.             PaintDialog(pMsg);
  101.             break;
  102.         
  103.         case WM_INIT_DIALOG:
  104.             InitDialog(pMsg);
  105.             break;
  106.         
  107.         case WM_KEY:
  108.             switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key)
  109.             {
  110.                 case GUI_KEY_ESCAPE:
  111.                     GUI_EndDialog(hWin, 1);
  112.                     break;
  113.                 case GUI_KEY_ENTER:
  114.                     GUI_EndDialog(hWin, 0);
  115.                     break;
  116.             }
  117.             break;
  118.             
  119.         case WM_NOTIFY_PARENT:
  120.             Id = WM_GetId(pMsg->hWinSrc);
  121.             NCode = pMsg->Data.v;      
  122.             switch (Id)
  123.             {
  124.                 case GUI_ID_OK:
  125.                     if(NCode==WM_NOTIFICATION_RELEASED)
  126.                         GUI_EndDialog(hWin, 0);
  127.                     break;
  128.                      
  129.                 case GUI_ID_CANCEL:
  130.                     if(NCode==WM_NOTIFICATION_RELEASED)
  131.                         GUI_EndDialog(hWin, 0);
  132.                     break;
  133.             }
  134.             break;
  135.             
  136.         default:
  137.             WM_DefaultProc(pMsg);
  138.     }
  139. }
  140. /*
  141. *********************************************************************************************************
  142. *    函 数 名: LoadFontTTF
  143. *    功能说明: 从SD卡中读取矢量字体库到SDRAM中并创建矢量字体
  144. *    形    参: sFilename  要读取的文件名
  145. *    返 回 值: 无
  146. *********************************************************************************************************
  147. */
  148. void LoadFontTTF(const char *sFilename)
  149. {
  150.      char *_acBuffer;
  151.      GUI_HMEM hMem;
  152.    
  153.      /* 打开文件 */        
  154.      result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
  155.      if (result != FR_OK)
  156.      {
  157.          return;
  158.      }
  159.       
  160.      /* 申请一块内存空间 并且将其清零 */
  161.      hMem = GUI_ALLOC_AllocZero(file.fsize);
  162.    
  163.      /* 将申请到内存的句柄转换成指针类型 */
  164.      _acBuffer = GUI_ALLOC_h2p(hMem);
  165.      /* 读取文件到动态内存 */
  166.      result = f_read(&file, _acBuffer, file.fsize, &bw);
  167.      if (result != FR_OK)
  168.      {
  169.          return;
  170.      }
  171.      /* 设置参数 */
  172.      Data.pData = _acBuffer;
  173.      Data.NumBytes = file.fsize;
  174.      /* 设置第1种字体显示方式 */
  175.      Cs0.pTTF = &Data;       /* 矢量字体数据地址 */
  176.      Cs0.PixelHeight = 16;   /* 字体高度 */
  177.      Cs0.FaceIndex = 0;
  178.    
  179.      /* 设置第2种字体显示方式 */
  180.      Cs1.pTTF = &Data;       /* 矢量字体数据地址 */
  181.      Cs1.PixelHeight = 24;   /* 字体高度 */
  182.      Cs1.FaceIndex = 0;
  183.    
  184.    
  185.      /* 设置第3种字体显示方式 */
  186.      Cs2.pTTF = &Data;       /* 矢量字体数据地址 */
  187.      Cs2.PixelHeight = 32;   /* 字体高度 */
  188.      Cs2.FaceIndex = 0;
  189.    
  190.      /* 设置第4种字体显示方式 */
  191.      Cs3.pTTF = &Data;      /* 矢量字体数据地址 */
  192.      Cs3.PixelHeight = 48;  /* 字体高度 */
  193.      Cs3.FaceIndex = 0;
  194.    
  195.    
  196.      /* 设置第5种字体显示方式 */
  197.      Cs4.pTTF = &Data;      /* 矢量字体数据地址 */
  198.      Cs4.PixelHeight = 72;  /* 字体高度 */
  199.      Cs4.FaceIndex = 0;
  200.    
  201.      /* 设置第6种字体显示方式 */
  202.      Cs5.pTTF = &Data;    /* 矢量字体数据地址 */
  203.      Cs5.PixelHeight = 120; /* 字体高度 */
  204.      Cs5.FaceIndex = 0;
  205.    
  206.      /* 创建6种字体 */
  207.      GUI_TTF_CreateFontAA(&Font16, &Cs0);
  208.      GUI_TTF_CreateFontAA(&Font24, &Cs1);
  209.      GUI_TTF_CreateFontAA(&Font32, &Cs2);
  210.      GUI_TTF_CreateFontAA(&Font48, &Cs3);
  211.      GUI_TTF_CreateFontAA(&Font72, &Cs4);
  212.      GUI_TTF_CreateFontAA(&Font120, &Cs5);
  213.    
  214.      f_close(&file);
  215. }
  216. /*
  217. *********************************************************************************************************
  218. *    函 数 名: MainTask
  219. *    功能说明: GUI主函数
  220. *    形    参: 无
  221. *    返 回 值: 无
  222. *********************************************************************************************************
  223. */
  224. void MainTask(void)
  225. {
  226.      uint16_t i;
  227.      char cDispBuf[80];
  228.    
  229.      /* 初始化 */
  230.      GUI_Init();
  231.       
  232.      /*
  233.       关于多缓冲和窗口内存设备的设置说明
  234.         1. 使能多缓冲是调用的如下函数,用户要在LCDConf_Lin_Template.c文件中配置了多缓冲,调用此函数才有效:
  235.            WM_MULTIBUF_Enable(1);
  236.         2. 窗口使能使用内存设备是调用函数:WM_SetCreateFlags(WM_CF_MEMDEV);
  237.         3. 如果emWin的配置多缓冲和窗口内存设备都支持,二选一即可,且务必优先选择使用多缓冲,实际使用
  238.            STM32F429BIT6 + 32位SDRAM + RGB565/RGB888平台测试,多缓冲可以有效的降低窗口移动或者滑动时的撕裂
  239.            感,并有效的提高流畅性,通过使能窗口使用内存设备是做不到的。
  240.         4. 所有emWin例子默认是开启三缓冲。
  241.      */
  242.      WM_MULTIBUF_Enable(1);
  243.    
  244.      /* 清屏 */
  245.      GUI_SetBkColor(GUI_BLUE);
  246.      GUI_Clear();
  247.    
  248.      /* 设置字体 */
  249.      GUI_SetFont(GUI_FONT_20_1);
  250.    
  251.      GUI_DispStringAt("1. Please make sure the song.ttf is saved in SD", 0, 0);
  252.      GUI_DispStringAt("2. if the song.ttf is not saved in SD, this lab will fail", 0, 24);
  253.    
  254.      /* 等待10s后开始进行复制,方便客户看屏幕上的显示信息 */
  255.      for(i = 0; i < 11; i++)
  256.      {
  257.          sprintf(cDispBuf, "3. 10 seconds will start, %ds..  ", 10 - i);
  258.          GUI_DispStringAt(cDispBuf, 0, 48);
  259.          GUI_Delay(1000);
  260.      }
  261.      GUI_DispStringAt("Loading song.ttf file from sdcard, please wait....", 0, 72);
  262.    
  263.      /*
  264.        触摸校准函数默认是注释掉的,电阻屏需要校准,电容屏无需校准。如果用户需要校准电阻屏的话,执行
  265.         此函数即可,会将触摸校准参数保存到EEPROM里面,以后系统上电会自动从EEPROM里面加载。
  266.      */
  267.     //TOUCH_Calibration();
  268.      /* 使能UTF-8编码 */   
  269.      GUI_UC_SetEncodeUTF8();
  270.    
  271.      /* 将字库从SD卡中加载到SP FLASH里面,加载一次即可,以后使用注释掉此函数 */
  272.      LoadFontTTF("song.ttf");
  273.    
  274.      /* 调用此函数会自动的刷新桌面窗口 */
  275.      WM_SetDesktopColor(GUI_BLUE);
  276.      /* 创建对话框 */
  277.      GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), &_cbCallback, 0, 0, 0);
  278.    
  279.      while(1)
  280.      {
  281.          GUI_Delay(10);
  282.      }
  283. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2017-2-6 17:06:09 | 显示全部楼层
28.8  总结


    本章节为大家讲解的矢量字体是可以用于项目实战的,实际项目中建议使用大容量的SDRAM,这样即使加载矢量字库后,还有大量空间供emWin动态内存使用。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-17 00:55 , Processed in 0.262441 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表