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

简介
HJ12864J是带汉字字库的LCD液晶显示模块,支持三种与MPU的通讯方式,可以通过PSB引脚来设置4位、8位并行或串行的通讯方式。工作电压支持3.3V或者5.0V,由出厂时设定后固定不变,支持自动上电复位功能和外置复位功能。具有48*16bit的字符显示RAM;支持2Mbit的中文字符ROM,共有8192个中文汉字;支持16Kbit的半宽字符ROM,共有126个字母或符号;支持64*16bit的自定义字符RAM;支持多功能指令。
lkdGui是一款为单色显示屏制作的图形化界面,lkdGui主要定位于工业控制领域,用于简单漂亮的图形界面设计。它包含了常用的画图函数如画点、画线、画矩形、文字显示、按钮控件、进度条控件等。它使用窗口进行统一管理和调度,使得各个应用显示模块之间低耦合,方便应用程序的开发和移植。

功能
本文通过自制的MM32F0140最小系统板结合HJ12864J液晶屏,通过8位并行控制方式实现显示驱动及lkdGui的移植和控制显示功能,包含如下内容:
1、HJ12864J显示汉字字符和半宽字符
2、HJ12864J显示自定义字符
3、HJ12864J显示绘图实现画点
4、基于HJ12864J的lkdGui移植
5、基于HJ12864J的lkdGui控件显示
    5.1.基本图形
    5.2.文本控件
    5.3.滚动条控件
    5.4.进度条控件
    5.5.按钮控件
    5.6.图形控制
    5.7.菜单窗口
