[综合信息] 华大单片机HC32L136笔段式段码LCD显示

[复制链接]
3498|31
 楼主| 键盘手没手 发表于 2021-1-26 23:34 | 显示全部楼层
根据笔段定义完成显示数值的定义。如数字0为笔段LCDSEG_A+LCDSEG_B+LCDSEG_C+LCDSEG_D+LCDSEG_E+LCDSEG_F,其它的数值或字母使用同样的方法都可以定义。现在做0~F的定义如下:
  1. #define CHAR_0   LCDSEG_A+LCDSEG_B+LCDSEG_C+LCDSEG_D+LCDSEG_E+LCDSEG_F
  2. #define CHAR_1   LCDSEG_B+LCDSEG_C
  3. #define CHAR_2   LCDSEG_A+LCDSEG_B+LCDSEG_D+LCDSEG_E+LCDSEG_G
  4. #define CHAR_3   LCDSEG_A+LCDSEG_B+LCDSEG_C+LCDSEG_D+LCDSEG_G
  5. #define CHAR_4   LCDSEG_B+LCDSEG_C+LCDSEG_F+LCDSEG_G
  6. #define CHAR_5   LCDSEG_A+LCDSEG_C+LCDSEG_D+LCDSEG_F+LCDSEG_G
  7. #define CHAR_6   LCDSEG_A+LCDSEG_C+LCDSEG_D+LCDSEG_E+LCDSEG_F+LCDSEG_G
  8. #define CHAR_7   LCDSEG_A+LCDSEG_B+LCDSEG_C
  9. #define CHAR_8   LCDSEG_A+LCDSEG_B+LCDSEG_C+LCDSEG_D+LCDSEG_E+LCDSEG_F+LCDSEG_G
  10. #define CHAR_9   LCDSEG_A+LCDSEG_B+LCDSEG_C+LCDSEG_D+LCDSEG_F+LCDSEG_G
  11. #define CHAR_A   LCDSEG_A+LCDSEG_B+LCDSEG_C+LCDSEG_E+LCDSEG_F+LCDSEG_G
  12. #define CHAR_b   LCDSEG_C+LCDSEG_D+LCDSEG_E+LCDSEG_F+LCDSEG_G
  13. #define CHAR_C   LCDSEG_A+LCDSEG_D+LCDSEG_E+LCDSEG_F
  14. #define CHAR_d   LCDSEG_B+LCDSEG_C+LCDSEG_D+LCDSEG_E+LCDSEG_G
  15. #define CHAR_E   LCDSEG_A+LCDSEG_D+LCDSEG_E+LCDSEG_F+LCDSEG_G
  16. #define CHAR_F   LCDSEG_A+LCDSEG_E+LCDSEG_F+LCDSEG_G
 楼主| 键盘手没手 发表于 2021-1-26 23:34 | 显示全部楼层
建立MCU LCD模块映射表。 679576010369be332f.png
 楼主| 键盘手没手 发表于 2021-1-26 23:35 | 显示全部楼层
