FreeRTOS移植

本博客基于野火FreeRTOS教程讲述FreeRTOS的移植原理,帮助大家移植到自己的开发平台。

FreeRTOS资料获取及文件夹内容介绍

1.Source 文件夹
这里我们再重点分析下 FreeRTOS/Source 文件夹下的文件,具体见图 13-6 。编号
包含的是 FreeRTOS 的通用的头文件和 C 文件,这两部分的文件试用于各种编译器和处
理器,是通用的。需要移植的头文件和 C 文件放在编号 portblle 这个文件夹。

移植FreeRTOS

将FreeRTOS官方文件移植到裸机工程

移植完成后文件结构如下:

修改文件

修改FreeRTOSConfig.h

这里我们推荐直接使用野火的 FreeRTOSConfig.h文件,野火对官方源文件只是做了中文注释,并且加入了FreeRTOS已有的默认宏定义,这样我们可以在配置文件中修改相关的默认配置。

修改与对应开发板的头文件,STM32F1 的开发板,则包含 F1 的头文件 #include "stm32f10x.h" ,同理是使用了其它系列的开发板,则包含与开发板对应的头文件即可,当然还需要包含我们的串口的头文件“bsp_usart.h ”,因为在我们 FreeRTOSConfig.h 中实现了断言操作,需要打印一些信息。

 提示:虽然FreeRTOS中默认是打开很多宏定义的,但是用户还是要根据需要选择打开与关闭,因为这样子的系统会更适合用户需要,更严谨与更加节省系统资源。

/*
    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
    All rights reserved

    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

    This file is part of the FreeRTOS distribution.

    FreeRTOS is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License (version 2) as published by the
    Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.

    ***************************************************************************
    >>!   NOTE: The modification to the GPL is included to allow you to     !<<
    >>!   distribute a combined work that includes FreeRTOS without being   !<<
    >>!   obliged to provide the source code for proprietary components     !<<
    >>!   outside of the FreeRTOS kernel.                                   !<<
    ***************************************************************************

    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  Full license text is available on the following
    link: http://www.freertos.org/a00114.html

    ***************************************************************************
     *                                                                       *
     *    FreeRTOS provides completely free yet professionally developed,    *
     *    robust, strictly quality controlled, supported, and cross          *
     *    platform software that is more than just the market leader, it     *
     *    is the industry's de facto standard.                               *
     *                                                                       *
     *    Help yourself get started quickly while simultaneously helping     *
     *    to support the FreeRTOS project by purchasing a FreeRTOS           *
     *    tutorial book, reference manual, or both:                          *
     *    http://www.FreeRTOS.org/Documentation                              *
     *                                                                       *
    ***************************************************************************

    http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading
    the FAQ page "My application does not run, what could be wrong?".  Have you
    defined configASSERT()?

    http://www.FreeRTOS.org/support - In return for receiving this top quality
    embedded software for free we request you assist our global community by
    participating in the support forum.

    http://www.FreeRTOS.org/training - Investing in training allows your team to
    be as productive as possible as early as possible.  Now you can receive
    FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
    Ltd, and the world's leading authority on the world's leading RTOS.

    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
    compatible FAT file system, and our tiny thread aware UDP/IP stack.

    http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
    Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.

    http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
    Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS
    licenses offer ticketed support, indemnification and commercial middleware.

    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
    engineered and independently SIL3 certified version for use in safety and
    mission critical applications that require provable dependability.

*/


#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#include "stm32f4xx.h"
#include "bsp_debug_usart.h"


//针对不同的编译器调用不同的stdint.h文件
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
    #include <stdint.h>
    extern uint32_t SystemCoreClock;
#endif

//断言
#define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
#define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)

/************************************************************************
 *               FreeRTOS基础配置配置选项 
 *********************************************************************/
/* 置1:RTOS使用抢占式调度器;置0:RTOS使用协作式调度器(时间片)
 * 
 * 注:在多任务管理机制上,操作系统可以分为抢占式和协作式两种。
 * 协作式操作系统是任务主动释放CPU后,切换到下一个任务。
 * 任务切换的时机完全取决于正在运行的任务。
 */
#define configUSE_PREEMPTION					  1

//1使能时间片调度(默认式使能的)
#define configUSE_TIME_SLICING					1		

/* 某些运行FreeRTOS的硬件有两种方法选择下一个要执行的任务:
 * 通用方法和特定于硬件的方法(以下简称“特殊方法”)。
 * 
 * 通用方法:
 *      1.configUSE_PORT_OPTIMISED_TASK_SELECTION 为 0 或者硬件不支持这种特殊方法。
 *      2.可以用于所有FreeRTOS支持的硬件
 *      3.完全用C实现,效率略低于特殊方法。
 *      4.不强制要求限制最大可用优先级数目
 * 特殊方法:
 *      1.必须将configUSE_PORT_OPTIMISED_TASK_SELECTION设置为1。
 *      2.依赖一个或多个特定架构的汇编指令(一般是类似计算前导零[CLZ]指令)。
 *      3.比通用方法更高效
 *      4.一般强制限定最大可用优先级数目为32
 * 一般是硬件计算前导零指令,如果所使用的,MCU没有这些硬件指令的话此宏应该设置为0!
 */
