这里使用的是 f407
1. 先用STM32CubeMX 建立一个可以运行的stm32项目,toolchain选择 SW4STM32
2. 官网下载源码
www.freertos.org
我这里下载的是FreeRTOSv202112.00.zip
解压缩后得到
需要以下几个文件夹或档案
FreeRTOS/Source下的所有的 .c 档案
FreeRTOS/Source/include
FreeRTOS/Source/portable/GCC/ARM_CM4F
FreeRTOS/Source/portable/MemMang里面的heap_4.c ( 可以参考
FreeRTOS基础二:堆内存管理之heap_4方案_哈士奇上蔚的博客-CSDN博客)
3.. 将 FreeRTOS/Demo/CORTEX_M4F_STM32F407ZG-SK里的FreeRTOSConfig.h拷贝到 FreeRTOS/Source/include 下面
全部需要的档案如下
把FreeRTOS的文件夹放到项目的根目录
4. 修改 FreeRTOSConfig.h
将45行的
#ifdef __ICCARM__
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
修改为
#if defined (__ICCARM__) || defined (__CC_ARM) || defined (__GNUC__)
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
或是直接去掉 #ifdef __ICCARM__的判断
将51行的configUSE_IDLE_HOOK 改为0
将52行的configUSE_TICK_HOOK改为0
将64行的configCHECK_FOR_STACK_OVERFLOW改为0
将66行的configUSE_MALLOC_FAILED_HOOK改为0
5. 修改cmake
在cmake里启用硬件浮点运算单元 FPU
#Uncomment for hardware floating point
add_compile_definitions(ARM_MATH_CM4;ARM_MATH_MATRIX_CHECK;ARM_MATH_ROUNDING)
add_compile_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
add_link_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
cmake里添加include path
FreeRTOS/Source/include
FreeRTOS/Source/portable/GCC/ARM_CM4F
cmake里添加
file(GLOB_RECURSE SOURCES "FreeRTOS/*.*")
6. 将 stm32f4xx_it.c 里的
SVC_Handler
PendSV_Handler
SysTick_Handler
三个方法前面都加上__weak
因为这三个方法在我们添加的 FreeRTOS/Source/portable/GCC/ARM_CM4F/prot.c文件里有定义,会导致重定义
7. 修改main函数运行
以下是代码。完整项目可以在这里下载,硬石YS-F4Pro (f407)开发板可以直接运行
https://download.csdn.net/download/howard789/87177250
cmake
#THIS FILE IS AUTO GENERATED FROM THE TEMPLATE! DO NOT CHANGE!
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_VERSION 1)
cmake_minimum_required(VERSION 3.23)
# specify cross-compilers and tools
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_AR arm-none-eabi-ar)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
set(SIZE arm-none-eabi-size)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
# project settings
project(freeRTOS_demo C CXX ASM)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 11)
#Uncomment for hardware floating point
add_compile_definitions(ARM_MATH_CM4;ARM_MATH_MATRIX_CHECK;ARM_MATH_ROUNDING)
add_compile_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
add_link_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
#Uncomment for software floating point
#add_compile_options(-mfloat-abi=soft)
add_compile_options(-mcpu=cortex-m4 -mthumb -mthumb-interwork)
add_compile_options(-ffunction-sections -fdata-sections -fno-common -fmessage-length=0)
# uncomment to mitigate c++17 absolute addresses warnings
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-register")
# Enable assembler files preprocessing
add_compile_options($<$<COMPILE_LANGUAGE:ASM>:-x$<SEMICOLON>assembler-with-cpp>)
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
message(STATUS "Maximum optimization for speed")
add_compile_options(-Ofast)
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
message(STATUS "Maximum optimization for speed, debug info included")
add_compile_options(-Ofast -g)
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")
message(STATUS "Maximum optimization for size")
add_compile_options(-Os)
else ()
message(STATUS "Minimal optimization, debug info included")
add_compile_options(-Og -g)
endif ()
include_directories(
FreeRTOS/Source/include
FreeRTOS/Source/portable/GCC/ARM_CM4F
Core/Inc Drivers/STM32F4xx_HAL_Driver/Inc Drivers/STM32F4xx_HAL_Driver/Inc/Legacy Drivers/CMSIS/Device/ST/STM32F4xx/Include Drivers/CMSIS/Include)
add_definitions(-DUSE_HAL_DRIVER -DSTM32F407xx)
file(GLOB_RECURSE SOURCES "startup/*.*" "Drivers/*.*" "Core/*.*" "FreeRTOS/*.*")
set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/STM32F407IGTx_FLASH.ld)
add_link_options(-Wl,-gc-sections,--print-memory-usage,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map)
add_link_options(-mcpu=cortex-m4 -mthumb -mthumb-interwork)
add_link_options(-T ${LINKER_SCRIPT})
add_executable(${PROJECT_NAME}.elf ${SOURCES} ${LINKER_SCRIPT})
set(HEX_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.hex)
set(BIN_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.bin)
add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${PROJECT_NAME}.elf> ${HEX_FILE}
COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${PROJECT_NAME}.elf> ${BIN_FILE}
COMMENT "Building ${HEX_FILE}
Building ${BIN_FILE}")
main
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2022 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "bsp_led.h"
#define USE_FREERTOS //是否使用freeRTOS
//如果要使用freeRTOS需要注意cmake里include要添加
// FreeRTOS/Source/include
//FreeRTOS/Source/portable/GCC/ARM_CM4F
//且GLOB_RECURSE要添加"FreeRTOS/*.*"
//同时以下的这些要取消注释
//add_compile_definitions(ARM_MATH_CM4;ARM_MATH_MATRIX_CHECK;ARM_MATH_ROUNDING)
//add_compile_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
//add_link_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
// 如果不使用freeRTOS,上述的要注释掉
#ifdef USE_FREERTOS
#include "FreeRTOS.h"
#include "task.h"
static TaskHandle_t xHandleTaskLED1 = NULL;
static TaskHandle_t xHandleTaskLED2 = NULL;
static TaskHandle_t xHandleTaskLED3 = NULL;
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
static void vTaskLED1(void *pvParameters);
static void vTaskLED2(void *pvParameters);
static void vTaskLED3(void *pvParameters);
static void AppTaskCreate (void);
void vTaskLED1(void *pvParameters)
{
while(1)
{
LED_StateSet(LED_ID_1,LED_TOGGLE);
vTaskDelay(1000);
}
}
void vTaskLED2(void *pvParameters)
{
while(1)
{
LED_StateSet(LED_ID_2,LED_TOGGLE);
vTaskDelay(2000);
}
}
void vTaskLED3(void *pvParameters)
{
while(1)
{
LED_StateSet(LED_ID_3,LED_TOGGLE);
vTaskDelay(3000);
}
}
void AppTaskCreate (void)
{
xTaskCreate( vTaskLED1, /* 任务函数 */
"vTaskLED1", /* 任务名 */
512, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
1, /* 任务优先级*/
&xHandleTaskLED1 ); /* 任务句柄 */
xTaskCreate( vTaskLED2, /* 任务函数 */
"vTaskLED2", /* 任务名 */
512, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
2, /* 任务优先级*/
&xHandleTaskLED2 ); /* 任务句柄 */
xTaskCreate( vTaskLED3, /* 任务函数 */
"vTaskLED3", /* 任务名 */
512, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
3, /* 任务优先级*/
&xHandleTaskLED3 ); /* 任务句柄 */
}
#endif
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
// 初始化LED
LED_GPIO_Init();
#ifndef USE_FREERTOS
// 没有用freeRTOS的测试方法
LED_GPIO_Test();
#else
// 使用freeRTOS
AppTaskCreate();
/* 启动调度,开始执行任务 */
vTaskStartScheduler();
#endif
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
bsp_led.h
//
// Created by hao on 2022/8/17.
//
#ifndef MY_BASIC_BSP_LED_H
#define MY_BASIC_BSP_LED_H
#include "stm32f4xx_hal.h"
#define LED_1_RCC_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE()
#define LED_1_GPIO_PIN GPIO_PIN_9
#define LED_1_GPIOx GPIOH
#define LED_2_RCC_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define LED_2_GPIO_PIN GPIO_PIN_5
#define LED_2_GPIOx GPIOE
#define LED_3_RCC_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define LED_3_GPIO_PIN GPIO_PIN_6
#define LED_3_GPIOx GPIOE
typedef enum {
LED_ON = 0,
LED_OFF = 1,
LED_TOGGLE = 2,
}LED_State_TypeDef;
typedef enum {
LED_ID_1 = 1,
LED_ID_2 = 2,
LED_ID_3 = 3,
}LED_ID_TypeDef;
#define IS_LED_ID_TYPEDEF(id) (((id) == LED_ID_1) || ((id) == LED_ID_2) || (id) == LED_ID_3))
#define IS_LED_State_TypeDef(state) (((state) == LED_ON) || ((state) == LED_OFF) || ((state) == LED_TOGGLE))
void LED_GPIO_Init();
void LED_StateSet(LED_ID_TypeDef id,LED_State_TypeDef state);
void LED_GPIO_Test();
#endif //USE_LED
bsp_led.c
//
// Created by hao on 2022/8/17.
//
#include "bsp_led.h"
void LED_GPIO_Init(){
/* 定义IO硬件初始化结构体变量 */
GPIO_InitTypeDef GPIO_InitStruct;
LED_1_RCC_CLK_ENABLE();
HAL_GPIO_WritePin(LED_1_GPIOx, LED_1_GPIO_PIN, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = LED_1_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(LED_1_GPIOx, &GPIO_InitStruct);
LED_2_RCC_CLK_ENABLE();
HAL_GPIO_WritePin(LED_2_GPIOx, LED_2_GPIO_PIN, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = LED_2_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(LED_2_GPIOx, &GPIO_InitStruct);
LED_3_RCC_CLK_ENABLE();
HAL_GPIO_WritePin(LED_3_GPIOx, LED_3_GPIO_PIN, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = LED_3_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(LED_3_GPIOx, &GPIO_InitStruct);
}
void LED_StateSet(LED_ID_TypeDef id,LED_State_TypeDef state){
assert_param(IS_LED_ID_TYPEDEF(LEDx));
assert_param(IS_LED_State_TypeDef(LEDx));
switch (state) {
case LED_ON:
switch (id) {
case LED_ID_1:
HAL_GPIO_WritePin(LED_1_GPIOx,LED_1_GPIO_PIN,GPIO_PIN_SET);break;
case LED_ID_2:
HAL_GPIO_WritePin(LED_2_GPIOx,LED_2_GPIO_PIN,GPIO_PIN_SET);break;
case LED_ID_3:
HAL_GPIO_WritePin(LED_3_GPIOx,LED_3_GPIO_PIN,GPIO_PIN_SET);break;
default:
break;
}
break;
case LED_OFF:
switch (id) {
case LED_ID_1:
HAL_GPIO_WritePin(LED_1_GPIOx,LED_1_GPIO_PIN,GPIO_PIN_RESET);
break;
case LED_ID_2:
HAL_GPIO_WritePin(LED_2_GPIOx,LED_2_GPIO_PIN,GPIO_PIN_RESET);
break;
case LED_ID_3:
HAL_GPIO_WritePin(LED_3_GPIOx,LED_3_GPIO_PIN,GPIO_PIN_RESET);
break;
default:
break;
}
break;
case LED_TOGGLE:
switch (id) {
case LED_ID_1:
HAL_GPIO_TogglePin(LED_1_GPIOx,LED_1_GPIO_PIN);
break;
case LED_ID_2:
HAL_GPIO_TogglePin(LED_2_GPIOx,LED_2_GPIO_PIN);
break;
case LED_ID_3:
HAL_GPIO_TogglePin(LED_3_GPIOx,LED_3_GPIO_PIN);
break;
default:
break;
}
break;
default:
break;
}
}
void LED_GPIO_Test(){
int count =0;
while (2){
switch (count%3) {
case 0:
LED_StateSet(LED_ID_1,LED_ON);
LED_StateSet(LED_ID_2,LED_OFF);
LED_StateSet(LED_ID_3,LED_OFF);
break;
case 1:
LED_StateSet(LED_ID_1,LED_OFF);
LED_StateSet(LED_ID_2,LED_ON);
LED_StateSet(LED_ID_3,LED_OFF);
break;
case 2:
LED_StateSet(LED_ID_1,LED_OFF);
LED_StateSet(LED_ID_2,LED_OFF);
LED_StateSet(LED_ID_3,LED_ON);
break;
default:
break;
}
count++;
if(count==1000)count=0;
HAL_Delay(1000);
}
}