1234下一页
返回列表 发新帖我要提问本帖赏金: 100.00元(功能说明)

[MM32生态] 【MM32+模块】系列:09、LCD12864显示驱动及lkdGui移植与演示

[复制链接]
 楼主| xld0932 发表于 2022-4-19 09:25 | 显示全部楼层 |阅读模式
<
本帖最后由 xld0932 于 2022-4-19 14:57 编辑

#申请原创#   @21小跑堂


简介
HJ12864J是带汉字字库的LCD液晶显示模块,支持三种与MPU的通讯方式,可以通过PSB引脚来设置4位、8位并行或串行的通讯方式。工作电压支持3.3V或者5.0V,由出厂时设定后固定不变,支持自动上电复位功能和外置复位功能。具有48*16bit的字符显示RAM;支持2Mbit的中文字符ROM,共有8192个中文汉字;支持16Kbit的半宽字符ROM,共有126个字母或符号;支持64*16bit的自定义字符RAM;支持多功能指令。
HJ12864J.png

lkdGui是一款为单色显示屏制作的图形化界面,lkdGui主要定位于工业控制领域,用于简单漂亮的图形界面设计。它包含了常用的画图函数如画点、画线、画矩形、文字显示、按钮控件、进度条控件等。它使用窗口进行统一管理和调度,使得各个应用显示模块之间低耦合,方便应用程序的开发和移植。


功能
本文通过自制的MM32F0140最小系统板结合HJ12864J液晶屏,通过8位并行控制方式实现显示驱动及lkdGui的移植和控制显示功能,包含如下内容:
1HJ12864J显示汉字字符和半宽字符
2HJ12864J显示自定义字符
3HJ12864J显示绘图实现画点
4、基于HJ12864JlkdGui移植
5、基于HJ12864JlkdGui控件显示
    5.1.基本图形
    5.2.文本控件
    5.3.滚动条控件
    5.4.进度条控件
    5.5.按钮控件
    5.6.图形控制
    5.7.菜单窗口


1HJ12864J显示汉字字符和半宽字符
HJ12864J显示分辨率为128*64像素点,每一个内置的汉字占16*16个点阵,而半宽字符则占8*16个点阵,所以整个屏幕在满屏时可以显示4*8个汉字字符或者是4*16个半宽型字符。对于汉字字符来说,在写入显示RAMDRAM)时,需要写入2个字节数据,第一个字节为汉字的高8位数据,第二个字节为汉字的低8位数据,两个字节组合成汉字对应码地址;对于半宽型字符而言,在写入显示RAMDRAM)时,也需要跟汉字一样的操作写入2个字节,一个字节为0代表空,另一个字节代表一个半宽型字符,可以参考附件手册中的HCGROM部分的字符对照表。参考代码如下所示:
  1. void LCD12864_CheckBusy(void)
  2. {
  3.     GPIO_InitTypeDef GPIO_InitStructure;

  4.     GPIO_Write(GPIOB, (GPIO_ReadOutputData(GPIOB) & 0xFF00) | 0xFF);

  5.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);

  6.     GPIO_StructInit(&GPIO_InitStructure);
  7.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |
  8.                                     GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 |
  9.                                     GPIO_Pin_6 | GPIO_Pin_7;
  10.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  11.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_FLOATING;
  12.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  13.     LCD12864_RS_L();
  14.     LCD12864_RW_H();
  15.     LCD12864_EN_H();

  16.     while(GPIO_ReadInputData(GPIOB) & 0x0080);

  17.     LCD12864_EN_L();

  18.     GPIO_StructInit(&GPIO_InitStructure);
  19.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |
  20.                                     GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 |
  21.                                     GPIO_Pin_6 | GPIO_Pin_7;
  22.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  23.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  24.     GPIO_Init(GPIOB, &GPIO_InitStructure);
  25. }

  26. void LCD12864_WriteCMD(uint8_t Command)
  27. {
  28.     LCD12864_CheckBusy();

  29.     LCD12864_RS_L();
  30.     LCD12864_RW_L();

  31.     GPIO_Write(GPIOB, (GPIO_ReadOutputData(GPIOB) & 0xFF00) | Command);

  32.     LCD12864_EN_H();
  33.     LCD12864_EN_L();
  34. }

  35. void LCD12864_WriteDAT(uint8_t Data)
  36. {
  37.     LCD12864_CheckBusy();

  38.     LCD12864_RS_H();
  39.     LCD12864_RW_L();

  40.     GPIO_Write(GPIOB, (GPIO_ReadOutputData(GPIOB) & 0xFF00) | Data);

  41.     LCD12864_EN_H();
  42.     LCD12864_EN_L();
  43. }

  44. void LCD12864_DisplayCGROM(uint8_t Address, char *str)
  45. {
  46.     LCD12864_WriteCMD(Address);

  47.     while(*str != '\0')
  48.     {
  49.         LCD12864_WriteDAT(*str++);
  50.     }
  51. }