#define configUSE_PORT_OPTIMISED_TASK_SELECTION	        1                       
                                                                        
/* 置1:使能低功耗tickless模式;置0:保持系统节拍(tick)中断一直运行
 * 假设开启低功耗的话可能会导致下载出现问题,因为程序在睡眠中,可用以下办法解决
 * 
 * 下载方法:
 *      1.将开发版正常连接好
 *      2.按住复位按键,点击下载瞬间松开复位按键
 *     
 *      1.通过跳线帽将 BOOT 0 接高电平(3.3V)
 *      2.重新上电,下载
 *    
 * 			1.使用FlyMcu擦除一下芯片,然后进行下载
 *			STMISP -> 清除芯片(z)
 */
#define configUSE_TICKLESS_IDLE													0   

/*
 * 写入实际的CPU内核时钟频率,也就是CPU指令执行频率,通常称为Fclk
 * Fclk为供给CPU内核的时钟信号,我们所说的cpu主频为 XX MHz,
 * 就是指的这个时钟信号,相应的,1/Fclk即为cpu时钟周期;
 */
#define configCPU_CLOCK_HZ						  (SystemCoreClock)

//RTOS系统节拍中断的频率。即一秒中断的次数,每次中断RTOS都会进行任务调度
#define configTICK_RATE_HZ						  (( TickType_t )1000)

//可使用的最大优先级
#define configMAX_PRIORITIES					  (32)

//空闲任务使用的堆栈大小
#define configMINIMAL_STACK_SIZE				((unsigned short)128)
  
//任务名字字符串长度
#define configMAX_TASK_NAME_LEN					(16)

 //系统节拍计数器变量数据类型,1表示为16位无符号整形,0表示为32位无符号整形
#define configUSE_16_BIT_TICKS					0                      

//空闲任务放弃CPU使用权给其他同优先级的用户任务
#define configIDLE_SHOULD_YIELD					1           

//启用队列
#define configUSE_QUEUE_SETS					  0    

//开启任务通知功能,默认开启
#define configUSE_TASK_NOTIFICATIONS    1   

//使用互斥信号量
#define configUSE_MUTEXES						    0    

//使用递归互斥信号量                                            
#define configUSE_RECURSIVE_MUTEXES			0   

//为1时使用计数信号量
#define configUSE_COUNTING_SEMAPHORES		0

/* 设置可以注册的信号量和消息队列个数 */
#define configQUEUE_REGISTRY_SIZE				10                                 
                                                                       
#define configUSE_APPLICATION_TASK_TAG		  0                       
                      

/*****************************************************************
              FreeRTOS与内存申请有关配置选项                                               
*****************************************************************/
//支持动态内存申请
#define configSUPPORT_DYNAMIC_ALLOCATION        1    
//支持静态内存
#define configSUPPORT_STATIC_ALLOCATION					0					
//系统所有总的堆大小
#define configTOTAL_HEAP_SIZE					((size_t)(36*1024))    


/***************************************************************
             FreeRTOS与钩子函数有关的配置选项                                            
**************************************************************/
/* 置1:使用空闲钩子(Idle Hook类似于回调函数);置0:忽略空闲钩子
 * 
 * 空闲任务钩子是一个函数,这个函数由用户来实现,
 * FreeRTOS规定了函数的名字和参数:void vApplicationIdleHook(void ),
 * 这个函数在每个空闲任务周期都会被调用
 * 对于已经删除的RTOS任务,空闲任务可以释放分配给它们的堆栈内存。
 * 因此必须保证空闲任务可以被CPU执行
 * 使用空闲钩子函数设置CPU进入省电模式是很常见的
 * 不可以调用会引起空闲任务阻塞的API函数
 */
#define configUSE_IDLE_HOOK						0      

/* 置1:使用时间片钩子(Tick Hook);置0:忽略时间片钩子
 * 
 * 
 * 时间片钩子是一个函数,这个函数由用户来实现,
 * FreeRTOS规定了函数的名字和参数:void vApplicationTickHook(void )
 * 时间片中断可以周期性的调用
 * 函数必须非常短小,不能大量使用堆栈,
 * 不能调用以”FromISR" 或 "FROM_ISR”结尾的API函数
 */
 /*xTaskIncrementTick函数是在xPortSysTickHandler中断函数中被调用的。因此,vApplicationTickHook()函数执行的时间必须很短才行*/
#define configUSE_TICK_HOOK						0           

//使用内存申请失败钩子函数
#define configUSE_MALLOC_FAILED_HOOK			0 

/*
 * 大于0时启用堆栈溢出检测功能,如果使用此功能 
 * 用户必须提供一个栈溢出钩子函数,如果使用的话
 * 此值可以为1或者2,因为有两种栈溢出检测方法 */
#define configCHECK_FOR_STACK_OVERFLOW			0   


/********************************************************************
          FreeRTOS与运行时间和任务状态收集有关的配置选项   
**********************************************************************/
//启用运行时间统计功能
#define configGENERATE_RUN_TIME_STATS	        0             
 //启用可视化跟踪调试
