freertos学习之路7-将freertos移植到STM32f103x

0. 说明与环境

  • 移植的开发板为野火指南者(stm32f103vet6)
  • 采用的是stm32标准库
  • 移植的是freertos的FreeRTOSv202112.00版本

1. 文件目录与工程目录

文件目录

├─Doc 
│ └─Readme.txt 
├─Libraries 
├─Middleware 
│ ├─Freertos_portable 
│ └─Freertos_source ------ // freertos源码
├─project 
└─User 
  ├─exti 
  │ ├─bsp_exti.c 
  │ └─bsp_exti.h 
  ├─FreeRTOSConfig.h 
  ├─key 
  │ ├─bsp_key.c 
  │ └─bsp_key.h 
  ├─Lcd_Driver 
  │ ├─Lcd_Driver.c 
  │ └─Lcd_Driver.h 
  ├─led 
  │ ├─bsp_led.c 
  │ └─bsp_led.h 
  ├─main.c 
  ├─stm32f10x_conf.h 
  ├─stm32f10x_it.c 
  ├─stm32f10x_it.h 
  └─uart 
    ├─bsp_usart.c 
    └─bsp_usart.h 

keil工程目录

freertos学习之路7-将freertos移植到STM32f103x_第1张图片

  • Freertos_source:FreeRTOS 内核的源代码,我们移植 FreeRTOS 的时候就需要这部分源代码
├─.gitmodules 
├─croutine.c 
├─event_groups.c 
├─include 
│ ├─atomic.h 
│ ├─croutine.h 
│ ├─deprecated_definitions.h 
│ ├─event_groups.h 
│ ├─FreeRTOS.h 
│ ├─list.h 
│ ├─message_buffer.h 
│ ├─mpu_prototypes.h 
│ ├─mpu_wrappers.h 
│ ├─portable.h 
│ ├─projdefs.h 
│ ├─queue.h 
│ ├─semphr.h 
│ ├─StackMacros.h 
│ ├─stack_macros.h 
│ ├─stdint.readme 
│ ├─stream_buffer.h 
│ ├─task.h 
│ └─timers.h 
├─list.c 
├─queue.c 
├─stream_buffer.c 
├─tasks.c 
└─timers.c 
  • Freertos_portable:FreeRTOS是软件,我们的开发版是硬件,软硬件必须有桥梁来连接,这些与处理器架构相
    关的代码, 可以称之为 RTOS 硬件接口层
├─Keil 
│ └─See-also-the-RVDS-directory.txt 
├─MemMang 
│ ├─heap_1.c 
│ ├─heap_2.c 
│ ├─heap_3.c 
│ ├─heap_4.c 
│ ├─heap_5.c 
│ └─ReadMe.url 
├─readme.txt 
└─RVDS 
  └─ARM_CM3 
    ├─port.c 
    └─portmacro.h 
  • heap_4.c:heap_4.c 是FreeRTOS中提供的一种内存管理实现,用于动态管理RTOS系统的内存,实现动态任务分配、变量分配等。 该文件的主要内容包括:

    • 实现了多个内存分配、释放函数,包括pvPortMallocvPortFreevPortInitialiseBlocks等。
    • 实现了内存块的管理数据结构,其中包括两个链表,一个链表用于存储已分配内存块,另一个链表用于存储未分配内存块。
    • 实现了内存分配算法,包括首次适配、最小适配等算法。
    • 实现了内存保护机制,通过配置硬件能力,可以使得实时嵌入式系统在申请与释放内存时进行内存边界的检查,预防指针溢出等错误。 总之,heap_4.c 提供了一套相对完整的内存管理实现方案,可以帮助用户方便地管理系统内存,并提供多样化的内存分配算法与保护机制。
  • port.c:FreeRTOS 的 port.c 是一个抽象层代码,用于将 FreeRTOS 内核代码与特定于处理器的代码分离开来,以便在不同的处理器架构上移植 FreeRTOS。 port.c 是 FreeRTOS 移植层的关键部分,它提供了处理器体系结构的抽象接口,包括:

    • 任务上下文切换函数,在任务之间进行上下文切换时调用。
    • 时钟节拍定时器初始化函数,为 FreeRTOS 提供时基。
    • 硬件中断处理函数,在中断处理程序中显示系统状态。
    • 实现系统调用函数,例如 vTaskDelay() 和 vTaskSuspend(),这些函数由核心内存管理代码调用。 port.c 还提供了多个处理器架构的实现,包括包括ARM,AVR32,RX,PowerPC等。用户可以基于这些实现来进行芯片平台移植,就可以在目标硬件平台上使用 FreeRTOS 操作系统。 总之,port.c 为移植 FreeRTOS 提供了一个抽象层,使得 FreeRTOS 可以轻松地移植到不同的处理器平台上。

    由于stm32f103x采用的是Cortex-M3 ,因此我们要移植的是ARM_CM3这个文件夹里面的文件

  • portmacro.hportmacro.h 是 FreeRTOS 移植层中的一个头文件,提供了与处理器架构相关的巨集和函数。主要内容包括:

    • 任务栈大小的定义,根据处理器不同而有所区别。

    • 定义了 FreeRTOS 运行所需的所有基本数据类型和运算符,因为不同处理器架构的基础数据类型和运算符可能存在差异。

    • 实现了 FreeRTOS 中使用的多个原子操作,例如互斥锁、临界区限制和原子操作。

    • 定义了挂起和恢复中断的宏,可以确保临界区代码的正确性。

    • 预定义了内核如何处理中断的方式。

