基于ST7789TFT移植emWin

原创 嵌入式Lee 2024-05-27 13:23

一. 前言

嵌入式GUI是嵌入式开发中经常要用到的组件,上一篇我们分享了LVGL的移植和使用,LVGL得益于其免费开源的策略,以及社区的不断开发维护,功能很完善,使用简单,资源多,现在越来越流行。提到嵌入式GUI这里免不得要提到嵌入式GUI领域曾经绝对的爆款uC/GUI,虽然它实际就是emWin,但是uC/GUI更出名,相信很多人就是通过其接触的嵌入式GUI开发的,甚是怀念当初对着3.9版本的源码以及其文档,买一本计算机图形学的书籍,从画点,到画线等算法,到各个组件开发,学习的过程。而提到uC/GUI又免不得要回忆下Micrium及其其提供的嵌入式开发的uC/XX全家桶。

相信很多嵌入式开发者对Micrium有着很深的感情,uC/XXX全家桶提供了常用嵌入式开发组件,基本是一条龙整套的解决方案。其提供的源码,文档是学习的宝贵资料,其源码的风格和规范,文档的组织与详尽程度是我目前所遇到的最最顶流,个人对于创始人Jean J.Labrosse也是非常的倾佩,其分享精神值得敬佩,其各个组件的文档比任何一本相关的书籍都适合作为学习使用,尤其是那本著名的《μC/OS, The Real-Time Kernel》是很多人入门RTOS的圣经,配合其源码,本书是至高无上学习RTOS的绝佳宝典,uC/OS最早很多人接触可能是通过邵贝贝翻译的本书来了解的,也是该翻译版让uC/OS甚至RTOS在国内风靡。个人更倾向于直接阅读官网原版文档,当时自己就是打印了官方的文档,反复阅读,翻到每一页都掉渣,直到每一行代码都彻底搞懂,也是从此自己完全掌握了RTOS的原理,也可以毫无压力的自行实现一个RTOS,现在各种RTOS满天飞,其实万变不离其宗。到后来研究文件系统,研究tcp/ip协议栈,USB协议栈等等都是基于Micrium的源码和文档进行的。所以可以说个人嵌入式开发的功力,有一大半是Micrium提供的,相信也有很多类似经历的嵌入式开发者会深有同感。

Micrium以提供uC/OSuC/OSII而闻名,还包括其他很多的嵌入式组件,有些是自己开发的,而有些实际并不是Micrium自己开发的,但是通过商业手段纳入了自己的商业版图,这也是商业上的一个决策,毕竟提供一整套嵌入式解决方案是很有吸引力的,我之前在某电力行业头部企业工作公司就采购了uC/FSuC/OSIII,而采购uC/FS就是为了解决文件系统损坏的问题而推动的,最终也不负所望,uC/FS确实其可靠性经得起考验。。

