前言:本篇文章,不是教你怎么学,只是教你怎么用。掌握好技巧,无论是什么操作系统的移植,FAT文件系统,STEWIN界面系统等的移植,都会从一个复杂的问题变成一个简单的问题。傻瓜式教程,一点都不为过。
操作系统的相关知识已经在 小白 30 分钟学会移植操作系统 - UCOS 系列一 中简述了。这一篇,便不会再讲解理论知识了。
在这一篇中,我并不想教大家学习操作系统的具体知识,毕竟,学习靠的是自己的努力与感悟。但是,我可以引导大家如何掌握一项新的东西的能力。
在下面的具体实践中,事先做好准备。正所谓:工欲善其事,必先利其器。善用工具,对于解决问题是可以事半功倍的。
STM32平台:STM32F429
文本对比软件:UltarCompare | Beyong Compare 4 | 免费的 diff
官方 uCOS-III 源码:可从 ucos 官网下载。( http://micrium.com/),也可以直接网盘链接获取。
链接:https://pan.baidu.com/s/1eVG8nPObCa2Ps1Kqs2mqlg
提取码:9ef3
STM32裸机程序:下面的操作系统是基于裸机程序进行移植的。
链接:https://pan.baidu.com/s/1oVILd3z-e4cx3XEThtxjVA
提取码:xbae
UCOS工程模板:
链接:https://pan.baidu.com/s/12zlCkcihtHRTGsf5HCHU5Q
提取码:1rem
UCOS单任务与多任务例程:
链接:https://pan.baidu.com/s/1BsYNsvTgl4OxvwyvbeBoyQ
提取码:75fj
裸机工程模板框架:
操作系统工程模板框架:
自己根据官网下载的源码亦步亦趋地根据系统工程模板移植,这里不多做讲解。
移植操作系统后,工程模板多了好几个文件夹,那里面就是移植了操作系统的相关文件。具体的,可以下载上面的网盘中的源码来对比下,到底多了什么文件。这里就不具体说了。
在相同的文件夹中,只有 USER 和 CMSIS 文件夹中的内容稍有变化。其中主要以 CMSIS 文件夹中的启动文件的进行修改。而 USER 文件夹则去掉不需要的文件。具体的对比两个工程的文件即可。
这里稍微讲解一下裸机与操作系统的启动文件之间的区别:
这时候,文本对比软件的作用就凸显出来了。
左边是裸机的启动程序,右边是系统工程的启动文件。
左边显示红色的地方,说明了此处的内容不相同。也就是修改过的地方。
点击一下第一条红色的地方,则会自动跳转。
第二条:
第三条:
至于为什么这么改,暂时没必要去纠结。只需要知道这样做即可。没必要死磕。[ 不得不说,善于借助工具去解决问题,看似复杂的事情,其实一点都不复杂。简单得一匹]。
至此,移植操作系统的任务完成了。那么该如何使用操作系统实现对应的功能呢。在上面的移植过程中,主要是裸机程序、操作系统工程模板与官网下载的源码文件之间的匹配。
而在操作系统的应用中,则主要是 操作系统工程模板与操作系统单任务、多任务文件之间的匹配。
匹配原则是:相同的保留,不同的复制粘贴修改,傻瓜式操作。
操作系统工程模板框架:
操作系统单任务框架:
它们之间的框架是一样的。而它们之间的不同只在于 APP/app.c 和 APP/app_cfg.h 文件 与 BSP(可以理解成板级支持包,里面就是各种功能模块,在裸机上就是 LED 、按键 、串口等功能模块)。所以说,操作系统的系统,只需学会如何操作这几个文件即可。操作系统的应用真没想象中的那么难,跟玩裸机差不多。而很多人觉得难,也许就是有很多人说RTOS的学习很难,这就导致学习的人一听到RTOS编程就在心理面忌惮三分,结果就是出师未捷身先死。
匹配 APP/app.c 文件:
在声明中多了
TCB :任务控制块
STACKS : 堆栈分配,也就是变量等的内存分配
FUNCTION PROTOTYPES :函数优先级,可以说是任务的优先级
main 函数之间的区别:
具体任务的实现:
主要看光标高亮处的 while 语句。而main中只是设置任务块的各种各种的参数[比如 任务切换,时间片等]。
匹配 APP/app_cfg.h 文件:
看到cfg,不用说肯定是配置文件了。而在上文中,也就涉及了 STACKS、 FUNCTION PROTOTYPES。故在app_cfg.h中,肯定 就是有关的设置。
操作系统的移植,仅仅需要处理好这两个文件的编写即可。真的不难。记得,是真的不难。
温馨提示:我写了那么多,也不见得有什么用。如果真想学,自己去操作一遍,胜于别人给你说一万遍。
单任务与多任务之间的区别,留给想学的你们自己去比较,发现,总结,移植。
有关操作系统随笔:
任务的定义与任务切换的实现
什么是任务
任务形式
void Task (void *parg)
创建任务
在多任务系统中,每个任务都是独立的,互不干扰的,所以要为每个任务都分配独立的栈空间,这个栈空间通常是一个预先定义好的全局数组。
定义任务堆栈
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
1 #define TASK1_STK_SIZE 128 (1)
2 #define TASK2_STK_SIZE 128
4 static CPU_STK Task1Stk[TASK1_STK_SIZE]; (2)
5 static CPU_STK Task2Stk[TASK2_STK_SIZE];
定义任务函数
/* flag 必须定义成全局变量才能添加到逻辑分析仪里面观察波形
** 在逻辑分析仪中要设置以 bit 的模式才能看到波形,不能用默认的模拟
*/
uint32_t flag1; (1)
uint32_t flag2;
/* 任务1 */
void Task1( void *p_arg ) (2)
{
for ( ;; ) {
flag1 = 1;
delay( 100 );
flag1 = 0;
delay( 100 );
}
}
/* 任务2 */
void Task2( void *p_arg ) (3)
{
for ( ;; ) {
flag2 = 1;
delay( 100 );
flag2 = 0;
delay( 100 ); 27 }
}
定义任务控制块TCB
在多任务系统中,任务的执行是由系统调度的。系统为了顺利的调度任务,为每个任务都额外定义了一个任务控制块TCB(Task Control Block),这个任务控制块就相当于任务的身份证,里面存有任务的所有信息,比如任务的堆栈,任务名称,任务的形参等。有了这个任务控制块之后,以后系统对任务的全部操作都可以通过这个TCB来实现。
/* 任务控制块重定义 */
typedef struct os_tcb OS_TCB; (1)
/* 任务控制块 数据类型声明 */
struct os_tcb { (2)
CPU_STK *StkPtr;
CPU_STK_SIZE StkSize;
};
static OS_TCB Task1TCB;
static OS_TCB Task2TCB;
实现任务创建函数
void OSTaskCreate ()
任务初始化函数
OSTaskStkInit()
奋斗的小青年,终生学习者
有趣的灵魂终会遇见。
扫码订阅给我【在看】
你也越好看!