2. main.c代码

#include "FreeRTOS.h"
#include "task.h"
#include "bsp_usart.h"
#include "bsp_exti.h"
#include "bsp_led.h"

static TaskHandle_t AppTaskCreate_Handle = NULL;
static TaskHandle_t LED1_Task_Handle = NULL;
static TaskHandle_t LED2_Task_Handle = NULL;

static void AppTaskCreate(void);
static void LED1_Task(void* pvParameters);
static void LED2_Task(void* pvParameters);
static void BSP_Init(void);




int main(void)
{
	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
	BSP_Init();
	printf("freertos初体验!!\n");
	xReturn = xTaskCreate((TaskFunction_t) AppTaskCreate,/* 任务入口函数 */
												(const char*)"MAIN_Task",/* 任务名字 */
												(uint16_t) 512,/* 任务栈大小 */
												(void*)		NULL,/* 任务入口函数参数 */
												(UBaseType_t)1,/* 任务的优先级 */
												(TaskHandle_t*) &AppTaskCreate_Handle);/* 任务控制块指针 */
	if(pdPASS == xReturn)
		vTaskStartScheduler();
	else
		return -1;
	while(1);
}

static void AppTaskCreate(void)
{
	BaseType_t xReturn = pdPASS;
	taskENTER_CRITICAL();
	
	xReturn = xTaskCreate((TaskFunction_t) LED1_Task,/* 任务入口函数 */
												(const char*)"LED1_Task",/* 任务名字 */
												(uint16_t) 512,/* 任务栈大小 */
												(void*)		NULL,/* 任务入口函数参数 */
												(UBaseType_t)2,/* 任务的优先级 */
												(TaskHandle_t*) &LED1_Task_Handle);/* 任务控制块指针 */
	if (pdPASS == xReturn)
		printf("创建LED1任务成功!!!!\n");
	
	
	xReturn = xTaskCreate((TaskFunction_t) LED2_Task,
												(const char*)"LED2_Task",
												(uint16_t) 512,
												(void*)		NULL,
												(UBaseType_t)3,
												(TaskHandle_t*) &LED2_Task_Handle);
	if (pdPASS == xReturn)
		printf("创建LED2任务成功!!!!");
	
	vTaskDelete(AppTaskCreate_Handle);
	taskEXIT_CRITICAL();
}


static void BSP_Init(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	LED_GPIO_Config();
	
	USART_Config();
}

static void LED1_Task(void* parameter)
{
	while(1)
	{
		LED1_ON;
		vTaskDelay(500);
		printf("LED1 ON!! \n\r");
		LED1_OFF;
		vTaskDelay(500);
		printf("LED1 OFF!! \n\r");
		
	}
}

static void LED2_Task(void* parameter)
{
	while(1)
	{
		LED2_ON;
		vTaskDelay(1000);
		printf("LED2 ON!!\n\r");
		LED2_OFF;
		vTaskDelay(1000);
		printf("LED2 OFF!!\n\r");
	}
}

这段代码是一个简单的 FreeRTOS 任务创建示例。下面是代码的功能和流程:

头文件及任务用到的其他函数,在主函数前声明。

  • 在 main 函数中首先初始化硬件资源,并使用 xTaskCreate() 函数创建名为 AppTaskCreate 的任务。此任务作为一个调度器,负责创建其余两个任务 LED1_Task 和 LED2_Task。
  • 在 AppTaskCreate() 中,使用 xTaskCreate() 函数创建 LED1_Task 和 LED2_Task 两个任务。它们分别控制两个 LED 灯的闪烁。这两个任务的创建和启动是在临界区内完成的。
  • 创建任务后,调用 vTaskDelete() 函数删除 AppTaskCreate 任务,以节省系统资源。
  • LED1_Task 和 LED2_Task 任务具有不同的优先级,任务间使用 vTaskDelay() 函数进行合理的时间调度。
  • LED1_Task 和 LED2_Task 中都包含了简单的 printf() 语句,用于输出任务运行状态,可使用串口通信进行调试。 总之,这段代码是使用 FreeRTOS 多任务操作系统创建了三个任务,其中一个是调度器,另外两个则是实际执行的任务,它们分别驱动不同的 LED 灯周期性地闪烁。该代码通过任务优先级和时间调度等方式,实现了多任务之间的协调和资源共享。

3. 实验现象

由于野火的板子灯只有一个,但是可以通过不同IO口的输出来控制灯的颜色,因此实验现象就是一会闪蓝灯一会闪红灯,并在串口输出LED1和LED2的信息

freertos学习之路7-将freertos移植到STM32f103x_第2张图片

查看这个串口打印出来的数据的时间可以发现,和我们预设的延迟500ms和1s基本一致,这也有力的验证了实时操作系统的实时性。

你可能感兴趣的:(freertos,stm32,学习,单片机)