自从Silicon Labs收购Micrium(现在的网址是https://www.silabs.com/developers/micrium),相应的也对uC/XXX全家桶进行了免费开源而之前uC/OS等源码是开源但并不是免费的。现在由weston-embedded进行维护,网址:https://weston-embedded.com/micrium/overview.而其文档也可从https://micrium.atlassian.net/wiki/spaces获取(强烈推荐,其文档是相关组件开发绝佳的学习资料),代码可以从https://github.com/weston-embedded/获取。

而做过GUI开发的相信对uC/GUI也会印象深刻,流出的3.9版本的源码,以及其对应的DOC文档,也是学习GUI的绝佳资料,实际uC/GUI并不是Micrium自己开发的,而是SEGGERemWin参考官网:https://www.segger.com/products/user-interface/emwin/,同时STM32STemWin也是来源于emWin(其是通过lib库提供的,不提供源码,用过的肯定知道其一个防止在非STM32芯片上使用的一个小招数即必须开启CRCRCC时钟)。而记得自已12年的第一份工作中就是使用uC/GUI设计了一个摩托车的仪表GUI,虽然只是作为演示并没有产品化,但也是实战的第一步,映像深刻。

这一篇我们就以网上能找到的比较新的版本的emWin506为例,分享其移植移植使用。

二. 获取源码

emWin是商业软件,不管是STemWin(使用STM32的芯片可以免费使用其库)还是uC/GUI实际都是不提供源码的(早期uC/GUI版本3左右是有源码的,网上能找到),都是以库形式提供。现在网上可以找到emWin5.06的源码,我们就以其来分享移植和使用。这里分享一个下载地址,仅供学习之用,如需使用可以购买商业授权。

链接:https://pan.baidu.com/s/11R3ySVSEXHwOCYc8ZvLYdQ?pwd=qgwb

提取码:qgwb

.移植准备

emWin506-Src复制到自己的工程目录,添加以下文件到工程

emWin506-Src/GUI/Antialias/*.cemWin506-Src/GUI/ConvertColor/*.cemWin506-Src/GUI/ConvertMono/*.cemWin506-Src/GUI/Core/*.cemWin506-Src/GUI/Font/*.cemWin506-Src/GUI/MemDev/*.cemWin506-Src/GUI/Widget/*.cemWin506-Src/GUI/WM/*.c

添加以下头文件包含路径

emWin506-Src/GUI/Core/emWin506-Src/GUI/WM/emWin506-Src/GUI/Widget

然后复制以下配置和接口文件到自己的工程中去,并添加头文件包含路径,以下文件分别是GUI需要实现的接口和配置,LCD需要实现的接口的配置,显示驱动接口。

GUI_X.c

LCD_X.c

GUIConf.h

LCDConf.h

GUIDRV_Template.c

GUIDRV_Template.h

现在就一般就可以编译通过了,或者可能有一两处问题,后面移植过程再修改。

.移植

4.1 显示移植

即前面的GUIDRV_Template.cGUIDRV_Template.h的实现。

可以复制GUI\DisplayDriver下的GUIDRV_Template.c/h,并添加到工程,放在GUI源码路径外,因为属于需要适配的实现,GUI的源码是无需任何修改的和其分开,当然也要添加头文件包含路径。

显示需要在GUIDRV_Template.c中实现结构体GUIDRV_Template_API,实际模板已经实现了框架,最低只需要用户实现

_SetPixelIndex_GetPixelIndex两个函数,其他接口在优化性能时可以优化,比如_FillRect等,默认是基于前面的_SetPixelIndex_GetPixelIndex两个接口实现。

GUI.hWIN32定义了,且宏LCD_SIMCONTROLLER0则使用GUIDRV_Win_API否则使用GUIDRV_Template_API,我们这里就是要实现GUIDRV_Template_API

/***********************************************************************       Display drivers*///// Addresses//extern const GUI_DEVICE_API GUIDRV_Win_API;
extern const GUI_DEVICE_API GUIDRV_Template_API;
//// Macros to be used in configuration files//#define GUIDRV_WIN32       &GUIDRV_Win_API
#if defined(WIN32) && !defined(LCD_SIMCONTROLLER)
  #define GUIDRV_TEMPLATE         &GUIDRV_Win_API
#else
  #define GUIDRV_TEMPLATE         &GUIDRV_Template_API
#endif

我这里实现的GUIDRV_Template.c如下,实际只需要修改两处,即写点和读点处,调用我们之前的st7789的接口实现

/**********************************************************************                SEGGER Microcontroller GmbH & Co. KG                **        Solutions for real time microcontroller applications        ************************************************************************                                                                    **        (c) 1996 - 2010  SEGGER Microcontroller GmbH & Co. KG       **                                                                    **        Internet: www.segger.com    Support:  support@segger.com    **                                                                    ***********************************************************************
** emWin V5.06 - Graphical user interface for embedded applications **emWin is protected by international copyright laws.   Knowledge of thesource code may not be used to write a similar product.  This file mayonly be used in accordance with a license and should not be re-distributed in any way. We appreciate your understanding and fairness.----------------------------------------------------------------------File        : GUIDRV_Template.cPurpose     : Template driver, should be used as starting point              for new display drivers.---------------------------END-OF-HEADER------------------------------*/
#include #include #include "st7789_itf.h"#include "LCD_Private.h"#include "GUI_Private.h"#include "LCD_SIM.h"#include "LCD_ConfDefaults.h"
/***********************************************************************       Defines************************************************************************//***********************************************************************       Macros for MIRROR_, SWAP_ and LUT_*/#if (!defined (LCD_LUT_COM) && !defined(LCD_LUT_SEG))  #if   (!LCD_MIRROR_X && !LCD_MIRROR_Y && !LCD_SWAP_XY)     #define LOG2PHYS_X(x, y) x    #define LOG2PHYS_Y(x, y) y  #elif (!LCD_MIRROR_X && !LCD_MIRROR_Y &&  LCD_SWAP_XY)     #define LOG2PHYS_X(x, y) y    #define LOG2PHYS_Y(x, y) x  #elif (!LCD_MIRROR_X &&  LCD_MIRROR_Y && !LCD_SWAP_XY)     #define LOG2PHYS_X(x, y) x    #define LOG2PHYS_Y(x, y) LCD_YSIZE - 1 - (y)  #elif (!LCD_MIRROR_X &&  LCD_MIRROR_Y &&  LCD_SWAP_XY)     #define LOG2PHYS_X(x, y) y    #define LOG2PHYS_Y(x, y) LCD_XSIZE - 1 - (x)  #elif ( LCD_MIRROR_X && !LCD_MIRROR_Y && !LCD_SWAP_XY)     #define LOG2PHYS_X(x, y) LCD_XSIZE - 1 - (x)    #define LOG2PHYS_Y(x, y) y  #elif ( LCD_MIRROR_X && !LCD_MIRROR_Y &&  LCD_SWAP_XY)     #define LOG2PHYS_X(x, y) LCD_YSIZE - 1 - (y)    #define LOG2PHYS_Y(x, y) x  #elif ( LCD_MIRROR_X &&  LCD_MIRROR_Y && !LCD_SWAP_XY)     #define LOG2PHYS_X(x, y) LCD_XSIZE - 1 - (x)    #define LOG2PHYS_Y(x, y) LCD_YSIZE - 1 - (y)  #elif ( LCD_MIRROR_X &&  LCD_MIRROR_Y &&  LCD_SWAP_XY)     #define LOG2PHYS_X(x, y) LCD_YSIZE - 1 - (y)    #define LOG2PHYS_Y(x, y) LCD_XSIZE - 1 - (x)  #endif#else  #if   ( defined (LCD_LUT_COM) && !defined(LCD_LUT_SEG))    #define LOG2PHYS_X(x, y) x    #define LOG2PHYS_Y(x, y) LCD__aLine2Com0[y]  #elif (!defined (LCD_LUT_COM) &&  defined(LCD_LUT_SEG))    #define LOG2PHYS_X(x, y) LCD__aCol2Seg0[x]    #define LOG2PHYS_Y(x, y) y  #elif ( defined (LCD_LUT_COM) &&  defined(LCD_LUT_SEG))    #define LOG2PHYS_X(x, y) LCD__aCol2Seg0[x]    #define LOG2PHYS_Y(x, y) LCD__aLine2Com0[y]  #endif#endif
/***********************************************************************       Types************************************************************************/typedef struct {  U32 VRAMAddr;  int xSize, ySize;  int vxSize, vySize;  int vxSizePhys;  int BitsPerPixel;} DRIVER_CONTEXT;
/***********************************************************************       Static functions************************************************************************//***********************************************************************       _SetPixelIndex** Purpose:*   Sets the index of the given pixel. The upper layers*   calling this routine make sure that the coordinates are in range, so*   that no check on the parameters needs to be performed.*/static void _SetPixelIndex(GUI_DEVICE * pDevice, int x, int y, int PixelIndex) {  #ifdef WIN32    LCDSIM_SetPixelIndex(x, y, PixelIndex, pDevice->LayerIndex);  #else    //    // Convert logical into physical coordinates (Dep. on LCDConf.h)    //    #if (LCD_MIRROR_X == 1) || (LCD_MIRROR_Y == 1) || (LCD_SWAP_XY == 1)      int xPhys, yPhys;
      xPhys = LOG2PHYS_X(x, y);      yPhys = LOG2PHYS_Y(x, y);    #else      #define xPhys x      #define yPhys y    #endif    GUI_USE_PARA(pDevice);    GUI_USE_PARA(x);    GUI_USE_PARA(y);    GUI_USE_PARA(PixelIndex);    {      //      // Write into hardware ... Adapt to your system      //      // TBD by customer...      //      st7789_itf_set_pixel(x,y,PixelIndex);      //printf("%d %d %x\r\n",x,y,PixelIndex);    }    #if (LCD_MIRROR_X == 0) && (LCD_MIRROR_Y == 0) && (LCD_SWAP_XY == 0)      #undef xPhys      #undef yPhys    #endif  #endif}
/***********************************************************************       _GetPixelIndex** Purpose:*   Returns the index of the given pixel. The upper layers*   calling this routine make sure that the coordinates are in range, so*   that no check on the parameters needs to be performed.*/static unsigned int _GetPixelIndex(GUI_DEVICE * pDevice, int x, int y) {  unsigned int PixelIndex;  #ifdef WIN32    PixelIndex = LCDSIM_GetPixelIndex(x, y, pDevice->LayerIndex);  #else    //    // Convert logical into physical coordinates (Dep. on LCDConf.h)    //    #if (LCD_MIRROR_X == 1) || (LCD_MIRROR_Y == 1) || (LCD_SWAP_XY == 1)      int xPhys, yPhys;
      xPhys = LOG2PHYS_X(x, y);      yPhys = LOG2PHYS_Y(x, y);    #else      #define xPhys x      #define yPhys y    #endif    GUI_USE_PARA(pDevice);    GUI_USE_PARA(x);    GUI_USE_PARA(y);    {      //      // Write into hardware ... Adapt to your system      //      // TBD by customer...      //      //PixelIndex = 0;      PixelIndex = st7789_itf_get_pixel(x,y);    }    #if (LCD_MIRROR_X == 0) && (LCD_MIRROR_Y == 0) && (LCD_SWAP_XY == 0)      #undef xPhys      #undef yPhys    #endif  #endif  return PixelIndex;}
/***********************************************************************       _XorPixel*/static void _XorPixel(GUI_DEVICE * pDevice, int x, int y) {  LCD_PIXELINDEX PixelIndex;  LCD_PIXELINDEX IndexMask;
  PixelIndex = _GetPixelIndex(pDevice, x, y);  IndexMask  = pDevice->pColorConvAPI->pfGetIndexMask();  _SetPixelIndex(pDevice, x, y, PixelIndex ^ IndexMask);}
/***********************************************************************       _DrawHLine*/static void _DrawHLine  (GUI_DEVICE * pDevice, int x0, int y,  int x1) {  LCD_PIXELINDEX ColorIndex;
  if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR) {    for (; x0 <= x1; x0++) {      _XorPixel(pDevice, x0, y);    }  } else {    ColorIndex = LCD__GetColorIndex();    for (; x0 <= x1; x0++) {      _SetPixelIndex(pDevice, x0, y, ColorIndex);    }  }}
/***********************************************************************       _DrawVLine, not optimized*/static void _DrawVLine  (GUI_DEVICE * pDevice, int x, int y0,  int y1) {  LCD_PIXELINDEX ColorIndex;
  if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR) {    for (; y0 <= y1; y0++) {      _XorPixel(pDevice, x, y0);    }  } else {    ColorIndex = LCD__GetColorIndex();    for (; y0 <= y1; y0++) {      _SetPixelIndex(pDevice, x, y0, ColorIndex);    }  }}
/***********************************************************************       _FillRect*/static void _FillRect(GUI_DEVICE * pDevice, int x0, int y0, int x1, int y1) {  for (; y0 <= y1; y0++) {    _DrawHLine(pDevice, x0, y0, x1);  }}
/***********************************************************************       Draw Bitmap 1 BPP*/static void _DrawBitLine1BPP(GUI_DEVICE * pDevice, unsigned x, unsigned y, U8 const GUI_UNI_PTR * p, int Diff, int xsize, const LCD_PIXELINDEX * pTrans) {  LCD_PIXELINDEX IndexMask, Index0, Index1, Pixel;
  Index0 = *(pTrans + 0);  Index1 = *(pTrans + 1);  x += Diff;  switch (GUI_Context.DrawMode & (LCD_DRAWMODE_TRANS | LCD_DRAWMODE_XOR)) {  case 0:    do {      _SetPixelIndex(pDevice, x++, y, (*p & (0x80 >> Diff)) ? Index1 : Index0);      if (++Diff == 8) {        Diff = 0;        p++;      }    } while (--xsize);    break;  case LCD_DRAWMODE_TRANS:    do {      if (*p & (0x80 >> Diff))        _SetPixelIndex(pDevice, x, y, Index1);      x++;      if (++Diff == 8) {        Diff = 0;        p++;      }    } while (--xsize);    break;  case LCD_DRAWMODE_XOR | LCD_DRAWMODE_TRANS:  case LCD_DRAWMODE_XOR:    IndexMask = pDevice->pColorConvAPI->pfGetIndexMask();    do {      if (*p & (0x80 >> Diff)) {        Pixel = _GetPixelIndex(pDevice, x, y);        _SetPixelIndex(pDevice, x, y, Pixel ^ IndexMask);      }      x++;      if (++Diff == 8) {        Diff = 0;        p++;      }    } while (--xsize);    break;  }}
/***********************************************************************       Draw Bitmap 2 BPP*/static void  _DrawBitLine2BPP(GUI_DEVICE * pDevice, int x, int y, U8 const GUI_UNI_PTR * p, int Diff, int xsize, const LCD_PIXELINDEX * pTrans) {  LCD_PIXELINDEX Pixels, PixelIndex;  int CurrentPixel, Shift, Index;
  Pixels = *p;  CurrentPixel = Diff;  x += Diff;  switch (GUI_Context.DrawMode & (LCD_DRAWMODE_TRANS | LCD_DRAWMODE_XOR)) {  case 0:    if (pTrans) {      do {        Shift = (3 - CurrentPixel) << 1;        Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift;        PixelIndex = *(pTrans + Index);        _SetPixelIndex(pDevice, x++, y, PixelIndex);        if (++CurrentPixel == 4) {          CurrentPixel = 0;          Pixels = *(++p);        }      } while (--xsize);    } else {      do {        Shift = (3 - CurrentPixel) << 1;        Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift;        _SetPixelIndex(pDevice, x++, y, Index);        if (++CurrentPixel == 4) {          CurrentPixel = 0;          Pixels = *(++p);        }      } while (--xsize);    }    break;  case LCD_DRAWMODE_TRANS:    if (pTrans) {      do {        Shift = (3 - CurrentPixel) << 1;        Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift;        if (Index) {          PixelIndex = *(pTrans + Index);          _SetPixelIndex(pDevice, x, y, PixelIndex);        }        x++;        if (++CurrentPixel == 4) {          CurrentPixel = 0;          Pixels = *(++p);        }      } while (--xsize);    } else {      do {        Shift = (3 - CurrentPixel) << 1;        Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift;        if (Index) {          _SetPixelIndex(pDevice, x, y, Index);        }        x++;        if (++CurrentPixel == 4) {          CurrentPixel = 0;          Pixels = *(++p);        }      } while (--xsize);    }    break;  }}
/***********************************************************************       Draw Bitmap 4 BPP*/static void  _DrawBitLine4BPP(GUI_DEVICE * pDevice, int x, int y, U8 const GUI_UNI_PTR * p, int Diff, int xsize, const LCD_PIXELINDEX * pTrans) {  LCD_PIXELINDEX Pixels, PixelIndex;  int CurrentPixel, Shift, Index;
  Pixels = *p;  CurrentPixel = Diff;  x += Diff;  switch (GUI_Context.DrawMode & (LCD_DRAWMODE_TRANS | LCD_DRAWMODE_XOR)) {  case 0:    if (pTrans) {      do {        Shift = (1 - CurrentPixel) << 2;        Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift;        PixelIndex = *(pTrans + Index);        _SetPixelIndex(pDevice, x++, y, PixelIndex);        if (++CurrentPixel == 2) {          CurrentPixel = 0;          Pixels = *(++p);        }      } while (--xsize);    } else {      do {        Shift = (1 - CurrentPixel) << 2;        Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift;        _SetPixelIndex(pDevice, x++, y, Index);        if (++CurrentPixel == 2) {          CurrentPixel = 0;          Pixels = *(++p);        }      } while (--xsize);    }    break;  case LCD_DRAWMODE_TRANS:    if (pTrans) {      do {        Shift = (1 - CurrentPixel) << 2;        Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift;        if (Index) {          PixelIndex = *(pTrans + Index);          _SetPixelIndex(pDevice, x, y, PixelIndex);        }        x++;        if (++CurrentPixel == 2) {          CurrentPixel = 0;          Pixels = *(++p);        }      } while (--xsize);    } else {      do {        Shift = (1 - CurrentPixel) << 2;        Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift;        if (Index) {          _SetPixelIndex(pDevice, x, y, Index);        }        x++;        if (++CurrentPixel == 2) {          CurrentPixel = 0;          Pixels = *(++p);        }      } while (--xsize);    }    break;  }}
/***********************************************************************       Draw Bitmap 8 BPP*/static void  _DrawBitLine8BPP(GUI_DEVICE * pDevice, int x, int y, U8 const GUI_UNI_PTR * p, int xsize, const LCD_PIXELINDEX * pTrans) {  LCD_PIXELINDEX Pixel;
  switch (GUI_Context.DrawMode & (LCD_DRAWMODE_TRANS | LCD_DRAWMODE_XOR)) {  case 0:    if (pTrans) {      for (; xsize > 0; xsize--, x++, p++) {        Pixel = *p;        _SetPixelIndex(pDevice, x, y, *(pTrans + Pixel));      }    } else {      for (; xsize > 0; xsize--, x++, p++) {        _SetPixelIndex(pDevice, x, y, *p);      }    }    break;  case LCD_DRAWMODE_TRANS:    if (pTrans) {      for (; xsize > 0; xsize--, x++, p++) {        Pixel = *p;        if (Pixel) {          _SetPixelIndex(pDevice, x, y, *(pTrans + Pixel));        }      }    } else {      for (; xsize > 0; xsize--, x++, p++) {        Pixel = *p;        if (Pixel) {          _SetPixelIndex(pDevice, x, y, Pixel);        }      }    }    break;  }}
/***********************************************************************       Draw Bitmap 16 BPP, not optimized*/static void _DrawBitLine16BPP(GUI_DEVICE * pDevice, int x, int y, U16 const GUI_UNI_PTR * p, int xsize) {  for (;xsize > 0; xsize--, x++, p++) {    _SetPixelIndex(pDevice, x, y, *p);  }}
/***********************************************************************       Draw Bitmap 32 BPP, not optimized*/static void _DrawBitLine32BPP(GUI_DEVICE * pDevice, int x, int y, U32 const GUI_UNI_PTR * p, int xsize) {  for (;xsize > 0; xsize--, x++, p++) {    _SetPixelIndex(pDevice, x, y, *p);  }}
/***********************************************************************       _DrawBitmap*/static void _DrawBitmap(GUI_DEVICE * pDevice, int x0, int y0,                       int xSize, int ySize,                       int BitsPerPixel,                        int BytesPerLine,                       const U8 GUI_UNI_PTR * pData, int Diff,                       const LCD_PIXELINDEX* pTrans) {  int i;
  switch (BitsPerPixel) {  case 1:    for (i = 0; i < ySize; i++) {      _DrawBitLine1BPP(pDevice, x0, i + y0, pData, Diff, xSize, pTrans);      pData += BytesPerLine;    }    break;  case 2:    for (i = 0; i < ySize; i++) {      _DrawBitLine2BPP(pDevice, x0, i + y0, pData, Diff, xSize, pTrans);      pData += BytesPerLine;    }    break;  case 4:    for (i = 0; i < ySize; i++) {      _DrawBitLine4BPP(pDevice, x0, i + y0, pData, Diff, xSize, pTrans);      pData += BytesPerLine;    }    break;  case 8:    for (i = 0; i < ySize; i++) {      _DrawBitLine8BPP(pDevice, x0, i + y0, pData, xSize, pTrans);      pData += BytesPerLine;    }    break;  case 16:    for (i = 0; i < ySize; i++) {      _DrawBitLine16BPP(pDevice, x0, i + y0, (const U16 *)pData, xSize);      pData += BytesPerLine;    }    break;  case 32:    for (i = 0; i < ySize; i++) {      _DrawBitLine32BPP(pDevice, x0, i + y0, (const U32 *)pData, xSize);      pData += BytesPerLine;    }    break;  }}
/***********************************************************************       _InitOnce** Purpose:*   Allocates a fixed block for the context of the driver** Return value:*   0 on success, 1 on error*/static int _InitOnce(GUI_DEVICE * pDevice) {  DRIVER_CONTEXT * pContext;
  if (pDevice->u.pContext == NULL) {    pDevice->u.pContext = GUI_ALLOC_GetFixedBlock(sizeof(DRIVER_CONTEXT));    pContext = (DRIVER_CONTEXT *)pDevice->u.pContext;    pContext->BitsPerPixel = LCD__GetBPP(pDevice->pColorConvAPI->pfGetIndexMask());  }  return pDevice->u.pContext ? 0 : 1;}
/***********************************************************************       _GetDevProp*/static I32 _GetDevProp(GUI_DEVICE * pDevice, int Index) {  DRIVER_CONTEXT * pContext;
  pContext = (DRIVER_CONTEXT *)pDevice->u.pContext;  switch (Index) {  case LCD_DEVCAP_XSIZE:    return pContext->xSize;  case LCD_DEVCAP_YSIZE:    return pContext->ySize;  case LCD_DEVCAP_VXSIZE:    return pContext->vxSize;  case LCD_DEVCAP_VYSIZE:    return pContext->vySize;  case LCD_DEVCAP_BITSPERPIXEL:    return pContext->BitsPerPixel;  case LCD_DEVCAP_NUMCOLORS:    return 0;  case LCD_DEVCAP_XMAG:    return 1;  case LCD_DEVCAP_YMAG:    return 1;  case LCD_DEVCAP_MIRROR_X:    return 0;  case LCD_DEVCAP_MIRROR_Y:    return 0;  case LCD_DEVCAP_SWAP_XY:    return 0;  }  return -1;}
/***********************************************************************       _GetDevData*/static void * _GetDevData(GUI_DEVICE * pDevice, int Index) {  GUI_USE_PARA(pDevice);  switch (Index) {  #if GUI_SUPPORT_MEMDEV    case LCD_DEVDATA_MEMDEV:      return (void *)&GUI_MEMDEV_DEVICE_32;  #endif  }  return NULL;}
/***********************************************************************       _GetRect*/static void _GetRect(GUI_DEVICE * pDevice, LCD_RECT * pRect) {  DRIVER_CONTEXT * pContext;
  pContext = (DRIVER_CONTEXT *)pDevice->u.pContext;  pRect->x0 = 0;  pRect->y0 = 0;  pRect->x1 = pContext->vxSize - 1;  pRect->y1 = pContext->vySize - 1;}
/***********************************************************************       _SetOrg*/static void _SetOrg(GUI_DEVICE * pDevice, int x, int y) {  LCD_X_SETORG_INFO Data = {0};
  Data.xPos = x;  Data.yPos = y;  LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_SETORG, (void *)&Data);}
/***********************************************************************       Static code: Functions available by _GetDevFunc()************************************************************************//***********************************************************************       _SetVRAMAddr*/static void _SetVRAMAddr(GUI_DEVICE * pDevice, void * pVRAM) {  DRIVER_CONTEXT * pContext;  LCD_X_SETVRAMADDR_INFO Data = {0};
  _InitOnce(pDevice);  if (pDevice->u.pContext) {    pContext = (DRIVER_CONTEXT *)pDevice->u.pContext;    pContext->VRAMAddr = (U32)pVRAM;    Data.pVRAM = pVRAM;    LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_SETVRAMADDR, (void *)&Data);  }}
/***********************************************************************       _SetVSize*/static void _SetVSize(GUI_DEVICE * pDevice, int xSize, int ySize) {  DRIVER_CONTEXT * pContext;
  _InitOnce(pDevice);  if (pDevice->u.pContext) {    pContext = (DRIVER_CONTEXT *)pDevice->u.pContext;    pContext->vxSize = xSize;    pContext->vySize = ySize;    pContext->vxSizePhys = xSize;  }}
/***********************************************************************       _SetSize*/static void _SetSize(GUI_DEVICE * pDevice, int xSize, int ySize) {  DRIVER_CONTEXT * pContext;  LCD_X_SETSIZE_INFO Data = {0};
  _InitOnce(pDevice);  if (pDevice->u.pContext) {    pContext = (DRIVER_CONTEXT *)pDevice->u.pContext;    pContext->vxSizePhys = (pContext->vxSizePhys == 0) ? xSize : pContext->vxSizePhys;    pContext->xSize = xSize;    pContext->ySize = ySize;    Data.xSize = xSize;    Data.ySize = ySize;    LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_SETSIZE, (void *)&Data);  }}/***********************************************************************       _Init*/static int  _Init(GUI_DEVICE * pDevice) {  int r;
  r = _InitOnce(pDevice);  r |= LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_INITCONTROLLER, NULL);  return r;}
