在这里就是稍微介绍一下ucosiii和emWin,f429在网上资源也是非常成熟了,在此就不啰嗦了。
**uC/OS-III**:(Micro C OS Three 微型的C 语言编写的操作系统第3版)是一个可升级的,可固化的,基于优先级的实时内核。它对任务的个数无限制(uC/OS-II在2.80版本之前 最多允许任务个数为64个,之后达到255个)。uC/OS-III 是一个第3 代的系统内核,支持现代的实时内核所期待的大部分功能。例如资源管理,同步,任务间的通信等等。然而,uC/OS-III 提供的特色功能在其它的实时内核中是找不到的,比如说完备的运行时间测量性能,直接地发送信号或者消息到任务,任务可以同时等待多个内核对象等。
**emWin/UCGUI**:是一款图像界面制作工具,在图像制作这一块应用相当广泛,可使用 M4 内核 MCU 的时候会移植 UCGUI 来制作精美的 UI, UCGUI 的高级版本就是 emWin,而 STemWin是 SEGGER授权给ST的 emWin版本,ST的芯片可以免费使用 STemWin,而且 STemWin 针对 ST 的芯片做了优化。 本章我们将向大家介绍如何STM32F429 开发板上移植 STemWin, 在文章通过使用原子配套开发板 ALIENTEK 及配套液晶屏来实现对图片制作, 硬件搭载包括 8080 接口的 2.8寸, 3.5 寸, 4.3 寸和 7 寸(SSD1963),还有 RGB 接口的 4.3 寸(480*272), 7 寸(800*480), 7 寸(1024*600)这七种不同尺寸和分辨率的屏幕。
在应用之前首先了解 UCOSII 相关的概念需要大家了解一下: 任务优先级,任务堆栈,任务控制块,任务就绪表和任务调度器。
任务优先级:这个概念比较好理解, ucos 中,每个任务都有唯一的一个优先级。优先级是任务的唯一标识。在 UCOSII 中, 使用 CPU 的时候,优先级高(数值小)的任务比优先级低的任务具有优先使用权,即任务就绪表中总是优先级最高的任务获得 CPU 使用权,只有高优先级的任务让出 CPU 使用权(比如延时)时,低优先级的任务才能获得 CPU 使用权。 UCOSII 不支持多个任务优先级相同,也就是每个任务的优先级必须不一样。在软件中可以类比成是线程,我们WINDOWS采用的也是单线程,即在同一时间下只有一个任务在允许,通过调节应用线程的优先级可以确认线程抢占顺序。
任务堆栈:就是存储器中的连续存储空间。为了满足任务切换和响应中断时保存 CPU 寄存器中的内容以及任务调用其他函数时的需要,每个任务都有自己的堆栈。在创建任务的时候,任务堆栈是任务创建的一个重要入口参数。
任务控制块 :OS_TCB,用来记录任务堆栈指针,任务当前状态以及任务优先级等任务属性。UCOSII 的任何任务都是通过任务控制块(TCB)的东西来控制的,一旦任务创建了,任务控制块 OS_TCB 就会被赋值。每个任务管理块有3个最重要的参数:1任务函数指针;2任务堆栈指针;3任务优先级;任务控制块就是任务在系统里面的身份证(UCOSII 通过优先级识别任务),任务控制块我们就不再详细介绍了,详细介绍请参考任哲老师的《嵌入式实时操作系统 UCOSII 原理及应用》一书第二章。
任务就绪表:简而言之就是用来记录系统中所有处于就绪状态的任务。 它是一个位图,系统中每个任都在这个位图中占据一个进制位,该位置的状态( 1 或者 0)就表示任务是否处于就绪状态。
任务调度:作用一是在任务就绪表中查找优先级最高的就绪任务,二是实现任务的切换。比如说,当一个任务释放 cpu 控制权后,进行一次任务调度,这个时候任务调度器首先要去任务就绪表查询优先级最高的就绪任务,查到之后,进行一次任务切换,转而去执行下一个任务。
UCOSII 的每个任务都是一个死循环。每个任务都处在以下 5 种状态之一的状态下,这 5种状态是:睡眠状态、 就绪状态、 运行状态、 等待状态(等待某一事件发生)和中断服务状态。将运行状态结合起来就是系统中一个任务的生命周期,即单个程序被调用从开始到结束的生命周期。
睡眠状态:任务在没有被配备任务控制块或被剥夺了任务控制块时的状态。
就绪状态: 系统为任务配备了任务控制块且在任务就绪表中进行了就绪登记, 任务已经准备好了, 但由于该任务的优先级比正在运行的任务的优先级低, 还暂时不能运行, 这时任务的状态叫做就绪状态。
运行状态:该任务获得 CPU 使用权,并正在运行中,此时的任务状态叫做运行状态。
等待状态: 正在运行的任务,需要等待一段时间或需要等待一个事件发生再运行时,该任务就会把 CPU 的使用权让给别的任务而使任务进入等待状态。
中断服务状态: 一个正在运行的任务一旦响应中断申请就会中止运行而去执行中断服务程序,这时任务的状态叫做中断服务状态。状态关系如下图所示
接下来 就到程序这一块,主要是对系统任务进行创建、删除、挂起和恢复进行操作。
在这里创建的是一个开始任务,其他的任务可在开始任务中按照这种格式进行创建多个任务,相当于在开始任务中进行main()函数的操作,即任务初始化以及系统死循环。任务操作代码意思见注释。在任务创建之前要确定好任务的优先级和任务堆栈大小
//创建开始任务
OSTaskCreate((OS_TCB * )&StartTaskTCB, //创建任务控制块
(CPU_CHAR * )"start task", /*非任务函数名称,系统本身不知道任务名称,
仅知道任务地址与指针,此为输出或调试时使
用任务名称的代替字符串*/
(OS_TASK_PTR )start_task, //任务函数
(void * )0, /*定义函数形参,可以为&取址全局变量。若只
有局部变量,可用static定义局部变量*/
(OS_PRIO )START_TASK_PRIO, //任务优先级
(CPU_STK * )&START_TASK_STK[0], //任务堆栈基地址
(CPU_STK_SIZE)START_STK_SIZE/10, //任务堆栈深度限位
(CPU_STK_SIZE)START_STK_SIZE, //任务堆栈大小
(OS_MSG_QTY )0, //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
(OS_TICK )0, //当使能时间片轮转时的时间片长度,为0时为默认长度,
(void * )0, //用户补充的存储区
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
//任务选项,是否需要清零该任务堆栈/是否储存浮点运算寄存器
(OS_ERR * )&err); //存放该函数错误时的返回值
通过创建任务执行函数任务start_task()函数内容,如下:
CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); //统计任务
#endif
#ifdef CPU_CFG_INT_DIS_MEAS_EN //如果使能了测量中断关闭时间
CPU_IntDisMeasMaxCurReset();
#endif
#if OS_CFG_SCHED_ROUND_ROBIN_EN //当使用时间片轮转的时候
//使能时间片轮转调度功能,设置默认的时间片长度
OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);
#endif
__HAL_RCC_CRC_CLK_ENABLE(); //使能CRC时钟
GUI_Init(); //STemWin初始化
WM_MULTIBUF_Enable(1); //开启STemWin多缓冲,RGB屏可能会用到
OS_CRITICAL_ENTER(); //进入临界区
//STemWin Demo任务
OSTaskCreate((OS_TCB* )&EmwindemoTaskTCB,
(CPU_CHAR* )"Emwindemo task",
(OS_TASK_PTR )emwindemo_task,
(void* )0,
(OS_PRIO )EMWINDEMO_TASK_PRIO,
(CPU_STK* )&EMWINDEMO_TASK_STK[0],
(CPU_STK_SIZE)EMWINDEMO_STK_SIZE/10,
(CPU_STK_SIZE)EMWINDEMO_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void* )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR* )&err);
//触摸屏任务
OSTaskCreate((OS_TCB* )&TouchTaskTCB,
(CPU_CHAR* )"Touch task",
(OS_TASK_PTR )touch_task,
(void* )0,
(OS_PRIO )TOUCH_TASK_PRIO,
(CPU_STK* )&TOUCH_TASK_STK[0],
(CPU_STK_SIZE)TOUCH_STK_SIZE/10,
(CPU_STK_SIZE)TOUCH_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void* )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR* )&err);
//LED0任务
OSTaskCreate((OS_TCB* )&Led0TaskTCB,
(CPU_CHAR* )"Led0 task",
(OS_TASK_PTR )led0_task,
(void* )0,
(OS_PRIO )LED0_TASK_PRIO,
(CPU_STK* )&LED0_TASK_STK[0],
(CPU_STK_SIZE)LED0_STK_SIZE/10,
(CPU_STK_SIZE)LED0_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void* )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR* )&err);
OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err); //挂起开始任务
OS_CRITICAL_EXIT(); //退出临界区
}
start_task()函数内容包括了emwindemo_task任务(emWin界面显示任务)、touch_task 任务(液晶触摸任务)和 led0_task任务(LED指示灯闪烁任务),每个任务需设置任务优先级以及堆栈空间大小,具体大小可结合实际需求设置。在 start_task 中创建了另外三个任务,在创建之后将自身( start_task)挂起。这里,我们单独创建 start_task,是为了提供一个单一任务,实现应用程序开始运行之前的准备工作(比如:外设初始化、创建信号量、创建邮箱、创建消息队列、创建信号量集、创建任务、初始化
统计任务等等)。任务创建完之后就执行任务定义的工作函数。
知道任务创建了,那么接下来就是任务的其他操作
删除任务主要就是调用OSTaskDel()函数进行实现,函数原型如下
void OSTaskDel (OS_TCB *p_tcb, //指向要删除的任务 TCB,也可以传递一个 NULL 指针来删除调用
//OSTaskDel()函数的任务自身。
OS_ERR *p_err) //指向一个变量用来保存调用 OSTaskDel()函数后返回的错误码。
{
比如我需要删除创建任务中的emWin,只需要调用这个函数,函数执行后将删除函数任务,不再执行。但是这个任务的任务堆栈、 OS_TCB 所占用的内存并没有释放掉,因此我们可以利用他们用于其他的任务,当然我们也可以使用内存管理的方法给任务堆栈和 OS_TCB 分配内存,这样当我们删除掉某个任务后我们就可以使用内存释放函数将这个任务的任务堆栈和 OS_TCB 所占用的内存空间释放掉。删除emWin任务操作如下
OSTaskDel((OS_TCB*)&EmwindemoTaskTCB,&err);
挂起任务意思就是将在抢占CPU资源的任务给暂停,让出资源给其他任务调用资源,此时不再有作用,保留了使用功能。当需要再次使用的时候,给任务进行恢复即可继续执行。比如我需要对emWin任务进行挂起和恢复,只需进行一下操作就好了
OSTaskSuspend((OS_TCB*)&EmwindemoTaskTCB,&err); //将emWin任务进行挂起
OSTaskResume((OS_TCB*)&EmwindemoTaskTCB,&err); //将emWin任务进行恢复
emWin是一种图形化界面操作库,能够对界面进行一系列的操作。如文字、颜色、控件、图片等等。还有专门的图形制作软件,可根据需求通过调用API函数对界面进行任意操作。
1 GUIBuilder应用
(1)在软件上仿真
emWin在vc++和vs上面都是可以通过仿真来模拟界面的,由于在实际过程中在硬件上每次编译和烧录都需要消耗很多时间,所以可以通过在模拟器上进行仿真,仿好之后就可以将界面移植到硬件上
首先打开GUIBuilder,界面中现在是什么都没有的,在添加控件之前,首先需要建立窗口,添加Franewin(有边框)或者Window(无边框)
(2)在硬件上使用
2 BMP图片生成
BMP图片显示可参照以下地址,其实emwin的操作在原子、野火、安富来都有操作,可以直接用pdf教程
http://blog.csdn.net/efm32/article/details/8496812
**
emwin的显示需要在ucosiii分配一个任务,ucosiii的任务优先级不能太低,由于系统的任务优先级是从3开始,前面的任务用于系统任务计数和系统定时器。建议任务定义优先级为4-5,可视实际情况而定。由于emwin相对ucgui所需内存要大,所以需要保证有足够的ram空间运行emwin,则必须加入外部sram,建议给emwin分配ram为2M,就这样,系统就能够跑emwin了
如有问题可加QQ875213753联系,谢谢
**