#define configUSE_TRACE_FACILITY				      0    
/* 与宏configUSE_TRACE_FACILITY同时为1时会编译下面3个函数
 * prvWriteNameToBuffer()
 * vTaskList(),
 * vTaskGetRunTimeStats()
*/
#define configUSE_STATS_FORMATTING_FUNCTIONS	1                       
                                                                        
                                                                        
/********************************************************************
                FreeRTOS与协程有关的配置选项                                                
*********************************************************************/
//启用协程,启用协程以后必须添加文件croutine.c
#define configUSE_CO_ROUTINES 			          0                 
//协程的有效优先级数目
#define configMAX_CO_ROUTINE_PRIORITIES       ( 2 )                   


/***********************************************************************
                FreeRTOS与软件定时器有关的配置选项      
**********************************************************************/
 //启用软件定时器
#define configUSE_TIMERS				            0                              
//软件定时器优先级
#define configTIMER_TASK_PRIORITY		        (configMAX_PRIORITIES-1)        
//软件定时器队列长度
#define configTIMER_QUEUE_LENGTH		        10                               
//软件定时器任务堆栈大小
#define configTIMER_TASK_STACK_DEPTH	      (configMINIMAL_STACK_SIZE*2)    

/************************************************************
            FreeRTOS可选函数配置选项                                                     
************************************************************/
#define INCLUDE_xTaskGetSchedulerState       1                       
#define INCLUDE_vTaskPrioritySet		         1
#define INCLUDE_uxTaskPriorityGet		         1
#define INCLUDE_vTaskDelete				           1
#define INCLUDE_vTaskCleanUpResources	       1
#define INCLUDE_vTaskSuspend			           1
#define INCLUDE_vTaskDelayUntil			         1
#define INCLUDE_vTaskDelay				           1
#define INCLUDE_eTaskGetState			           1
#define INCLUDE_xTimerPendFunctionCall	     0
//#define INCLUDE_xTaskGetCurrentTaskHandle       1
//#define INCLUDE_uxTaskGetStackHighWaterMark     0
//#define INCLUDE_xTaskGetIdleTaskHandle          0


/******************************************************************
            FreeRTOS与中断有关的配置选项                                                 
******************************************************************/
#ifdef __NVIC_PRIO_BITS
	#define configPRIO_BITS       		__NVIC_PRIO_BITS
#else
	#define configPRIO_BITS       		4                  
#endif
//中断最低优先级
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			15     

//系统可管理的最高中断优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5 

#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )	/* 240 */

#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )


/****************************************************************
            FreeRTOS与中断服务函数有关的配置选项                         
****************************************************************/
#define xPortPendSVHandler 	PendSV_Handler
#define vPortSVCHandler 	SVC_Handler


/* 以下为使用Percepio Tracealyzer需要的东西,不需要时将 configUSE_TRACE_FACILITY 定义为 0 */
#if ( configUSE_TRACE_FACILITY == 1 )
#include "trcRecorder.h"
#define INCLUDE_xTaskGetCurrentTaskHandle               1   // 启用一个可选函数(该函数被 Trace源码使用,默认该值为0 表示不用)
#endif


#endif /* FREERTOS_CONFIG_H */

 为了方便使用配置文件,我们直接在原来基础上加入红色文字作为注释

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#include "stm32f4xx.h"//修改为自己的单片机型号,官方有的话就直接使用官方的即可
#include "bsp_debug_usart.h"//串口头文件,使用断言


//针对不同的编译器调用不同的stdint.h文件
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)

    #include <stdint.h>
    extern uint32_t SystemCoreClock;
#endif

//断言
#define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
#define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)

/************************************************************************
 *               FreeRTOS基础配置配置选项 
 *********************************************************************/
/* 置1:RTOS使用抢占式调度器;置0:RTOS使用协作式调度器(时间片)
 * 
 * 注:在多任务管理机制上,操作系统可以分为抢占式和协作式两种。
 * 协作式操作系统是任务主动释放CPU后,切换到下一个任务。
 * 任务切换的时机完全取决于正在运行的任务。
 */
#define configUSE_PREEMPTION                      1

//1使能时间片调度(默认式使能的)
#define configUSE_TIME_SLICING                    1        

/* 某些运行FreeRTOS的硬件有两种方法选择下一个要执行的任务:
 * 通用方法和特定于硬件的方法(以下简称“特殊方法”)。
 * 
 * 通用方法:
 *      1.configUSE_PORT_OPTIMISED_TASK_SELECTION 为 0 或者硬件不支持这种特殊方法。
 *      2.可以用于所有FreeRTOS支持的硬件
 *      3.完全用C实现,效率略低于特殊方法。
 *      4.不强制要求限制最大可用优先级数目
 * 特殊方法:
 *      1.必须将configUSE_PORT_OPTIMISED_TASK_SELECTION设置为1。
 *      2.依赖一个或多个特定架构的汇编指令(一般是类似计算前导零[CLZ]指令)。
 *      3.比通用方法更高效
 *      4.一般强制限定最大可用优先级数目为32
 * 一般是硬件计算前导零指令,如果所使用的,MCU没有这些硬件指令的话此宏应该设置为0!
 */