通过上面的图我们可以知道,我们选择LCD 显示模式 0 (MODE = 0)时,要在LCD屏1的位置显示数字0,需要把装有PIN5和PIN6组成的一个字节数据按高4位和低4位拆成两个字节,分别装入MCU的LCDRAM中才可以显示 ,其它位置的显示道理相同,因此我们可以做出如下的映射数组
  1. const uint16_t u16DisTable[] = {
  2.                                  ((CHAR_0 & 0xf0) <<4 | (CHAR_0 & 0x0f)),  //0
  3.                                  ((CHAR_1 & 0xf0) <<4 | (CHAR_1 & 0x0f)),  //1
  4.                                      ((CHAR_2 & 0xf0) <<4 | (CHAR_2 & 0x0f)),  //2
  5.                                      ((CHAR_3 & 0xf0) <<4 | (CHAR_3 & 0x0f)),  //3
  6.                                      ((CHAR_4 & 0xf0) <<4 | (CHAR_4 & 0x0f)),  //4
  7.                                      ((CHAR_5 & 0xf0) <<4 | (CHAR_5 & 0x0f)),  //5
  8.                                      ((CHAR_6 & 0xf0) <<4 | (CHAR_6 & 0x0f)),  //6
  9.                                      ((CHAR_7 & 0xf0) <<4 | (CHAR_7 & 0x0f)),  //7
  10.                                      ((CHAR_8 & 0xf0) <<4 | (CHAR_8 & 0x0f)),  //8
  11.                                      ((CHAR_9 & 0xf0) <<4 | (CHAR_9 & 0x0f)),  //9
  12.                                      ((CHAR_A & 0xf0) <<4 | (CHAR_A & 0x0f)),  //A
  13.                                      ((CHAR_b & 0xf0) <<4 | (CHAR_b & 0x0f)),  //b
  14.                                      ((CHAR_C & 0xf0) <<4 | (CHAR_C & 0x0f)),  //C
  15.                                      ((CHAR_d & 0xf0) <<4 | (CHAR_d & 0x0f)),  //d
  16.                                      ((CHAR_E & 0xf0) <<4 | (CHAR_E & 0x0f)),  //E
  17.                                      ((CHAR_F & 0xf0) <<4 | (CHAR_F & 0x0f)),  //F
  18.        
  19.                                };
 楼主| 键盘手没手 发表于 2021-1-26 23:36 | 显示全部楼层
定义数据类型。由于每个LCDRAM都是32位的的寄存器,里面装的是LCD中两个位置的数据 ,要是直接改变其中的显示数据不是很方便,我们使用共用体来定义成我们方便操作的数据类型,定义如下:
  1. /******************************************************************************
  2. ** \brief LCDRAM
  3. *****************************************************************************/
  4. typedef union{
  5.             uint8_t  u8_dis[4];
  6.                 uint16_t u16_dis[2];
  7.                 uint32_t u32_dis;
  8. }un_Ram_Data;
 楼主| 键盘手没手 发表于 2021-1-26 23:36 | 显示全部楼层
我们之前做的只是数字和字母的映射,特殊点我们并没有映射,现在我们可以做下特殊点的定义如下
  1. /******************************************************************************
  2. ** \brief LCD特殊点
  3. *****************************************************************************/
  4. typedef union{
  5.         uint32_t LcdSegTotle;
  6.         struct{
  7.                 uint8_t LcdSeg_1P:1;
  8.                 uint8_t LcdSeg_2P:1;
  9.                 uint8_t LcdSeg_3P:1;
  10.                 uint8_t LcdSeg_4P:1;
  11.      }stc_Lcd_SP;
  12. }un_Lcd_SP;
 楼主| 键盘手没手 发表于 2021-1-26 23:37 | 显示全部楼层