/***********************************************************************       _On*/static void _On (GUI_DEVICE * pDevice) {  LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_ON, NULL);}
/***********************************************************************       _Off*/static void _Off (GUI_DEVICE * pDevice) {  LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_OFF, NULL);}
/***********************************************************************       _SetLUTEntry*/static void _SetLUTEntry(GUI_DEVICE * pDevice, U8 Pos, LCD_COLOR Color) {  LCD_X_SETLUTENTRY_INFO Data = {0};
  Data.Pos   = Pos;  Data.Color = Color;  LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_SETLUTENTRY, (void *)&Data);}
/***********************************************************************       _GetDevFunc*/static void (* _GetDevFunc(GUI_DEVICE ** ppDevice, int Index))(void) {  GUI_USE_PARA(ppDevice);  switch (Index) {  case LCD_DEVFUNC_SET_VRAM_ADDR:    return (void (*)(void))_SetVRAMAddr;  case LCD_DEVFUNC_SET_VSIZE:    return (void (*)(void))_SetVSize;  case LCD_DEVFUNC_SET_SIZE:    return (void (*)(void))_SetSize;  case LCD_DEVFUNC_INIT:    return (void (*)(void))_Init;  case LCD_DEVFUNC_ON:    return (void (*)(void))_On;  case LCD_DEVFUNC_OFF:    return (void (*)(void))_Off;  case LCD_DEVFUNC_SETLUTENTRY:    return (void (*)(void))_SetLUTEntry;  }  return NULL;}
/***********************************************************************       Public data************************************************************************//***********************************************************************       GUI_DEVICE_API structure*/const GUI_DEVICE_API GUIDRV_Template_API = {  //  // Data  //  DEVICE_CLASS_DRIVER,  //  // Drawing functions  //  _DrawBitmap,  _DrawHLine,  _DrawVLine,  _FillRect,  _GetPixelIndex,  _SetPixelIndex,  _XorPixel,  //  // Set origin  //  _SetOrg,  //  // Request information  //  _GetDevFunc,  _GetDevProp,  _GetDevData,  _GetRect,};
/*************************** End of file ****************************/

GUIDRV_Template.h

/**********************************************************************                SEGGER Microcontroller GmbH & Co. KG                **        Solutions for real time microcontroller applications        ************************************************************************                                                                    **        (c) 1996 - 2010  SEGGER Microcontroller GmbH & Co. KG       **                                                                    **        Internet: www.segger.com    Support:  support@segger.com    **                                                                    ***********************************************************************
** emWin V5.06 - Graphical user interface for embedded applications **emWin is protected by international copyright laws.   Knowledge of thesource code may not be used to write a similar product.  This file mayonly be used in accordance with a license and should not be re-distributed in any way. We appreciate your understanding and fairness.----------------------------------------------------------------------File        : GUIDRV_Template.hPurpose     : Interface definition for GUIDRV_Template driver---------------------------END-OF-HEADER------------------------------*/
#ifndef GUIDRV_TEMPLATE_H#define GUIDRV_TEMPLATE_H
/***********************************************************************       Display drivers*///// Addresses//extern const GUI_DEVICE_API GUIDRV_Win_API;
extern const GUI_DEVICE_API GUIDRV_Template_API;
//// Macros to be used in configuration files//#if defined(WIN32) && !defined(LCD_SIMCONTROLLER)
  #define GUIDRV_TEMPLATE            &GUIDRV_Win_API
#else
  #define GUIDRV_TEMPLATE            &GUIDRV_Template_API
#endif
#endif
/*************************** End of file ****************************/

4.2 用户需要实现的GUI接口和配置

GUI_X.c中实现打印,时间戳,OS相关等接口。

4.2.1 初始化配置:堆和设备驱动配置

GUI_X_ConfigGUI_X_InitGUI_Init中被调用。

GUI_ALLOC_AssignMemory设置GUI内部管理的堆空间和大小。

如果没定义宏GUI_ALLOC_ALLOC则使用GUI_ALLOC_AssignMemory分配空间,GUI内部自己实现堆的申请和释放。

如果定义了GUI_ALLOC_ALLOC宏,则使用用户定义的接口,还需要定义GUI_ALLOC_FREE等接口见Core/GUI_Alloc.c

这里为了简单我们使用GUI内部的实现,只需要GUI_ALLOC_AssignMemory分配空间。

GUI_DEVICE_CreateAndLink链接设备驱动和颜色模式,即设备驱动GUIDRV_Template_API(前面显示部分的移植),颜色为RGB565.

static uint8_t gui_memory[3*1024];//// Configuration//void GUI_X_Config(void){  GUI_ALLOC_AssignMemory(gui_memory,sizeof(gui_memory));
  // Set display driver and color conversion  //  GUI_DEVICE_CreateAndLink(&GUIDRV_Template_API, GUICC_M565, 0, 0);}
void GUI_X_Init(void){
}

4.2.2 空闲处理接口

实现为空即可

//// ExecIdle - called if nothing else is left to do//void GUI_X_ExecIdle(void){
}

