[其他ST产品] STM32关于驱动段码屏显示

[复制链接]
674|17
 楼主| 原来是wjc 发表于 2022-12-25 15:06 | 显示全部楼层 |阅读模式
本篇文章主要记录一下我在工作中用STM32单片机驱动段码屏显示内容,不讲解具体的驱动原理,只是单纯记录如何编写驱动屏幕图标显示的代码,以便**后查看。

单片机:STM32L152RCT6A
IDE:Keil5.25.2.0
代码生成:STM32CUBEMX4.23.0

具体段码屏的驱动代码我直接贴出来:

  1. /* LCD init function */
  2. static void MX_LCD_Init(void)
  3. {
  4.     hlcd.Instance = LCD;
  5.     hlcd.Init.Prescaler = LCD_PRESCALER_1;
  6.     hlcd.Init.Divider = LCD_DIVIDER_31;
  7.     hlcd.Init.Duty = LCD_DUTY_1_4;
  8.     hlcd.Init.Bias = LCD_BIAS_1_3;
  9.     hlcd.Init.VoltageSource = LCD_VOLTAGESOURCE_INTERNAL;
  10.     hlcd.Init.Contrast = LCD_CONTRASTLEVEL_3;
  11.     hlcd.Init.DeadTime = LCD_DEADTIME_0;
  12.     hlcd.Init.PulseOnDuration = LCD_PULSEONDURATION_4;
  13.     hlcd.Init.MuxSegment = LCD_MUXSEGMENT_DISABLE;
  14.     hlcd.Init.BlinkMode = LCD_BLINKMODE_OFF;
  15.     hlcd.Init.BlinkFrequency = LCD_BLINKFREQUENCY_DIV8;
  16.     if (HAL_LCD_Init(&hlcd) != HAL_OK)
  17.     {
  18.         _Error_Handler(__FILE__, __LINE__);
  19.     }
  20. }


  21. void HAL_LCD_MspInit(LCD_HandleTypeDef* hlcd)
  22. {
  23.     GPIO_InitTypeDef GPIO_InitStruct;
  24.     if(hlcd->Instance==LCD)
  25.     {
  26.         /* USER CODE BEGIN LCD_MspInit 0 */

  27.         /* USER CODE END LCD_MspInit 0 */
  28.         /* Peripheral clock enable */
  29.         __HAL_RCC_LCD_CLK_ENABLE();

  30.         /**LCD GPIO Configuration
  31.         PB8     ------> LCD_SEG16
  32.         PA15    ------> LCD_SEG17
  33.         PC0     ------> LCD_SEG18
  34.         PC1     ------> LCD_SEG19
  35.         PC2     ------> LCD_SEG20
  36.         PC3     ------> LCD_SEG21
  37.         PC4     ------> LCD_SEG22
  38.         PC5     ------> LCD_SEG23
  39.         PC6     ------> LCD_SEG24
  40.         PC7     ------> LCD_SEG25
  41.         PC8     ------> LCD_SEG26
  42.                 PC9     ------> LCD_SEG27
  43.         PA8     ------> LCD_COM0
  44.         PA9     ------> LCD_COM1
  45.         PA10    ------> LCD_COM2
  46.         PB9     ------> LCD_COM3
  47.         */
  48.         GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
  49.                               |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
  50.                               |GPIO_PIN_8|GPIO_PIN_9;
  51.         GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  52.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  53.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  54.         GPIO_InitStruct.Alternate = GPIO_AF11_LCD;
  55.         HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  56.         GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_15;
  57.         GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  58.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  59.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  60.         GPIO_InitStruct.Alternate = GPIO_AF11_LCD;
  61.         HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  62.         GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_8;
  63.         GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  64.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  65.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  66.         GPIO_InitStruct.Alternate = GPIO_AF11_LCD;
  67.         HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  68.         /* USER CODE BEGIN LCD_MspInit 1 */

  69.         /* USER CODE END LCD_MspInit 1 */
  70.     }
  71. }

  72. void HAL_LCD_MspDeInit(LCD_HandleTypeDef* hlcd)
  73. {

  74.     if(hlcd->Instance==LCD)
  75.     {
  76.         /* USER CODE BEGIN LCD_MspDeInit 0 */

  77.         /* USER CODE END LCD_MspDeInit 0 */
  78.         /* Peripheral clock disable */
  79.         __HAL_RCC_LCD_CLK_DISABLE();

  80.         /**LCD GPIO Configuration
  81.         PB8     ------> LCD_SEG16
  82.         PA15    ------> LCD_SEG17
  83.         PC0     ------> LCD_SEG18
  84.         PC1     ------> LCD_SEG19
  85.         PC2     ------> LCD_SEG20
  86.         PC3     ------> LCD_SEG21
  87.         PC4     ------> LCD_SEG22
  88.         PC5     ------> LCD_SEG23
  89.         PC6     ------> LCD_SEG24
  90.         PC7     ------> LCD_SEG25
  91.         PC8     ------> LCD_SEG26
  92.         PC9     ------> LCD_SEG27
  93.         PA8     ------> LCD_COM0
  94.         PA9     ------> LCD_COM1
  95.         PA10     ------> LCD_COM2
  96.         PB9     ------> LCD_COM3
  97.         */
  98.         HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
  99.                         |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
  100.                         |GPIO_PIN_8|GPIO_PIN_9);

  101.         HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_15);

  102.         HAL_GPIO_DeInit(GPIOB, GPIO_PIN_9|GPIO_PIN_8);

  103.         /* USER CODE BEGIN LCD_MspDeInit 1 */

  104.         /* USER CODE END LCD_MspDeInit 1 */
  105.     }
  106. }