#define configUSE_PORT_OPTIMISED_TASK_SELECTION            1                       
                                                                        
/* 置1:使能低功耗tickless模式;置0:保持系统节拍(tick)中断一直运行
 * 假设开启低功耗的话可能会导致下载出现问题,因为程序在睡眠中,可用以下办法解决
 * 
 * 下载方法:
 *      1.将开发版正常连接好
 *      2.按住复位按键,点击下载瞬间松开复位按键
 *     
 *      1.通过跳线帽将 BOOT 0 接高电平(3.3V)
 *      2.重新上电,下载
 *    
 *             1.使用FlyMcu擦除一下芯片,然后进行下载
 *            STMISP -> 清除芯片(z)
 */
#define configUSE_TICKLESS_IDLE                                                    0   

/*
 * 写入实际的CPU内核时钟频率,也就是CPU指令执行频率,通常称为Fclk
 * Fclk为供给CPU内核的时钟信号,我们所说的cpu主频为 XX MHz,
 * 就是指的这个时钟信号,相应的,1/Fclk即为cpu时钟周期;
 */
#define configCPU_CLOCK_HZ                          (SystemCoreClock)

//RTOS系统节拍中断的频率。即一秒中断的次数,每次中断RTOS都会进行任务调度
#define configTICK_RATE_HZ                          (( TickType_t )1000)

//可使用的最大优先级
#define configMAX_PRIORITIES                      (32)

//空闲任务使用的堆栈大小
#define configMINIMAL_STACK_SIZE                ((unsigned short)128)
  
//任务名字字符串长度
#define configMAX_TASK_NAME_LEN                    (16)

 //系统节拍计数器变量数据类型,1表示为16位无符号整形,0表示为32位无符号整形
#define configUSE_16_BIT_TICKS                    0                      

//空闲任务放弃CPU使用权给其他同优先级的用户任务
#define configIDLE_SHOULD_YIELD                    1           

//启用队列
#define configUSE_QUEUE_SETS                      0    

//开启任务通知功能,默认开启
#define configUSE_TASK_NOTIFICATIONS    1   

//使用互斥信号量
#define configUSE_MUTEXES                            0    

//使用递归互斥信号量                                            
#define configUSE_RECURSIVE_MUTEXES            0   

//为1时使用计数信号量
#define configUSE_COUNTING_SEMAPHORES        0

/* 设置可以注册的信号量和消息队列个数 */
#define configQUEUE_REGISTRY_SIZE                10                                 
                                                                       
#define configUSE_APPLICATION_TASK_TAG          0                       
                      

/*****************************************************************
              FreeRTOS与内存申请有关配置选项                                               
*****************************************************************/
//支持动态内存申请
#define configSUPPORT_DYNAMIC_ALLOCATION        1    
//支持静态内存
#define configSUPPORT_STATIC_ALLOCATION                    0                    
//系统所有总的堆大小
#define configTOTAL_HEAP_SIZE                    ((size_t)(36*1024))    


/***************************************************************
             FreeRTOS与钩子函数有关的配置选项                                            
**************************************************************/
/* 置1:使用空闲钩子(Idle Hook类似于回调函数);置0:忽略空闲钩子
 * 
 * 空闲任务钩子是一个函数,这个函数由用户来实现,
 * FreeRTOS规定了函数的名字和参数:void vApplicationIdleHook(void ),
 * 这个函数在每个空闲任务周期都会被调用
 * 对于已经删除的RTOS任务,空闲任务可以释放分配给它们的堆栈内存。
 * 因此必须保证空闲任务可以被CPU执行
 * 使用空闲钩子函数设置CPU进入省电模式是很常见的
 * 不可以调用会引起空闲任务阻塞的API函数
 */
#define configUSE_IDLE_HOOK                        0      

/* 置1:使用时间片钩子(Tick Hook);置0:忽略时间片钩子
 * 
 * 
 * 时间片钩子是一个函数,这个函数由用户来实现,
 * FreeRTOS规定了函数的名字和参数:void vApplicationTickHook(void )
 * 时间片中断可以周期性的调用
 * 函数必须非常短小,不能大量使用堆栈,
 * 不能调用以”FromISR" 或 "FROM_ISR”结尾的API函数
 */
 /*xTaskIncrementTick函数是在xPortSysTickHandler中断函数中被调用的。因此,vApplicationTickHook()函数执行的时间必须很短才行*/
#define configUSE_TICK_HOOK                        0           

//使用内存申请失败钩子函数
#define configUSE_MALLOC_FAILED_HOOK            0 

/*
 * 大于0时启用堆栈溢出检测功能,如果使用此功能 
 * 用户必须提供一个栈溢出钩子函数,如果使用的话
 * 此值可以为1或者2,因为有两种栈溢出检测方法 */
#define configCHECK_FOR_STACK_OVERFLOW            0   


/********************************************************************
          FreeRTOS与运行时间和任务状态收集有关的配置选项   
**********************************************************************/
//启用运行时间统计功能
#define configGENERATE_RUN_TIME_STATS            0             
 //启用可视化跟踪调试