LCD显示。上面的工作都做完后只要写个简单的LCD显示函数就可以完成LCD的显示工作了。显示代码如下:
  1. void App_LcdDis(uint8_t *u8LcdDisData , un_Lcd_SP *punLcdSp)
  2. {
  3.     un_Ram_Data unRamData[2];
  4.     un_Lcd_SP unLcdSP;
  5.        
  6.         unLcdSP = *punLcdSp;
  7.         unRamData[0].u16_dis[0] = u16DisTable[*u8LcdDisData++];         //取LCD屏第一个位置显示内容
  8.         unRamData[0].u16_dis[1] = u16DisTable[*u8LcdDisData++];         //取LCD屏第二个位置显示内容
  9.         unRamData[1].u16_dis[0] = u16DisTable[*u8LcdDisData++];         //取LCD屏第三个位置显示内容
  10.         unRamData[1].u16_dis[1] = u16DisTable[*u8LcdDisData];           //取LCD屏第四个位置显示内容
  11.         if ( unLcdSP.LcdSegTotle )                                      //检查是否要显示特殊点
  12.         {
  13.                 if(unLcdSP.stc_Lcd_SP.LcdSeg_1P)
  14.                 {
  15.                         unRamData[0].u8_dis[0] |= LCDPOINT1P ;                  //显示第一个位置的特殊点
  16.                 }
  17.                 if(unLcdSP.stc_Lcd_SP.LcdSeg_2P)
  18.                 {
  19.                         unRamData[0].u8_dis[2] |= LCDPOINT2P ;                  //显示第二个位置的特殊点
  20.                 }
  21.                 if(unLcdSP.stc_Lcd_SP.LcdSeg_3P)
  22.                 {
  23.                         unRamData[1].u8_dis[0] |= LCDPOINT3P ;                  //显示第三个位置的特殊点
  24.                 }
  25.                 if(unLcdSP.stc_Lcd_SP.LcdSeg_4P)
  26.                 {
  27.                         unRamData[1].u8_dis[2] |= LCDPOINT4P ;                  //显示第四个位置的特殊点
  28.                 }
  29.         }       
  30.        
  31.         Lcd_WriteRam(0,unRamData[0].u32_dis);  ///< 赋值寄存器LCDRAM0   调用官方的库
  32.     Lcd_WriteRam(1,unRamData[1].u32_dis);  ///< 赋值寄存器LCDRAM1
  33. }
 楼主| 键盘手没手 发表于 2021-1-26 23:37 | 显示全部楼层
主程序如下:
  1. int32_t main(void)
  2. {
  3.     uint8_t   u8LcdData[4] = {0x00};
  4.     un_Lcd_SP unLcdSP;
  5.     Sysctrl_ClkSourceEnable(SysctrlClkRCL,TRUE);            ///< 使能RCL时钟
  6.     Sysctrl_SetRCLTrim(SysctrlRclFreq32768);                ///< 配置内部低速时钟频率为32.768kHz

  7.     Sysctrl_SetPeripheralGate(SysctrlPeripheralLcd,TRUE);   ///< 开启LCD时钟
  8.     Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);  ///< 开启GPIO时钟
  9.    
  10.         DDL_ZERO_STRUCT(unLcdSP);
  11.     App_PortCfg();                                           ///< LCD端口配置
  12.     App_LcdCfg();                                            ///< LCD模块配置

  13.     Lcd_ClearDisp();                                         ///< 清屏     调用官方库清屏
  14.           
  15.         u8LcdData[0] = 9;                                        //显示 9527           
  16.         u8LcdData[1] = 5;
  17.         u8LcdData[2] = 2;
  18.         u8LcdData[3] = 7;
  19.         unLcdSP.stc_Lcd_SP.LcdSeg_1P = 0;
  20.         unLcdSP.stc_Lcd_SP.LcdSeg_2P = 0;
  21.         unLcdSP.stc_Lcd_SP.LcdSeg_3P = 0;
  22.         unLcdSP.stc_Lcd_SP.LcdSeg_4P = 0;          
  23.     App_LcdDis(u8LcdData , &unLcdSP);
  24.        
  25.     while(1);
  26. }
 楼主| 键盘手没手 发表于 2021-1-26 23:38 | 显示全部楼层
程序运行结果如下图 77638601037631654a.png
 楼主| 键盘手没手 发表于 2021-1-26 23:39 | 显示全部楼层
结尾
就我们自己来说,使用最多的屏就是1/4duty和1/3bias的LCD屏,自己在做产品的时候不同的产品使用的屏真值表会不同,我们用几分钟更改下笔段的宏定义,LCD屏直接显示成功。当然,现在我们自己家的产品在做笔段宏定义时按屏的类型做条件编译来定义,使用屏的时候只要做下屏的类型宏定义就可以直接使用,这样更方便。
 楼主| 键盘手没手 发表于 2021-1-26 23:41 | 显示全部楼层
欢迎讨论
linguanghua 发表于 2021-2-4 16:35 | 显示全部楼层
LCD驱动器才5毛钱。。。。3个IO和MCU通信。而带LCD驱动的MCU价格增加不只1元。。。。。
除非体积不够,一般还是用驱动IC便宜。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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