4.2.3 时间相关接口

GUI_X_GetTime用于获取ms时间戳,需要实现,

GUI_X_Delay多任务时可以用于调用OSdleay释放CPU,这里为空即可。

//// Timing routines//int  GUI_X_GetTime(void){    return get_ticks();}
void GUI_X_Delay(int Period){    (void)Period;}

4.2.4 OS相关接口

我这里只用一个任务跑GUI或者裸机跑,则都实现为空即可

//// Multitask routines - required only if multitasking is used (#define GUI_OS 1)//void GUI_X_Unlock(void){
}void GUI_X_Lock(void){
}U32  GUI_X_GetTaskId(void){    return 0;}void GUI_X_InitOS(void){
}

4.2.5 事件相关接口

用于事件驱动,这里都实现为空

//// Event driving (optional with multitasking)//void GUI_X_WaitEvent(void){
}void GUI_X_WaitEventTimed(int Period){    (void)Period;}void GUI_X_SignalEvent(void){
}

4.2.6 日志打印相关接口

GUIConf.h中定义宏

#define GUI_DEBUG_LEVEL GUI_DEBUG_LEVEL_LOG_ALL

GUI_Debug.h中定义了几个等级

#define GUI_DEBUG_LEVEL_NOCHECK       0  /* No run time checks are performed */#define GUI_DEBUG_LEVEL_CHECK_PARA    1  /* Parameter checks are performed to avoid crashes */#define GUI_DEBUG_LEVEL_CHECK_ALL     2  /* Parameter checks and consistency checks are performed */#define GUI_DEBUG_LEVEL_LOG_ERRORS    3  /* Errors are recorded */#define GUI_DEBUG_LEVEL_LOG_WARNINGS  4  /* Errors & Warnings are recorded */#define GUI_DEBUG_LEVEL_LOG_ALL       5  /* Errors, Warnings and Messages are recorded. */

