基于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的非常好的资料值得好好学习。


评论
  • 根据环洋市场咨询(Global Info Research)项目团队最新调研,预计2030年全球无人机锂电池产值达到2457百万美元,2024-2030年期间年复合增长率CAGR为9.6%。 无人机锂电池是无人机动力系统中存储并释放能量的部分。无人机使用的动力电池,大多数是锂聚合物电池,相较其他电池,锂聚合物电池具有较高的能量密度,较长寿命,同时也具有良好的放电特性和安全性。 全球无人机锂电池核心厂商有宁德新能源科技、欣旺达、鹏辉能源、深圳格瑞普和EaglePicher等,前五大厂商占有全球
    GIRtina 2025-01-07 11:02 124浏览
  •  在全球能源结构加速向清洁、可再生方向转型的今天,风力发电作为一种绿色能源,已成为各国新能源发展的重要组成部分。然而,风力发电系统在复杂的环境中长时间运行,对系统的安全性、稳定性和抗干扰能力提出了极高要求。光耦(光电耦合器)作为一种电气隔离与信号传输器件,凭借其优秀的隔离保护性能和信号传输能力,已成为风力发电系统中不可或缺的关键组件。 风力发电系统对隔离与控制的需求风力发电系统中,包括发电机、变流器、变压器和控制系统等多个部分,通常工作在高压、大功率的环境中。光耦在这里扮演了
    晶台光耦 2025-01-08 16:03 61浏览
  • 在智能家居领域中,Wi-Fi、蓝牙、Zigbee、Thread与Z-Wave等无线通信协议是构建短距物联局域网的关键手段,它们常在实际应用中交叉运用,以满足智能家居生态系统多样化的功能需求。然而,这些协议之间并未遵循统一的互通标准,缺乏直接的互操作性,在进行组网时需要引入额外的网关作为“翻译桥梁”,极大地增加了系统的复杂性。 同时,Apple HomeKit、SamSung SmartThings、Amazon Alexa、Google Home等主流智能家居平台为了提升市占率与消费者
    华普微HOPERF 2025-01-06 17:23 204浏览
  • 每日可见的315MHz和433MHz遥控模块,你能分清楚吗?众所周知,一套遥控设备主要由发射部分和接收部分组成,发射器可以将控制者的控制按键经过编码,调制到射频信号上面,然后经天线发射出无线信号。而接收器是将天线接收到的无线信号进行解码,从而得到与控制按键相对应的信号,然后再去控制相应的设备工作。当前,常见的遥控设备主要分为红外遥控与无线电遥控两大类,其主要区别为所采用的载波频率及其应用场景不一致。红外遥控设备所采用的射频信号频率一般为38kHz,通常应用在电视、投影仪等设备中;而无线电遥控设备
    华普微HOPERF 2025-01-06 15:29 167浏览
  • 故障现象一辆2017款东风风神AX7车,搭载DFMA14T发动机,累计行驶里程约为13.7万km。该车冷起动后怠速运转正常,热机后怠速运转不稳,组合仪表上的发动机转速表指针上下轻微抖动。 故障诊断 用故障检测仪检测,发动机控制单元中无故障代码存储;读取发动机数据流,发现进气歧管绝对压力波动明显,有时能达到69 kPa,明显偏高,推断可能的原因有:进气系统漏气;进气歧管绝对压力传感器信号失真;发动机机械故障。首先从节气门处打烟雾,没有发现进气管周围有漏气的地方;接着拔下进气管上的两个真空
    虹科Pico汽车示波器 2025-01-08 16:51 70浏览
  • 彼得·德鲁克被誉为“现代管理学之父”,他的管理思想影响了无数企业和管理者。然而,关于他的书籍分类,一种流行的说法令人感到困惑:德鲁克一生写了39本书,其中15本是关于管理的,而其中“专门写工商企业或为企业管理者写的”只有两本——《为成果而管理》和《创新与企业家精神》。这样的表述广为流传,但深入探讨后却发现并不完全准确。让我们一起重新审视这一说法,解析其中的矛盾与根源,进而重新认识德鲁克的管理思想及其著作的真正价值。从《创新与企业家精神》看德鲁克的视角《创新与企业家精神》通常被认为是一本专为企业管
    优思学院 2025-01-06 12:03 158浏览
  • By Toradex 秦海1). 简介嵌入式平台设备基于Yocto Linux 在开发后期量产前期,为了安全以及提高启动速度等考虑,希望将 ARM 处理器平台的 Debug Console 输出关闭,本文就基于 NXP i.MX8MP ARM 处理器平台来演示相关流程。 本文所示例的平台来自于 Toradex Verdin i.MX8MP 嵌入式平台。  2. 准备a). Verdin i.MX8MP ARM核心版配合Dahlia载板并
    hai.qin_651820742 2025-01-07 14:52 108浏览
  • 这篇内容主要讨论三个基本问题,硅电容是什么,为什么要使用硅电容,如何正确使用硅电容?1.  硅电容是什么首先我们需要了解电容是什么?物理学上电容的概念指的是给定电位差下自由电荷的储藏量,记为C,单位是F,指的是容纳电荷的能力,C=εS/d=ε0εrS/4πkd(真空)=Q/U。百度百科上电容器的概念指的是两个相互靠近的导体,中间夹一层不导电的绝缘介质。通过观察电容本身的定义公式中可以看到,在各个变量中比较能够改变的就是εr,S和d,也就是介质的介电常数,金属板有效相对面积以及距离。当前
    知白 2025-01-06 12:04 223浏览
  • 村田是目前全球量产硅电容的领先企业,其在2016年收购了法国IPDiA头部硅电容器公司,并于2023年6月宣布投资约100亿日元将硅电容产能提升两倍。以下内容主要来自村田官网信息整理,村田高密度硅电容器采用半导体MOS工艺开发,并使用3D结构来大幅增加电极表面,因此在给定的占位面积内增加了静电容量。村田的硅技术以嵌入非结晶基板的单片结构为基础(单层MIM和多层MIM—MIM是指金属 / 绝缘体/ 金属) 村田硅电容采用先进3D拓扑结构在100um内,使开发的有效静电容量面积相当于80个
    知白 2025-01-07 15:02 144浏览
  • 大模型的赋能是指利用大型机器学习模型(如深度学习模型)来增强或改进各种应用和服务。这种技术在许多领域都显示出了巨大的潜力,包括但不限于以下几个方面: 1. 企业服务:大模型可以用于构建智能客服系统、知识库问答系统等,提升企业的服务质量和运营效率。 2. 教育服务:在教育领域,大模型被应用于个性化学习、智能辅导、作业批改等,帮助教师减轻工作负担,提高教学质量。 3. 工业智能化:大模型有助于解决工业领域的复杂性和不确定性问题,尽管在认知能力方面尚未完全具备专家级的复杂决策能力。 4. 消费
    丙丁先生 2025-01-07 09:25 117浏览
  • 根据Global Info Research项目团队最新调研,预计2030年全球封闭式电机产值达到1425百万美元,2024-2030年期间年复合增长率CAGR为3.4%。 封闭式电机是一种电动机,其外壳设计为密闭结构,通常用于要求较高的防护等级的应用场合。封闭式电机可以有效防止外部灰尘、水分和其他污染物进入内部,从而保护电机的内部组件,延长其使用寿命。 环洋市场咨询机构出版的调研分析报告【全球封闭式电机行业总体规模、主要厂商及IPO上市调研报告,2025-2031】研究全球封闭式电机总体规
    GIRtina 2025-01-06 11:10 126浏览
  • 本文介绍编译Android13 ROOT权限固件的方法,触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。关闭selinux修改此文件("+"号为修改内容)device/rockchip/common/BoardConfig.mkBOARD_BOOT_HEADER_VERSION ?= 2BOARD_MKBOOTIMG_ARGS :=BOARD_PREBUILT_DTB
    Industio_触觉智能 2025-01-08 00:06 92浏览
  • 「他明明跟我同梯进来,为什么就是升得比我快?」许多人都有这样的疑问:明明就战绩也不比隔壁同事差,升迁之路却比别人苦。其实,之间的差异就在于「领导力」。並非必须当管理者才需要「领导力」,而是散发领导力特质的人,才更容易被晓明。许多领导力和特质,都可以通过努力和学习获得,因此就算不是天生的领导者,也能成为一个具备领导魅力的人,进而被老板看见,向你伸出升迁的橘子枝。领导力是什么?领导力是一种能力或特质,甚至可以说是一种「影响力」。好的领导者通常具备影响和鼓励他人的能力,并导引他们朝着共同的目标和愿景前
    优思学院 2025-01-08 14:54 66浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