目录
一、资料准备
裸机时空工程:stm32H743+0.96寸OLED 屏幕
FreeRTOS空工程:stm32H743+0.96寸OLED 屏幕+FreeRTOS
STEmwin:STemWin_Library_V1.2.0:https://www.st.com/en/embedded-software/stemwin.htmlhttps://www.st.com/en/embedded-software/stemwin.html
二、目录简介
STemWin_Library_V1.2.0\Libraries\STemWinLibrary532
- Config文件夹:LCD接口以及emwin配置文件,移植时使用
- Documentation:STEmwin的函数说明文件
- inc:STEmwin函数的头文件,移植时使用
- Lib:STEmwin的函数库,移植时使用我们是H7,内核是CM7,开发环境为Keil。所以裸机程序选用STemWin532_CM7_Keil.lib,OS是选用STemWin532_CM7_OS_Keil.lib
- OS:裸机情况下的驱动文件:选用GUI_X.c,使用OS是使用GUI_X_OS.c
- Simulation:仿真用到的文件
- Software:STEmwin开发使用到的软件
三、裸机移植
3.1 添加文件
将STemWinLibrary532文件复制到工程文件夹中,并重名为STEmwin文件夹,
向工程里添加文件:
添加头文件路径后进行编译,发现提示没有LCDConf.h,我们自己新建一个该文件放到STEmwin下的Config文件夹中。再编译就没有报错了。
CUI_X.c:GUI所依赖的外部配置;
CUIConf.c:GUI初始化配置;
CUIConf.h:GUI配置设置;
CUIDRV_Template.c:GUI读点、画点、画线等函数配置,需要我们根据自己的LCD驱动函数进行修改;
LCDConf_FlexColor_Template.c:LCD的初始化配置
STemWin532_CM7_Keil.lib:裸机对应的STEmwin函数库文件
3.2 修改文件
GUIConf.h:
设置是否使用操作系统、是否支持触摸、默认字体、显示的最大层数等参数。由于是裸机,设置OS_SUPPORT为0,而0.96寸的OLED 屏幕不支持触摸,则设置GUI_SUPPORT_TOUCH为0, 设置默认字体 GUI_DEFAULT_FONT为 &GUI_Font6x8;其他参数如下。
#ifndef GUICONF_H
#define GUICONF_H
#define GUI_NUM_LAYERS 2 // Maximum number of available layers
#define OS_SUPPORT 0
#define GUI_SUPPORT_TOUCH 0
#ifdef OS_SUPPORT
#define GUI_OS (1) // Compile with multitasking support
#else
#define GUI_OS (0)
#endif
#ifndef GUI_SUPPORT_TOUCH
#define GUI_SUPPORT_TOUCH (1) // Support touchscreen
#endif
#define GUI_DEFAULT_FONT &GUI_Font6x8
#define GUI_SUPPORT_MOUSE (0) /* Support a mouse */
#define GUI_WINSUPPORT (1) /* Use window manager */
#define GUI_SUPPORT_MEMDEV (1) /* Memory device package available */
#define GUI_SUPPORT_DEVICES (1) /* Enable use of device pointers */
#endif /* Avoid multiple inclusion */
GUIConf.c:定义了STEmwin所使用的的内存,并使用申请此内存。
#include "GUI.h"
#define GUI_NUMBYTES 30*1024
#define GUI_BLOCKSIZE 0x80
void GUI_X_Config(void) {
static U32 aMemory[GUI_NUMBYTES / 4];
GUI_ALLOC_AssignMemory(aMemory, GUI_NUMBYTES);
GUI_ALLOC_SetAvBlockSize(GUI_BLOCKSIZE);
GUI_SetDefaultFont(GUI_FONT_6X8);
}
GUIDRV_Template.c中需要修改两个函数_SetPixelIndex、_GetPixelIndex。
_SetPixelIndex为画点函数,其中需要我们自己修改,添加OLED 屏幕驱动的画点函数,
static void _SetPixelIndex(GUI_DEVICE * pDevice, int x, int y, int PixelIndex) {
#if (LCD_MIRROR_X == 1) || (LCD_MIRROR_Y == 1) || (LCD_SWAP_XY == 1)
int xPhys, yPhys;
xPhys = LOG2PHYS_X(x, y);
yPhys = LOG2PHYS_Y(x, y);
#else
#define xPhys x
#define yPhys y
#endif
GUI_USE_PARA(pDevice);
GUI_USE_PARA(x);
GUI_USE_PARA(y);
GUI_USE_PARA(PixelIndex);
{
OLED_DrawPoint(xPhys,yPhys,PixelIndex);//0.96寸OLED 屏幕画点函数
}
#if (LCD_MIRROR_X == 0) && (LCD_MIRROR_Y == 0) && (LCD_SWAP_XY == 0)
#undef xPhys
#undef yPhys
#endif
}
_GetPixelIndex为读点函数,其中也需要我们自己修改,添加OLED 屏幕驱动的读点函数,
static unsigned int _GetPixelIndex(GUI_DEVICE * pDevice, int x, int y) {
unsigned int PixelIndex;
#if (LCD_MIRROR_X == 1) || (LCD_MIRROR_Y == 1) || (LCD_SWAP_XY == 1)
int xPhys, yPhys;
xPhys = LOG2PHYS_X(x, y);
yPhys = LOG2PHYS_Y(x, y);
#else
#define xPhys x
#define yPhys y
#endif
GUI_USE_PARA(pDevice);
GUI_USE_PARA(x);
GUI_USE_PARA(y);
{
//PixelIndex = 0;
PixelIndex = OLED_GetPixel(xPhys,yPhys);//0.96寸OLED 屏幕读点函数
}
#if (LCD_MIRROR_X == 0) && (LCD_MIRROR_Y == 0) && (LCD_SWAP_XY == 0)
#undef xPhys
#undef yPhys
#endif
return PixelIndex;
}
编译通过
四、含FreeRTOS移植
基本与裸机移植一致,不一样的是
- 裸机程序选用STemWin532_CM7_Keil.lib,现在OS是选用STemWin532_CM7_OS_Keil.lib
- 裸机选用GUI_X.c,现在OS是选用GUI_X_OS.c
最重要的现在使用的FreeRTOS,所以GUI_X_OS.c具体选用GUI_X_FreeRTOS.c文件。
/*File : GUI_X_FreeRTOS.C*/
#include "GUI.h"
/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
static xSemaphoreHandle xQueueMutex = NULL;
static xSemaphoreHandle xSemaTxDone = NULL;
int GUI_X_GetTime(void)
{
return ((int) xTaskGetTickCount());
}
void GUI_X_Delay(int ms)
{
vTaskDelay( ms );
}
void GUI_X_Init(void) {
}
void GUI_X_ExecIdle(void) {
}
void GUI_X_InitOS(void)
{
/* 创建互斥信号量 用于资源共享 */
xQueueMutex = xSemaphoreCreateMutex();
configASSERT (xQueueMutex != NULL);
/* 创建二值信号量 用于事件触发 */
vSemaphoreCreateBinary( xSemaTxDone );
configASSERT ( xSemaTxDone != NULL );
}
void GUI_X_Unlock(void)
{
/* 给出互斥量 */
xSemaphoreGive(xQueueMutex);
}
void GUI_X_Lock(void)
{
if(xQueueMutex == NULL)
{
GUI_X_InitOS();
}
/* 获取互斥量 */
xSemaphoreTake(xQueueMutex, /* 互斥量句柄 */
portMAX_DELAY);/* 阻塞等待 */
}
/* Get Task handle */
U32 GUI_X_GetTaskId(void)
{
return ((U32) xTaskGetCurrentTaskHandle());
}
void GUI_X_WaitEvent (void)
{
/* 获取信号量 */
while(xSemaphoreTake(xSemaTxDone, /* 信号量句柄 */
portMAX_DELAY) != pdTRUE);/* 阻塞等待 */
}
void GUI_X_SignalEvent (void)
{
/* 给出信号量 */
xSemaphoreGive(xSemaTxDone);
}
void GUI_X_Log (const char *s) { }
void GUI_X_Warn (const char *s) { }
void GUI_X_ErrorOut(const char *s) { }
五、测试
5.1 裸机测试
#include "sys.h"
#include "delay.h"
#include "timer.h"
#include "oled.h"
#include "GUI.h"
int main(void)
{
Cache_Enable(); //打开L1-Cache
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(160,5,2,4); //设置时钟,400Mhz
delay_init(400); //延时初始化
TIM3_Init(50000-1,200-1); //定时器3初始化,定时器时钟为200M,分频系数为20000-1, 50ms 刷新屏幕
__HAL_RCC_CRC_CLK_ENABLE();//使能CRC时钟,否则STemWin不能使用
GUI_Init();
GUI_SetBkColor(GUI_WHITE); //设置背景颜色
GUI_Clear();//全部显示背景色
GUI_DispStringAt("hello world",0,0);
while(1)
{
delay_ms(1000);
}
}
5.2 含系统测试
//main.c
#include "sys.h"
#include "delay.h"
#include "timer.h"
#include "oled.h"
#include "GUI.h"
#include "textdisplay.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define Screen_update_TASK_PRIO 2
//任务堆栈大小
#define Screen_update_STK_SIZE 50
//任务句柄
TaskHandle_t Screen_update_Task_Handler;
//任务函数
void Screen_update_task(void *pvParameters);
int main(void)
{
Cache_Enable(); //打开L1-Cache
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(160,5,2,4); //设置时钟,400Mhz
delay_init(400); //延时初始化
TIM3_Init(50000-1,200-1); //定时器3初始化,定时器时钟为200M,分频系数为20000-1, 50ms 刷新屏幕
__HAL_RCC_CRC_CLK_ENABLE();//使能CRC时钟,否则STemWin不能使用
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度
}
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
//创建LED0任务
xTaskCreate((TaskFunction_t )Screen_update_task,
(const char* )"Screen_update_task",
(uint16_t )Screen_update_STK_SIZE,
(void* )NULL,
(UBaseType_t )Screen_update_TASK_PRIO,
(TaskHandle_t* )&Screen_update_Task_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
GUI_Init();
emwin_texttest();
taskEXIT_CRITICAL(); //退出临界区
}
void Screen_update_task(void *pvParameters)
{
while(1)
{
vTaskDelay(50); //50ms
OLED_Refresh_Gram();
}
}
#include "textdisplay.h"
#include "GUI.h"
void emwin_texttest(void)
{
GUI_SetBkColor(GUI_BLUE); //设置背景颜色
GUI_Clear(); //清屏
GUI_SetPenSize(10); //设置笔大小
GUI_SetFont(&GUI_Font8_ASCII); //设置字体
GUI_DispStringHCenterAt("HELLO WORD!",63,0);
GUI_SetTextMode(GUI_TM_REV); //反转文本
GUI_DispStringHCenterAt("GUI_TM_REV" ,63,8);
GUI_SetTextMode(GUI_TM_TRANS); //透明文本
GUI_DispStringHCenterAt("GUI_TM_TRANS" ,63,16);
GUI_SetTextMode(GUI_TM_XOR); //异或文本
GUI_DispStringHCenterAt("GUI_TM_XOR" ,63,24);
GUI_SetTextMode(GUI_TM_TRANS|GUI_TM_REV);//透明反转文本
GUI_DispStringHCenterAt("GUI_EM_TRANS|GUI_TM_REV",63,32);
}