1.前言
前面刚把SPI的2.42寸OLED点亮,看的效果还是比0.96寸OLED舒服,想来做项目经常要做菜单,每次没有GUI辅助,着实麻烦,都要徒手写GUI,多级菜单更是麻烦。于是就想移植一个GUI,主要目的就是给STM32F103,F407之类的没有LCD接口的显示器做一个GUI。
因为都是串行协议(SPI或是IIC)通信速率不是很快,再就是基本都是单色屏幕,就更没有必要上LVGL之类的大型GUI,过于复杂了。只不过就是每次写屏幕的时候能简化一点流程。
2.GUI选择
关于GUI选择问题,最开始想搞U8g2的,但是死活搞不出来,而且貌似对u8g2对硬件SPI,IIC支持不是很好,这就很头疼了。
开源轻量化GUI主要还有SimpleGUI,LiteGUI
不过这两款GUI移植起来非常麻烦,我都没移植成功(应该是我的问题),没办法于是再找GUI也就是lkdGUI了。
最开始我是先移植SimpleGUI的,结果发现也是过于复杂了。于是又搞lkdGUI了,lkdGUI相较于其他GUI的好处是程序的耦合性极低,相较于U8g2与SimpleGUI来说,lkdGUI和驱动层分离的非常开,我几乎不用动驱动层的东西。
3.前期准备
首先我们要先准备一个屏幕和STM32的板子,这里我选择STM32F407和一个2.42寸的OLED
连接好线之后就要把驱动写好,保证你的OLED能正常点亮,一般厂家都是有写这些驱动,稍微改改就行。
之后我们要下载GuiLite的源码,这个gitee上就有
地址:lkdGui: 单片机单色屏GUI库 (gitee.com)
4.移植
我们需要的所有文件都在lkdgui source这个文件夹下面
把整个文件夹放到我们STM32的文件夹下面
添加好文件夹路径后,我们在工程里加入GUI的文件,首先是port文件夹下面的这三个文件
在port文件夹下面还有两个文件夹,font是字库,lcd是一些屏幕的驱动,驱动如果有你用的屏幕你可以试着用用,但我还是建议你自己写驱动。
在font文件夹下面,有几种字库,我们一般用的是6x12的ASCII与12x12的汉字,在里面也有,我们将这两个加入工程。
然后是sourse文件夹下面,都添加进去
最后工程里应该是这样
编译后应该是0错误
如果报告没有发现lkdgui.h就说明你的头文件路径没加
在这里记得加一下
5.底层接口
下面我们需要把操作OLED的底层函数告诉GUI
我们需要在lcddriverport这个文件里写,这里我来一个个解释
首先是guiupdate
这个一般商家都会提供这个函数,也就是Refresh这个函数
这个RangeRefresh函数是区域刷新不写也没关系
之后是画点函数
这个函数商家也提供,就是DrawPoint和ClearPoint
这里稍微注意一下,color是颜色,需要按照一下这种写法就可实现反显的效果。
之后的3个函数可以不用写,开关显示商家也提供了,大家可以自行添加
最终程序
/**
* @file lcdDriverPort.c
* @author guoweilkd
* @version V0.0.0
* @date 2018/04/18
* @brief lkdGui液晶显示屏驱动接口,由移植者填充函数的具体内容。
*/
#include "lkdGui.h"
#include "oled7.h"
/**
*@brief 将Gui缓冲区数据显示到lcd上
*@param None
*@retval None
*/
void GuiUpdateDisplayAll(void)
{
/* 添加用户代码 */
OLED7_Refresh();
}
/**
*@brief 将Gui指定缓冲区数据显示到lcd上
*@param beginx,beginy,endx,endy 坐标
*@retval None
*/
void GuiRangeUpdateDisplay(lkdCoord beginx, lkdCoord beginy,lkdCoord endx, lkdCoord endy)
{
/* 添加用户代码 */
}
/**
*@brief 向缓冲区画点
*@param x,y 坐标
*@param color 颜色 <目前只有黑:CBLACK 白:CWHITLE>
*@retval None
*/
void GuiDrawPoint(lkdCoord x, lkdCoord y, lkdColour color)
{
/* 添加用户代码 */
if(color)
OLED7_DrawPoint(x,y);
else
OLED7_ClearPoint(x,y);
}
/**
*@brief 读取当前显示的点
*@param x,y 坐标
*@param color 颜色 <目前只有黑:CBLACK 白:CWHITLE>
*@retval None
*/
void GuiReadPoint(lkdCoord x, lkdCoord y, lkdColour *pColor)
{
/* 添加用户代码 */
}
/**
*@brief 关显示
*@param None
*@retval None
*/
void CloseLcdDisplay(void)
{
/* 添加用户代码 */
}
/**
*@brief 开显示
*@param None
*@retval None
*/
void OpenLcdDisplay(void)
{
/* 添加用户代码 */
}
6.字体驱动接口
下面我们需要告诉gui我们的字模信息
我们先打开userfontport这个文件,别打开错了
首先是汉字字模
这个函数在GBK2312这个C文件中,我们把文件拉到最底下就能看见这个函数了
在接口文件里我们首先要声明这个函数,之后调用即可
同理也是ASCII字模
然后是字体初始化函数,我们改几个数字即可
修改成你想要字体的大小
最后程序
/**
* @file userFontPort.c
* @author guoweilkd
* @version V0.0.0
* @date 2018/04/18
* @brief lkdGui字体驱动接口,由移植者填充函数的具体内容。
*/
#include "lkdGui.h"
/* 字体控制实体 */
static lkdFont defaultFont;
/**
*@brief 获取汉字字模
*@param code1,code2 汉字编码[H,L]
*@param pBuff 字模buff
*@retval 0
*/
static uint8_t GetDfontData(uint8_t code1, uint8_t code2,uint8_t *pBuff)
{
/* 添加用户代码 */
uint8_t GetFontGb2312_12_12(uint8_t codeH, uint8_t codeL, uint8_t *pBuff);
GetFontGb2312_12_12(code1,code2,pBuff);
return 0;
}
/**
*@brief 获取ASCII字模
*@param code1, 编码
*@param pBuff 字模buff
*@retval 0
*/
static uint8_t GetSfontData(uint8_t code1, uint8_t *pBuff)
{
/* 添加用户代码 */
uint8_t GetFontASCII_6_12(uint8_t code1, uint8_t *pBuff);
GetFontASCII_6_12(code1,pBuff);
return 0;
}
/**
*@brief 字体初始化
*@param None
*@retval None
*/
void defaultFontInit(void)
{
/* 根据字体要求做相应的修改 */
/* 此buff的大小由最大字模大小决定 */
static uint8_t dataBuff[12*2];
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);
}
7.主函数
至此gui正式移植成功了,下面我们开始写主函数
首先加入lkdgui.h
之后依次初始化spi,oled,gui即可
我们首先显示一串字符吧,程序比较简洁,也都有注释
我们把需要显示的字符添加到testStr这个数组里,然后把用GuiText显示,最后刷新页面即可,其中的几个参数大家可以自行根据需要调节,也都有注释。
8.显示中文
ASCII比较好处理,那中文怎么办呢?这里我们遵循的GB2312编码方式,我们可以到网上去找汉字对应的编码,或是直接在C文件里看。
这里以“你好”为例,可以看到“你”对应的编码为0xC4E3,“好”则是0xBAC3
我们在程序里可以以将4个16位拆为两组,程序会自行判断汉字
没毛病
程序
#include "key.h"
void defaultFontInit(void);
void testLkdGUI(void)
{
unsigned char textStr[8]={0xC4,0xE3,0xBA,0xC3,'A'};
/* -----------显示文字--------------- */
fontTextInfo textInfo;
textInfo.x = 0;/* 文本起始坐标 */
textInfo.y = 0;
textInfo.wide = 128;/* 文本范围大小 */
textInfo.high = 64;
textInfo.wInterval = 0;/* 字符间距 */
textInfo.hInterval = 0;/* 行间距 */
textInfo.flag = 0;/* 反显 */
textInfo.beginOffset = textInfo.wide * 0;/* 开始偏移,首行缩进 */
GuiText(&textInfo, textStr);
GuiUpdateDisplayAll();
}
int main(void)
{
Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz
NVIC_SetGroup(1);//设置中断分组,分组1
init_PinClock();//初始化所有时钟
delay_init(168);//初始化延时
init_spi2();//初始化SPI2
OLED7_242_Init();//0.96寸7针SPI的oled初始化
defaultFontInit();/* 字库初始化 */
testLkdGUI();
while(1)
{
}
}
9.结语
lkdGUI移植还是非常简单的,在本来的文件里有更复杂的功能,比如进度条和多级菜单等功能,大家可以自己进行测试,我已经都移植成功了。大家根据项目需要进行学习和测试。那还是老样子,有问题发在评论区,我会尽力解答,我们下篇文章见。