————————————————
版权声明:本文为CSDN博主「兰亭集旭」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/CSDN_Gao_16/article/details/115463499

 楼主| 原来是wjc 发表于 2022-12-25 15:14 | 显示全部楼层
从上面的初始化代码可以知道,段码屏共有4个 COM 端,12个 SEG 端。下图是某厂商生产的段码屏的资料:
1101563a7f830b3508.png
 楼主| 原来是wjc 发表于 2022-12-25 15:15 | 显示全部楼层
最终程序中驱动段码屏显示图标的代码如下:
  1. #include "main.h"
  2. extern LCD_HandleTypeDef hlcd;

  3. //T1 minus
  4. //T2 gps
  5. //T3 cloud
  6. //T4 bluetooth
  7. //T5 play
  8. //T6 stop
  9. //T7 charge

  10. const u32 DISP_PLAY[2] = {9, LCD_RAM_REGISTER0};
  11. const u32 DISP_STOP[2] = {9, LCD_RAM_REGISTER2};
  12. const u32 DISP_GPS[2] = {4, LCD_RAM_REGISTER0};               
  13. const u32 DISP_CLOUD[2] = {4, LCD_RAM_REGISTER2};       
  14. const u32 DISP_BT[2] = {4, LCD_RAM_REGISTER4};               
  15. const u32 DISP_CHARGE[2] = {9, LCD_RAM_REGISTER4};       
  16. const u32 DISP_BATCASE[2] = {9, LCD_RAM_REGISTER6};
  17. const u32 DISP_NOSIGN[2] = {11, LCD_RAM_REGISTER6};
  18. const u32 DISP_EMAX[2] = {1, LCD_RAM_REGISTER2};
  19. const u32 DISP_EMIN[2] = {1, LCD_RAM_REGISTER6};
  20. const u32 DISP_DGREE[2] = {11, LCD_RAM_REGISTER0};
  21. const u32 DISP_RH[2] = {11, LCD_RAM_REGISTER4};
  22. const u32 DISP_DAY[2] = {11, LCD_RAM_REGISTER2};       
  23. const u32 DISP_DOT[2] = {7, LCD_RAM_REGISTER6};
  24. const u32 DISP_MINUS[2] = {1, LCD_RAM_REGISTER4};
  25. const u32 DISP_BAT[4][2] = {
  26.         {10, LCD_RAM_REGISTER2}, //BAR1
  27.         {10, LCD_RAM_REGISTER4}, //BAR2
  28.         {10, LCD_RAM_REGISTER0}, //BAR3
  29.         {10, LCD_RAM_REGISTER6}, //BAR4
  30. };
  31. const u32 DISP_SIGN[5][2] = {
  32.         {0, LCD_RAM_REGISTER6}, //L1
  33.         {0, LCD_RAM_REGISTER4}, //L2
  34.         {0, LCD_RAM_REGISTER2}, //L3
  35.         {0, LCD_RAM_REGISTER0}, //L4
  36.         {1, LCD_RAM_REGISTER0}, //L5
  37. };

  38. const u8 DISP_NUM[3] = {2, 5, 7};
  39. const u8 DISP_NUM_TAB[10][4] =
  40. {
  41.         {3, 2, 3, 2},         //0
  42.         {0, 2, 2, 0},         //1
  43.         {2, 3, 1, 2},         //2
  44.         {2, 3, 2, 2},         //3
  45.         {1, 3, 2, 0},        //4
  46.         {3, 1, 2, 2},         //5
  47.         {3, 1, 3, 2},         //6
  48.         {2, 2, 2, 0},         //7
  49.         {3, 3, 3, 2},         //8
  50.         {3, 3, 2, 2},        //9
  51. };

  52. void Set_Lcd_Dot(const u32 *dot)
  53. {
  54.     HAL_LCD_Write(&hlcd, dot[1], (u32)~(1<<(dot[0]+16)), (u32)(1<<(dot[0]+16)));
  55. }

  56. void Clr_Lcd_Dot(const u32 *dot)
  57. {
  58.     HAL_LCD_Write(&hlcd, dot[1], (u32)~(1<<(dot[0]+16)), 0);
  59. }

  60. void Set_Lcd_Num(const u8 c, u8 num)
  61. {
  62.     HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER0, (u32)~(3<<(DISP_NUM[c]+16)), (u32)(DISP_NUM_TAB[num][0]<<(DISP_NUM[c]+16)));
  63.     HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER2, (u32)~(3<<(DISP_NUM[c]+16)), (u32)(DISP_NUM_TAB[num][1]<<(DISP_NUM[c]+16)));
  64.     HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER4, (u32)~(3<<(DISP_NUM[c]+16)), (u32)(DISP_NUM_TAB[num][2]<<(DISP_NUM[c]+16)));
  65.     HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER6, (u32)~(2<<(DISP_NUM[c]+16)), (u32)(DISP_NUM_TAB[num][3]<<(DISP_NUM[c]+16)));
  66. }

  67. void Clr_Lcd_Num(const u8 c)
  68. {
  69.     HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER0, (u32)~(3<<(DISP_NUM[c]+16)), 0);
  70.     HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER2, (u32)~(3<<(DISP_NUM[c]+16)), 0);
  71.     HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER4, (u32)~(3<<(DISP_NUM[c]+16)), 0);
  72.     HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER6, (u32)~(2<<(DISP_NUM[c]+16)), 0);
  73. }
 楼主| 原来是wjc 发表于 2022-12-25 15:16 | 显示全部楼层