2HJ12864J显示自定义字符
HJ12864J液晶屏预留了几个可自定义字符空间CGRAM,大小为64*16bit。一个自定义字符为16*16点阵,第一个存入的数据从(40H+00H)地址开始,到(40H+3FH)结束,每个地址存入2个字节数据;先横向取两个字节,再纵向进行累加,共16行。所以自定义的字符为416*16点阵的空间,我们可以利用这个实现16*16的自定义字符的显示,也可以组合成32*32点阵来显示一个更大的图形等用途。参考代码如下所示:
  1. uint8_t LCD12864_CGRAM[128] =
  2. {
  3. 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XC1,0X0F,0XC3,0X1F,0XC7,
  4. 0X3F,0XCF,0X7F,0XDF,0XFF,0XDF,0XFF,0X9F,0XFF,0X1F,0XFE,0X1F,0XFC,0X1F,0XF8,0X1F,

  5. 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XE0,0XFF,0XE0,0XFF,0XE0,
  6. 0XFF,0XE0,0XFF,0XE0,0XFB,0XFF,0XF1,0XFF,0XE0,0XFF,0XC0,0X7F,0X80,0X3F,0X00,0X3F,

  7. 0XFC,0X01,0XFE,0X03,0XFF,0X07,0XFF,0X8F,0XFF,0XDF,0X07,0XFF,0X07,0XFF,0X07,0XFF,
  8. 0X07,0XFF,0X07,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,

  9. 0XF8,0X3F,0XF8,0X7F,0XF8,0XFF,0XF9,0XFF,0XFB,0XFF,0XF7,0XFE,0XE7,0XFC,0XC7,0XF8,
  10. 0X87,0XF0,0X07,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
  11. };

  12. void LCD12864_WriteCGRAM(void)
  13. {
  14.     for(uint8_t i = 0; i < 64; i++)
  15.     {
  16.         LCD12864_WriteCMD(0x40 + i);
  17.         LCD12864_WriteDAT(LCD12864_CGRAM[i*2]);      
  18.         LCD12864_WriteDAT(LCD12864_CGRAM[i*2+1]);      
  19.     }
  20. }

  21. void LCD12864_DisplayCGRAM(uint8_t Address, uint8_t Index)
  22. {
  23.     if((Address >= 0x80) && (Address <= 0x9F))
  24.     {
  25.         Index = (Index % 4) * 2;

  26.         LCD12864_WriteCMD(Address);
  27.         LCD12864_WriteDAT(0x00);
  28.         LCD12864_WriteDAT(Index);
  29.     }
  30. }

3HJ12864J显示绘图实现画点
对于显示内置的汉字或者是半宽型字符而言,大小都是固定的;对于自定义的CGRAM而言,最大也仅仅能显示32*32点阵的大小;而LCD的分辨率达到128*64,如果需要全显示自定义的内容,此时就需要使用到HJ12864J液晶屏的绘图RAM功能。HJ12864J带有64*128bit的绘图RAMGDRAM),通过对GDRAM写入数据,再映射到显示RAM上,可以实现全屏的自定义内容的显示。而此时最基础的操作就是在128*64分辨率的显示屏上实现何意一个位置显示一个像素点,通过一个像素点的绘制来实现全屏内容的显示。参考代码如下所示:
  1. uint8_t LCD12864_GDRAM[64][16];

  2. void LCD12864_DisplayGDRAM(void)
  3. {
  4.     LCD12864_WriteCMD(0x34);
  5.     LCD12864_WriteCMD(0x36);

  6.     for(uint8_t i = 0; i < 32; i++)
  7.     {
  8.         LCD12864_WriteCMD(0x80 + i);
  9.         LCD12864_WriteCMD(0x80 + 0);

  10.         for(uint8_t j = 0; j < 16; j++)
  11.         {
  12.             LCD12864_WriteDAT(LCD12864_GDRAM[i+0x00][j]);
  13.         }
  14.     }

  15.     for(uint8_t i = 0; i < 32; i++)
  16.     {
  17.         LCD12864_WriteCMD(0x80 + i);
  18.         LCD12864_WriteCMD(0x80 + 8);

  19.         for(uint8_t j = 0; j < 16; j++)
  20.         {
  21.             LCD12864_WriteDAT(LCD12864_GDRAM[i+0x20][j]);
  22.         }
  23.     }
  24. }

  25. void LCD12864_DrawPoint(uint8_t x, uint8_t y, uint8_t en)
  26. {
  27.     if(en)
  28.     {
  29.         LCD12864_GDRAM[y][x/8] |=  (0x80 >> (x % 8));
  30.     }
  31.     else
  32.     {
  33.         LCD12864_GDRAM[y][x/8] &= ~(0x80 >> (x % 8));
  34.     }
  35. }


示例代码:
  1. void LCD12864_DisplayDEMO(void)
  2. {
  3.     /* CGROM  : 2Mbit的中文字库ROM,总共有8192个中文字符 */
  4.     LCD12864_DisplayCGROM(0x88, "上海灵动微电子股");
  5.     LCD12864_DisplayCGROM(0x99, "份有限公司");

  6.     /* CGRAM  : 64*16bit的自定义字符RAM */
  7.     LCD12864_WriteCGRAM();

  8.     LCD12864_DisplayCGRAM(0x80, 0);
  9.     LCD12864_DisplayCGRAM(0x81, 1);
  10.     LCD12864_DisplayCGRAM(0x90, 2);
  11.     LCD12864_DisplayCGRAM(0x91, 3);

  12.     /* HCGROM : 16Kbit的半宽字库ROM,总共有126个字母符号 */
  13.     char HCGROM[] = {0x01, 0x03, 0x0};

  14.     LCD12864_DisplayCGROM(0x9E, HCGROM);

  15.     LCD12864_DisplayCGROM(0x82, "Hello World!");
  16.     LCD12864_DisplayCGROM(0x92, "21ic:xld0932");

  17.     SysTick_DelayMS(1000); LCD12864_WriteCMD(0x01); SysTick_DelayMS(3);

  18.     /* GDRAM  : 64*128bit的绘图RAM */
  19.     memset(LCD12864_GDRAM, 0, sizeof(LCD12864_GDRAM));

  20.     LCD12864_DisplayGDRAM();
  21. }

  22. void LCD12864_Init(void)
  23. {
  24.     GPIO_InitTypeDef GPIO_InitStructure;

  25.     /* 控制线:PSB/RS/RW/EN/RST */
  26.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);

  27.     GPIO_StructInit(&GPIO_InitStructure);
  28.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 |
  29.                                     GPIO_Pin_6 | GPIO_Pin_7;
  30.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  31.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  32.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  33.     /* 并行接口 */
  34.     LCD12864_PSB_H();

  35.     /* 默认电平 */
  36.     LCD12864_RS_L();
  37.     LCD12864_RW_L();
  38.     LCD12864_EN_L();

  39.     /* 上电复位 */
  40.     LCD12864_RST_H(); SysTick_DelayMS(50);
  41.     LCD12864_RST_L(); SysTick_DelayMS(50);
  42.     LCD12864_RST_H(); SysTick_DelayMS(50);

  43.     /* 数据线:D0~D7 */
  44.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);

  45.     GPIO_StructInit(&GPIO_InitStructure);
  46.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |
  47.                                     GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 |
  48.                                     GPIO_Pin_6 | GPIO_Pin_7;
  49.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  50.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  51.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  52.     LCD12864_WriteCMD(0x30); /* 8位控制模式 */  SysTick_DelayMS(100);

  53.     LCD12864_WriteCMD(0x30); /* 8位控制模式 */
  54.     LCD12864_WriteCMD(0x06); /* 输入点设定  */
  55.     LCD12864_WriteCMD(0x01); /* 清除显示    */  SysTick_DelayMS(3);
  56.     LCD12864_WriteCMD(0x0C); /* 显示状态开  */
  57.     LCD12864_WriteCMD(0x02); /* 地址归零    */

  58.     LCD12864_DisplayDEMO();

  59.     TASK_Append(TASK_ID_LCD12864, LCD12864_Handler, 1000);
  60. }


