|

楼主 |
发表于 2017-1-12 16:43:12
|
显示全部楼层
18.4 实验例程说明(RTOS)
配套例子:
V6-522_STemWin实验_GIF图片显示(RTOS)
实验目的:
1. 学习emWin的GIF图片显示。
2. emWin功能的实现在MainTask.c文件里面。
实验内容:
1. K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
2. K2按键按下,实现截图功能,将图片以BMP格式保存到SD卡中。
3. 各个任务实现的功能如下:
App Task Start 任务:实现按键和触摸扫描。
App Task MspPro任务 :实现截图功能,将图片以BMP格式保存到SD卡中。
App Task UserIF 任务:按键消息处理。
App Task COM 任务:暂未使用。
App Task GUI 任务:GUI任务。
实验注意:
1. 本实验主要学习emWin的GIF图片显示功能,实验所需的图片文件1.gif已经存储到本工程的Doc文件夹下,使用此例子前,请务必将此文件存储到SD卡根目录中,并将SD卡插到开发板上面。
μCOS-III任务调试信息(按K1按键,串口打印):
STemWin界面显示效果:
800*480分辨率界面效果。
STemWin动态内存配置:
GUIConf.c文件中的配置如下:
- #define EX_SRAM 1/*1 used extern sram, 0 used internal sram */
-
- #if EX_SRAM
- #define GUI_NUMBYTES (1024*1024*8)
- #else
- #define GUI_NUMBYTES (100*1024)
- #endif
复制代码 通过宏定义来配置使用内部SRAM还是外部的SDRAM做为emWin的动态内存,当配置:
#define EX_SRAM 1 表示使用外部SDRAM作为emWin动态内存,大小8MB。
#define EX_SRAM 0 表示使用内部SRAM作为emWin动态内存,大小100KB。
默认情况下,本教程配套的所有emWin例子都是用外部SDRAM作为emWin动态内存。
STemWin底层接口配置:
LCDConf_Lin_Template.c文件中共12项emWin配置:
对于这12个配置选项,注释说明已经比较详细。默认情况下,本教程配套的emWin例子都是用的三缓冲,RGB565格式,且仅使用单图层。
程序设计:
任务栈大小分配:
μCOS-III任务栈大小在os_cfg.h文件中配置:
#define APP_CFG_TASK_START_STK_SIZE 512u
#define APP_CFG_TASK_MsgPro_STK_SIZE 512u
#define APP_CFG_TASK_COM_STK_SIZE 512u
#define APP_CFG_TASK_USER_IF_STK_SIZE 512u
#define APP_CFG_TASK_GUI_STK_SIZE 1024u
任务栈大小的单位是4字节,那么每个任务的栈大小如下:
App Task Start 任务:2048字节。
App Task MspPro任务 :2048字节。
App Task UserIF 任务:2048字节。
App Task COM 任务:2048字节。
App Task GUI 任务:4096字节。
系统栈大小分配:
μCOS-III的系统栈大小在os_cfg_app.h文件中配置:
#define OS_CFG_ISR_STK_SIZE 512u
系统栈大小的单位是4字节,那么这里就是配置系统栈大小为2KB。
μCOS-III初始化:
- /*
- *********************************************************************************************************
- * 函 数 名: main
- * 功能说明: 标准c程序入口。
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- int main(void)
- {
- OS_ERR err;
-
- /* 初始化uC/OS-III 内核 */
- OSInit(&err);
-
- /* 创建一个启动任务(也就是主任务)。启动任务会创建所有的应用程序任务 */
- OSTaskCreate((OS_TCB *)&AppTaskStartTCB, /* 任务控制块地址 */
- (CPU_CHAR *)"App Task Start", /* 任务名 */
- (OS_TASK_PTR )AppTaskStart, /* 启动任务函数地址 */
- (void *)0, /* 传递给任务的参数 */
- (OS_PRIO )APP_CFG_TASK_START_PRIO, /* 任务优先级 */
- (CPU_STK *)&AppTaskStartStk[0], /* 堆栈基地址 */
- (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE / 10, /* 堆栈监测区,这里表示后10%作为监测区 */
- (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE, /* 堆栈空间大小 */
- (OS_MSG_QTY )0, /* 本任务支持接受的最大消息数 */
- (OS_TICK )0, /* 设置时间片 */
- (void *)0, /* 堆栈空间大小 */
- (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
-
- /* 定义如下:
- OS_OPT_TASK_STK_CHK 使能检测任务栈,统计任务栈已用的和未用的
- OS_OPT_TASK_STK_CLR 在创建任务时,清零任务栈
- OS_OPT_TASK_SAVE_FP 如果CPU有浮点寄存器,则在任务切换时保存浮点寄存器的内容
- */
- (OS_ERR *)&err);
-
- /* 启动多任务系统,控制权交给uC/OS-III */
- OSStart(&err);
-
- (void)&err;
-
- return (0);
- }
复制代码 硬件外设初始化
硬件外设的初始化是在bsp.c文件实现:
- /*
- *********************************************************************************************************
- * 函 数 名: bsp_Init
- * 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void bsp_Init(void)
- {
- /*
- 由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
- 启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
-
- 系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
- */
- /* 使能CRC 因为使用STemWin前必须要使能 */
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
-
- /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
-
- SystemCoreClockUpdate(); /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */
-
- bsp_InitUart(); /* 初始化串口 */
- bsp_InitKey(); /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */
-
- bsp_InitExtIO(); /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */
- bsp_InitLed(); /* 初始LED指示灯端口 */
-
- bsp_InitI2C(); /* 配置I2C总线 */
-
- bsp_InitExtSDRAM(); /* 初始化SDRAM */
- bsp_DetectLcdType(); /* 检测触摸板和LCD面板型号, 结果存在全局变量 g_TouchType, g_LcdType */
-
- TOUCH_InitHard(); /* 初始化配置触摸芯片 */
- LCD_ConfigLTDC(); /* 初始化配置LTDC */
-
- result = f_mount(&fs, "0:/", 0); /* 挂载文件系统 */
- }
复制代码 五个μCOS-III任务的实现:
- /*
- *********************************************************************************************************
- * 函 数 名: AppTaskStart
- * 功能说明: 这是一个启动任务,在多任务系统启动后,必须初始化滴答计数器。本任务主要实现按键和触摸检测。
- * 形 参: p_arg 是在创建该任务时传递的形参
- * 返 回 值: 无
- 优 先 级: 2
- *********************************************************************************************************
- */
- static void AppTaskStart (void *p_arg)
- {
- OS_ERR err;
- uint8_t ucCount = 0;
- uint8_t ucCount1 = 0;
-
- /* 仅用于避免编译器告警,编译器不会产生任何目标代码 */
- (void)p_arg;
-
- /* BSP 初始化。 BSP = Board Support Package 板级支持包,可以理解为底层驱动。*/
- CPU_Init(); /* 此函数要优先调用,因为外设驱动中使用的us和ms延迟是基于此函数的 */
- bsp_Init();
- BSP_Tick_Init();
-
- #if OS_CFG_STAT_TASK_EN > 0u
- OSStatTaskCPUUsageInit(&err);
- #endif
-
- #ifdef CPU_CFG_INT_DIS_MEAS_EN
- CPU_IntDisMeasMaxCurReset();
- #endif
-
- /* 创建应用程序的任务 */
- AppTaskCreate();
-
- /* 创建任务通信 */
- AppObjCreate();
-
- while(1)
- {
- /* 1ms一次触摸扫描,电阻触摸屏 */
- if(g_tTP.Enable == 1)
- {
- TOUCH_Scan();
-
- /* 按键扫描 */
- ucCount++;
- if(ucCount == 10)
- {
- ucCount = 0;
- bsp_KeyScan();
- }
- OSTimeDly(1, OS_OPT_TIME_DLY, &err);
- }
-
- /* 20ms一次触摸扫描,电容触摸屏GT811
- GT811取20ms比较稳定,取10ms偶尔会有跳动。
- */
- if(g_GT811.Enable == 1)
- {
- bsp_KeyScan();
- ucCount1++;
- if(ucCount1 == 2)
- {
- ucCount1 = 0;
- GT811_OnePiontScan();
- }
- OSTimeDly(10, OS_OPT_TIME_DLY, &err);
- }
-
- /* 10ms一次触摸扫描,电容触摸屏FT5X06 */
- if(g_tFT5X06.Enable == 1)
- {
- bsp_KeyScan();
- FT5X06_OnePiontScan();
- OSTimeDly(10, OS_OPT_TIME_DLY, &err);
- }
- }
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: AppTaskMsgPro
- * 功能说明: 实现截图功能,将图片以BMP格式保存到SD卡中
- * 形 参: p_arg 是在创建该任务时传递的形参
- * 返 回 值: 无
- 优 先 级: 3
- *********************************************************************************************************
- */
- static void AppTaskMsgPro(void *p_arg)
- {
- uint32_t ulStart, ulEnd;
- OS_ERR err;
- uint8_t Pic_Name = 0;
- char buf[20];
-
- (void)p_arg;
-
- while(1)
- {
- /* 等待获取信号量同步消息,接收到后执行串口打印 */
- OSSemPend((OS_SEM *)&SEM_SYNCH,
- (OS_TICK )0,
- (OS_OPT )OS_OPT_PEND_BLOCKING,
- (CPU_TS )0,
- (OS_ERR *)&err);
-
- if(err == OS_ERR_NONE)
- {
- sprintf(buf,"0:/PicSave/%d.bmp",Pic_Name);
-
- /* 记录截图前起始时间 */
- ulStart = OSTimeGet(&err);
-
- /* 开启调度锁 */
- OSSchedLock(&err);
-
- /* 如果SD卡中没有PicSave文件,会进行创建 */
- result = f_mkdir("0:/PicSave");
-
- /* 创建截图 */
- result = f_open(&file,buf, FA_WRITE|FA_CREATE_ALWAYS);
-
- /* 向SD卡绘制BMP图片 */
- GUI_BMP_Serialize(_WriteByte2File, &file);
-
- /* 创建完成后关闭file */
- result = f_close(&file);
-
- /* 开启调度锁 */
- OSSchedUnlock(&err);
-
- /* 记录截图后时间并获取截图过程耗时 */
- ulEnd = OSTimeGet(&err);
- ulEnd -= ulStart;
-
- App_Printf("截图完成,耗时 = %dms\\r\\n", ulEnd);
- Pic_Name++;
- }
- }
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: AppTaskUserIF
- * 功能说明: 按键消息处理
- * 形 参: p_arg 是在创建该任务时传递的形参
- * 返 回 值: 无
- 优 先 级: 4
- *********************************************************************************************************
- */
- static void AppTaskUserIF(void *p_arg)
- {
- OS_ERR err;
- uint8_t ucKeyCode;
-
- (void)p_arg; /* 避免编译器报警 */
-
-
- while (1)
- {
- ucKeyCode = bsp_GetKey();
-
- if (ucKeyCode != KEY_NONE)
- {
- switch (ucKeyCode)
- {
- case KEY_DOWN_K1: /* K1键按下 打印任务执行情况 */
- DispTaskInfo();
- break;
-
- case KEY_DOWN_K2: /* K2键按下 向消息队列发送数据 */
- OSSemPost((OS_SEM *)&SEM_SYNCH,
- (OS_OPT )OS_OPT_POST_1,
- (OS_ERR *)&err);
- break;
-
- default: /* 其他的键值不处理 */
- break;
- }
- }
-
- OSTimeDly(20, OS_OPT_TIME_DLY, &err);
- }
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: AppTaskCom
- * 功能说明: 暂未使用
- * 形 参: p_arg 是在创建该任务时传递的形参
- * 返 回 值: 无
- 优 先 级: 5
- *********************************************************************************************************
- */
- static void AppTaskCOM(void *p_arg)
- {
- OS_ERR err;
-
- (void)p_arg;
-
- while(1)
- {
- OSTimeDly(500, OS_OPT_TIME_DLY, &err);
- }
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: AppTaskGUI
- * 功能说明: GUI任务,最低优先级
- * 形 参:p_arg 是在创建该任务时传递的形参
- * 返 回 值: 无
- * 优 先 级:OS_CFG_PRIO_MAX - 4u
- *********************************************************************************************************
- */
- static void AppTaskGUI(void *p_arg)
- {
- (void)p_arg; /* 避免编译器告警 */
-
- while (1)
- {
- MainTask();
- }
- }
复制代码 emWin任务的具体实现(在MainTask.c文件里面):
- #include "MainTask.h"
- #include "includes.h"
-
-
-
-
- /*
- *********************************************************************************************************
- * 宏定义
- *********************************************************************************************************
- */
- /* 边加载边显示的方式选择 :Method1
- 直接加载到SDRAM进行显示选择 :Method2
- */
- #define Method2
-
-
- /*
- *********************************************************************************************************
- * 变量
- *********************************************************************************************************
- */
- static char acBuffer[8192];
-
- static GUI_GIF_INFO InfoGif;
- static GUI_GIF_IMAGE_INFO ImagInfoGif;
-
- /*
- *********************************************************************************************************
- * 函 数 名: _GetData
- * 功能说明: 被函数GUI_JPEG_DrawEx调用
- * 形 参:p FIL类型数据
- * NumBytesReq 请求读取的字节数
- * ppData 数据指针
- * Off 如果Off = 1,那么将重新从起始位置读取
- * 返 回 值: 返回读取的字节数
- *********************************************************************************************************
- */
- int _GetData(void * p, const U8 ** ppData, unsigned NumBytesReq, U32 Off)
- {
- static int FileAddress = 0;
- UINT NumBytesRead;
- FIL *PicFile;
-
- PicFile = (FIL *)p;
-
- /*
- * 检测缓存大小
- */
- if (NumBytesReq > sizeof(acBuffer)) {
- NumBytesReq = sizeof(acBuffer);
- }
-
- /*
- * 设置读取位置
- */
- if(Off == 1) FileAddress = 0;
- else FileAddress = Off;
- result =f_lseek(PicFile, FileAddress);
-
- /*
- * 读取数据到缓存
- */
- result = f_read(PicFile, acBuffer, NumBytesReq, &NumBytesRead);
-
- /*
- * 让指针ppData指向读取的数据
- */
- *ppData = (const U8 *)acBuffer;
-
- /*
- * 返回读取的字节数
- */
- return NumBytesRead;
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: _ShowGIF1
- * 功能说明: 显示GIF片
- * 形 参: sFilename 要显示的图片名字
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void _ShowGIF1(const char * sFilename)
- {
- uint16_t i = 0;
- uint32_t t0, t1;
- char buf[50];
-
- /* 打开文件 */
- result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
- if (result != FR_OK)
- {
- return;
- }
-
- /* 获取GIF图片信息 */
- GUI_GIF_GetInfoEx(_GetData, &file,&InfoGif);
-
- while(1)
- {
- /* 变量用来设置当前播放的帧数,InfoGif.NumImages是GIF图片总的帧数 */
- if(i < InfoGif.NumImages)
- {
- /* 获取当前帧GIF图片信息,注意第4个参数是从0开始计数的 */
- GUI_GIF_GetImageInfoEx(_GetData, &file, &ImagInfoGif, i);
-
- /* 如果此帧延迟时间是0,默认是延迟100ms */
- if(ImagInfoGif.Delay == 0)
- {
- GUI_Delay(100);
- }
- else
- {
- t0 = GUI_GetTime();
- /* 显示当前播放的帧数 */
- sprintf(buf, " Frame:%d/%d ", i+1, InfoGif.NumImages);
- GUI_DispStringHCenterAt(buf, LCD_GetXSize()/2, 0);
-
- /* 解码并显示此帧GIF图片,注意第5个参数是从0开始计数的 */
- GUI_GIF_DrawSubEx(_GetData,
- &file,
- (LCD_GetXSize() - InfoGif.xSize)/2,
- (LCD_GetYSize() - InfoGif.ySize)/2,
- i++);
-
- /* 获取本次解码和显示消耗的时间 */
- t1 = GUI_GetTime() - t0;
-
- /* 如果GIF的解码和显示的时间超时就不做延迟 */
- if (t1 < ImagInfoGif.Delay * 10)
- {
- GUI_Delay(ImagInfoGif.Delay * 10 - t1);
- }
- }
- }
- else
- {
- i = 0;
- }
- }
-
- /* 实际应用中,根据实际情况释放动态内存 */
- // GUI_ALLOC_Free(hMem);
- // f_close(&file);
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: _ShowGIF2
- * 功能说明: 显示GIF片
- * 形 参: sFilename 要显示的图片名字
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void _ShowGIF2(const char * sFilename)
- {
- uint16_t i = 0;
- uint32_t t0, t1;
- char *_acBuffer;
- GUI_HMEM hMem;
- char buf[50];
-
- /* 打开文件 */
- result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
- if (result != FR_OK)
- {
- return;
- }
-
- /* 申请一块内存空间 并且将其清零 */
- hMem = GUI_ALLOC_AllocZero(file.fsize);
-
- /* 将申请到内存的句柄转换成指针类型 */
- _acBuffer = GUI_ALLOC_h2p(hMem);
-
- /* 读取文件到动态内存 */
- result = f_read(&file, _acBuffer, file.fsize, &bw);
- if (result != FR_OK)
- {
- return;
- }
-
- /* 获取GIF图片信息 */
- GUI_GIF_GetInfo(_acBuffer, file.fsize, &InfoGif);
-
- while(1)
- {
- /* 变量用来设置当前播放的帧数,InfoGif.NumImages是GIF图片总的帧数 */
- if(i < InfoGif.NumImages)
- {
- /* 获取当前帧GIF图片信息,注意第4个参数是从0开始计数的 */
- GUI_GIF_GetImageInfo(_acBuffer, file.fsize, &ImagInfoGif, i);
-
- /* 如果此帧延迟时间是0,默认是延迟100ms */
- if(ImagInfoGif.Delay == 0)
- {
- GUI_Delay(100);
- }
- else
- {
- t0 = GUI_GetTime();
- /* 显示当前播放的帧数 */
- sprintf(buf, " Frame:%d/%d ", i+1, InfoGif.NumImages);
- GUI_DispStringHCenterAt(buf, LCD_GetXSize()/2, 0);
-
- /* 解码并显示此帧GIF图片,注意第5个参数是从0开始计数的 */
- GUI_GIF_DrawSub(_acBuffer,
- file.fsize,
- (LCD_GetXSize() - InfoGif.xSize)/2,
- (LCD_GetYSize() - InfoGif.ySize)/2,
- i++);
-
- /* 获取本次解码和显示消耗的时间 */
- t1 = GUI_GetTime() - t0;
-
- /* 如果GIF的解码和显示的时间超时就不做延迟 */
- if (t1 < ImagInfoGif.Delay * 10)
- {
- GUI_Delay(ImagInfoGif.Delay * 10 - t1);
- }
- }
- }
- else
- {
- i = 0;
- }
- }
-
- /* 实际应用中,根据实际情况释放动态内存 */
- // GUI_ALLOC_Free(hMem);
- // f_close(&file);
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: MainTask
- * 功能说明: GUI主函数
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void MainTask(void)
- {
- /* 初始化 */
- GUI_Init();
-
- /* 设置字体,文本模式和前景色 */
- GUI_SetFont(&GUI_Font24B_ASCII);
- GUI_SetColor(GUI_WHITE);
-
- /* 设置背景色 */
- GUI_SetBkColor(GUI_BLUE);
- GUI_Clear();
-
- /*
- 关于多缓冲和窗口内存设备的设置说明
- 1. 使能多缓冲是调用的如下函数,用户要在LCDConf_Lin_Template.c文件中配置了多缓冲,调用此函数才有效:
- WM_MULTIBUF_Enable(1);
- 2. 窗口使能使用内存设备是调用函数:WM_SetCreateFlags(WM_CF_MEMDEV);
- 3. 如果emWin的配置多缓冲和窗口内存设备都支持,二选一即可,且务必优先选择使用多缓冲,实际使用
- STM32F429BIT6 + 32位SDRAM + RGB565/RGB888平台测试,多缓冲可以有效的降低窗口移动或者滑动时的撕裂
- 感,并有效的提高流畅性,通过使能窗口使用内存设备是做不到的。
- 4. 所有emWin例子默认是开启三缓冲。
- */
- WM_MULTIBUF_Enable(1);
-
- /*
- 触摸校准函数默认是注释掉的,电阻屏需要校准,电容屏无需校准。如果用户需要校准电阻屏的话,执行
- 此函数即可,会将触摸校准参数保存到EEPROM里面,以后系统上电会自动从EEPROM里面加载。
- */
- //TOUCH_Calibration();
-
-
- /* GIF图片显示方式一:实际项目不推荐,会用即可 */
- #if defined Method1
- _ShowGIF1("1.gif");
-
- /* GIF图片显示方式二:实际项目推荐 */
- #elif defined Method2
- _ShowGIF2("1.gif");
-
- #endif
-
- /* 如果进入到这里,说明GIF图片加载失败 */
- GUI_DispStringAt("GIF Load failed!!", 0, 0);
-
- while(1)
- {
- GUI_Delay(10);
- }
- }
复制代码 |
|