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


评论
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2024-12-02 10:40 143浏览
  • TOF多区传感器: ND06   ND06是一款微型多区高集成度ToF测距传感器,其支持24个区域(6 x 4)同步测距,测距范围远达5m,具有测距范围广、精度高、测距稳定等特点。适用于投影仪的无感自动对焦和梯形校正、AIoT、手势识别、智能面板和智能灯具等多种场景。                 如果用ND06进行手势识别,只需要经过三个步骤: 第一步&
    esad0 2024-12-04 11:20 103浏览
  • 戴上XR眼镜去“追龙”是种什么体验?2024年11月30日,由上海自然博物馆(上海科技馆分馆)与三湘印象联合出品、三湘印象旗下观印象艺术发展有限公司(下简称“观印象”)承制的《又见恐龙》XR嘉年华在上海自然博物馆重磅开幕。该体验项目将于12月1日正式对公众开放,持续至2025年3月30日。双向奔赴,恐龙IP撞上元宇宙不久前,上海市经济和信息化委员会等部门联合印发了《上海市超高清视听产业发展行动方案》,特别提到“支持博物馆、主题乐园等场所推动超高清视听技术应用,丰富线下文旅消费体验”。作为上海自然
    电子与消费 2024-11-30 22:03 107浏览
  • 作为优秀工程师的你,已身经百战、阅板无数!请先醒醒,新的项目来了,这是一个既要、又要、还要的产品需求,ARM核心板中一个处理器怎么能实现这么丰富的外围接口?踌躇之际,你偶阅此文。于是,“潘多拉”的魔盒打开了!没错,USB资源就是你打开新世界得钥匙,它能做哪些扩展呢?1.1  USB扩网口通用ARM处理器大多带两路网口,如果项目中有多路网路接口的需求,一般会选择在主板外部加交换机/路由器。当然,出于成本考虑,也可以将Switch芯片集成到ARM核心板或底板上,如KSZ9897、
    万象奥科 2024-12-03 10:24 96浏览
  • RDDI-DAP错误通常与调试接口相关,特别是在使用CMSIS-DAP协议进行嵌入式系统开发时。以下是一些可能的原因和解决方法: 1. 硬件连接问题:     检查调试器(如ST-Link)与目标板之间的连接是否牢固。     确保所有必要的引脚都已正确连接,没有松动或短路。 2. 电源问题:     确保目标板和调试器都有足够的电源供应。     检查电源电压是否符合目标板的规格要求。 3. 固件问题: &n
    丙丁先生 2024-12-01 17:37 114浏览
  • 概述 说明(三)探讨的是比较器一般带有滞回(Hysteresis)功能,为了解决输入信号转换速率不够的问题。前文还提到,即便使能滞回(Hysteresis)功能,还是无法解决SiPM读出测试系统需要解决的问题。本文在说明(三)的基础上,继续探讨为SiPM读出测试系统寻求合适的模拟脉冲检出方案。前四代SiPM使用的高速比较器指标缺陷 由于前端模拟信号属于典型的指数脉冲,所以下降沿转换速率(Slew Rate)过慢,导致比较器检出出现不必要的问题。尽管比较器可以使能滞回(Hysteresis)模块功
    coyoo 2024-12-03 12:20 170浏览
  • 当前,智能汽车产业迎来重大变局,随着人工智能、5G、大数据等新一代信息技术的迅猛发展,智能网联汽车正呈现强劲发展势头。11月26日,在2024紫光展锐全球合作伙伴大会汽车电子生态论坛上,紫光展锐与上汽海外出行联合发布搭载紫光展锐A7870的上汽海外MG量产车型,并发布A7710系列UWB数字钥匙解决方案平台,可应用于数字钥匙、活体检测、脚踢雷达、自动泊车等多种智能汽车场景。 联合发布量产车型,推动汽车智能化出海紫光展锐与上汽海外出行达成战略合作,联合发布搭载紫光展锐A7870的量产车型
    紫光展锐 2024-12-03 11:38 126浏览
  • 《高速PCB设计经验规则应用实践》+PCB绘制学习与验证读书首先看目录,我感兴趣的是这一节;作者在书中列举了一条经典规则,然后进行详细分析,通过公式推导图表列举说明了传统的这一规则是受到电容加工特点影响的,在使用了MLCC陶瓷电容后这一条规则已经不再实用了。图书还列举了高速PCB设计需要的专业工具和仿真软件,当然由于篇幅所限,只是介绍了一点点设计步骤;我最感兴趣的部分还是元件布局的经验规则,在这里列举如下:在这里,演示一下,我根据书本知识进行电机驱动的布局:这也算知行合一吧。对于布局书中有一句:
    wuyu2009 2024-11-30 20:30 142浏览
  • 遇到部分串口工具不支持1500000波特率,这时候就需要进行修改,本文以触觉智能RK3562开发板修改系统波特率为115200为例,介绍瑞芯微方案主板Linux修改系统串口波特率教程。温馨提示:瑞芯微方案主板/开发板串口波特率只支持115200或1500000。修改Loader打印波特率查看对应芯片的MINIALL.ini确定要修改的bin文件#查看对应芯片的MINIALL.ini cat rkbin/RKBOOT/RK3562MINIALL.ini修改uart baudrate参数修改以下目
    Industio_触觉智能 2024-12-03 11:28 110浏览
  • 最近几年,新能源汽车愈发受到消费者的青睐,其销量也是一路走高。据中汽协公布的数据显示,2024年10月,新能源汽车产销分别完成146.3万辆和143万辆,同比分别增长48%和49.6%。而结合各家新能源车企所公布的销量数据来看,比亚迪再度夺得了销冠宝座,其10月新能源汽车销量达到了502657辆,同比增长66.53%。众所周知,比亚迪是新能源汽车领域的重要参与者,其一举一动向来为外界所关注。日前,比亚迪汽车旗下品牌方程豹汽车推出了新车方程豹豹8,该款车型一上市就迅速吸引了消费者的目光,成为SUV
    刘旷 2024-12-02 09:32 138浏览
  • 11-29学习笔记11-29学习笔记习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-02 23:58 92浏览
  •         温度传感器的精度受哪些因素影响,要先看所用的温度传感器输出哪种信号,不同信号输出的温度传感器影响精度的因素也不同。        现在常用的温度传感器输出信号有以下几种:电阻信号、电流信号、电压信号、数字信号等。以输出电阻信号的温度传感器为例,还细分为正温度系数温度传感器和负温度系数温度传感器,常用的铂电阻PT100/1000温度传感器就是正温度系数,就是说随着温度的升高,输出的电阻值会增大。对于输出
    锦正茂科技 2024-12-03 11:50 141浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