#define configUSE_TRACE_FACILITY                      0    
/* 与宏configUSE_TRACE_FACILITY同时为1时会编译下面3个函数
 * prvWriteNameToBuffer()
 * vTaskList(),
 * vTaskGetRunTimeStats()
*/
#define configUSE_STATS_FORMATTING_FUNCTIONS    1                       
                                                                        
                                                                        
/********************************************************************
                FreeRTOS与协程有关的配置选项                                                
*********************************************************************/
//启用协程,启用协程以后必须添加文件croutine.c
#define configUSE_CO_ROUTINES                       0                 
//协程的有效优先级数目
#define configMAX_CO_ROUTINE_PRIORITIES       ( 2 )                   


/***********************************************************************
                FreeRTOS与软件定时器有关的配置选项      
**********************************************************************/
 //启用软件定时器
#define configUSE_TIMERS                            0                              
//软件定时器优先级
#define configTIMER_TASK_PRIORITY                (configMAX_PRIORITIES-1)        
//软件定时器队列长度
#define configTIMER_QUEUE_LENGTH                10                               
//软件定时器任务堆栈大小
#define configTIMER_TASK_STACK_DEPTH          (configMINIMAL_STACK_SIZE*2)    

/************************************************************
            FreeRTOS可选函数配置选项                                                     
************************************************************/

//  启用或禁用获取调度器状态的功能。设置为 1 时,允许使用 xTaskGetSchedulerState()函数,该函数返回调度器的当前状态(如是否正在运行任务调度)
#define INCLUDE_xTaskGetSchedulerState       1 

//启用或禁用任务优先级设置功能。设置为 1 时,允许使用 vTaskPrioritySet() 函数,该函数可用于更改任务的优先级。              
#define INCLUDE_vTaskPrioritySet                 1

//启用或禁用获取任务优先级功能。设置为 1 时,允许使用 uxTaskPriorityGet() 函数,该函数返回指定任务的当前优先级。
#define INCLUDE_uxTaskPriorityGet                 1

//启用或禁用删除任务的功能。设置为 1 时,允许使用 vTaskDelete() 函数,删除指定的任务。
#define INCLUDE_vTaskDelete                           1

//启用或禁用任务资源清理功能。设置为 1 时,允许在删除任务时执行资源清理(如动态分配的内存释放)。
#define INCLUDE_vTaskCleanUpResources           1

//启用或禁用任务挂起功能。设置为 1 时,允许使用 vTaskSuspend() 函数,挂起指定的任务。
#define INCLUDE_vTaskSuspend                       1

//启用或禁用任务延迟直到指定时间点功能。设置为 1 时,允许使用 vTaskDelayUntil() 函数,任务将延迟执行直到指定的时间点。
#define INCLUDE_vTaskDelayUntil                     1

//启用或禁用任务延迟功能。设置为 1 时,允许使用 vTaskDelay() 函数,任务延迟执行一段时间。
#define INCLUDE_vTaskDelay                           1

//启用或禁用获取任务状态功能。设置为 1 时,允许使用 eTaskGetState() 函数,该函数返回任务的当前状态(例如就绪、运行、挂起等)。
#define INCLUDE_eTaskGetState                       1

//启用或禁用定时器挂起函数调用功能。设置为 0 表示禁用该功能,设置为 1 时,允许使用 xTimerPendFunctionCall() 函数,该函数用于挂起一个定时器回调。
#define INCLUDE_xTimerPendFunctionCall         0

//启用或禁用获取当前任务句柄功能。设置为 1 时,允许使用 xTaskGetCurrentTaskHandle() 函数,返回当前正在执行的任务的句柄。这个功能在一些版本的 FreeRTOS 中可能会默认启用。
//#define INCLUDE_xTaskGetCurrentTaskHandle       1

//启用或禁用获取任务栈的最大空闲水位功能。设置为 0 时,禁用该功能。设置为 1 时,允许使用 uxTaskGetStackHighWaterMark() 函数,检查任务栈的使用情况。
//#define INCLUDE_uxTaskGetStackHighWaterMark     0

//启用或禁用获取空闲任务句柄功能。设置为 0 时,禁用该功能。设置为 1 时,允许使用 xTaskGetIdleTaskHandle() 函数,返回空闲任务的句柄。
//#define INCLUDE_xTaskGetIdleTaskHandle          0


/******************************************************************
            FreeRTOS与中断有关的配置选项                                                 
******************************************************************/
#ifdef __NVIC_PRIO_BITS
    #define configPRIO_BITS               __NVIC_PRIO_BITS
#else
    #define configPRIO_BITS               4                  
#endif
//中断最低优先级
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY            15     

//系统可管理的最高中断优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5 

#define configKERNEL_INTERRUPT_PRIORITY         ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )    /* 240 */

#define configMAX_SYSCALL_INTERRUPT_PRIORITY     ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )


/****************************************************************
            FreeRTOS与中断服务函数有关的配置选项                         
****************************************************************/
#define xPortPendSVHandler     PendSV_Handler
#define vPortSVCHandler     SVC_Handler


/* 以下为使用Percepio Tracealyzer需要的东西,不需要时将 configUSE_TRACE_FACILITY 定义为 0 */
#if ( configUSE_TRACE_FACILITY == 1 )
#include "trcRecorder.h"
#define INCLUDE_xTaskGetCurrentTaskHandle               1   // 启用一个可选函数(该函数被 Trace源码使用,默认该值为0 表示不用)
#endif