综上显示效果图:
DEMO.jpg


4、基于HJ12864JlkdGui移植
在实现了前3点代码功能的基础上,我们再来移植lkdGui就变得简单不少了,我们需要实现3个部分的操作:
4.1.lkdGuiConfig.h文件中实现对LCD液晶显示屏分辨率大小的设定,如下所示:
  1. /* LCD屏幕大小 */
  2. #define GUI_LCM_XMAX        128
  3. #define GUI_LCM_YMAX        64


4.2.userFontPort.c文件中实现对自定义字库提取字模数据的功能,由于MM32F0140芯片内部FLASH空间大小的限制,在本例程中暂不支持全中文字符显示,仅仅用显示英文字符来举例。参考代码如下所示:
  1. lkdFont defaultFont;

  2. static uint8_t GetDfontData(uint8_t code1, uint8_t code2,uint8_t *pBuff)
  3. {
  4.     /* 添加用户代码 */
  5.     return 0;
  6. }

  7. static uint8_t GetSfontData(uint8_t code1, uint8_t *pBuff)
  8. {
  9.     /* 添加用户代码 */
  10.     extern uint8_t GetFontASCII_6_12(uint8_t code1, uint8_t *pBuff);

  11.     GetFontASCII_6_12(code1, pBuff);

  12.     return 0;
  13. }

  14. void defaultFontInit(void)
  15. {
  16.     /* 根据字体要求做相应的修改 */

  17.     /* 此buff的大小由最大字模大小决定 */
  18.     static uint8_t dataBuff[12*12];

  19.     defaultFont.name     = "汉字字模为12*12的GB2312,ASCII字模为12*6";
  20.     defaultFont.dhigh    = 12;
  21.     defaultFont.dwide    = 12;
  22.     defaultFont.shigh    = 12;
  23.     defaultFont.swide    = 6;
  24.     defaultFont.pZmBuff  = dataBuff;
  25.     defaultFont.getDfont = GetDfontData;
  26.     defaultFont.getSfont = GetSfontData;

  27.     /* 设置为系统默认字体 */
  28.     GuiFontSet(&defaultFont);
  29.     GuiSetbackcolor(CWHITLE);
  30.     GuiSetForecolor(CBLACK);
  31. }


4.3.lcdDriverPort文件中实现lkdGui API函数所依赖的LCD底层调用函数,在这些函数中根据实际功能需要进行实现。在我们这个示例程序中需要完成GuiUpdateDisplayAllGuiDrawPoint这两个函数功能,参考代码如下所示:
  1. void GuiUpdateDisplayAll(void)
  2. {
  3.     /* 添加用户代码 */
  4.     LCD12864_DisplayGDRAM();
  5. }

  6. void GuiRangeUpdateDisplay(lkdCoord beginx, lkdCoord beginy,lkdCoord endx, lkdCoord endy)
  7. {
  8.     /* 添加用户代码 */
  9. }

  10. void GuiDrawPoint(lkdCoord x, lkdCoord y, lkdColour color)
  11. {
  12.     /* 添加用户代码 */
  13.     if(color) LCD12864_DrawPoint(x, y, 1);
  14.     else      LCD12864_DrawPoint(x, y, 0);
  15. }

  16. void  GuiReadPoint(lkdCoord x, lkdCoord y, lkdColour *pColor)
  17. {
  18.         /* 添加用户代码 */
  19. }

  20. void CloseLcdDisplay(void)
  21. {
  22.     /* 添加用户代码 */
  23. }

  24. void OpenLcdDisplay(void)
  25. {
  26.     /* 添加用户代码 */
  27. }



5、基于HJ12864JlkdGui控件显示

