STM32上FreeRTOS移植

1 下载源码

直接在官网下载或github下载,这里给出官网链接https://www.freertos.org/zh-cn-cmn-s/index.html

我这里下载的是最新版的。此外,还可以在官网下载参考手册和资料:https://www.freertos.org/zh-cn-cmn-s/FreeRTOS-quick-start-guide.html

下载完成后打开压缩包,内有三个文件夹:

FreeRTOS里是基础的源码和一些例程,FreeRTOS-Plus里是一些增加了其他功能,如TCP等的源码,这里我们只需要用到FreeRTOS里的文件。

在FreeRTOS里有四个文件夹:

对于移植freeRTOS,需要的文件夹只有两个:Source和Demo。Source里当然是最重要的源码;Demo里有各种架构、编译方式下的例程,感兴趣可以打开看看,例如我们的stm32f103:

2 开始移植

2.1 新建KEIL工程

使用模板新建一个keil工程,我这里直接使用的正点原子的模板工程:

2.2 在工程中添加FreeRTOS源码

  1. 1在工程下新建三个文件夹,如下图:

  1. 2将FreeRTOS文件夹下的Source->include文件夹下所有文件复制过来放入新建的include文件夹里;

  1. Source文件夹内的7个.c文件放入src里;

  1. Source->portable->RVDS下的ARM_CM3文件夹复制到port文件夹下。Source->portable下包含各类编译器所需要的port.c文件,这里我们是用keil编译,选择keil文件夹,但是我们通过文件夹里的.txt文件知道,keil环境所需的port.c与RVDS一样,所以进入RVDS文件夹,由于stm32f103采用的是arm cortex-m3所以需要的是ARM_CM3里的文件

  1. Source->portable下的MemMang文件夹复制到port文件夹。MemMang文件夹里的几个.c是几种不同的内存管理方式,感兴趣的uu自己去了解,我们后面只用到heap_4.c一种。

  1. 现在我们还缺一个FreeRTOSConfig.h。这个文件是用来根据我们的平台以及需求对freeRTOS进行配置的。这里我们先使用Demo->CORTEX_STM32F103_KEIL里的FreeRTOSConfig.h,将其复制到项目工程的USER文件夹,后续我们会对它进行修改。

2.3 KEIL里的配置

  1. 打开keil工程文件,左侧AddGroup,新建FreeRTOS/src和FreeRTOS/port两个文件夹。将以下文件分别加入项目工程中的FreeRTOS/src、FreeRTOS/port、USER:

  1. 添加头文件路径:点击魔术棒按钮,选择C/C++,点击include path后的三个点:

增加刚刚有头文件的两个路径:include和port\ARM_CM3

这样工程的内容就算配置好了

2.4 修改代码内容

  1. 修改FreeRTOSConfig.h

关于FreeRTOSConfig.h这个文件每个宏定义的具体意义大家可以参考https://www.freertos.org/zh-cn-cmn-s/a00110.html#configUSE_STATS_FORMATTING_FUNCTIONS,我这里就不具体讲解了。

我们现在只需要在demo的基础上在FreeRTOSConfig.h里增加以下代码:

#define xPortPendSVHandler    PendSV_Handler
#define vPortSVCHandler    SVC_Handler
#define xPortSysTickHandler    SysTick_Handler
  1. 修改stm32f10x_it.c

由于我们在freeRTOS中已经实现了PendSV_Handler、SVX_handler、SysTick_Handler,那我们现在就需要把stm32f10x_it.c里原来的这几个函数注释掉。注释完大家可以尝试编译一下,应该到现在是可以编译通过了的。

3 测试

目前为止我们就成功移植了FreeRTOS啦!是不是还挺简单!

那现在就写一个程序来测试一下吧!

下面是我的测试程序大家可以参考:

/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"
#include "led.h"

static void AppTaskCreate(void);/* AppTask任务 */

 /* 创建任务句柄 */
static TaskHandle_t AppTask_Handle1 = NULL;
static TaskHandle_t AppTask_Handle2 = NULL;
static void AppTask1(void* parameter)
{    
    while (1)
    {
        LED0=!LED0;
        vTaskDelay(500);   /* 延时500个tick */             
    }
}
static void AppTask2(void* parameter)
{    
    while (1)
    {
        LED1=!LED1;
        vTaskDelay(1000);   /* 延时500个tick */                 
    }
}
int main(void)
{    
  BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */

  /* 开发板硬件初始化 */
  LED_Init();
   /* 创建AppTaskCreate任务 */
  xReturn = xTaskCreate((TaskFunction_t )AppTask1,  /* 任务入口函数 */
                        (const char*    )"AppTask1",/* 任务名字 */
                        (uint16_t       )512,  /* 任务栈大小 */
                        (void*          )NULL,/* 任务入口函数参数 */
                        (UBaseType_t    )1, /* 任务的优先级 */
                        (TaskHandle_t*  )&AppTask_Handle1);/* 任务控制块指针 */ 

  xReturn = xTaskCreate((TaskFunction_t )AppTask2,  /* 任务入口函数 */
                        (const char*    )"AppTask2",/* 任务名字 */
                        (uint16_t       )512,  /* 任务栈大小 */
                        (void*          )NULL,/* 任务入口函数参数 */
                        (UBaseType_t    )1, /* 任务的优先级 */
                        (TaskHandle_t*  )&AppTask_Handle2);/* 任务控制块指针 */ 
  /* 启动任务调度 */           
  if(pdPASS == xReturn)
    vTaskStartScheduler();   /* 启动任务,开启调度 */
  else
    return -1;  
  
  while(1);   /* 正常不会执行到这里 */    
}

注意哦,这里我们的AppTask1和AppTask2里面都是死循环,然而两个任务都可以执行,看起来好像是“并发”的一样,这就是我们操作系统在成功切换调度任务啦!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值