STM32F103移植FreeRTOS工程(HAL库)

一、下载FreeRTOS源码

上一篇文章介绍了通过修改FreeRTOS官方例程,制作自己的FreeRTOS工程模板的方法

移植FreeRTOS工程(标准库)-优快云博客文章浏览阅读446次,点赞9次,收藏14次。裁剪FreeRTOS官方示例工程(v2022.12.01),制作自己的FreeRTOS工程模板,更新其中的库函数 https://blog.youkuaiyun.com/weixin_69034136/article/details/146118975?fromshare=blogdetail&sharetype=blogdetail&sharerId=146118975&sharerefer=PC&sharesource=weixin_69034136&sharefrom=from_link这篇文章介绍另一种方法,不修改官方示例工程,直接将FreeRTOS源码移植到自己的工程中,以下面这个OLED工程为例

【免费】江协科技0.96寸OLED驱动函数(HAL库移植)_stm32串口调试助手资源-优快云文库https://download.youkuaiyun.com/download/weixin_69034136/89945311?spm=1001.2014.3001.5503还是先下载FreeRTOS官方源码(v202212.01)https://github.com/FreeRTOS/FreeRTOS/releases/download/202212.01/FreeRTOSv202212.01.zip

二、移植FreeRTOS源码到自己的工程

在自己的工程文件夹中新建一个FreeRTOS文件夹,将官方源码中的FreeRTOS\Source目录复制到这个文件夹中,把官方源码中的FreeRTOS\Demo\CORTEX_STM32F103_Keil目录下的FreeRTOSConfig.h文件复制到FreeRTOS\Source\include目录下

进入Keil工程,新建一个FreeRTOS组,把FreeRTOS\Source目录下的list.c、queue.c、 tasks.c、把FreeRTOS\Source\portable\RVDS\ARM_CM3目录下的port.c、把FreeRTOS\Source\portable\MemMang目录下的heap_4.c添加到FreeRTOS组中

添加头文件路径FreeRTOS\Source\include

FreeRTOS\Source\portable\RVDS\ARM_CM3

在工程中添加LED.c、LED.h文件,用于测试

LED.c文件内容如下:

#include "stm32f1xx_hal.h"

#define LED_PORTA_Pin	(GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4)

/* LED点亮方式 0表示低电平点亮,1表示高电平点亮 */
#define LED_Light_Mode	0

void LED_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure = {0};
	
	__HAL_RCC_GPIOA_CLK_ENABLE();
	
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStructure.Pin = LED_PORTA_Pin;
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	HAL_GPIO_WritePin(GPIOA, LED_PORTA_Pin,(GPIO_PinState)(!LED_Light_Mode));
}

void LED_ON(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
	HAL_GPIO_WritePin(GPIOx, GPIO_Pin,(GPIO_PinState)(LED_Light_Mode));
}

void LED_OFF(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
	HAL_GPIO_WritePin(GPIOx, GPIO_Pin,(GPIO_PinState)(!LED_Light_Mode));
}

void LED_Turn(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
	HAL_GPIO_WritePin(GPIOx, GPIO_Pin,(GPIO_PinState)(!(HAL_GPIO_ReadPin(GPIOx, GPIO_Pin))));
}

LED.h文件内容如下:

#ifndef __LED_H
#define __LED_H

void LED_Init(void);
void LED_ON(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void LED_OFF(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void LED_Turn(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

#endif

进入tasks.c文件,在第1959行处,右键跳转到configSUPPORT_STATIC_ALLOCATION定义处,

把configSUPPORT_STATIC_ALLOCATION这个宏的值从0改为1

进入STM32CubeMx,把HAL库的时基源从Systick改为其他的定时器

因为FreeRTOS也使用Systick作为时基,防止冲突,所以修改HAL库的时基源

配置USART1

配置PA1、PA2、PA3,配置为通用推挽输出模式,初始电平为高电平

进入stm32f1xx_it.c文件,定义这三个宏

进入FreeRTOS.h文件,进入FreeRTOSConfig.h文件,在这个文件中定义这三个宏

 在FreeRTOS中,SysTick_Handler(),PendSV_Handler()与 SVC_Handler()这三个很重要的函数都帮我们实现了,分别叫xPortPendSVHandler()、xPortSysTick_Handler()、 vPortSVCHandler()。在FreeRTOS官方例程的启动文件中,xPortPendSVHandler、xPortSysTick_Handler与 vPortSVCHandler直接取代了SysTick_Handler,PendSV_Handler与 SVC_Handler。也就是FreeRTOS源码中的启动文件是在原版的基础上经过了一定的修改,为了尽可能不去修改启动文件,所以我们通过宏定义来互换这些函数的名称,也能实现相同的效果

三、测试

创建五个任务,任务一到任务三实现LED闪烁,任务四和任务五使用一个函数,分别打印4和5

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "OLED.h"
#include "LED.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
const char  task4 = 0;
const char  task5 = 1;
TaskHandle_t task2_handle;

void Task1(void *param)
{
	
	while(1)
	{
		LED_Turn(GPIOA,GPIO_PIN_1);
		vTaskDelay(100);
	}
}

void Task2(void *param)
{
	
	while(1)
	{
		LED_Turn(GPIOA,GPIO_PIN_2);
		vTaskDelay(200);
	}
}

void Task3(void *param)
{
	
	while(1)
	{
		LED_Turn(GPIOA,GPIO_PIN_3);
		vTaskDelay(300);
	}
}

void Task4(void *param)
{
	
	while(1)
	{
		if ((int)param == 0)
		{
			printf("4");
			vTaskDelay(1);
		}
		if ((int)param == 1)
		{
			printf("5");
			vTaskDelay(1);
		}		
	}
}

StaticTask_t ppxIdleTaskTCB;
StackType_t ppxIdleTaskStack[100];

void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
    *ppxIdleTaskTCBBuffer = &ppxIdleTaskTCB;
	*ppxIdleTaskStackBuffer = ppxIdleTaskStack;
	*pulIdleTaskStackSize = 100;
}
/* 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();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  OLED_Init();
  
  xTaskCreate(Task1,"Task1",100,NULL,1,NULL);
  xTaskCreate(Task2,"Task2",100,NULL,1,&task2_handle);	
  xTaskCreate(Task3,"Task3",100,NULL,1,NULL);
  xTaskCreate(Task4,"Task4",100,(void *)task4,1,NULL);
  xTaskCreate(Task4,"Task5",100,(void *)task5,1,NULL);

  vTaskStartScheduler();
	
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  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_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

int fputc(int ch, FILE * f)
{
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,1000);
	return ch;
}

/* USER CODE END 4 */

/**
  * @brief  Period elapsed callback in non blocking mode
  * @note   This function is called  when TIM1 interrupt took place, inside
  * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
  * a global variable "uwTick" used as application time base.
  * @param  htim : TIM handle
  * @retval None
  */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM1) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */

  /* USER CODE END Callback 1 */
}

/**
  * @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 */

 编译后将其下载到开发板上,现象如下:

video_20250308_164905

下载地址:

【免费】FreeRTOS-STM32F103C8-HAL.zip资源-优快云文库https://download.youkuaiyun.com/download/weixin_69034136/90472178

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值