μ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文件夹,并新建如下目录:
UCOS文件夹
  将下载好的源码解压后会在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 我们之前在裸机工程里面就有 所以这里就不用了。如下图:
config文件夹
  :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 文件夹下面的文件,如图:
config文件
  同理,工程组UCOSIII_BSP、UCOSIII_CPU、UCOSIII_LIB 分别对应工程文件夹下面的\UCOSIII\UCOS_BSP、\UCOSIII\uC-CPU、\UCOSIII\uC-LIB 并分别添加对应的文件。具体分别见下图:
bsp文件
cpu文件
lib文件
  最后的两个工程组分别对应 工程文件夹 \UCOSIII\uCOS-III 下面的 PORT 和 CORE 文件夹,并添加如下图内容:
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下载


如果有不对的地方、需要调整的地方或者好的建议,欢迎留言,我看到的话我会及早的处理。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部