5.1.基本图形
lkdGui的基本图形包含了斜线、水平线、垂直线、水平点线、垂直点线、矩形、填充矩形。参考程序如下所示:
  1. void lkdGui_Demo1(void)
  2. {
  3.     /* 画点 */
  4.     GuiPoint(5, 5, forecolor);

  5.     /* 画斜线 */
  6.     GuiBiasLine(10, 0, 20, 20, forecolor);
  7.     GuiBiasLine(20, 0, 40, 20, forecolor);
  8.     GuiBiasLine(30, 0, 60, 20, forecolor);
  9.     GuiBiasLine(40, 0, 80, 20, forecolor);

  10.     /* 画水平点线 */
  11.     GuiHPointLine(90,  5, 120, 2, forecolor);
  12.     GuiHPointLine(90, 10, 120, 3, forecolor);
  13.     GuiHPointLine(90, 15, 120, 4, forecolor);
  14.     GuiHPointLine(90, 20, 120, 5, forecolor);

  15.     /* 画水平线 */
  16.     GuiHLine(0, 25, 127, forecolor);

  17.     /* 画垂直点线 */
  18.     GuiRPointLine(10, 30, 50, 2, forecolor);
  19.     GuiRPointLine(20, 30, 50, 3, forecolor);
  20.     GuiRPointLine(30, 30, 50, 4, forecolor);
  21.     GuiRPointLine(40, 30, 50, 5, forecolor);

  22.     /* 画垂直线 */
  23.     GuiRLine(50, 30, 50, forecolor);

  24.     /* 画矩形 */
  25.     GuiRect(55, 30, 75, 50, forecolor);

  26.     /* 画填充矩形 */
  27.     GuiFillRect(80, 30, 120, 50, forecolor);

  28.     /* 更新 */
  29.     GuiUpdateDisplayAll();
  30.     SysTick_DelayMS(1000);

  31.     GuiClearScreen(0);
  32.     GuiUpdateDisplayAll();
  33. }

基本图形显示效果:
基本图形.jpg

5.2.文本控件
lkdGui文本控件可以显示单行文本,也可以显示多行文本;可以设置文本显示的起始坐标、宽高、字符间距、行间距、缩进显示,以及是否是反显示显示等参数。参考程序如下所示:
  1. void lkdGui_Demo2(void)
  2. {
  3.     uint8_t *textStr = (uint8_t *)("Hello World!");

  4.     fontTextInfo textInfo;/* 定义文本信息结构 */

  5.     /* -----------1--------------- */
  6.     GuiRect(0, 0, 127, 16, forecolor);
  7.     textInfo.x           = 2;   /* 文本起始坐标 */
  8.     textInfo.y           = 3;
  9.     textInfo.wide        = 156; /* 文本范围大小 */
  10.     textInfo.high        = 16;
  11.     textInfo.wInterval   = 0;   /* 字符间距 */
  12.     textInfo.hInterval   = 2;   /* 行间距   */
  13.     textInfo.flag        = 0;   /* 不反显   */
  14.     textInfo.beginOffset = defaultFont.dwide * 2;   /* 开始偏移,首行缩进 */
  15.     GuiText(&textInfo, textStr);

  16.     /* -----------2--------------- */
  17.     GuiFillRect(0, 20, 127, 36, forecolor);
  18.     textInfo.x           = 2;   /* 文本起始坐标 */
  19.     textInfo.y           = 23;
  20.     textInfo.flag        = 1;   /* 反显 */
  21.     textInfo.beginOffset = defaultFont.dwide * 2;   /* 开始偏移,首行缩进 */
  22.     GuiText(&textInfo, textStr);

  23.     /* -----------3---------------- */
  24.     GuiRect(0, 40, 127, 56, forecolor);
  25.     textInfo.x           = 2;   /* 文本起始坐标 */
  26.     textInfo.y           = 43;
  27.     textInfo.flag        = 1;   /* 反显 */
  28.     textInfo.beginOffset = defaultFont.dwide * 2;   /* 开始偏移,首行缩进 */
  29.     GuiText(&textInfo, textStr);

  30.     /* 更新 */
  31.     GuiUpdateDisplayAll();
  32.     SysTick_DelayMS(1000);

  33.     GuiClearScreen(0);
  34.     GuiUpdateDisplayAll();
  35. }

文本控件显示效果:
文本控件.jpg

5.3.滚动条控件
lkdGui滚动条支持水平滚动条和垂直滚动条这两种,可以设置滚动条的起始坐标、显示长度,以及平均把显示长度分成几等分等参数,参考程序如下所示:
  1. void lkdGui_Demo3(void)
  2. {
  3.     lkdScroll VScroll;
  4.     lkdScroll HScroll;

  5.     HScroll.x     = 0x00;
  6.     HScroll.y     = 0x3C;
  7.     HScroll.hight = 0x80;
  8.     HScroll.max   = 0x0A;        

  9.     for(uint8_t i = 0; i < HScroll.max; i++)
  10.     {
  11.         HScroll.lump = i;       /* 进度快控制 */
  12.         GuiHScroll(&HScroll);   /* 水平进度条 */

  13.         GuiUpdateDisplayAll();  /* 更新进度条 */
  14.         SysTick_DelayMS(0xFA);
  15.     }

  16.     GuiClearScreen(0);
  17.     GuiUpdateDisplayAll();

  18.     VScroll.x     = 0x7C;
  19.     VScroll.y     = 0x00;
  20.     VScroll.hight = 0x40;
  21.     VScroll.max   = 0x0A;        

  22.     for(uint8_t i = 0; i < VScroll.max; i++)
  23.     {
  24.         VScroll.lump = i;       /* 进度快控制 */
  25.         GuiVScroll(&VScroll);   /* 垂直进度条 */

  26.         GuiUpdateDisplayAll();  /* 更新进度条 */
  27.         SysTick_DelayMS(0xFA);
  28.     }

  29.     GuiClearScreen(0);
  30.     GuiUpdateDisplayAll();
  31. }

滚动条控件显示效果:
滚动条.GIF

