simplegui/Documents/02-移植演示程序.md

232 lines
16 KiB
Markdown
Raw Permalink Normal View History

#移植演示程序
---
## 1. **准备工作**
#### 1.1. 环境准备
  如果您确定或拥有了已经成型的硬件平台想要尽快的获知SimpleGUI在您预期的硬件平台上的表现效果那么可以尝试先将SimpleGUI的演示程序移植到您的硬件平台上。由于演示程序需要操作交互考虑到大家使用的硬件各有差异输入端是编码器还是按键、有几个按键都是未知数所以最终Demo程序设计使用串口模拟按键交互动作。
#### 1.2. 准备工程模板
  首先,请先依照个人习惯,创建一个空白的用于目标平台的工程。工程应保证能够正常编译且添加的代码能够在目标平台上正常运行。  然后请在您的空白工程中实现以下驱动程序以及功能。
- 屏幕驱动程序
这里需要您在使用的目标平台上实现您使用屏幕的驱动程序驱动程序需要至少包含初始化、读点、写点三个功能。需要注意的是由于屏幕的控制程序是以函数指针的方式注册到SimpleGUI的设备对象模型所以函数的原型声明请务必与以下形式相同否则将出现不可预知的运行时错误。
```
void OLED_Initialize(void);
void OLED_SetPixel(int iPosX, int iPosY, int iColor);
int OLED_GetPixel(int iPosX, int iPosY);
```
- 串口驱动程序
由于Demo程序使用串口模拟键盘需要通过串口发送虚拟的按键码所以请至少实现串口的接收功能。
- 简单的定时器
定时器将用于动态曲线等简单动态效果的演示,用于虚拟数据的生成于发送,如果没有此方面要求,可以暂时无视此需求。
  在本文中将以Keil MDK平台下STM32F103芯片开发环境为例讲解如何快速简要的将Simple GUI的Demo程序移植到预期的目标平台上。演示的平台为STM32F103ZE芯片+UC1604C主控制器的19264显示屏。由于中文字库需要消耗大量的片内资源或使用片外Flash资源所以演示程序暂时只使用纯ASCII字符的英文界面。
## 2. **移植演示程序**
#### 2.1. 移植默认演示程序
  首先,请准备并确认您的空白工程已经搭建完毕。
  接下来将SimpleGUI根目录下的GUI、HMI和DemoProc文件夹复制到准备好的空白工程中然后打开工程。