#endif /* FREERTOS_CONFIG_H */

可以根据需要来改变宏添加或删除部分功能

修改stm32f10x_it.c

SysTick 中断服务函数是一个非常重要的函数, FreeRTOS 所有跟时间相关的事情都在里面处理, SysTick 就是 FreeRTOS 的一个心跳时钟,驱动着 FreeRTOS的运行,就像人的 心跳一样,假如没有心跳,我们就相当于“死了”,同样的,FreeRTOS 没有了心跳,那么它就会卡死在某个地方,不能进行任务调度,不能运行任何的东西,因此我们需要实现一 个 FreeRTOS 的心跳时钟, FreeRTOS 帮我们实现了 SysTick 的启动的配置:在 port.c 文件 中已经实现 vPortSetupTimerInterrupt() 函数,并且 FreeRTOS 通用的 SysTick 中断服务函数 也实现了:在 port.c 文件中已经实现 xPortSysTickHandler() 函数,所以移植的时候只需要我 们在 stm32f10x_it.c 文件中实现我们对应( STM32 )平台上 SysTick_Handler() 函数即可。 FreeRTOS 为开发者考虑得特别多, PendSV_Handler() SVC_Handler() 这两个很重要的函 数都帮我们实现了,在 port.c 文件中已经实现 xPortPendSVHandler() vPortSVCHandler() 函数,防止我们自己实现不了,那么在 stm32f10x_it.c 中就需要我们注释掉 PendSV_Handler()与 SVC_Handler() 这两个函数了

stm32f10x_it.c文件内容 

/**
  ******************************************************************************
  * @file    FMC_SDRAM/stm32f4xx_it.c 
  * @author  MCD Application Team
  * @version V1.0.1
  * @date    11-November-2013
  * @brief   Main Interrupt Service Routines.
  *         This file provides template for all exceptions handler and
  *         peripherals interrupt service routine.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2013 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software 
  * distributed under the License is distributed on an "AS IS" BASIS, 
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_it.h"

#include "FreeRTOS.h"                    //FreeRTOS使用          
#include "task.h" 


/** @addtogroup STM32F429I_DISCOVERY_Examples
  * @{
  */

/** @addtogroup FMC_SDRAM
  * @{
  */ 

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/******************************************************************************/
/*            Cortex-M4 Processor Exceptions Handlers                         */
/******************************************************************************/

/**
  * @brief  This function handles NMI exception.
  * @param  None
  * @retval None
  */
void NMI_Handler(void)
{
}

/**
  * @brief  This function handles Hard Fault exception.
  * @param  None
  * @retval None
  */
void HardFault_Handler(void)
{
  /* Go to infinite loop when Hard Fault exception occurs */
  while (1)
  {}
}

/**
  * @brief  This function handles Memory Manage exception.
  * @param  None
  * @retval None
  */
void MemManage_Handler(void)
{
  /* Go to infinite loop when Memory Manage exception occurs */
  while (1)
  {}
}

/**
  * @brief  This function handles Bus Fault exception.
  * @param  None
  * @retval None
  */
void BusFault_Handler(void)
{
  /* Go to infinite loop when Bus Fault exception occurs */
  while (1)
  {}
}

/**
  * @brief  This function handles Usage Fault exception.
  * @param  None
  * @retval None
  */
void UsageFault_Handler(void)
{
  /* Go to infinite loop when Usage Fault exception occurs */
  while (1)
  {}
}

/**
  * @brief  This function handles Debug Monitor exception.
  * @param  None
  * @retval None
  */
void DebugMon_Handler(void)
{}


/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
extern void xPortSysTickHandler(void);
//systick中断服务函数
void SysTick_Handler(void)
{    
    #if (INCLUDE_xTaskGetSchedulerState  == 1 )
      if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
      {
    #endif  /* INCLUDE_xTaskGetSchedulerState */  
        xPortSysTickHandler();
    #if (INCLUDE_xTaskGetSchedulerState  == 1 )
      }
    #endif  /* INCLUDE_xTaskGetSchedulerState */
}

/******************************************************************************/
/*                 STM32F4xx Peripherals Interrupt Handlers                   */
/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
/*  available peripheral interrupt handler's name please refer to the startup */
/*  file (startup_stm32f429_439xx.s).                         */
/******************************************************************************/

/**
  * @}
  */ 

/**
  * @}
  */ 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
 

修改main.c 

/**
  *********************************************************************
  * @file    main.c
  * @author  fire
  * @version V1.0
  * @date    2018-xx-xx
  * @brief   FreeRTOS v9.0.0 + STM32 工程模版
  *********************************************************************
  * @attention
  *
  * 实验平台:野火 STM32全系列开发板 
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  **********************************************************************
  */ 
 
/*
*************************************************************************
*                             包含的头文件
*************************************************************************
*/ 
/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"
/* 开发板硬件bsp头文件 */
#include "bsp_led.h"
#include "bsp_debug_usart.h"//普通的串口初始化,打印


int main(void)
{    

}
/********************************END OF FILE****************************/

 任务创建