5.4.进度条控件
lkdGui进度条控制当前仅支持水平方向的显示,可以设置进度条的起始坐标、宽度、高度,以及当前的进度百分比,可以结合文件控件显示当前的进度百分比数值,参考程序如下所示:
  1. void lkdGui_Demo4(void)
  2. {
  3.     lkdProgress tProGress;
  4.     uint8_t ratioStr[8];

  5.     tProGress.x     = 0;
  6.     tProGress.y     = 10;
  7.     tProGress.wide  = 100;
  8.     tProGress.high  = defaultFont.dhigh;
  9.     tProGress.ratio = 0;

  10.     for(uint8_t i = 0; i <= 100; i+=5)
  11.     {
  12.         tProGress.ratio = i;    /* 进度控制 */
  13.         GuiProGress(&tProGress);/* 画进度条 */

  14.         sprintf((char *)ratioStr, "%d%%", tProGress.ratio);

  15.         GuiFillRect(102, 11, 122, 22, backcolor);

  16.         GuiRowText(102, 11, 24, FONT_RIGHT, ratioStr);

  17.         GuiUpdateDisplayAll();  /* 更新 */
  18.         SysTick_DelayMS(0xFA);
  19.         SysTick_DelayMS(0xFA);
  20.     }

  21.     GuiClearScreen(0);
  22.     GuiUpdateDisplayAll();
  23. }

进度条控件显示效果:
进度条.GIF

5.5.按钮控件
lkdGui按钮控件支持按下和抬起两种按键效果,支持按键控件的起始坐标、宽度、高度、初始状态以及按键显示内容的参数设定,参考程序如下所示:
  1. void lkdGui_Demo5(void)
  2. {
  3.     lkdButton tButton;

  4.     tButton.x    = 16;
  5.     tButton.y    = 10;
  6.     tButton.wide = defaultFont.dwide * 2 + 15;
  7.     tButton.high = defaultFont.dhigh + 5;
  8.     tButton.name = (uint8_t *)"OK";
  9.     tButton.flag = 0;       /* 抬起状态 */
  10.     GuiButton(&tButton);

  11.     tButton.x    = 16;
  12.     tButton.y    = 40;
  13.     tButton.wide = defaultFont.dwide * 2 + 15;
  14.     tButton.high = defaultFont.dhigh + 5;
  15.     tButton.name = (uint8_t *)"RUN";
  16.     tButton.flag = 0;       /* 抬起状态 */
  17.     GuiButton(&tButton);

  18.     tButton.x    = 73;
  19.     tButton.y    = 40;
  20.     tButton.wide = defaultFont.dwide * 2 + 15;
  21.     tButton.high = defaultFont.dhigh + 5;
  22.     tButton.name = (uint8_t *)"STOP";
  23.     tButton.flag = 0;       /* 抬起状态 */
  24.     GuiButton(&tButton);

  25.     GuiUpdateDisplayAll();  /* 更新显示 */
  26.     SysTick_DelayMS(1000);

  27.     for(uint8_t i = 0; i < 3; i++)
  28.     {
  29.         tButton.x    = 16;
  30.         tButton.y    = 10;
  31.         tButton.wide = defaultFont.dwide * 2 + 15;
  32.         tButton.high = defaultFont.dhigh + 5;
  33.         tButton.name = (uint8_t *)"CACLE";
  34.         tButton.flag = 1;       /* 按下状态 */
  35.         GuiButton(&tButton);

  36.         GuiUpdateDisplayAll();
  37.         SysTick_DelayMS(0xFA);
  38.         SysTick_DelayMS(0xFA);

  39.         tButton.x    = 16;
  40.         tButton.y    = 10;
  41.         tButton.wide = defaultFont.dwide * 2 + 15;
  42.         tButton.high = defaultFont.dhigh + 5;
  43.         tButton.name = (uint8_t *)"OK";
  44.         tButton.flag = 0;       /* 抬起状态 */
  45.         GuiButton(&tButton);

  46.         GuiUpdateDisplayAll();
  47.         SysTick_DelayMS(0xFA);
  48.         SysTick_DelayMS(0xFA);
  49.     }

  50.     GuiClearScreen(0);
  51.     GuiUpdateDisplayAll();
  52. }

按钮控件显示效果:
按钮控件.GIF