1、HJ12864J显示汉字字符和半宽字符
HJ12864J显示分辨率为128*64像素点,每一个内置的汉字占16*16个点阵,而半宽字符则占8*16个点阵,所以整个屏幕在满屏时可以显示4行*8个汉字字符或者是4行*16个半宽型字符。对于汉字字符来说,在写入显示RAM(DRAM)时,需要写入2个字节数据,第一个字节为汉字的高8位数据,第二个字节为汉字的低8位数据,两个字节组合成汉字对应码地址;对于半宽型字符而言,在写入显示RAM(DRAM)时,也需要跟汉字一样的操作写入2个字节,一个字节为0代表空,另一个字节代表一个半宽型字符,可以参考附件手册中的HCGROM部分的字符对照表。参考代码如下所示:
void LCD12864_CheckBusy(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;



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



    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);



    GPIO_StructInit(&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |

                                    GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 |

                                    GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_FLOATING;

    GPIO_Init(GPIOB, &GPIO_InitStructure);



    LCD12864_RS_L();

    LCD12864_RW_H();

    LCD12864_EN_H();



    while(GPIO_ReadInputData(GPIOB) & 0x0080);



    LCD12864_EN_L();



    GPIO_StructInit(&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |

                                    GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 |

                                    GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

}



void LCD12864_WriteCMD(uint8_t Command)

{

    LCD12864_CheckBusy();



    LCD12864_RS_L();

    LCD12864_RW_L();



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



    LCD12864_EN_H();

    LCD12864_EN_L();

}



void LCD12864_WriteDAT(uint8_t Data)

{

    LCD12864_CheckBusy();



    LCD12864_RS_H();

    LCD12864_RW_L();



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



    LCD12864_EN_H();

    LCD12864_EN_L();

}



void LCD12864_DisplayCGROM(uint8_t Address, char *str)

{

    LCD12864_WriteCMD(Address);



    while(*str != '\0')

    {

        LCD12864_WriteDAT(*str++);

    }

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

{

0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XC1,0X0F,0XC3,0X1F,0XC7,

0X3F,0XCF,0X7F,0XDF,0XFF,0XDF,0XFF,0X9F,0XFF,0X1F,0XFE,0X1F,0XFC,0X1F,0XF8,0X1F,



0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XE0,0XFF,0XE0,0XFF,0XE0,

0XFF,0XE0,0XFF,0XE0,0XFB,0XFF,0XF1,0XFF,0XE0,0XFF,0XC0,0X7F,0X80,0X3F,0X00,0X3F,



0XFC,0X01,0XFE,0X03,0XFF,0X07,0XFF,0X8F,0XFF,0XDF,0X07,0XFF,0X07,0XFF,0X07,0XFF,

0X07,0XFF,0X07,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,



0XF8,0X3F,0XF8,0X7F,0XF8,0XFF,0XF9,0XFF,0XFB,0XFF,0XF7,0XFE,0XE7,0XFC,0XC7,0XF8,

0X87,0XF0,0X07,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,

};



void LCD12864_WriteCGRAM(void)

{

    for(uint8_t i = 0; i < 64; i++)

    {

        LCD12864_WriteCMD(0x40 + i);

        LCD12864_WriteDAT(LCD12864_CGRAM[i*2]);       

        LCD12864_WriteDAT(LCD12864_CGRAM[i*2+1]);       

    }

}



void LCD12864_DisplayCGRAM(uint8_t Address, uint8_t Index)

{

    if((Address >= 0x80) && (Address <= 0x9F))

    {

        Index = (Index % 4) * 2;



        LCD12864_WriteCMD(Address);

        LCD12864_WriteDAT(0x00);

        LCD12864_WriteDAT(Index); 

    }

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



void LCD12864_DisplayGDRAM(void)

{

    LCD12864_WriteCMD(0x34);

    LCD12864_WriteCMD(0x36);



    for(uint8_t i = 0; i < 32; i++)

    {

        LCD12864_WriteCMD(0x80 + i);

        LCD12864_WriteCMD(0x80 + 0);



        for(uint8_t j = 0; j < 16; j++)

        {

            LCD12864_WriteDAT(LCD12864_GDRAM[i+0x00][j]);

        }

    }



    for(uint8_t i = 0; i < 32; i++)

    {

        LCD12864_WriteCMD(0x80 + i);

        LCD12864_WriteCMD(0x80 + 8);



        for(uint8_t j = 0; j < 16; j++)

        {

            LCD12864_WriteDAT(LCD12864_GDRAM[i+0x20][j]);

        }

    }

}



void LCD12864_DrawPoint(uint8_t x, uint8_t y, uint8_t en)

{

    if(en)

    {

        LCD12864_GDRAM[y][x/8] |=  (0x80 >> (x % 8));

    }

    else

    {

        LCD12864_GDRAM[y][x/8] &= ~(0x80 >> (x % 8));

    }

}示例代码:
void LCD12864_DisplayDEMO(void)

{

    /* CGROM  : 2Mbit的中文字库ROM,总共有8192个中文字符 */

    LCD12864_DisplayCGROM(0x88, "上海灵动微电子股");

    LCD12864_DisplayCGROM(0x99, "份有限公司");



    /* CGRAM  : 64*16bit的自定义字符RAM */

    LCD12864_WriteCGRAM();



    LCD12864_DisplayCGRAM(0x80, 0);

    LCD12864_DisplayCGRAM(0x81, 1);

    LCD12864_DisplayCGRAM(0x90, 2);

    LCD12864_DisplayCGRAM(0x91, 3);



    /* HCGROM : 16Kbit的半宽字库ROM,总共有126个字母符号 */

    char HCGROM[] = {0x01, 0x03, 0x0};



    LCD12864_DisplayCGROM(0x9E, HCGROM);



    LCD12864_DisplayCGROM(0x82, "Hello World!");

    LCD12864_DisplayCGROM(0x92, "21ic:xld0932");



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



    /* GDRAM  : 64*128bit的绘图RAM */

    memset(LCD12864_GDRAM, 0, sizeof(LCD12864_GDRAM));



    LCD12864_DisplayGDRAM();

}



void LCD12864_Init(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;



    /* 控制线:PSB/RS/RW/EN/RST */

    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);



    GPIO_StructInit(&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 |

                                    GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOA, &GPIO_InitStructure);



    /* 并行接口 */

    LCD12864_PSB_H();



    /* 默认电平 */

    LCD12864_RS_L();

    LCD12864_RW_L();

    LCD12864_EN_L();



    /* 上电复位 */

    LCD12864_RST_H(); SysTick_DelayMS(50);

    LCD12864_RST_L(); SysTick_DelayMS(50);

    LCD12864_RST_H(); SysTick_DelayMS(50);



    /* 数据线:D0~D7 */

    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);



    GPIO_StructInit(&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |

                                    GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 |

                                    GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOB, &GPIO_InitStructure);



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



    LCD12864_WriteCMD(0x30); /* 8位控制模式 */

    LCD12864_WriteCMD(0x06); /* 输入点设定  */

    LCD12864_WriteCMD(0x01); /* 清除显示    */  SysTick_DelayMS(3);

    LCD12864_WriteCMD(0x0C); /* 显示状态开  */

    LCD12864_WriteCMD(0x02); /* 地址归零    */



    LCD12864_DisplayDEMO();



    TASK_Append(TASK_ID_LCD12864, LCD12864_Handler, 1000);

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

#define GUI_LCM_XMAX        128

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



static uint8_t GetDfontData(uint8_t code1, uint8_t code2,uint8_t *pBuff)

{

    /* 添加用户代码 */

    return 0;

}



static uint8_t GetSfontData(uint8_t code1, uint8_t *pBuff)

{

    /* 添加用户代码 */

    extern uint8_t GetFontASCII_6_12(uint8_t code1, uint8_t *pBuff);



    GetFontASCII_6_12(code1, pBuff);



    return 0;

}



void defaultFontInit(void)

{

    /* 根据字体要求做相应的修改 */



    /* 此buff的大小由最大字模大小决定 */

    static uint8_t dataBuff[12*12];



    defaultFont.name     = "汉字字模为12*12的GB2312,ASCII字模为12*6";

    defaultFont.dhigh    = 12;

    defaultFont.dwide    = 12;

    defaultFont.shigh    = 12;

    defaultFont.swide    = 6;

    defaultFont.pZmBuff  = dataBuff;

    defaultFont.getDfont = GetDfontData;

    defaultFont.getSfont = GetSfontData;



    /* 设置为系统默认字体 */

    GuiFontSet(&defaultFont);

    GuiSetbackcolor(CWHITLE);

    GuiSetForecolor(CBLACK);

}
 
4.3.在lcdDriverPort文件中实现lkdGui API函数所依赖的LCD底层调用函数,在这些函数中根据实际功能需要进行实现。在我们这个示例程序中需要完成GuiUpdateDisplayAll和GuiDrawPoint这两个函数功能,参考代码如下所示:
void GuiUpdateDisplayAll(void)

{

    /* 添加用户代码 */

    LCD12864_DisplayGDRAM();

}



void GuiRangeUpdateDisplay(lkdCoord beginx, lkdCoord beginy,lkdCoord endx, lkdCoord endy)

{

    /* 添加用户代码 */

}



void GuiDrawPoint(lkdCoord x, lkdCoord y, lkdColour color)

{

    /* 添加用户代码 */

    if(color) LCD12864_DrawPoint(x, y, 1);

    else      LCD12864_DrawPoint(x, y, 0);

}



void  GuiReadPoint(lkdCoord x, lkdCoord y, lkdColour *pColor)

{

        /* 添加用户代码 */

}



void CloseLcdDisplay(void)

{

    /* 添加用户代码 */

}



void OpenLcdDisplay(void)

{

    /* 添加用户代码 */

}5、基于HJ12864J的lkdGui控件显示
5.1.基本图形
 
lkdGui的基本图形包含了斜线、水平线、垂直线、水平点线、垂直点线、矩形、填充矩形。参考程序如下所示:
void lkdGui_Demo1(void)

{

    /* 画点 */

    GuiPoint(5, 5, forecolor);



    /* 画斜线 */

    GuiBiasLine(10, 0, 20, 20, forecolor);

    GuiBiasLine(20, 0, 40, 20, forecolor);

    GuiBiasLine(30, 0, 60, 20, forecolor);

    GuiBiasLine(40, 0, 80, 20, forecolor);



    /* 画水平点线 */

    GuiHPointLine(90,  5, 120, 2, forecolor);

    GuiHPointLine(90, 10, 120, 3, forecolor);

    GuiHPointLine(90, 15, 120, 4, forecolor);

    GuiHPointLine(90, 20, 120, 5, forecolor);



    /* 画水平线 */

    GuiHLine(0, 25, 127, forecolor);



    /* 画垂直点线 */

    GuiRPointLine(10, 30, 50, 2, forecolor);

    GuiRPointLine(20, 30, 50, 3, forecolor);

    GuiRPointLine(30, 30, 50, 4, forecolor);

    GuiRPointLine(40, 30, 50, 5, forecolor);



    /* 画垂直线 */

    GuiRLine(50, 30, 50, forecolor);



    /* 画矩形 */

    GuiRect(55, 30, 75, 50, forecolor);



    /* 画填充矩形 */

    GuiFillRect(80, 30, 120, 50, forecolor);



    /* 更新 */

    GuiUpdateDisplayAll();

    SysTick_DelayMS(1000);



    GuiClearScreen(0);

    GuiUpdateDisplayAll();

}
 
基本图形显示效果:

5.2.文本控件

lkdGui文本控件可以显示单行文本,也可以显示多行文本;可以设置文本显示的起始坐标、宽高、字符间距、行间距、缩进显示,以及是否是反显示显示等参数。参考程序如下所示:

void lkdGui_Demo2(void)

{

    uint8_t *textStr = (uint8_t *)("Hello World!");



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



    /* -----------1--------------- */

    GuiRect(0, 0, 127, 16, forecolor);

    textInfo.x           = 2;   /* 文本起始坐标 */

    textInfo.y           = 3;

    textInfo.wide        = 156; /* 文本范围大小 */

    textInfo.high        = 16;

    textInfo.wInterval   = 0;   /* 字符间距 */

    textInfo.hInterval   = 2;   /* 行间距   */

    textInfo.flag        = 0;   /* 不反显   */

    textInfo.beginOffset = defaultFont.dwide * 2;   /* 开始偏移,首行缩进 */

    GuiText(&textInfo, textStr);



    /* -----------2--------------- */

    GuiFillRect(0, 20, 127, 36, forecolor);

    textInfo.x           = 2;   /* 文本起始坐标 */

    textInfo.y           = 23;

    textInfo.flag        = 1;   /* 反显 */

    textInfo.beginOffset = defaultFont.dwide * 2;   /* 开始偏移,首行缩进 */

    GuiText(&textInfo, textStr);



    /* -----------3---------------- */

    GuiRect(0, 40, 127, 56, forecolor);

    textInfo.x           = 2;   /* 文本起始坐标 */

    textInfo.y           = 43;

    textInfo.flag        = 1;   /* 反显 */

    textInfo.beginOffset = defaultFont.dwide * 2;   /* 开始偏移,首行缩进 */

    GuiText(&textInfo, textStr);



    /* 更新 */

    GuiUpdateDisplayAll();

    SysTick_DelayMS(1000);



    GuiClearScreen(0);

    GuiUpdateDisplayAll();

}

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

{

    lkdScroll VScroll;

    lkdScroll HScroll;



    HScroll.x     = 0x00;

    HScroll.y     = 0x3C;

    HScroll.hight = 0x80;

    HScroll.max   = 0x0A;        



    for(uint8_t i = 0; i < HScroll.max; i++)

    {

        HScroll.lump = i;       /* 进度快控制 */

        GuiHScroll(&HScroll);   /* 水平进度条 */



        GuiUpdateDisplayAll();  /* 更新进度条 */

        SysTick_DelayMS(0xFA);

    }



    GuiClearScreen(0);

    GuiUpdateDisplayAll();



    VScroll.x     = 0x7C;

    VScroll.y     = 0x00;

    VScroll.hight = 0x40;

    VScroll.max   = 0x0A;        



    for(uint8_t i = 0; i < VScroll.max; i++)

    {

        VScroll.lump = i;       /* 进度快控制 */

        GuiVScroll(&VScroll);   /* 垂直进度条 */



        GuiUpdateDisplayAll();  /* 更新进度条 */

        SysTick_DelayMS(0xFA);

    }



    GuiClearScreen(0);

    GuiUpdateDisplayAll();

}

滚动条控件显示效果:

5.4.进度条控件

lkdGui进度条控制当前仅支持水平方向的显示,可以设置进度条的起始坐标、宽度、高度,以及当前的进度百分比,可以结合文件控件显示当前的进度百分比数值,参考程序如下所示:

 

void lkdGui_Demo4(void)

{

    lkdProgress tProGress;

    uint8_t ratioStr[8];



    tProGress.x     = 0;

    tProGress.y     = 10;

    tProGress.wide  = 100;

    tProGress.high  = defaultFont.dhigh;

    tProGress.ratio = 0;



    for(uint8_t i = 0; i <= 100; i+=5)

    {

        tProGress.ratio = i;    /* 进度控制 */

        GuiProGress(&tProGress);/* 画进度条 */



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



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



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



        GuiUpdateDisplayAll();  /* 更新 */

        SysTick_DelayMS(0xFA);

        SysTick_DelayMS(0xFA);

    }



    GuiClearScreen(0);

    GuiUpdateDisplayAll();

}
进度条控件显示效果:

5.5.按钮控件

lkdGui按钮控件支持按下和抬起两种按键效果,支持按键控件的起始坐标、宽度、高度、初始状态以及按键显示内容的参数设定,参考程序如下所示:

void lkdGui_Demo5(void)

{

    lkdButton tButton;



    tButton.x    = 16;

    tButton.y    = 10;

    tButton.wide = defaultFont.dwide * 2 + 15;

    tButton.high = defaultFont.dhigh + 5;

    tButton.name = (uint8_t *)"OK";

    tButton.flag = 0;       /* 抬起状态 */

    GuiButton(&tButton);



    tButton.x    = 16;

    tButton.y    = 40;

    tButton.wide = defaultFont.dwide * 2 + 15;

    tButton.high = defaultFont.dhigh + 5;

    tButton.name = (uint8_t *)"RUN";

    tButton.flag = 0;       /* 抬起状态 */

    GuiButton(&tButton);



    tButton.x    = 73;

    tButton.y    = 40;

    tButton.wide = defaultFont.dwide * 2 + 15;

    tButton.high = defaultFont.dhigh + 5;

    tButton.name = (uint8_t *)"STOP";

    tButton.flag = 0;       /* 抬起状态 */

    GuiButton(&tButton);



    GuiUpdateDisplayAll();  /* 更新显示 */

    SysTick_DelayMS(1000);



    for(uint8_t i = 0; i < 3; i++)

    {

        tButton.x    = 16;

        tButton.y    = 10;

        tButton.wide = defaultFont.dwide * 2 + 15;

        tButton.high = defaultFont.dhigh + 5;

        tButton.name = (uint8_t *)"CACLE";

        tButton.flag = 1;       /* 按下状态 */

        GuiButton(&tButton);



        GuiUpdateDisplayAll();

        SysTick_DelayMS(0xFA);

        SysTick_DelayMS(0xFA);



        tButton.x    = 16;

        tButton.y    = 10;

        tButton.wide = defaultFont.dwide * 2 + 15;

        tButton.high = defaultFont.dhigh + 5;

        tButton.name = (uint8_t *)"OK";

        tButton.flag = 0;       /* 抬起状态 */

        GuiButton(&tButton);



        GuiUpdateDisplayAll();

        SysTick_DelayMS(0xFA);

        SysTick_DelayMS(0xFA);

    }



    GuiClearScreen(0);

    GuiUpdateDisplayAll();

}
 
按钮控件显示效果:

5.6.图形控件

lkdGui图形控件最大运行满屏显示效果,对于图形控件,可以指定显示坐标、宽度、高度、图片的数据源等参数后进行绘制;可以根据图片偏移坐标来实现图片的移动效果,支持图片在显示区域范围内上下左右的方向进行移动显示。参考程序如下所示:

lkdGui图形控件最大运行满屏显示效果,对于图形控件,可以指定显示坐标、宽度、高度、图片的数据源等参数后进行绘制;可以根据图片偏移坐标来实现图片的移动效果,支持图片在显示区域范围内上下左右的方向进行移动显示。参考程序如下所示:
复制
void lkdGui_Demo6(void)

{

    uint8_t lkdGuiImage1[] =

    {

        0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,

        0X00,0X00,0X00,0X00,0X07,0XC1,0XFF,0XE0,0X0F,0XC3,0XFF,0XE0,0X1F,0XC7,0XFF,0XE0,

        0X3F,0XCF,0XFF,0XE0,0X7F,0XDF,0XFF,0XE0,0XFF,0XDF,0XFB,0XFF,0XFF,0X9F,0XF1,0XFF,

        0XFF,0X1F,0XE0,0XFF,0XFE,0X1F,0XC0,0X7F,0XFC,0X1F,0X80,0X3F,0XF8,0X1F,0X00,0X3F,

        0XFC,0X01,0XF8,0X3F,0XFE,0X03,0XF8,0X7F,0XFF,0X07,0XF8,0XFF,0XFF,0X8F,0XF9,0XFF,

        0XFF,0XDF,0XFB,0XFF,0X07,0XFF,0XF7,0XFE,0X07,0XFF,0XE7,0XFC,0X07,0XFF,0XC7,0XF8,

        0X07,0XFF,0X87,0XF0,0X07,0XFF,0X07,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,

        0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,

    };



    uint8_t lkdGuiImage2[] =

    {

        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x78,0x00,

        0x00,0x01,0xE0,0x01,0xFC,0x00,0x00,0x00,0x03,0x00,0x01,0xF0,0xFC,0x00,0x00,0x03,

        0xF0,0x0F,0xFF,0x00,0x00,0x00,0x07,0x80,0x03,0xF8,0xFC,0x00,0x00,0x03,0xF8,0x1F,

        0xFF,0x80,0x00,0x00,0x0F,0xC0,0x03,0xF9,0xEE,0x00,0x00,0x07,0xF8,0x3F,0xFF,0xC0,

        0x00,0x00,0x1C,0xE0,0x07,0x1D,0xCE,0x00,0x00,0x07,0x38,0x7C,0x01,0xE0,0x00,0x00,

        0x18,0x60,0x07,0x1D,0xCE,0x00,0x00,0x07,0x38,0xF0,0x00,0xF0,0x30,0x0C,0x1C,0xE0,

        0x07,0x1D,0xCE,0x1E,0x01,0xFF,0x3C,0xE1,0xFC,0x70,0x7C,0x1F,0x0F,0xC0,0x07,0x1D,

        0xCE,0x7F,0x03,0xFF,0x3C,0xE7,0xFF,0x70,0xFE,0x3F,0x87,0x80,0x07,0x1D,0xCE,0xFF,

        0x87,0xFF,0x3D,0xC7,0xFF,0xF0,0xEE,0x3B,0x8F,0xC0,0x07,0x1D,0xCF,0xE3,0x8F,0x03,

        0x3D,0xCF,0x00,0x01,0xC6,0x31,0x9C,0xE0,0x07,0x1D,0xCF,0xC7,0x9E,0x00,0x3D,0x8E,

        0x1F,0xF9,0xC6,0x31,0xDC,0xE0,0x07,0x1D,0xC7,0x0F,0x1C,0x7C,0x3D,0x8E,0x3F,0xFD,

        0xC6,0x31,0xDC,0xE0,0x07,0x1D,0xC0,0x1E,0x1C,0xFE,0x3D,0x8E,0x38,0x1D,0xC6,0x31,

        0xDC,0xE0,0x07,0x1D,0xC0,0x18,0x18,0xFE,0x3D,0x8E,0x30,0x0D,0xC6,0x31,0xDC,0xE0,

        0x07,0x1D,0xC0,0x1C,0x18,0xFE,0x3D,0xCE,0x3E,0x79,0xC6,0x31,0xDC,0xE0,0x07,0x1D,

        0xC3,0x0E,0x18,0xFE,0x3D,0xCF,0x3E,0x79,0xC6,0x71,0xDC,0xE0,0x07,0x1D,0xC7,0xC7,

        0x1C,0xFE,0x3D,0xC7,0xFE,0x71,0xC7,0xF1,0xDC,0xE0,0x07,0x1D,0xCF,0xC7,0x9C,0x7C,

        0x3C,0xE3,0xFC,0x71,0xC7,0xF1,0xDC,0xE0,0x07,0x1D,0xCF,0xE3,0xDC,0x00,0x38,0xF0,

        0xF0,0x71,0xE3,0xE3,0xDC,0xE0,0x07,0x1D,0xCE,0xF3,0xCF,0x00,0x38,0x78,0x00,0x70,

        0xE0,0x03,0x9C,0xE0,0x03,0x19,0xEC,0x7F,0xCF,0xFF,0xF8,0x7F,0xFE,0x70,0xFF,0xFF,

        0x9C,0xE0,0x03,0xF9,0xFC,0x3F,0x87,0xFF,0xF8,0x3F,0xFF,0xE0,0x7F,0xFF,0x9F,0xE0,

        0x03,0xF8,0xFC,0x1F,0x03,0xFF,0xF0,0x1F,0xFF,0xE0,0x3F,0xFF,0x8F,0xC0,0x01,0xF0,

        0x78,0x0E,0x00,0xFF,0xE0,0x07,0xFF,0xC0,0x0F,0xFF,0x07,0x80,0x00,0x00,0x00,0x00,

        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

    };



    lkdBitmap tImage;



    tImage.beginx = 0;              /* 图像开始显示偏移 */

    tImage.beginy = 0;

    tImage.wide   = 32;             /* 图像本身的大小 */

    tImage.high   = 32;

    tImage.bitmap = lkdGuiImage1;   /* 图像 */

    GuiAreaBitMap(&tImage, 0+8, 0, 32+8, 32, 0);



    GuiUpdateDisplayAll();          /* 更新 */



    tImage.beginx = 0;              /* 图像开始显示偏移 */

    tImage.beginy = 0;

    tImage.wide   = 112;            /* 图像本身的大小 */

    tImage.high   = 28;

    tImage.bitmap = lkdGuiImage2;   /* 图像 */

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



    GuiUpdateDisplayAll();          /* 更新 */

    SysTick_DelayMS(0xFA);



    for(uint8_t i = 0; i < 112; i++)

    {

        tImage.beginx = i;

        tImage.beginy = 0;



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



        GuiUpdateDisplayAll();

        SysTick_DelayMS(0x32);

    }



    for(int16_t i = 112; i >= 0; i--)

    {

        tImage.beginx = i;

        tImage.beginy = 0;



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



        GuiUpdateDisplayAll();

        SysTick_DelayMS(0x32);

    }



    for(uint8_t i = 0; i <= 28; i++)

    {

        tImage.beginx = 0;

        tImage.beginy = i;



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



        GuiUpdateDisplayAll();

        SysTick_DelayMS(0x32);

    }



    for(int8_t i = 28; i >= 0; i--)

    {

        tImage.beginx = 0;

        tImage.beginy = i;



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



        GuiUpdateDisplayAll();

        SysTick_DelayMS(0x32);

    }



    GuiClearScreen(0);

    GuiUpdateDisplayAll();

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



uint32_t GetIntervalTick(uint32_t Tick)

{

    if(SysTick_Tick > Tick)

    {

        return (SysTick_Tick - Tick);

    }

    else

    {

        return (SysTick_Tick + (UINT32_MAX - Tick));

    }

}



void TestWIN_CallBack(void)

{

    /* 窗口内容具体代码实现 */

    static uint8_t     State = 0;

    static uint32_t    Test_Tick;

    static lkdProgress Progress;



    if(State == 0)

    {

        State = 1;



        Progress.x     = 9;

        Progress.y     = 15;

        Progress.ratio = 0;

        Progress.wide  = 109;

        Progress.high  = 10;

    }



    if(State == 1)

    {

        State = 2;



        GuiProGress(&Progress);

        GuiUpdateDisplayAll();



        Test_Tick = SysTick_Tick;

    }



    if(State == 2)

    {

        if(GetIntervalTick(Test_Tick) > 1000)

        {

            State = 1;



            Progress.ratio += 5;



            if(Progress.ratio > 100)

            {

                State = 3;

            }

        }

    }



    if(State == 3)

    {

        State = 0;



        /* 删除当前窗口 */

        GuiWinDeleteTop();



        GuiUpdateDisplayAll();

    }

}



void MainWIN_Callback(void)

{

    /* 窗口内容具体代码实现 */

    static uint8_t  State = 0;

    static uint32_t Main_Tick;



    if(State == 0)

    {

        State = 1;

    }



    if(State == 1)

    {

        State = 2;



        GuiRowText(0, 0, 128, FONT_MID, (uint8_t *)"MAIN");

        GuiUpdateDisplayAll();



        Main_Tick = SysTick_Tick;

    }



    if(State == 2)

    {

        if(GetIntervalTick(Main_Tick) > 5000)

        {

            State = 0;



            /* 创建窗口 */

            TestWIN.x     = 0;

            TestWIN.y     = 0;

            TestWIN.hight = 128;

            TestWIN.wide  = 128;

            TestWIN.title = NULL;

            TestWIN.WindowFunction = (void *)TestWIN_CallBack;



            /* 添加窗口 */

            GuiWinAdd(&TestWIN);

        }

    }

}



void lkdGui_Demo7(void)

{

    /* 1. 定义一个菜单项 */

    #define MENUSTACK_NUM 8



    MenuStack userMenuStack[MENUSTACK_NUM];



    /* 2. 定义二级菜单 */

    lkdMenuNode Node3_3 = {6, (uint8_t *)"no1-3", NULL,     NULL,     NULL};

    lkdMenuNode Node2_2 = {5, (uint8_t *)"no1-2", &Node3_3, NULL,     NULL};

    lkdMenuNode Node1_1 = {4, (uint8_t *)"no1-1", &Node2_2, NULL,     NULL};



    /* 3. 定义一级菜单 */

    lkdMenuNode Node3   = {3, (uint8_t *)"no3",   NULL,     NULL,     NULL};

    lkdMenuNode Node2   = {2, (uint8_t *)"no2",   &Node3,   NULL,     NULL};

    lkdMenuNode Node1   = {1, (uint8_t *)"no1",   &Node2,   &Node1_1, NULL};



    /* 3. 定义根菜单 */

    lkdMenuNode NodeRoot0 = {0, (uint8_t *)"root",NULL,     &Node1,   NULL};



    /* 初始化根节点 */

    lkdMenu root =

    {

        .x         = 0,

        .y         = 0,

        .wide      = 128,

        .hight     = 64,

        .ItemsWide = 48,

        .Itemshigh = 15,

        .index     = 1,     /* 默认选中节点 */

        .stackNum  = MENUSTACK_NUM,

        .stack     = userMenuStack,

        .Root      = &NodeRoot0

    };



    /* 初始化菜单 */

    GuiMenuInit(&root);



    /* 展开当前选中节点 */

    GuiMenuCurrentNodeSonUnfold(&root);



    GuiUpdateDisplayAll();  /* 更新显示 */

    SysTick_DelayMS(0xFA);

    SysTick_DelayMS(0xFA);



    GuiMenuCurrentNodeSonUnfold(&root);



    GuiUpdateDisplayAll();  /* 更新显示 */

    SysTick_DelayMS(0xFA);

    SysTick_DelayMS(0xFA);



    /* 选中下移 */

    GuiMenuItemDownMove(&root);



    GuiUpdateDisplayAll();  /* 更新显示 */

    SysTick_DelayMS(1000);



    GuiClearScreen(0);



    /* 创建窗口 */

    MainWIN.x     = 0;

    MainWIN.y     = 0;

    MainWIN.hight = 128;

    MainWIN.wide  = 128;

    MainWIN.title = NULL;

    MainWIN.WindowFunction = (void *)MainWIN_Callback;



    /* 添加窗口 */

        GuiWinAdd(&MainWIN);

}


---------------------
作者:xld0932
链接:https://bbs.21ic.com/icview-3214070-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

 

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值