/**
  *********************************************************************
  * @file    main.c
  * @author  fire
  * @version V1.0
  * @date    2018-xx-xx
  * @brief   FreeRTOS v9.0.0 + STM32 固件库实验
  *********************************************************************
  * @attention
  *
  * 实验平台:野火 STM32全系列开发板 
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  **********************************************************************
  */ 
 
/*
*************************************************************************
*                             包含的头文件
*************************************************************************
*/ 
/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"
/* 开发板硬件bsp头文件 */
#include "bsp_led.h"
#include "bsp_debug_usart.h"

/**************************** 任务句柄 ********************************/
/* 
 * 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
 * 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
 * 这个句柄可以为NULL。
 */
 /* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LED任务句柄 */
static TaskHandle_t LED_Task_Handle = NULL;

/********************************** 内核对象句柄 *********************************/
/*
 * 信号量,消息队列,事件标志组,软件定时器这些都属于内核的对象,要想使用这些内核
 * 对象,必须先创建,创建成功之后会返回一个相应的句柄。实际上就是一个指针,后续我
 * 们就可以通过这个句柄操作这些内核对象。
 *
 * 内核对象说白了就是一种全局的数据结构,通过这些数据结构我们可以实现任务间的通信,
 * 任务间的事件同步等各种功能。至于这些功能的实现我们是通过调用这些内核对象的函数
 * 来完成的
 * 
 */


/******************************* 全局变量声明 ************************************/
/*
 * 当我们在写应用程序的时候,可能需要用到一些全局变量。
 */


/*
*************************************************************************
*                             函数声明
*************************************************************************
*/
static void AppTaskCreate(void);/* 用于创建任务 */

static void LED_Task1(void* pvParameters);/* LED_Task任务实现 */
static void LED_Task2(void* pvParameters);/* LED_Task任务实现 */

static void BSP_Init(void);/* 用于初始化板载相关资源 */

/*****************************************************************
  * @brief  主函数
  * @param  无
  * @retval 无
  * @note   第一步:开发板硬件初始化 
            第二步:创建APP应用任务
            第三步:启动FreeRTOS,开始多任务调度
  ****************************************************************/
int main(void)
{    
  BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */

  /* 开发板硬件初始化 */
  BSP_Init();
  printf("这是一个[野火]-STM32全系列开发板-FreeRTOS-固件库例程!\r\n");
   /* 创建AppTaskCreate任务 */
  xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,  /* 任务入口函数 */
                        (const char*    )"AppTaskCreate",/* 任务名字 */
                        (uint16_t       )512,  /* 任务栈大小 */
                        (void*          )NULL,/* 任务入口函数参数 */
                        (UBaseType_t    )1, /* 任务的优先级 */
                        (TaskHandle_t*  )&AppTaskCreate_Handle);/* 任务控制块指针 */ 
  /* 启动任务调度 */           
  if(pdPASS == xReturn)
    vTaskStartScheduler();   /* 启动任务,开启调度 */
  else
    return -1;  
  
  while(1);   /* 正常不会执行到这里 */    
}


/***********************************************************************
  * @ 函数名  : AppTaskCreate
  * @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面
  * @ 参数    : 无  
  * @ 返回值  : 无
  **********************************************************************/
static void AppTaskCreate(void)
{
  BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  
  taskENTER_CRITICAL();           //进入临界区
  
  /* 创建LED_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )LED_Task1, /* 任务入口函数 */
                        (const char*    )"LED_Task1",/* 任务名字 */
                        (uint16_t       )512,   /* 任务栈大小 */
                        (void*          )NULL,    /* 任务入口函数参数 */
                        (UBaseType_t    )2,        /* 任务的优先级 */
                        (TaskHandle_t*  )&LED_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
    printf("创建LED_Task1任务成功!\r\n");
  
  
    /* 创建LED_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )LED_Task2, /* 任务入口函数 */
                        (const char*    )"LED_Task2",/* 任务名字 */
                        (uint16_t       )512,   /* 任务栈大小 */
                        (void*          )NULL,    /* 任务入口函数参数 */
                        (UBaseType_t    )2,        /* 任务的优先级 */
                        (TaskHandle_t*  )&LED_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
    printf("创建LED_Task1任务成功!\r\n");
  vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
  
  taskEXIT_CRITICAL();            //退出临界区
}

/**********************************************************************
  * @ 函数名  : LED_Task
  * @ 功能说明: LED_Task任务主体
  * @ 参数    :   
  * @ 返回值  : 无
  ********************************************************************/
static void LED_Task1(void* parameter)
{    
    while (1)
    {
        LED1_ON;
        vTaskDelay(500);   /* 延时500个tick */
        printf("LED_Task Running,LED1_ON\r\n");
        
        LED1_OFF;     
        vTaskDelay(500);   /* 延时500个tick */                 
        printf("LED_Task Running,LED1_OFF\r\n");
    }
}


/**********************************************************************
  * @ 函数名  : LED_Task
  * @ 功能说明: LED_Task任务主体
  * @ 参数    :   
  * @ 返回值  : 无
  ********************************************************************/