5.6.图形控件
lkdGui图形控件最大运行满屏显示效果,对于图形控件,可以指定显示坐标、宽度、高度、图片的数据源等参数后进行绘制;可以根据图片偏移坐标来实现图片的移动效果,支持图片在显示区域范围内上下左右的方向进行移动显示。参考程序如下所示:
  1. void lkdGui_Demo6(void)
  2. {
  3.     uint8_t lkdGuiImage1[] =
  4.     {
  5.         0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
  6.         0X00,0X00,0X00,0X00,0X07,0XC1,0XFF,0XE0,0X0F,0XC3,0XFF,0XE0,0X1F,0XC7,0XFF,0XE0,
  7.         0X3F,0XCF,0XFF,0XE0,0X7F,0XDF,0XFF,0XE0,0XFF,0XDF,0XFB,0XFF,0XFF,0X9F,0XF1,0XFF,
  8.         0XFF,0X1F,0XE0,0XFF,0XFE,0X1F,0XC0,0X7F,0XFC,0X1F,0X80,0X3F,0XF8,0X1F,0X00,0X3F,
  9.         0XFC,0X01,0XF8,0X3F,0XFE,0X03,0XF8,0X7F,0XFF,0X07,0XF8,0XFF,0XFF,0X8F,0XF9,0XFF,
  10.         0XFF,0XDF,0XFB,0XFF,0X07,0XFF,0XF7,0XFE,0X07,0XFF,0XE7,0XFC,0X07,0XFF,0XC7,0XF8,
  11.         0X07,0XFF,0X87,0XF0,0X07,0XFF,0X07,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
  12.         0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
  13.     };

  14.     uint8_t lkdGuiImage2[] =
  15.     {
  16.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  17.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x78,0x00,
  18.         0x00,0x01,0xE0,0x01,0xFC,0x00,0x00,0x00,0x03,0x00,0x01,0xF0,0xFC,0x00,0x00,0x03,
  19.         0xF0,0x0F,0xFF,0x00,0x00,0x00,0x07,0x80,0x03,0xF8,0xFC,0x00,0x00,0x03,0xF8,0x1F,
  20.         0xFF,0x80,0x00,0x00,0x0F,0xC0,0x03,0xF9,0xEE,0x00,0x00,0x07,0xF8,0x3F,0xFF,0xC0,
  21.         0x00,0x00,0x1C,0xE0,0x07,0x1D,0xCE,0x00,0x00,0x07,0x38,0x7C,0x01,0xE0,0x00,0x00,
  22.         0x18,0x60,0x07,0x1D,0xCE,0x00,0x00,0x07,0x38,0xF0,0x00,0xF0,0x30,0x0C,0x1C,0xE0,
  23.         0x07,0x1D,0xCE,0x1E,0x01,0xFF,0x3C,0xE1,0xFC,0x70,0x7C,0x1F,0x0F,0xC0,0x07,0x1D,
  24.         0xCE,0x7F,0x03,0xFF,0x3C,0xE7,0xFF,0x70,0xFE,0x3F,0x87,0x80,0x07,0x1D,0xCE,0xFF,
  25.         0x87,0xFF,0x3D,0xC7,0xFF,0xF0,0xEE,0x3B,0x8F,0xC0,0x07,0x1D,0xCF,0xE3,0x8F,0x03,
  26.         0x3D,0xCF,0x00,0x01,0xC6,0x31,0x9C,0xE0,0x07,0x1D,0xCF,0xC7,0x9E,0x00,0x3D,0x8E,
  27.         0x1F,0xF9,0xC6,0x31,0xDC,0xE0,0x07,0x1D,0xC7,0x0F,0x1C,0x7C,0x3D,0x8E,0x3F,0xFD,
  28.         0xC6,0x31,0xDC,0xE0,0x07,0x1D,0xC0,0x1E,0x1C,0xFE,0x3D,0x8E,0x38,0x1D,0xC6,0x31,
  29.         0xDC,0xE0,0x07,0x1D,0xC0,0x18,0x18,0xFE,0x3D,0x8E,0x30,0x0D,0xC6,0x31,0xDC,0xE0,
  30.         0x07,0x1D,0xC0,0x1C,0x18,0xFE,0x3D,0xCE,0x3E,0x79,0xC6,0x31,0xDC,0xE0,0x07,0x1D,
  31.         0xC3,0x0E,0x18,0xFE,0x3D,0xCF,0x3E,0x79,0xC6,0x71,0xDC,0xE0,0x07,0x1D,0xC7,0xC7,
  32.         0x1C,0xFE,0x3D,0xC7,0xFE,0x71,0xC7,0xF1,0xDC,0xE0,0x07,0x1D,0xCF,0xC7,0x9C,0x7C,
  33.         0x3C,0xE3,0xFC,0x71,0xC7,0xF1,0xDC,0xE0,0x07,0x1D,0xCF,0xE3,0xDC,0x00,0x38,0xF0,
  34.         0xF0,0x71,0xE3,0xE3,0xDC,0xE0,0x07,0x1D,0xCE,0xF3,0xCF,0x00,0x38,0x78,0x00,0x70,
  35.         0xE0,0x03,0x9C,0xE0,0x03,0x19,0xEC,0x7F,0xCF,0xFF,0xF8,0x7F,0xFE,0x70,0xFF,0xFF,
  36.         0x9C,0xE0,0x03,0xF9,0xFC,0x3F,0x87,0xFF,0xF8,0x3F,0xFF,0xE0,0x7F,0xFF,0x9F,0xE0,
  37.         0x03,0xF8,0xFC,0x1F,0x03,0xFF,0xF0,0x1F,0xFF,0xE0,0x3F,0xFF,0x8F,0xC0,0x01,0xF0,
  38.         0x78,0x0E,0x00,0xFF,0xE0,0x07,0xFF,0xC0,0x0F,0xFF,0x07,0x80,0x00,0x00,0x00,0x00,
  39.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  40.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  41.     };

  42.     lkdBitmap tImage;

  43.     tImage.beginx = 0;              /* 图像开始显示偏移 */
  44.     tImage.beginy = 0;
  45.     tImage.wide   = 32;             /* 图像本身的大小 */
  46.     tImage.high   = 32;
  47.     tImage.bitmap = lkdGuiImage1;   /* 图像 */
  48.     GuiAreaBitMap(&tImage, 0+8, 0, 32+8, 32, 0);

  49.     GuiUpdateDisplayAll();          /* 更新 */

  50.     tImage.beginx = 0;              /* 图像开始显示偏移 */
  51.     tImage.beginy = 0;
  52.     tImage.wide   = 112;            /* 图像本身的大小 */
  53.     tImage.high   = 28;
  54.     tImage.bitmap = lkdGuiImage2;   /* 图像 */
  55.     GuiAreaBitMap(&tImage, 8, 32, 120, 60, 0);

  56.     GuiUpdateDisplayAll();          /* 更新 */
  57.     SysTick_DelayMS(0xFA);

  58.     for(uint8_t i = 0; i < 112; i++)
  59.     {
  60.         tImage.beginx = i;
  61.         tImage.beginy = 0;

  62.         GuiAreaBitMap(&tImage, 8, 32, 120, 60, 0);

  63.         GuiUpdateDisplayAll();
  64.         SysTick_DelayMS(0x32);
  65.     }

  66.     for(int16_t i = 112; i >= 0; i--)
  67.     {
  68.         tImage.beginx = i;
  69.         tImage.beginy = 0;

  70.         GuiAreaBitMap(&tImage, 8, 32, 120, 60, 0);

  71.         GuiUpdateDisplayAll();
  72.         SysTick_DelayMS(0x32);
  73.     }

  74.     for(uint8_t i = 0; i <= 28; i++)
  75.     {
  76.         tImage.beginx = 0;
  77.         tImage.beginy = i;

  78.         GuiAreaBitMap(&tImage, 8, 32, 120, 60, 0);

  79.         GuiUpdateDisplayAll();
  80.         SysTick_DelayMS(0x32);
  81.     }

  82.     for(int8_t i = 28; i >= 0; i--)
  83.     {
  84.         tImage.beginx = 0;
  85.         tImage.beginy = i;

  86.         GuiAreaBitMap(&tImage, 8, 32, 120, 60, 0);

  87.         GuiUpdateDisplayAll();
  88.         SysTick_DelayMS(0x32);
  89.     }

  90.     GuiClearScreen(0);
  91.     GuiUpdateDisplayAll();
  92. }