上面的驱动代码中 DISP_PLAY 这样的数组是怎么得来的?根据段码屏资料有如下表(表1):
1388263a7f8c001f3f.png
 楼主| 原来是wjc 发表于 2022-12-25 15:17 | 显示全部楼层
我们把上表转换一下,方便我们查看(表2):
7796663a7f8e879824.png
 楼主| 原来是wjc 发表于 2022-12-25 15:21 | 显示全部楼层
其中 COM1 对应 STM32 的 LCD_RAM_REGISTER 为 LCD_RAM_REGISTER0,COM2 对应 LCD_RAM_REGISTER2,COM3 对应 LCD_RAM_REGISTER4,COM4 对应 LCD_RAM_REGISTER6,如下表:
1247363a7fa096b73f.png
 楼主| 原来是wjc 发表于 2022-12-25 15:22 | 显示全部楼层
所以,我们来看一下 DISP_PLAY[2] = {9, LCD_RAM_REGISTER0},其中第一个值 9 就是 表2 中 T5 所处的列数(SEG端);第二个值 LCD_RAM_REGISTER0 为 T5 所在的行数(COM端)。使用这种方法把段码屏中的所有图标都写下来即可。
 楼主| 原来是wjc 发表于 2022-12-25 15:23 | 显示全部楼层