调试时可以设置为LOG_ALL,使用时可以降低等级减少打印。

打印调试信息,根据实际实现

//// Recording (logs/warnings and errors) - required only for higher levels//void GUI_X_Log(const char *s){    printf("%s\r\n",s);}void GUI_X_Warn(const char *s){    printf("%s\r\n",s);}void GUI_X_ErrorOut(const char *s){    printf("%s\r\n",s);}

4.2.7 完整代码

完整的GUI_X.C如下


#include "GUI.h"#include "os_utils.h"
static uint8_t gui_memory[3*1024];//// Configuration//void GUI_X_Config(void){ GUI_ALLOC_AssignMemory(gui_memory,sizeof(gui_memory));
// Set display driver and color conversion // GUI_DEVICE_CreateAndLink(&GUIDRV_Template_API, GUICC_M565, 0, 0);}
void GUI_X_Init(void){
}
//// ExecIdle - called if nothing else is left to do//void GUI_X_ExecIdle(void){
}
//// Timing routines//int GUI_X_GetTime(void){ return os_get_ticks();}
void GUI_X_Delay(int Period){ (void)Period;}
//// Multitask routines - required only if multitasking is used (#define GUI_OS 1)//void GUI_X_Unlock(void){
}void GUI_X_Lock(void){
}U32 GUI_X_GetTaskId(void){ return 0;}void GUI_X_InitOS(void){
}
//// Event driving (optional with multitasking)//void GUI_X_WaitEvent(void){
}void GUI_X_WaitEventTimed(int Period){ (void)Period;}void GUI_X_SignalEvent(void){
}
//// Recording (logs/warnings and errors) - required only for higher levels//void GUI_X_Log(const char *s){    printf("%s\r\n",s);}void GUI_X_Warn(const char *s){    printf("%s\r\n",s);}void GUI_X_ErrorOut(const char *s){    printf("%s\r\n",s);}