static void LED_Task2(void* parameter)
{    
    while (1)
    {
        LED2_ON;
        vTaskDelay(1500);   /* 延时500个tick */
        printf("LED_Task Running,LED1_ON\r\n");
        
        LED2_OFF;     
        vTaskDelay(1500);   /* 延时500个tick */                 
        printf("LED_Task Running,LED1_OFF\r\n");
    }
}

/***********************************************************************
  * @ 函数名  : BSP_Init
  * @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
  * @ 参数    :   
  * @ 返回值  : 无
  *********************************************************************/
static void BSP_Init(void)
{
    /*
     * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
     * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
     * 都统一用这个优先级分组,千万不要再分组,切忌。
     */
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
    
    /* LED 初始化 */
    LED_GPIO_Config();

    /* 串口初始化    */
    Debug_USART_Config();
  
}

/********************************END OF FILE****************************/
 

main函数说明:在main函数中我们并没有去配置系统的时钟等操作,其实在我们单片机上电后在启动文件startup_stm32f40xx.s中,最先执行的不是main(),而是系统初始函数。这个函数也帮我们直接配置系统时钟到该芯片的最高频率。

 其他内容

 LDRLoad Register(加载寄存器)的缩写。它的作用是将内存中的数据加载到寄存器中。LDR 指令常用于从内存中读取数据并将其存入一个指定的寄存器。

    指令基本语法

LDR <寄存器>, [<内存地址>]

BLXBranch with Link and Exchange 的缩写。它是一条指令,用于执行函数调用,同时支持在 ARM 和 Thumb 模式之间的切换。具体来说,BLX 指令会跳转到指定的地址,并将当前指令的下一条指令的地址(即返回地址)保存到链接寄存器 LR(R14)中,这样程序在函数执行完毕后可以返回到调用点继续执行。

基本语法

 BLX <target>

在 ARM 汇编语言中,BXBranch and Exchange 的缩写。它用于执行跳转指令,并且支持在 ARM 模式Thumb 模式 之间进行切换。BX 指令将程序计数器(PC)设置为目标地址,并根据目标地址的最低位(最低位 0 表示 ARM 模式,最低位 1 表示 Thumb 模式)来决定是执行 ARM 模式的指令还是 Thumb 模式的指令。

基本语法

BX <register>

ENDP 告诉汇编器当前的过程(函数)已结束,它用于标记一个过程(或子程序)的结束位置,通常与 PROC 指令配对出现。

MCU寄存器相关说明

  • R0-R3 寄存器通常用来传递最多 4 个输入参数。
  • R4-R11 通常用于存储函数内部的数据和临时值。
  • R12 被称为 IP (Intra-Procedure-call temporary),也用作临时数据存储。
  • R13 是栈指针(SP,Stack Pointer),用于栈操作。
  • R14 是链接寄存器(LR,Link Register),用于存储返回地址。
  • R15 是程序计数器(PC,Program Counter),指示当前执行指令的位置。

Free是如何启用Tick中断的 

 vTaskStartScheduler();   /* 启动任务,开启调度 */

在这个函数中有这么一句代码

我们可以看到这个函数点进去有下图这个函数

这么一个函数,再点进去,这个就是我们Tick中断的函数

### FreeRTOS 移植教程和指南 #### 1. 准备工作 为了成功移植FreeRTOS至特定硬件平台,需准备目标硬件开发板及其配套工具链。确保已安装集成开发环境(IDE),如Keil MDK或IAR Embedded Workbench。 #### 2. 获取并解压FreeRTOS源码包 下载最新版本的FreeRTOS压缩包,并将其解压到本地磁盘上的合适位置。该软件包包含了多个子目录,其中`Source`文件夹内有核心组件;而`Demo`则提供了不同架构下的实例项目[^1]。 #### 3. 创建新工程项目结构 建立一个新的嵌入式C/C++工程,在此过程中创建必要的文件夹用于分类管理各类资源。特别注意要设立专门的空间存储与具体MCU相关的端口层实现代码(`port.c`)以及内存分配方案(heap_x.c)。 #### 4. 配置FreeRTOSConfig.h 复制位于官方示例中的`FreeRTOSConfig.h`模板至用户的自定义路径下。此配置文件允许开发者调整操作系统的行为特性以适应实际需求,比如设定最大优先级数量、启用/禁用某些功能模块等。务必仔细阅读文档说明完成相应参数设置[^2]。 ```c // 示例:部分重要宏定义 #define configUSE_PREEMPTION 1 /* 使用抢占式调度 */ #define configMAX_PRIORITIES (5) /* 支持的最大优先级数目 */ #define configTICK_RATE_HZ ((TickType_t)1000)/* 系统节拍频率(Hz)*/ ``` #### 5. 实现Port Layer接口函数 针对选定的目标CPU体系结构编写相应的底层支持代码(port.c), 它们负责处理诸如上下文切换、中断服务程序入口等功能逻辑。这部分通常依赖于厂商提供的SDK手册指导完成。 #### 6. 测试验证基本功能 编译链接整个应用程序之后加载固件映像到目标设备上运行测试案例,观察预期行为是否正常达成。如果遇到任何异常情况,则返回排查错误直至稳定可靠为止。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值