><p align='center'><img src='images/02/001.png' title='01-新建工程' style='max-width:1024px'></img></p>
&emsp;&emsp;接下来,加入屏幕、定时器和串口初始化代码,这里也包括串口中断服务函数以及定时器中断服务函数。
&emsp;&emsp;需要注意的是由于SimpleGUI并没有做线程安全设计所以GUI接口只允许工作在同一个线程中如果多个线程或在中断服务函数中同时调用SimpleGUI的接口将导致一些不可预知的错误。由此在需要使用中断的地方推荐使用“中断标记-主处理读取”的工作模式。
><p align='center'><img src='images/02/002.png' title='02-添加基础支持代码' style='max-width:1024px'></img></p>
&emsp;&emsp;然后将SimpleGUI代码中的GUI目录、HMI目录、DemoProc目录复制并添加到当前工程。
><p align='center'><img src='images/02/003.png' title='03-添加演示程序' style='max-width:1024px'></img></p>
><p align='center'><img src='images/02/004.png' title='04-添加演示程序' style='max-width:1024px'></img></p>
&emsp;&emsp;至此,演示程序需要的所有文件都已经加入工程组织接下来就需要将之前实现的针对当前硬件平台的驱动代码添加到演示程序对应的位置。
&emsp;&emsp;然后将GUI目录、HMI目录、DemoProc目录下inc文件夹添加到工程的包含路径(Include path)中。
><p align='center'><img src='images/02/005.png' title='05-添加包含路径' style='max-width:1024px'></img></p>
&emsp;&emsp;接下来打开GUI\\inc目录下的SGUI_Config.h文件大致内容如下
```c++
//=======================================================================//
//= Used for SimpleGUI virtual SDK. =//
//=======================================================================//
#ifdef _SIMPLE_GUI_ENCODE_TEXT_
#define _SIMPLE_GUI_ENCODE_TEXT_SRC_ ("UTF-8")
#define _SIMPLE_GUI_ENCODE_TEXT_DEST_ ("GB2312")
#endif // _SIMPLE_GUI_ENCODE_TEXT_
#define _SIMPLE_GUI_IN_VIRTUAL_SDK_
//=======================================================================//
//= Used for SimpleGUI interface. =//
//=======================================================================//
//#define _SIMPLE_GUI_ENABLE_DYNAMIC_MEMORY_
```
&emsp;&emsp;此文件中定义了SimpleGUI中用于全局配置的宏定义默认状态下是为了在VirtualSDK环境下运行而配置的所以直接编译会产生一些错误为了规避这些错误我们需要对文件项目做如下修改
- 将宏\_SIMPLE\_GUI\_IN\_VIRTUAL\_SDK\_的定义注释掉。
- 将宏\_SIMPLE\_GUI\_ENABLE\_DYNAMIC\_MEMORY\_的定义注释掉。
&emsp;&emsp;此修改完成如下图:
><p align='center'><img src='images/02/006.png' title='06-编辑预置宏' style='max-width:1024px'></img></p>
&emsp;&emsp;接下来添加演示代码中必要的驱动程序调用。
&emsp;&emsp;首先需要打开DemoProc.c并定位到InitializeHMIEngineObj函数演示程序在这里向设备对象模型注册屏幕设备的操作接口。
><p align='center'><img src='images/02/007.png' title='07-HMI引擎初始化函数' style='max-width:1024px'></img></p>
&emsp;&emsp;在这个函数中我们可以找到一句宏定义。
```c++
#error Add screen device object initialize process here.
```
><p align='center'><img src='images/02/008.png' title='08-HMI引擎初始化函数' style='max-width:1024px'></img></p>
&emsp;&emsp;我们需要删除掉这行宏定义,并参照上面宏定义分支中的代码,添加必要的函数接口注册处理。
><p align='center'><img src='images/02/009.png' title='09-设备初始化代码' style='max-width:1024px'></img></p>
&emsp;&emsp;在代码中我们向设备对象模型注册了屏幕的读点、写点、清空、同步四个动作的操作接口。读点和写点分别是读取和写入屏幕上一个像素的值0或1通常0代表灭、1代表亮必须注册清空为清除屏幕的内容如果没有注册请将此位置置为NULLSimpleGUI在处理时会通过像色操作清空屏幕效率稍差同步操作意为将显示缓存中的内容同步到屏幕显示只有在启用显示缓存时才会用到。
&emsp;&emsp;这里的的显示缓存并不是由SimpleGUI来开辟和管理而是由开发者来定义和操作。现实情况是因为现在几乎所有的单色屏幕操作都是以字节为单位一次控制八个像素如果只想控制其中一个点而不影响其他七个点的话那么就需要将这个字节读取出来按位操作写回去。但是这些屏幕控制器在通过串行接口IIC/SPI通信时通常只能接受写入操作无法读取点而且就算再并行操作下读取操作也会比写入操作慢得多。
&emsp;&emsp;基于以上情况我自己使用的解决方案就是在芯片内部开辟一处二维数组作为显示缓存程序的读写都针对这个显示缓存进行操作在操作完成后再调用同步函数将显示缓存中的内容集中写入的屏幕。这样做的好处就是第一针对片内运存的操作肯定快于直接操作外设接口第二避免了读取屏幕的操作对于屏幕设备来说只有写操作大大提升了运行速度第二基于前一点屏幕将可以不考虑读操作直接工作再串行模式下节省了GPIO的使用。
&emsp;&emsp;在处理完屏幕初始化操作后,接下来需要处理的就是按键操作的移植。按照前文所说,按键操作是使用串口操作模拟的,所以本质上就是对串口节收内容的处理。
&emsp;&emsp;同样在DemoProc.c文件中与上面添加屏幕设备的初始化代码类似这里添加按键的处理函数由于按键操作是由串口模拟所以需要在文件内定义一个全局变量用于保存接收的模拟键码。
><p align='center'><img src='images/02/010.png' title='10-键码保存变量' style='max-width:1024px'></img></p>
&emsp;&emsp;然后定位到KeyPressEventProc函数并在函数中找到以下宏定义。
```c++
#error Add key event data prepare process here.
```
&emsp;&emsp;与上面添加屏幕设备的初始化代码类似,删除此宏定义并在这里添加按键的处理函数。
><p align='center'><img src='images/02/011.png' title='11-键码处理' style='max-width:1024px'></img></p>
&emsp;&emsp;然后定位到UserEventTriggered函数找到以下宏定义。
```c++
#error Add user event trigger process here.
```
&emsp;&emsp;删除此宏定义并将读取串口接收数据并保存在全局变量的操作添加到这里。
><p align='center'><img src='images/02/012.png' title='12-键码保存' style='max-width:1024px'></img></p>
&emsp;&emsp;至此串口模拟按键部分的处理移植完成。接下来需要移植的是通用定时器的处理。同样在DemoProc.c文件中找到SysTickTimerTriggered函数并找到以下宏定义。
```c++
#error Add sys-tick timer trigger process here.
```
&emsp;&emsp;删除此宏定义,并添加定时器触发的判断处理。
><p align='center'><img src='images/02/013.png' title='13-基本定时器触发判断' style='max-width:1024px'></img></p>
&emsp;&emsp;与上面类似在SysTickTimerEnable函数中找到以下宏定义。
```c++
#error Add sys-tick timer enable/disable process here.
```
&emsp;&emsp;然后添加基本定时器的使能和失能控制接口。
><p align='center'><img src='images/02/014.png' title='14-定时器中断控制' style='max-width:1024px'></img></p>
&emsp;&emsp;至此,所有机能代码移植完成,可以尝试编译代码了。
><p align='center'><img src='images/02/015.png' title='15-机能移植后编译' style='max-width:1024px'></img></p>
&emsp;&emsp;一切正常的话截至这里的移植应该没有错误可以顺利编译通过。但此时的演示程序尚不能正常运行需要将演示程序的主处理加入到main函数中。
><p align='center'><img src='images/02/016.png' title='16-主处理函数' style='max-width:1024px'></img></p>
&emsp;&emsp;至此SimpleGUI的演示程序就已经移植完成了可以开始编译并烧录到芯片。
><p align='center'><img src='images/02/017.png' title='17-编译结果' style='max-width:1024px'></img></p>
&emsp;&emsp;实际运行效果如图。
><p align='center'><img src='images/02/018.png' title='18-实际运行效果' style='max-width:1024px'></img></p>
#### 2.2. 与演示程序交互
&emsp;&emsp;Demo程序为了使同一套演示代码在VirtualSDK中与实际硬件平台中均可以正常运行都使用了PC键盘的键码进行交互键码的定义在DemoActions.h文件中。
```c++
#define KEY_VALUE_NONE (0x0000)
#define KEY_VALUE_BACKSPACE (0x0008)
#define KEY_VALUE_TAB (0x0009)
#define KEY_VALUE_ENTER (0x000D)
#define KEY_VALUE_ESC (0x001B)
#define KEY_VALUE_SPACE (0x0020)
#define KEY_VALUE_DEL (0x007F)
#define KEY_VALUE_HOME (0x0139)
#define KEY_VALUE_END (0x0138)
#define KEY_VALUE_LEFT (0x013A)
#define KEY_VALUE_UP (0x013B)
#define KEY_VALUE_RIGHT (0x013C)
#define KEY_VALUE_DOWN (0x013D)
#define KEY_VALUE_INSERT (0x0142)
#define KEY_VALUE_F1 (0x0154)
#define KEY_VALUE_F2 (0x0155)
#define KEY_VALUE_F3 (0x0156)
#define KEY_VALUE_F4 (0x0157)
#define KEY_VALUE_F5 (0x0158)
#define KEY_VALUE_F6 (0x0159)
#define KEY_VALUE_F7 (0x015A)
#define KEY_VALUE_F8 (0x015B)
#define KEY_VALUE_F9 (0x015C)
#define KEY_VALUE_F10 (0x015D)
#define KEY_VALUE_F11 (0x015E)
#define KEY_VALUE_F12 (0x015F)
#define KEY_VALUE_ENTER_PAD (0x0172)
#define KEY_VALUE_PLUS_PAD (0x0184)
#define KEY_VALUE_SUB_PAD (0x0186)
// User option flag value define
#define KEY_OPTION_CTRL (0x1000)
#define KEY_OPTION_ALT (0x2000)
#define KEY_OPTION_SHIFT (0x4000)
#define KEY_CODE_VALUE(CODE) (CODE & 0x0FFF)
#define KEY_CODE_OPT(CODE) (CODE & 0xF000)
```
&emsp;&emsp;完成前文描述的移植操作并成功烧录到芯片中运行并确保芯片的串口正确连接到电脑后就可以尝试与SimpleGUI的Demo程序进行交互了。在此之前请准保好一个您习惯使用的串口调试软件但此软件需要支持发送十六进制数据。
&emsp;&emsp;演示程序的初始化面在列表画面中,此时根据上面的键码定义,您可以发送十六进制数据[01 3D]来模拟向下按键,选择列表的下一项,发送[00 0D]来模拟回车键等等。
><p align='center'><img src='images/02/019.png' title='19-通过串口交互' style='max-width:1024px'></img></p>
#### 2.3. 启用中文
&emsp;&emsp;SimpleGUI的本身对系统资源的消耗量并不大但是如果启用中文支持的话对Flash资源的需求就会急剧增加以12像素中文为例每个GB2312字符需要24字节GB2312中共计6763个字符这样一来一个完整的GB2312的12像素字库就需要6763\*24=163K(162312字节)的Flash资源而如果是16像素文字每个文字就需要32字节则字库总计需要消耗6763\*32=217K(216416字节)的数据。
&emsp;&emsp;当然SimpleGUI的演示程序中也预置了中文字库资源只不过考虑到其对资源的消耗不适合在所有芯片上启用所以默认为屏蔽状态。如果您使用的是类似于STM32F103ZET6这样的大容量芯片则可以尝试启用中文字库。
&emsp;&emsp;打开Keil MDK的工程配置选择C/C++标签然后在Define项目中添加全局宏定义“_SIMPLE_GUI_DEMO_INNER_CHS_”然后点击OK。
><p align='center'><img src='images/02/020.png' title='20-添加全局宏定义' style='max-width:1024px'></img></p>
&emsp;&emsp;然后重新编译工程这时可以看到编译好的固件对FLASH资源的需求大幅增加。
><p align='center'><img src='images/02/021.png' title='21-启用中文后的编译结果' style='max-width:1024px'></img></p>
&emsp;&emsp;将编译好的程序烧录到芯片,就可以看到实际效果了。
><p align='center'><img src='images/02/022.png' title='22-启用中文后的实际效果' style='max-width:1024px'></img></p>
&emsp;&emsp;
## 1. **联系开发者**
&emsp;&emsp;首先感谢您对SimpleGUI的赏识与支持。
&emsp;&emsp;虽然最早仅仅作为一套GUI接口库使用但我最终希望SimpleGUI能够为您提供一套完整的单色屏GUI及交互设计解决方案如果您有新的需求、提议亦或想法欢迎在以下地址留言或加入[QQ交流群799501887](https://jq.qq.com/?_wv=1027&k=5ahGPvK)留言交流。
- SimpleGUI@开源中国https://www.oschina.net/p/simplegui
- SimpleGUI@码云https://gitee.com/Polarix/simplegui
&emsp;&emsp;本人并不是全职的开源开发者,依然有工作及家庭的琐碎事务要处理,所以对于大家的需求和疑问反馈的可能并不及时,多有怠慢,敬请谅解。
&emsp;&emsp;最后,再次感谢您的支持。