承接这篇文章,本篇讲述如何把FreeRTOS移植到启明欣欣STM32开发板里,比较简单,网上也有各种教程,本文也是参考其它文章,这里再记录一下。
一 搭建基础工程
启明欣欣STM32开发板上的MCU是STM32F407ZGT6,根据这个创建Keil工程,直接参照之前文章中那个点亮LED的工程也可以,工程创建出来保证可以读写GPIO就行了,这里不再赘述。
本人使用Keil 5.35,使用软件自带CMSIS 5.5.0,编译器版本使用版本5,
二 下载FreeRTOS
点击https://www.freertos.org/进入FreeRTOS官网,点击下载,
在新的页面里继续点击下载,如下图,当前最新版本是202212.00
下载下来之后解压如下,
内核代码位于FreeRTOS/Source,如下,
三 移植
在Keil工程目录下创建文件夹freertos_src,
然后把FreeRTOS的内核代码拷贝到freertos_src里,即FreeRTOS/Source/里的代码,如下图,
打开Keil工程,点击“Manage Project Items”按钮,
弹出的界面如下,在Groups栏下添加新的group — freertos_src
然后点击这个新的group,在Files栏下点击“Add Files…”
然后把以下点c文件添加进来,
接着把port.c添加进来,位于freertos_src/portable/RVDS/ARM_CM4F/
最后把heap_4.c添加进来,位于freertos_src/portable/MemMang/
此时工程如下,
然后点击OK,工程结构如下,
后面会遇到编译问题,参考这篇文章,可以解决,非常简单。
本文与这篇参考文章的区别是CMSIS的使用,本文使用Keil自带的,该文使用的是外部CMSIS库,都可以。相对来说,本文的更简洁一点,但要注意CMSIS的兼容性。使用外部CMSIS库可以让整个工程更加独立,其它Keil版本都可以编译。
四 测试
工程中的main.c如下,
#include "stm32f4xx.h"
#include "stm32f4xx_hal_gpio.h"
#include "stm32f4xx_hal_rcc_ex.h"
#include "FreeRTOS.h"
#include "task.h"
void LED_Init()
{
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_3 | GPIO_PIN_4;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStructure.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_9;
HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3 | GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_9, GPIO_PIN_RESET);
}
void task_blink_led0(void * arg)
{
while(1)
{
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_9);
vTaskDelay(500); //延时500ms
}
}
void task_blink_led2(void * arg)
{
while(1)
{
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_3);
vTaskDelay(1000); //延时1000ms
}
}
int main(void)
{
LED_Init();
TaskHandle_t StartTask_Handler;
//创建开始任务
xTaskCreate((TaskFunction_t )task_blink_led0, //任务函数
(const char* )"task_blink_led0", //任务名称
(uint16_t )128, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )1, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
TaskHandle_t StartTask_Handler2;
//创建开始任务
xTaskCreate((TaskFunction_t )task_blink_led2, //任务函数
(const char* )"task_blink_led2", //任务名称
(uint16_t )128, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )1, //任务优先级
(TaskHandle_t* )&StartTask_Handler2); //任务句柄
//开启任务调度
vTaskStartScheduler();
}
编译完成后下载到板子上,可以发现2个led以不同频率闪烁。