GUIConf.h如下

/**********************************************************************                SEGGER MICROCONTROLLER SYSTEME GmbH                 **        Solutions for real time microcontroller applications        ************************************************************************                                                                    **        (c) 2002         SEGGER Microcontroller Systeme GmbH        **                                                                    **        Internet: www.segger.com    Support:  support@segger.com    **                                                                    ***********************************************************************
**** emWin/GSC Grafical user interface for embedded applications ****emWin is protected by international copyright laws. Knowledge of thesource code may not be used to write a similar product. This file mayonly be used in accordance with a license and should not be re-distributed in any way. We appreciate your understanding and fairness.----------------------------------------------------------------------File : GUIConf.hPurpose : Configures emWins abilities, fonts etc.----------------------------------------------------------------------*/
#ifndef GUICONF_H#define GUICONF_H
#define GUI_DEBUG_LEVEL 5#define GUI_ALLOC_SIZE 1024/*********************************************************************** Multi layer/display support*/#define GUI_NUM_LAYERS 1 // Maximum number of available layers
/*********************************************************************** Multi tasking support*/#define GUI_OS (0) // Compile with multitasking support
/*********************************************************************** Configuration of touch support*/#define GUI_SUPPORT_TOUCH (0) // Support a touch screen (req. win-manager)
/*********************************************************************** Default font*/#define GUI_DEFAULT_FONT &GUI_Font6x8
/*********************************************************************** Configuration of available packages*/#define GUI_SUPPORT_MOUSE 0 /* Support a mouse */#define GUI_WINSUPPORT 1 /* Use window manager */#define GUI_SUPPORT_MEMDEV 0 /* Memory device package available */
// NOTE! THE HARDWARE BUILD HAS A DIFFERENT GUIConf.h!!!// COPY CHANGES FROM HERE TO THERE// KMC#define BUTTON_REACT_ON_LEVEL 1///* Define colors *///// KMC - turn these defaults off to use bitmap buttons// #define BUTTON_BKCOLOR0_DEFAULT GUI_BLUE// #define BUTTON_BKCOLOR1_DEFAULT GUI_WHITE// #define BUTTON_BKCOLOR2_DEFAULT GUI_LIGHTCYAN #define BUTTON_TEXTCOLOR0_DEFAULT GUI_WHITE// #define BUTTON_TEXTCOLOR1_DEFAULT GUI_BLACK// #define BUTTON_TEXTCOLOR2_DEFAULT GUI_LIGHTGREEN #define BUTTON_FOCUSCOLOR_DEFAULT GUI_GRAY// #define BUTTON_FRAMECOLOR_DEFAULT GUI_GRAY#define BUTTON_3D_MOVE_X 0#define BUTTON_3D_MOVE_Y 0
// Define ICONVIEW selected state background color as transparent// = max alpha blending (0xFF) on BLACK - any color would do (0xxxxxxx)#define ICONVIEW_BKCOLOR1_DEFAULT 0xFF000000
#endif /* Avoid multiple inclusion */

4.3 用户需要实现的LCD接口和配置

即对应LCD_X.cLCDConf.h

LCD_X.c实现以下接口,LCD_X_DisplayDriverLCD_X_Config