接下来看下 DISP_NUM[3] = {2, 5, 7} 这行是怎么来的?
变量 DISP_NUM 是记录段码屏中数字所在列位置的起始位置。例如,段码屏中的第 1 个数字最先出现在 表2 中的第 2 列;第 2 个数字最先出现在第 5 列;第 3 个数字最先出现在第 7 列。所以用一个变量 DISP_NUM 记录这些数字就得到 DISP_NUM[3] = {2, 5, 7} 。
 楼主| 原来是wjc 发表于 2022-12-25 15:26 | 显示全部楼层
接下来再看下 DISP_NUM_TAB[10][4] 二维数组里面的一堆数字是怎么来的?
注意,DISP_NUM,以及 DISP_NUM_TAB 里面的内容可以按自己的方法写,这里不一定要这样写。我这样写的目的是配合 Set_Lcd_Num() 这个函数的,此函数不同的实现方法,会导致 DISP_NUM、DISP_NUM_TAB 变量里面的内容不同。
 楼主| 原来是wjc 发表于 2022-12-25 15:27 | 显示全部楼层
由于 Set_Lcd_Num() 函数是一行一行显示段码屏中数字部分内容的,所以 DISP_NUM_TAB 里面的每一个一维数组从 [0] ~ [3] 都完整表达了一个数字。我们就 {3, 2, 3, 2}, //0 数字 0 来说:
 楼主| 原来是wjc 发表于 2022-12-25 15:29 | 显示全部楼层
 楼主| 原来是wjc 发表于 2022-12-25 15:30 | 显示全部楼层
因为 3 个数字的段码一样,所以我们只解析一个数字,把 DISP_NUM_TAB 里的内容填满即可。因为段码每个段都是独立的,显示时不能相互干扰,所以有上图中的权值,就相当于左移,避免段码显示时干扰。那我们来先来填 0,数字 0 占用段码为 A,B,C,D,E,F(只看其中一个数字),第一行 F*1+A*2 = 3; 第二行 0*1+B*2 = 2;第三行 E*1+C*2 = 3;第四行 0*1+D*2 = 2,所以最终数字 0 为 {3, 2, 3, 2};我们再写一个数字 1,数字 1 点段码 B,C,第一行没有B,C,所以为 0*1+0*2 = 0;第二行 0*1+B*2 = 2;第三行 0*1+C*2 = 2;第四行 0*0+0*0 = 0,所以数字 1 最终表示为 {0, 2, 2, 0},后面 2 ~ 9 都是这样写的。
 楼主| 原来是wjc 发表于 2022-12-25 15:31 | 显示全部楼层
接下来看一下 Set_Lcd_Num() 函数中 16 是怎么来的?
7947563a7fc1534427.png
 楼主| 原来是wjc 发表于 2022-12-25 15:32 | 显示全部楼层
这里就要看 STM32L152RC 数据手册了,手册中 LCD 显示缓存如下图:
9048863a7fc62766e1.png
 楼主| 原来是wjc 发表于 2022-12-25 15:33 | 显示全部楼层
上图中 LCD_RAM 寄存器中每一位都是一个 SEG,而我们实际硬件中段码屏的 SEG 只接了 12 个,分别为 SEG16 ~ SEG 27,其它没有用到,所以最终的段码屏数据也要写到 SEG16 ~ SEG27 之中,因此,在写的时候需要偏移到第 16位,因为 0 ~ 15硬件中没使用,写入无效。比如你的硬件中段码屏使用的是 SEG18 ~ SEG26,那你写数据的时候就必须要偏移到第18位。
 楼主| 原来是wjc 发表于 2022-12-25 15:33 | 显示全部楼层
最后我们来看一下 Set_Lcd_Num() 函数中 3,3,3,2 这四个数字怎么来的?
7109563a7fcd0d3da8.png
 楼主| 原来是wjc 发表于 2022-12-25 15:34 | 显示全部楼层
上图中的 3,3,3,2 的意思就是在写数字之前,要先把对应位置的缓存给清除掉,看下图就会明白:
4516663a7fcf242761.png
 楼主| 原来是wjc 发表于 2022-12-25 15:34 | 显示全部楼层
后面还有 Clr_Lcd_Num() 函数,此函数里的内容就很简单了,搞清楚前面文章内容,此函数内容就不成问题了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

87

主题

1250

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0