图形控件显示效果:
图形控制1.GIF 图形控件2.GIF

5.7.菜单窗口
lkdGui是使用窗口进行统一管理和调度的,所以在while(1)循环中需要调用GuiWinDisplay窗口高度函数;在系统上电的时候通过调用GuiWinInit函数来初始化窗口的相关资源,随后通过GuiWinAdd函数来添加窗口、通过GuiGetTopWin函数来获取当前显示的窗口、以及通过调用GuiWinDeleteTop函数来实现将当前的窗口对象从窗口调度中移除等操作;我们结合菜单的实例来进行功能演示,参考程序如下所示:
  1. lkdWin TestWIN, MainWIN;

  2. uint32_t GetIntervalTick(uint32_t Tick)
  3. {
  4.     if(SysTick_Tick > Tick)
  5.     {
  6.         return (SysTick_Tick - Tick);
  7.     }
  8.     else
  9.     {
  10.         return (SysTick_Tick + (UINT32_MAX - Tick));
  11.     }
  12. }

  13. void TestWIN_CallBack(void)
  14. {
  15.     /* 窗口内容具体代码实现 */
  16.     static uint8_t     State = 0;
  17.     static uint32_t    Test_Tick;
  18.     static lkdProgress Progress;

  19.     if(State == 0)
  20.     {
  21.         State = 1;

  22.         Progress.x     = 9;
  23.         Progress.y     = 15;
  24.         Progress.ratio = 0;
  25.         Progress.wide  = 109;
  26.         Progress.high  = 10;
  27.     }

  28.     if(State == 1)
  29.     {
  30.         State = 2;

  31.         GuiProGress(&Progress);
  32.         GuiUpdateDisplayAll();

  33.         Test_Tick = SysTick_Tick;
  34.     }

  35.     if(State == 2)
  36.     {
  37.         if(GetIntervalTick(Test_Tick) > 1000)
  38.         {
  39.             State = 1;

  40.             Progress.ratio += 5;

  41.             if(Progress.ratio > 100)
  42.             {
  43.                 State = 3;
  44.             }
  45.         }
  46.     }

  47.     if(State == 3)
  48.     {
  49.         State = 0;

  50.         /* 删除当前窗口 */
  51.         GuiWinDeleteTop();

  52.         GuiUpdateDisplayAll();
  53.     }
  54. }

  55. void MainWIN_Callback(void)
  56. {
  57.     /* 窗口内容具体代码实现 */
  58.     static uint8_t  State = 0;
  59.     static uint32_t Main_Tick;

  60.     if(State == 0)
  61.     {
  62.         State = 1;
  63.     }

  64.     if(State == 1)
  65.     {
  66.         State = 2;

  67.         GuiRowText(0, 0, 128, FONT_MID, (uint8_t *)"MAIN");
  68.         GuiUpdateDisplayAll();

  69.         Main_Tick = SysTick_Tick;
  70.     }

  71.     if(State == 2)
  72.     {
  73.         if(GetIntervalTick(Main_Tick) > 5000)
  74.         {
  75.             State = 0;

  76.             /* 创建窗口 */
  77.             TestWIN.x     = 0;
  78.             TestWIN.y     = 0;
  79.             TestWIN.hight = 128;
  80.             TestWIN.wide  = 128;
  81.             TestWIN.title = NULL;
  82.             TestWIN.WindowFunction = (void *)TestWIN_CallBack;

  83.             /* 添加窗口 */
  84.             GuiWinAdd(&TestWIN);
  85.         }
  86.     }
  87. }

  88. void lkdGui_Demo7(void)
  89. {
  90.     /* 1. 定义一个菜单项 */
  91.     #define MENUSTACK_NUM 8

  92.     MenuStack userMenuStack[MENUSTACK_NUM];

  93.     /* 2. 定义二级菜单 */
  94.     lkdMenuNode Node3_3 = {6, (uint8_t *)"no1-3", NULL,     NULL,     NULL};
  95.     lkdMenuNode Node2_2 = {5, (uint8_t *)"no1-2", &Node3_3, NULL,     NULL};
  96.     lkdMenuNode Node1_1 = {4, (uint8_t *)"no1-1", &Node2_2, NULL,     NULL};

  97.     /* 3. 定义一级菜单 */
  98.     lkdMenuNode Node3   = {3, (uint8_t *)"no3",   NULL,     NULL,     NULL};
  99.     lkdMenuNode Node2   = {2, (uint8_t *)"no2",   &Node3,   NULL,     NULL};
  100.     lkdMenuNode Node1   = {1, (uint8_t *)"no1",   &Node2,   &Node1_1, NULL};

  101.     /* 3. 定义根菜单 */
  102.     lkdMenuNode NodeRoot0 = {0, (uint8_t *)"root",NULL,     &Node1,   NULL};

  103.     /* 初始化根节点 */
  104.     lkdMenu root =
  105.     {
  106.         .x         = 0,
  107.         .y         = 0,
  108.         .wide      = 128,
  109.         .hight     = 64,
  110.         .ItemsWide = 48,
  111.         .Itemshigh = 15,
  112.         .index     = 1,     /* 默认选中节点 */
  113.         .stackNum  = MENUSTACK_NUM,
  114.         .stack     = userMenuStack,
  115.         .Root      = &NodeRoot0
  116.     };

  117.     /* 初始化菜单 */
  118.     GuiMenuInit(&root);

  119.     /* 展开当前选中节点 */
  120.     GuiMenuCurrentNodeSonUnfold(&root);

  121.     GuiUpdateDisplayAll();  /* 更新显示 */
  122.     SysTick_DelayMS(0xFA);
  123.     SysTick_DelayMS(0xFA);

  124.     GuiMenuCurrentNodeSonUnfold(&root);

  125.     GuiUpdateDisplayAll();  /* 更新显示 */
  126.     SysTick_DelayMS(0xFA);
  127.     SysTick_DelayMS(0xFA);

  128.     /* 选中下移 */
  129.     GuiMenuItemDownMove(&root);

  130.     GuiUpdateDisplayAll();  /* 更新显示 */
  131.     SysTick_DelayMS(1000);

  132.     GuiClearScreen(0);

  133.     /* 创建窗口 */
  134.     MainWIN.x     = 0;
  135.     MainWIN.y     = 0;
  136.     MainWIN.hight = 128;
  137.     MainWIN.wide  = 128;
  138.     MainWIN.title = NULL;
  139.     MainWIN.WindowFunction = (void *)MainWIN_Callback;

  140.     /* 添加窗口 */
  141.         GuiWinAdd(&MainWIN);
  142. }