这里只要是LCD_X_Config中设置屏幕大小,在GUI_Init中被调用。

LCD_X.c如下

#include "GUI.h"
int LCD_X_DisplayDriver(unsigned LayerIndex, unsigned Cmd, void * pData) {  int r;  (void) LayerIndex;  (void) pData;    switch (Cmd) {  case LCD_X_INITCONTROLLER: {    return 0;  }  default:    r = -1;  }  return r;}
void LCD_X_Config(void){  //  // Display driver configuration, required for Lin-driver  //  LCD_SetSizeEx (0, 240 , 320);  LCD_SetVSizeEx(0, 240, 320);}

LCDConf.h如下,定义屏幕大小的宏

/**********************************************************************                SEGGER Microcontroller GmbH & Co. KG                **        Solutions for real time microcontroller applications        ************************************************************************                                                                    **        (c) 1996 - 2009  SEGGER Microcontroller GmbH & Co. KG       **                                                                    **        Internet: www.segger.com    Support:  support@segger.com    **                                                                    ***********************************************************************
** emWin V5.00 - Graphical user interface for embedded applications **emWin is protected by international copyright laws.   Knowledge of thesource code may not be used to write a similar product.  This file mayonly be used in accordance with a license and should not be re-distributed in any way. We appreciate your understanding and fairness.----------------------------------------------------------------------File        : LCDConf.hPurpose     : Display driver configuration file----------------------------------------------------------------------*/
#ifndef LCDCONF_H#define LCDCONF_H
#define LCD_XSIZE 240#define LCD_YSIZE 320#define LCD_BITSPERPIXEL 16
#define LCD_GET_XSIZE() LCD_XSIZE#define LCD_GET_YSIZE() LCD_YSIZE
#endif /* LCDCONF_H */
/*************************** End of file ****************************/

4.4运行

#include "GUI.h"
GUI_Init();
while (1) {
GUI_Exec();
}

五. 测试

添加如下文件

emWin506-Src/GUI/GUIDemo/*.c

添加头文件包含路径

emWin506-Src/GUI/GUIDemo/

我们用一个任务专门用于刷屏,一个任务跑Demo

void main(vcoid){    st7789_itf_init();    create_task(gui_task, NULL, 7, 1024, "gui_task");    while(1)    {         uint32_t pre_time = os_get_ticks();        uint32_t cur_time = pre_time;        while (1) {            cur_time = os_get_ticks();            if(cur_time - pre_time >= 25)            {                pre_time = cur_time;                st7789_itf_sync();
            }        }    }    return;}

static void gui_task(void *arg){    (void)arg;    GUI_Init();    printf("gui task start\r\n");    GUIDEMO_main();    }

测试见视频,

如下图测试可换算帧率为5483980/(240x320x2)=35.7FPS,当然刷屏率要大于该值才行,我们之前的测试是42FPS

.总结

emWin的可移植性也非常好,类似LVGL也只需要简单的实现写点(刷屏)接口,时间时间戳获取接口,如果使用OS实现一些OS相关的接口即可。uC/GUI的知名度可能更高于emWin,其源码和文档也是学习GUI的非常好的资料值得好好学习。


评论 (0)
  • 在智慧城市领域中,当一个智慧路灯项目因信号盲区而被迫增设数百个网关时,当一个传感器网络因入网设备数量爆增而导致系统通信失效时,当一个智慧交通系统因基站故障而导致交通瘫痪时,星型网络拓扑与蜂窝网络拓扑在构建广覆盖与高节点数物联网网络时的局限性便愈发凸显,行业内亟需一种更高效、可靠与稳定的组网技术以满足构建智慧城市海量IoT网络节点的需求。星型网络的无线信号覆盖范围高度依赖网关的部署密度,同时单一网关的承载设备数量有限,难以支撑海量IoT网络节点的城市物联系统;而蜂窝网络的无线信号覆盖范围同样高度依
    华普微HOPERF 2025-03-24 17:00 239浏览
  • 在智能语音产品的开发过程中,麦克风阵列的选型直接决定了用户体验的优劣。广州唯创电子提供的单麦克风与双麦克风解决方案,为不同场景下的语音交互需求提供了灵活选择。本文将深入解析两种方案的性能差异、适用场景及工程实现要点,为开发者提供系统化的设计决策依据。一、基础参数对比分析维度单麦克风方案双麦克风方案BOM成本¥1.2-2.5元¥4.8-6.5元信噪比(1m)58-62dB65-68dB拾音角度全向360°波束成形±30°功耗8mW@3.3V15mW@3.3V典型响应延迟120ms80ms二、技术原
    广州唯创电子 2025-03-27 09:23 172浏览
  • 家电,在人们的日常生活中扮演着不可或缺的角色,也是提升人们幸福感的重要组成部分,那你了解家电的发展史吗?#70年代结婚流行“四大件”:手表、自行车、缝纫机,收音机,合成“三转一响”。#80年代随着改革开放的深化,中国经济开始飞速发展,黑白电视机、冰箱、洗衣机这“新三件”,成为了人们对生活的新诉求。#90年代彩电、冰箱、全自动洗衣机开始大量进入普通家庭,快速全面普及,90年代末,家电产品实现了从奢侈品到必需品的转变。#00年代至今00年代,随着人们追求高品质生活的愿望,常用的电视机、洗衣机等已经远
    启英AI平台 2025-03-25 14:12 90浏览
  • 在电子设计中,电磁兼容性(EMC)是确保设备既能抵御外部电磁干扰(EMI),又不会对自身或周围环境产生过量电磁辐射的关键。电容器、电感和磁珠作为三大核心元件,通过不同的机制协同作用,有效抑制电磁干扰。以下是其原理和应用场景的详细解析:1. 电容器:高频噪声的“吸尘器”作用原理:电容器通过“通高频、阻低频”的特性,为高频噪声提供低阻抗路径到地,形成滤波效果。例如,在电源和地之间并联电容,可吸收电源中的高频纹波和瞬态干扰。关键应用场景:电源去耦:在IC电源引脚附近放置0.1μF陶瓷电容,滤除数字电路
    时源芯微 2025-03-27 11:19 171浏览
  • 在智能终端设备开发中,语音芯片与功放电路的配合直接影响音质表现。广州唯创电子的WTN6、WT588F等系列芯片虽功能强大,但若硬件设计不当,可能导致输出声音模糊、杂音明显。本文将以WTN6与WT588F系列为例,解析音质劣化的常见原因及解决方法,帮助开发者实现清晰纯净的语音输出。一、声音不清晰的典型表现与核心原因当语音芯片输出的音频信号存在以下问题时,需针对性排查:背景杂音:持续的“沙沙”声或高频啸叫,通常由信号干扰或滤波不足导致。语音失真:声音断断续续或含混不清,可能与信号幅度不匹配或功放参数
    广州唯创电子 2025-03-25 09:32 112浏览
  • 汽车导航系统市场及应用环境参照调研机构GII的研究报告中的市场预测,全球汽车导航系统市场预计将于 2030年达到472亿美元的市场规模,而2024年至2030年的年复合成长率则为可观的6.7%。汽车导航系统无疑已成为智能汽车不可或缺的重要功能之一。随着人们在日常生活中对汽车导航功能的日渐依赖,一旦出现定位不准确或地图错误等问题,就可能导致车主开错路线,平白浪费更多行车时间,不仅造成行车不便,甚或可能引发交通事故的发生。有鉴于此,如果想要提供消费者完善的使用者体验,在车辆开发阶段便针对汽车导航功能
    百佳泰测试实验室 2025-03-27 14:51 204浏览
  • 六西格玛首先是作为一个量度质量水平的指标,它代表了近乎完美的质量的水平。如果你每天都吃一个苹果,有一间水果店的老板跟你说,他们所卖的苹果,质量达到六西格玛水平,换言之,他们每卖一百万个苹果,只会有3.4个是坏的。你算了一下,发现你如果要从这个店里买到一个坏苹果,需要805年。你会还会选择其他店吗?首先发明六西格玛这个词的人——比尔·史密斯(Bill Smith)他是摩托罗拉(Motorloa)的工程师,在追求这个近乎完美的质量水平的时候,发明了一套方法模型,开始时是MAIC,后来慢慢演变成DMA
    优思学院 2025-03-27 11:47 160浏览
  •       知识产权保护对工程师的双向影响      正向的激励,保护了工程师的创新成果与权益,给企业带来了知识产权方面的收益,企业的创新和发明大都是工程师的劳动成果,他们的职务发明应当受到奖励和保护,是企业发展的重要源泉。专利同时也成了工程师职称评定的指标之一,专利体现了工程师的创新能力,在求职、竞聘技术岗位或参与重大项目时,专利证书能显著增强个人竞争力。专利将工程师的创意转化为受法律保护的“无形资产”,避免技术成果被他人抄袭或无偿使
    广州铁金刚 2025-03-25 11:48 181浏览
  • WT588F02B是广州唯创电子推出的一款高性能语音芯片,广泛应用于智能家电、安防设备、玩具等领域。然而,在实际开发中,用户可能会遇到烧录失败的问题,导致项目进度受阻。本文将从下载连线、文件容量、线路长度三大核心因素出发,深入分析烧录失败的原因并提供系统化的解决方案。一、检查下载器与芯片的物理连接问题表现烧录时提示"连接超时"或"设备未响应",或烧录进度条卡顿后报错。原因解析接口错位:WT588F02B采用SPI/UART双模通信,若下载器引脚定义与芯片引脚未严格对应(如TXD/RXD交叉错误)
    广州唯创电子 2025-03-26 09:05 149浏览
  • 长期以来,智能家居对于大众家庭而言就像空中楼阁一般,华而不实,更有甚者,还将智能家居认定为资本家的营销游戏。商家们举着“智慧家居、智慧办公”的口号,将原本价格亲民、能用几十年的家电器具包装成为了高档商品,而消费者们最终得到的却是家居设备之间缺乏互操作性、不同品牌生态之间互不兼容的碎片化体验。这种早期的生态割裂现象致使消费者们对智能家居兴趣缺失,也造就了“智能家居无用论”的刻板印象。然而,自Matter协议发布之后,“命运的齿轮”开始转动,智能家居中的生态割裂现象与品牌生态之间的隔阂正被基于IP架
    华普微HOPERF 2025-03-27 09:46 125浏览
  • 在嵌入式语音系统的开发过程中,广州唯创电子推出的WT588系列语音芯片凭借其优异的音质表现和灵活的编程特性,广泛应用于智能终端、工业控制、消费电子等领域。作为该系列芯片的关键状态指示信号,BUSY引脚的设计处理直接影响着系统交互的可靠性和功能拓展性。本文将从电路原理、应用场景、设计策略三个维度,深入解析BUSY引脚的技术特性及其工程实践要点。一、BUSY引脚工作原理与信号特性1.1 电气参数电平标准:输出3.3V TTL电平(与VDD同源)驱动能力:典型值±8mA(可直接驱动LED)响应延迟:语
    广州唯创电子 2025-03-26 09:26 211浏览
  • ​2025年3月27日​,贞光科技授权代理品牌紫光同芯正式发布新一代汽车安全芯片T97-415E。作为T97-315E的迭代升级产品,该芯片以大容量存储、全球化合规认证、双SPI接口协同为核心突破,直击智能网联汽车"多场景安全并行"与"出口合规"两大行业痛点,助力车企抢占智能驾驶与全球化市场双赛道。行业趋势锚定:三大升级回应智能化浪潮1. 大容量存储:破解车联网多任务瓶颈随着​车机功能泛在化​(数字钥匙、OTA、T-BOX等安全服务集成),传统安全芯片面临存储资源挤占难题。T97-415E创新性
    贞光科技 2025-03-27 13:50 156浏览
  • 在当今竞争激烈的工业环境中,效率和响应速度已成为企业制胜的关键。为了满足这一需求,我们隆重推出宏集Panorama COOX,这是Panorama Suite中首款集成的制造执行系统(MES)产品。这一创新产品将Panorama平台升级为全面的工业4.0解决方案,融合了工业SCADA和MES技术的双重优势,帮助企业实现生产效率和运营能力的全面提升。深度融合SCADA与MES,开启工业新纪元宏集Panorama COOX的诞生,源于我们对创新和卓越运营的不懈追求。通过战略性收购法国知名MES领域专
    宏集科技 2025-03-27 13:22 207浏览
  • 文/陈昊编辑/cc孙聪颖‍2025 年,作为中国实施制造强国战略第一个十年计划的关键里程碑,被赋予了极为重大的意义。两会政府工作报告清晰且坚定地指出,要全力加速新质生产力的发展进程,推动传统产业全方位向高端化、智能化与绿色化转型。基于此,有代表敏锐提议,中国制造应从前沿技术的应用切入,逐步拓展至产业生态的构建,最终延伸到提升用户体验的维度,打出独树一帜、具有鲜明特色的发展牌。正是在这样至关重要的时代背景之下,于 AWE 2025(中国家电及消费电子博览会)这一备受瞩目的舞台上,高端厨房的中国方案
    华尔街科技眼 2025-03-25 16:10 87浏览
  • 案例概况在丹麦哥本哈根,西门子工程师们成功完成了一项高安全设施的数据集成项目。他们利用宏集Cogent DataHub软件,将高安全设施内的设备和仪器与远程监控位置连接起来,让技术人员能够在不违反安全规定、不引入未经授权人员的情况下,远程操作所需设备。突破OPC 服务器的远程连接难题该项目最初看似是一个常规的 OPC 应用:目标是将高安全性设施中的冷水机(chiller)设备及其 OPC DA 服务器,与远程监控站的两套 SCADA 系统(作为 OPC DA 客户端)连接起来。然而,在实际实施过
    宏集科技 2025-03-27 13:20 117浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