[原创] 【NUCLEO-U083RC】4.驱动段式LCD屏(1)

电子烂人   2024-5-11 16:16 楼主

本来在计划中准备使用LCD1602作为显示屏的,但是看过ST对U0“延长电池使用时间”的定义后,发现LCD1602对于电池供电貌似不是很友好。所以本次测评使用LCD数码管进行测试

 

1.LCD简介

    段式LCD(Liquid Crystal Display,液晶显示屏)是一种显示屏技术,通过排列成段的单个液晶单元格来形成文字和数字。与全点阵LCD不同,段式LCD的显示能力较为有限,通常用于显示简单的文本和数字,如计算器、电子表、家用电器和工业设备上的显示屏。
    段式LCD的基本结构包括七个或更多的段,每个段可以独立控制,通过不同的组合可以形成不同的字符。最简单的段式LCD由七个段组成,用于显示0到9的数字,这种LCD被称为七段显示。还有一些更复杂的段式LCD,比如14段、16段甚至更多,它们可以显示更多的字符和符号。
    段式LCD的工作原理是利用液晶对光的偏振性质。当电流通过特定的段时,液晶分子的排列方式会改变,从而改变偏振光的方向。通过偏振片和滤色片,可以控制光线是否通过,从而显示出明暗不同的段,形成可见的字符或图像。优点在于其结构简单、功耗低、成本较低,适合用于显示信息量不大的场合。由于其显示能力的限制,不适合用于显示复杂的图形或大量的文本。

2.LCD代码解析

ST的LCD库里有数码管的定义,不过数码管不同于常用的“日”字型数码管,而是“米”字型的,具体定义如下:

(以下代码来自U083-DK的示例“LCD_Segments_Drive,仅供参考)

 

/** @defgroup STM32U083C_DK_GLASS_LCD_Private_Variables Private Variables
  * @{
  */

/* this variable can be used for accelerate the scrolling exit when push user button */
__IO uint8_t bLCDGlass_KeyPressed = 0;

/**
  @verbatim
================================================================================
                              GLASS LCD MAPPING
================================================================================
LCD allows to display information on six 14-segment digits and 4 bars:

  1       2       3       4       5       6
-----   -----   -----   -----   -----   -----
|\|/| o |\|/| o |\|/| o |\|/| o |\|/|   |\|/|   BAR3
-- --   -- --   -- --   -- --   -- --   -- --   BAR2
|/|\| o |/|\| o |/|\| o |/|\| o |/|\|   |/|\|   BAR1
----- * ----- * ----- * ----- * -----   -----   BAR0

LCD segment mapping:
--------------------
  -----A-----        _
  |\   |   /|   COL |_|
  F H  J  K B
  |  \ | /  |        _
  --G-- --M--   COL |_|
  |  / | \  |
  E Q  P  N C
  |/   |   \|        _
  -----D-----   DP  |_|

 An LCD character coding is based on the following matrix:
COM           0   1   2     3
SEG(n)      { E , D , P ,   N   }
SEG(n+1)    { M , C , COL , DP  }
SEG(23-n-1) { B , A , K ,   J   }
SEG(23-n)   { G , F , Q ,   H   }
with n positive odd number.

 The character 'A' for example is:
  -------------------------------
LSB   { 1 , 0 , 0 , 0   }
      { 1 , 1 , 0 , 0   }
      { 1 , 1 , 0 , 0   }
MSB   { 1 , 1 , 0 , 0   }
      -------------------
  'A' =  F    E   0   0 hexa

  @endverbatim
  */

LCD_HandleTypeDef LCDHandle;

/* Constant table for cap characters 'A' --> 'Z' */
const uint16_t CapLetterMap[26] =
{
  /* A      B      C      D      E      F      G      H      I  */
  0xFE00, 0x6714, 0x1D00, 0x4714, 0x9D00, 0x9C00, 0x3F00, 0xFA00, 0x0014,
  /* J      K      L      M      N      O      P      Q      R  */
  0x5300, 0x9841, 0x1900, 0x5A48, 0x5A09, 0x5F00, 0xFC00, 0x5F01, 0xFC01,
  /* S      T      U      V      W      X      Y      Z  */
  0xAF00, 0x0414, 0x5b00, 0x18C0, 0x5A81, 0x00C9, 0x0058, 0x05C0
};

/* Constant table for number '0' --> '9' */
const uint16_t NumberMap[10] =
{
  /* 0      1      2      3      4      5      6      7      8      9  */
  0x5F00, 0x4200, 0xF500, 0x6700, 0xEa00, 0xAF00, 0xBF00, 0x04600, 0xFF00, 0xEF00
};

uint32_t Digit[4];     /* Digit frame buffer */

