μCOS-III系统移植--STM32F1为例
μCOS-III系统移植--STM32F1为例
- 1.1 获取μC/OS源码
- 1.2 建立裸机工程(库函数版)
- 1.3 在裸机工程文件里建立μC/OS文件夹
- 1.4 在裸机工程里面添加工程组及相应的文件
- 1.5 对部分文件进行修改
- a、修改 os_cpu_a.s 或者 startup_stm32f10x_hd.s 文件
- b、修改 stm32f10x_it.c 和 stm32f10x_it.h文件
- c、修改bsp.c 和 bsp.h 文件
- d、修改 includes.h 文件
- e、修改 lib_cfg.h 文件
- 1.6 写一个简单的DEMO进行编译测试
1.1 获取μC/OS源码
进入 Micrium 公司官网下载中心:http://micrium.com/downloadcenter/
选择对应的(相近的)MCU型号;比如我需要移植μC/OS-III到STM32F103C8T6,那么我就去下载STM32F107对应的源代码。见下图:

注:在 Micrium 官网下载需要账号登陆,并且下载速度很慢,所以可以到处找找资源。
1.2 建立裸机工程(库函数版)
在 ST 官网(https://www.st.com/content/st_com/en.html)下载对应MCU的标准函数库。
因为它也需要注册登陆等等,所以这里直接贴上下载地址:
标准库:https://www.st.com/en/embedded-software/stm32-standard-peripheral-libraries.html
HAL库:https://www.st.com/en/embedded-software/stm32cube-mcu-mpu-packages.html
建立如下工程目录:

CORE目录下:存放的是一些有关该CPU的内核文件和启动文件。F1系列就是core_cm3.c、core_cm3.h、startup_stmewf10x_hd.s。(.s启动文件需要结合自己的硬件进行容量选择; 再F4系列里面不在有core_cm4.c文件,但还是会有一些内核相关文件)
FWLib目录下:就是存放该工程的标准函数库包了。直接复制 STM32F10x_FWLib 里面的文件到相关目录即可。
HARDWARE目录下:存放一些自己写的硬件模块文件。比如led.c、led.h、oled.c、oled.h……
SYSTEM目录下:存放一些有关系统方面的文件。具体的可以查看正点原子的《STM32F4开发指南–库函数版本》里面的第五章。
USER目录下:main.c 、stm32f10x.h、stm32f10x_conf.h、stm32f10x_it.h、stm32f10x_it.h、system_stm32f10x.c、system_stm32f10x.h
注:一般我们还会建立OBJ文件夹没用来存储工程编译的输出文件。有些还有建立专门的DOC文件夹用来说明工程相关内容。
目录建好以后就需要建立工程了,在工程里面建立相应的工作组,添加相应的文件以及头文件地址等等。具体的步骤再仔细查阅相关资料。建好后如下图:

1.3 在裸机工程文件里建立μC/OS文件夹
在裸机工程文件下面建立UCOSIII文件夹,并新建如下目录:

将下载好的源码解压后会在Software文件下面发现四个文件夹:

EvalBoards:评估(开发)板相关文件;主要是配置底层和系统,我们会提取部分有效文件。
uC-CPU:CPU相关文件;我们使用ST标准外设库配置一些模块,不更改该文件夹下文件。
uC-LIB:这个是Micrium官方的库,初学者这里也不更改。
uCOS-III:这个文件夹才是关键,我们移植的内容基本上就是这里的文件。
所以我们一次来看看我们新建文件下面具体都存放了些什么文件:
uC_CPU:就是我们解压后的 μC_CPU 文件夹,我们直接将里面所有的内容复制过去就可以了。
uC_LIB:这个文件夹和上面的一样,直接复制解压后的 μC_LIB 文件夹里面的内容即可。
UCOS_BSP:这个文件夹就不同了,这个文件夹我峨嵋你只需要存放 bsp.c 和 bsp.h 两个文件夹即可。这两个文件在 \Software\EvalBoards\Micrium\uC-Eval-STM32F107\BSP 目录下面。
uCOS_CONFIG:存放一些配置文件,复制 \Software\EvalBoards\Micrium\uC- Eval-STM32F107\uCOS-III 目录下的这些文件。不要 app.c 是因为这个文件就类似于 我们裸机工程里面的 main.c 文件,在新的工程中,我们仍然使用 main.c 作为主题程序的接入口;至于 stm32f10x_conf.h 我们之前在裸机工程里面就有 所以这里就不用了。如下图:

注:app.c 我们使用 main.c 代替后,也可以不要 app_cfg.h 文件的。这是一个对所有 APP(任务)进行配置的文件,可以保留在需要的时候进行修改引用。
uCOS-III:直接复制解压后的 μCOS-III 文件夹内容即可。
注:取名字的时候不要使用中文 和特殊字符,比如 μ 就不要用,最好用 u 代替。因为MDK不能正确识别。如果修改了文件夹名,那么该文件夹下的所有文件都需要重新加载。
总结:我们自己建立了 5 个文件夹,其中有 3个(μC_CPU、μC_LIB、μCOS-III)文件夹是直接复制的原来的解压后的文件,而其余 两个 (UCOS_BSP、UCOS_CONFIG)文件里面的内容都是从 \Software\EvalBoards\Micrium\uC-Eval-STM32F107 的两个文件夹中进行提取的。
1.4 在裸机工程里面添加工程组及相应的文件
在裸机工程里面添加如下的工程组:

在UCOSIII_CONFIG 工程组下面添加 工程文件夹 \UCOSIII\UCOS_CONFIG 文件夹下面的文件,如图:

同理,工程组UCOSIII_BSP、UCOSIII_CPU、UCOSIII_LIB 分别对应工程文件夹下面的\UCOSIII\UCOS_BSP、\UCOSIII\uC-CPU、\UCOSIII\uC-LIB 并分别添加对应的文件。具体分别见下图:



最后的两个工程组分别对应 工程文件夹 \UCOSIII\uCOS-III 下面的 PORT 和 CORE 文件夹,并添加如下图内容:


注:如果在对应的文件下面没有找到所需的文件,那就在该文件夹下面的子文件夹里面去寻找,根据不同的平台,选择对应的文件。比如我们使用的是KEIL,那么,对应的文件就在 RealView 文件夹下面。
注:对于一些 .h 头文件是否要直接添加的在对应工程组的问题,这里我们没有去深究。只是简单的理解为,如果在工程组里面添加了 .h 文件 那么这个 .h 文件就会直接显示在工程组下面的文件按列表中,而不是隐藏在 .c 文件下面。我常用的做法是,如果这个 .h 文件有对应的(同名的) .c 文件 那么就不直接添加在工程组中,其它时候则相反。
注:使用系统时,还需要在SYSTEM工作组中添加delay.c、sys.c、usart.c文件,这几个文件中delay.c文件是必须的,而其余文件则根据使用要求进行选择,一般都是需要的。
1.5 对部分文件进行修改
a、修改 os_cpu_a.s 或者 startup_stm32f10x_hd.s 文件
注:这两个文件直选哟修改其中一个即可,建议修改 os_cpu_a.s。
os_cpu_a.s文件:它和 startup_stm32f10x_hd.s 都应该属于启动文件,只需要将它们关联起来 即可。修改如下图所示的地方:

注:使用 “;” 注释掉第 41行,添加第42行。

注释掉第 139行,添加第 140行;注释掉第 143行,添加第 144行。

注释掉第 154行,添加第 155行。
或者修改startup_stm32f10x_hd.s文件:
修改如下图所示部分即可:

注:如果不清楚可以查看 《野火]uCOS-III内核实现与应用开发实战指南——基于STM32》第256页的内容。
b、修改 stm32f10x_it.c 和 stm32f10x_it.h文件
stm32f10x_it.c文件:这是一个中断相关函数的文件,如果在其他地方没有定义有关的中断函数声明,那么中断函数默认的入口函数就在这里。因为它们上面修改了启动文件,并且在使用系统的时候,不能出现重复定义,所以这里我们也需要去注释掉 两个 相关的函数。如下图:

同样的,stm32f10x_it.h文件也熬做出相应的修改:

c、修改bsp.c 和 bsp.h 文件
bsp.c文件:bsp 就是板级相关的文件,也就是对应开发板的文件,而 μC/OS-III 源码的 bsp 肯定是 与我们的板子不一样,所以就需要进行修改,而且以后我们的板级外设都在 bsp.c 文件进行初始化。
在不考虑板级相关的情况下,bsp.c文件只需要保留与 时间戳相关的 3个 函数 以及一些与之相关的预定义即可。详细情况如下图:






只需要上面部分的内容即可,其余部分均可删除或者注释掉。
bsp.h文件:也只需要保留它最基本的内容即可。如下图:




注:这一部分原来是 stm32f10x_lib.h 后来者部分改成了stm32f10x_conf.h

d、修改 includes.h 文件
includes.h文件:这个是系统相关的头文件,有点类似于 stm32f10x.h 文件。这个主要还是修改之前的一个问题,就是将 stm32f10x_lib.h 修改为 stm32f10x_conf.h 如下图所示:

e、修改 lib_cfg.h 文件
lib_cfg.h文件:中有这样一个定义:

表示把堆的空间设置为27KB,但是我使用的stm32f103c8t6的RAM总共才20K。所以我们需要修改它为合适的值,一般我们改为如下:

这一部分需要在使用内存管理 lib_mem.c 时才会被使用到,如果不使用也可以不管,不过还是建议先改一下。
到上面 移植算是结束了。
1.6 写一个简单的DEMO进行编译测试
//μCOS 系统使用
#include "misc.h"
#include "includes.h" //SYSTEM 使用
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include //功能模块
#include "led.h"//其它
#include //任务初始化控制块
OS_TCB app_task_tcb_init;
void app_task_init(void *parg);
CPU_STK app_task_stk_init[512]; //任务堆栈,大小为512字,也就是2048字节 2K//任务串口控制块
OS_TCB app_task_tcb_usart;
void app_task_usart(void *parg);
CPU_STK app_task_stk_usart[512]; //任务堆栈,大小为512字,也就是2048字节 2K//任务led控制块
OS_TCB app_task_tcb_led;
void app_task_led(void *parg);
CPU_STK app_task_stk_led[512]; //任务堆栈,大小为512字,也就是2048字节 2KOS_MUTEX g_mutex_printf; //互斥量的对象 //用户对串口发送的数据进行完整性的保护
//如果不使能串口接收,那么下面的就不需要
OS_Q g_queue_usart1; //消息队列的对象 //用于处理串口接收到消息//调试用代码 = 1 就开启调试
#define DEBUG_PRINTF_EN 1
void dgb_printf_safe(const char *format, ...)
{
#if DEBUG_PRINTF_EN OS_ERR err;va_list args;va_start(args, format);OSMutexPend(&g_mutex_printf,0,OS_OPT_PEND_BLOCKING,NULL,&err); vprintf(format, args);OSMutexPost(&g_mutex_printf,OS_OPT_POST_NONE,&err);va_end(args);
#else(void)0;
#endif
}int main ( void )
{ OS_ERR err;systick_init();NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组配置usart_init(115200);OSInit(&err);//创建任务OSTaskCreate( &app_task_tcb_init, //任务控制块,等同于线程id"app_task_init", //任务的名字,名字可以自定义的app_task_init, //任务函数,等同于线程函数0, //传递参数,等同于线程的传递参数7, //任务的优先级6 app_task_stk_init, //任务堆栈基地址512/10, //任务堆栈深度限位,用到这个位置,任务不能再继续使用512, //任务堆栈大小 0, //禁止任务消息队列0, //默认是抢占式内核 0, //不需要补充用户存储区OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR, //开启堆栈检测与清空任务堆栈&err //返回的错误码); OSStart(&err);printf("never run.......\r\n"); //启动OSStart之后 这一句永远不会执行while(1);
}void app_task_init(void *parg)
{OS_ERR err;dgb_printf_safe("task init is create ok\r\n");//模块初始化led_init();//创建互斥量OSMutexCreate(&g_mutex_printf, "g_mutex_printf", &err); //创建消息队列,用于处理串口1数据OSQCreate(&g_queue_usart1, "g_queue_usart1", 16, &err); //创建任务1OSTaskCreate( (OS_TCB *)&app_task_tcb_usart, //任务控制块,等同于线程id(CPU_CHAR *)"app_task_usart", //任务的名字,名字可以自定义的(OS_TASK_PTR)app_task_usart, //任务函数,等同于线程函数(void *)0, //传递参数,等同于线程的传递参数(OS_PRIO)6, //任务的优先级6 前面的0123都被系统使用了(CPU_STK *)app_task_stk_usart, //任务堆栈基地址(CPU_STK_SIZE)512/10, //任务堆栈深度限位,用到这个位置,任务不能再继续使用 %10的空间给任务堆栈检测函数使用,任务实用为%90(CPU_STK_SIZE)512, //任务堆栈大小 (OS_MSG_QTY)0, //禁止任务消息队列(OS_TICK)0, //默认时间片长度 (void *)0, //不需要补充用户存储区(OS_OPT)OS_OPT_TASK_NONE, //没有任何选项&err //返回的错误码);//创建任务2OSTaskCreate( (OS_TCB *)&app_task_tcb_led, //任务控制块(CPU_CHAR *)"app_task_led", //任务的名字(OS_TASK_PTR)app_task_led, //任务函数(void *)0, //传递参数(OS_PRIO)6, //任务的优先级7 (CPU_STK *)app_task_stk_led, //任务堆栈基地址(CPU_STK_SIZE)512/10, //任务堆栈深度限位,用到这个位置,任务不能再继续使用(CPU_STK_SIZE)512, //任务堆栈大小 (OS_MSG_QTY)0, //禁止任务消息队列(OS_TICK)0, //默认时间片长度 (void *)0, //不需要补充用户存储区(OS_OPT)OS_OPT_TASK_NONE, //没有任何选项&err //返回的错误码);//删除自身任务,进入休眠态OSTaskDel(NULL, &err);}void app_task_usart(void *parg)
{OS_ERR err;uint8_t *pmsg=NULL;OS_MSG_SIZE msg_size;uint16_t i;dgb_printf_safe("task1 is create ok\r\n");while(1){//等待消息队列pmsg=OSQPend(&g_queue_usart1, 0, OS_OPT_PEND_BLOCKING, &msg_size, NULL, &err);if(err != OS_ERR_NONE){dgb_printf_safe("[app_task_usart1][OSQPend]Error Code = %d\r\n", err);continue;}//正确接收到消息if(pmsg && msg_size){OSMutexPend(&g_mutex_printf, 0, OS_OPT_PEND_BLOCKING, NULL, &err);for(i=0; i<msg_size; i++){ printf("%c", pmsg[i]);}printf("\n");OSMutexPost(&g_mutex_printf, OS_OPT_POST_NONE, &err);}memset(pmsg, 0, msg_size);}
}void app_task_led(void *parg)
{dgb_printf_safe("task2 is create ok\r\n");while(1){PBout(2) = 1;delay_ms(1000);PBout(2) = 0;delay_ms(1000);}
}
注:关于测试程序,不仅仅需要上面的主程序,还需要对应的 SYSTEM文件夹 对应的3个文件。这里我们就不再一一赘述了。
最后附上工程模板链接:CSDN下载
如果有不对的地方、需要调整的地方或者好的建议,欢迎留言,我看到的话我会及早的处理。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