菜单窗口显示效果:
菜单窗口.GIF


附件:
HJ12864J带汉字液晶显示模块说明书: HJ12864J带汉字液晶显示模块说明书.pdf (551.55 KB, 下载次数: 33)
软件工程源代码: 09.LCD12864J.zip (1.19 MB, 下载次数: 46)
字模提取的工具: 点阵液晶取模.zip (255.91 KB, 下载次数: 33)

打赏榜单

21小跑堂 打赏了 100.00 元 2022-04-20
理由:恭喜通过原创文章审核!请多多加油哦!

评论

厉害了我的哥  发表于 2022-5-13 09:09
www5911839 发表于 2022-4-19 12:16 | 显示全部楼层
太赞了,要搞块MM32的评估板实操起来啦
 楼主| xld0932 发表于 2022-4-19 12:52 | 显示全部楼层
www5911839 发表于 2022-4-19 12:16
太赞了,要搞块MM32的评估板实操起来啦

看我这个系列帖的第一篇,在附件中有Gerber文件的,可以直接在嘉立创上下单,打个PCB样板;自己做一块,就可以玩起来了哈……
www5911839 发表于 2022-4-19 16:25 | 显示全部楼层
ok, 谢谢
ysf 发表于 2022-4-19 16:45 | 显示全部楼层
原来这类带字库的LCD,是不能在汉字后写8*16数字。这个问题困扰了我好久。发现写8*16字数,它也总是要占用16*16,一直以为是程序问题
 楼主| xld0932 发表于 2022-4-19 17:09 | 显示全部楼层
ysf 发表于 2022-4-19 16:45
原来这类带字库的LCD,是不能在汉字后写8*16数字。这个问题困扰了我好久。发现写8*16字数,它也总是要占用1 ...

希望这篇**可以给你提供些参考哦
tpgf 发表于 2022-5-3 16:51 | 显示全部楼层
这个移植很不错啊
aoyi 发表于 2022-5-3 16:58 | 显示全部楼层
这是哪块评估板啊
nawu 发表于 2022-5-3 17:14 | 显示全部楼层
这个动态显示的很好啊
zljiu 发表于 2022-5-3 18:02 | 显示全部楼层
这种动态更新的怎么做呢
gwsan 发表于 2022-5-3 18:05 | 显示全部楼层
请问如何把控字库的大小呢
tfqi 发表于 2022-5-3 18:19 | 显示全部楼层
手头资源一定要利用起来才能学到东西啊
 楼主| xld0932 发表于 2022-5-3 21:58 | 显示全部楼层
tfqi 发表于 2022-5-3 18:19
手头资源一定要利用起来才能学到东西啊

 楼主| xld0932 发表于 2022-5-4 21:46 | 显示全部楼层
gwsan 发表于 2022-5-3 18:05
请问如何把控字库的大小呢

如果是LCD自带字库的,这个大小点阵是相对固定的;对字库的实现方式有很多呀,比如你自己通过PC软件取模,生成点阵数据;又或者是专门的字库芯片,这类的芯片支持的大小、字体样式、以及多语种都有丰富的选择性。
 楼主| xld0932 发表于 2022-5-4 21:47 | 显示全部楼层
zljiu 发表于 2022-5-3 18:02
这种动态更新的怎么做呢

下载附件软件源码工程,看代码中是怎么实现的哦
 楼主| xld0932 发表于 2022-5-4 21:49 | 显示全部楼层
aoyi 发表于 2022-5-3 16:58
这是哪块评估板啊

这个是自己制作的板子,你可以看这个系列的第一篇,附件中有GERBER文件,你可以直接打板哦
kiwis66 发表于 2022-5-12 20:35 | 显示全部楼层
很不错啊
 楼主| xld0932 发表于 2022-5-12 21:02 | 显示全部楼层
yangxiaor520 发表于 2022-5-13 08:34 来自手机 | 显示全部楼层
现在用12864液晶的很少了吧
kiwis66 发表于 2022-5-14 14:21 | 显示全部楼层
yangxiaor520 发表于 2022-5-13 08:34
现在用12864液晶的很少了吧

上学的时候用过,留了一块一直到现在
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:King.Xu

77

主题

3023

帖子

38

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