/* LCD BAR status: To save the bar setting after writing in LCD RAM memory */
uint8_t LCDBar = BATTERYLEVEL_FULL;

具体的应用代码在这个示例里也给出了,主要使用的是“HAL_LCD_Write”这个函数;

函数定义如下:

HAL_StatusTypeDef HAL_LCD_Write(LCD_HandleTypeDef *hlcd, uint32_t RAMRegisterIndex, uint32_t RAMRegisterMask,
                                uint32_t Data)
{
  uint32_t tickstart;
  HAL_LCD_StateTypeDef state = hlcd->State;

  if ((state == HAL_LCD_STATE_READY) || (state == HAL_LCD_STATE_BUSY))
  {
    /* Check the parameters */
    assert_param(IS_LCD_RAM_REGISTER(RAMRegisterIndex));

    if (hlcd->State == HAL_LCD_STATE_READY)
    {
      /* Process Locked */
      __HAL_LOCK(hlcd);
      hlcd->State = HAL_LCD_STATE_BUSY;

      /* Get timeout */
      tickstart = HAL_GetTick();

      /*!< Wait Until the LCD is ready */
      while (__HAL_LCD_GET_FLAG(hlcd, LCD_FLAG_UDR) != RESET)
      {
        if ((HAL_GetTick() - tickstart) > LCD_TIMEOUT_VALUE)
        {
          hlcd->ErrorCode = HAL_LCD_ERROR_UDR;

          /* Process Unlocked */
          __HAL_UNLOCK(hlcd);

          return HAL_TIMEOUT;
        }
      }
    }

    /* Copy the new Data bytes to LCD RAM register */
    MODIFY_REG(hlcd->Instance->RAM[RAMRegisterIndex], ~(RAMRegisterMask), Data);

    return HAL_OK;
  }
  else
  {
    return HAL_ERROR;
  }
}

可以看到,该代码足够简洁,能够加速段式LCD相关项目的开发。

3.配置LCD外设

本次选用的LCD,LCD液晶管引脚多达32个,其中有8个COM脚,24个SEG脚

微信截图_20240510191350.png

 

根据驱动数据在CUBEMX中定义LCD功能(引脚占用非常多。。。)

由于LCD的时钟和RTC为同源,故还需要使能RTC,详情可以看上一篇文章:

微信截图_20240510201241.png

 

配置完后,生成的LCD代码如下:
static void MX_LCD_Init(void)
{

  /* USER CODE BEGIN LCD_Init 0 */

  /* USER CODE END LCD_Init 0 */

  /* USER CODE BEGIN LCD_Init 1 */

  /* USER CODE END LCD_Init 1 */
  hlcd.Instance = LCD;
  hlcd.Init.Prescaler = LCD_PRESCALER_1;
  hlcd.Init.Divider = LCD_DIVIDER_16;
  hlcd.Init.Duty = LCD_DUTY_1_8;
  hlcd.Init.Bias = LCD_BIAS_1_4;
  hlcd.Init.VoltageSource = LCD_VOLTAGESOURCE_INTERNAL;
  hlcd.Init.Contrast = LCD_CONTRASTLEVEL_3;
  hlcd.Init.DeadTime = LCD_DEADTIME_2;
  hlcd.Init.PulseOnDuration = LCD_PULSEONDURATION_7;
  hlcd.Init.BlinkMode = LCD_BLINKMODE_OFF;
  hlcd.Init.BlinkFrequency = LCD_BLINKFREQUENCY_DIV8;
  hlcd.Init.MuxSegment = LCD_MUXSEGMENT_DISABLE;
  if (HAL_LCD_Init(&hlcd) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN LCD_Init 2 */

  /* USER CODE END LCD_Init 2 */

}

正好买的屏幕到了,但是遇到一个尴尬的问题,没法连线。。。

微信图片_20240511160341.jpg

三片屏幕都是2.0MM的引脚间距,手上唯一的洞洞板和面包板都是2.54MM间距的,这个引脚还很脆弱,不适合接杜邦线。。。

只能动手解决问题了,立创EDA启动!

微信截图_20240511160141.png

正巧,立创EDA标准版库文件里有GDC05720屏幕的封装,直接做一个板子引出即可。

这周就先这样,接下来就等PCB制作完成了。。。

20240511161528140.zip (8.15 MB)
(下载次数: 2, 2024-5-11 16:15 上传)
本帖最后由 电子烂人 于 2024-5-11 16:15 编辑
没用比没有强

回复评论 (1)

立创EDA标准版库文件里有GDC05720屏幕的封装,这个屏的出货量应该挺高的

在爱好的道路上不断前进,在生活的迷雾中播撒光引
点赞  2024-5-12 08:15
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复