FreeRTOS项目工程完善指南:STM32系列
本文是FreeRTOS + STM32开发系列教程的一部分。我们将完善之前移植的FreeRTOS工程,添加串口功能并优化配置文件。
更多优质资源,请访问我的GitHub仓库:https://github.com/Despacito0o/FreeRTOS
准备工作
首先,我们需要准备以下文件:
- FreeRTOS配置文件(FreeRTOSConfig.h)
- 串口初始化文件(usart.h和usart.c)
📝 准备工作说明:这些文件是构建完整FreeRTOS工程的基础。FreeRTOSConfig.h用于配置RTOS的核心参数,而串口文件则提供了与PC通信的接口,这对于调试和监控系统运行状态至关重要。
关键文件解析
usart.h文件核心部分
这个文件定义了STM32串口通信所需的宏和函数声明。以下是文件的核心部分:
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include <stdio.h>
/**
* 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
* 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
* 2-修改GPIO的宏
*/
// 串口1-USART1
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
// 其他串口配置...
void USART_Config(void);
#endif /* __USART_H */
🔍 注意:上述代码只展示了部分内容,完整的串口配置支持USART1~USART5,可以根据自己的需求选择使用。完整代码请访问我的GitHub仓库获取。
📝 串口配置详解:
- 时钟配置:USART1使用APB2总线,其他USART使用APB1总线,这决定了时钟频率和性能
- GPIO配置:定义了TX和RX引脚的具体位置,便于硬件连接
- 波特率设置:115200是常用的调试波特率,可以根据需要调整
- 中断配置:通过NVIC配置实现串口中断处理,提高通信效率
usart.c文件核心部分
此文件实现了串口初始化和重定向printf函数的功能:
#include "usart.h"
/**
* @brief 配置嵌套向量中断控制器NVIC
* @param 无
* @retval 无
*/
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* 抢断优先级*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
// 更多串口初始化和重定向函数...
🚀 提示:完整代码包含了USART_Config函数以及C标准库printf函数的重定向实现。这使得你可以在FreeRTOS项目中轻松使用printf进行调试输出。
📝 中断配置详解:
- 优先级分组:使用NVIC_PriorityGroup_2,将4位优先级分为2位抢占优先级和2位子优先级
- 中断优先级:抢占优先级1和子优先级1的设置确保了串口中断的及时响应
- 中断使能:通过NVIC_Init使能中断,使系统能够响应串口事件
FreeRTOSConfig.h文件核心部分
FreeRTOSConfig.h是FreeRTOS的核心配置文件,通过修改这些宏定义,可以灵活调整RTOS的行为:
/**
* @file FreeRTOSConfig.h
* @author Despacito (https://github.com/Despacito0o/FreeRTOS)
* @brief FreeRTOS配置文件
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#include "stm32f10x.h" // 设备头文件
// 调度器配置
#define configUSE_PREEMPTION 1 // 启用抢占式调度器
#define configUSE_TICKLESS_IDLE 1 // 启用低功耗无滴答模式
// 时钟配置
#define configCPU_CLOCK_HZ (SystemCoreClock) // CPU 时钟频率
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) // 系统节拍频率
#define configUSE_16_BIT_TICKS 0 // 使用 32 位节拍计数器
// 更多配置项...
⚙️ 配置说明:这个FreeRTOSConfig.h文件比之前移植时使用的配置文件更加完整和详细,添加了许多有用的配置项和注释。完整的配置文件可在GitHub仓库中获取,里面包含了60+的配置选项,覆盖了从内存管理到中断优先级的各个方面。
📝 配置详解:
- 抢占式调度:启用抢占式调度器,允许高优先级任务抢占低优先级任务
- 低功耗模式:启用Tickless模式,在系统空闲时降低功耗
- 时钟配置:使用系统时钟作为基准,确保时间精度
- 节拍配置:1000Hz的节拍频率提供了良好的任务调度粒度
工程完善步骤
1. 准备新工程
复制003动态创建工程模板并重命名为005,这将作为我们新的工程模板:
📝 步骤说明:创建新工程模板的目的是为了保持原有工程结构的同时,添加新的功能。这样可以避免破坏原有功能,同时方便进行功能扩展。
2. 替换FreeRTOSConfig.h文件
打开005工程,导航到...\Despacito\005\FreeRTOS
目录,更换我们准备好的FreeRTOSConfig.h文件:
📝 步骤说明:替换配置文件是为了使用更完整的FreeRTOS配置选项。新的配置文件提供了更多的可配置项,使系统更加灵活和可定制。
3. 创建驱动文件夹
导航到...\Desktop\Despacito\005
,新建一个Driver文件夹:
📝 步骤说明:创建Driver文件夹是为了更好地组织代码结构,将硬件驱动相关的代码集中管理。这种组织方式使代码结构更清晰,便于维护和扩展。
4. 添加串口文件
在Driver文件夹中新建一个usart文件夹,用来存放串口初始化文件,并将usart.c和usart.h这两个文件放进该目录下:
📝 步骤说明:添加串口文件是为了实现与PC的通信功能。这些文件包含了串口初始化和配置的代码,是实现调试和监控功能的基础。
5. 配置工程包含路径
打开工程,点击魔法棒->C/C++(AC6)->Include Paths->…添加如下路径,点击OK->OK:
📝 步骤说明:配置包含路径是为了让编译器能够找到新添加的头文件。这是确保代码能够正确编译的重要步骤。
6. 添加Driver组和串口文件
添加Driver组以及串口初始化文件,并整理一下点击OK:
📝 步骤说明:在工程中添加Driver组是为了在keil中更好地组织和管理驱动相关的文件。这使项目结构更清晰,便于开发和维护。
7. 修改main.c
在main.c中添加#include "usart.h"
头文件,并调用串口初始化函数USART_Config();
📝 步骤说明:修改main.c是为了初始化串口功能。通过调用USART_Config()函数,系统可以正确配置串口参数,为后续的调试输出做好准备。
8. 处理静态内存分配问题
编译后发现有错误,这是因为我们开启了静态内存分配但没有实现相关函数。有两种解决方法:
- 将
configSUPPORT_STATIC_ALLOCATION
改为0 - 自己实现相关函数
我们选择方法2,从004项目中复制静态任务创建函数:
StaticTask_t IdleTaskTCB;
StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskStackSize )
{
* ppxIdleTaskTCBBuffer = &IdleTaskTCB;
* ppxIdleTaskStackBuffer = IdleTaskStack;
* pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
📝 步骤说明:处理静态内存分配是为了解决编译错误。通过实现vApplicationGetIdleTaskMemory函数,我们为FreeRTOS的空闲任务提供了静态内存分配的支持。这种方法比动态分配更可靠,适合在资源受限的嵌入式系统中使用。
9. 优化SysTick中断处理
前面我们在FreeRTOSConfig.h中注释了xPortSysTickHandler
的定义,现在我们需要规范化SysTick中断处理:
- 打开port.c,找到xPortSysTickHandler函数
- 在stm32f10x_it.c中修改SysTick_Handler函数,加入FreeRTOS调度相关代码:
#include "stm32f10x_it.h"
#include "FreeRTOS.h"
#include "task.h"
// ...
void SysTick_Handler(void)
{
#if(INCLUDE_xTaskGetSchedulerState==1)
if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
#endif
{
xPortSysTickHandler();
}
}
📝 步骤说明:优化SysTick中断处理是为了确保FreeRTOS的调度器能够正常工作。通过修改SysTick_Handler函数,我们实现了与FreeRTOS调度器的正确集成,确保任务调度的时间精度和可靠性。
10. 最终编译
完成以上步骤后,我们的工程就可以方便地使用宏配置和printf打印信息了:
📝 步骤说明:最终编译成功标志着我们的工程已经完成了所有必要的配置和修改。现在系统具备了完整的调试输出功能,可以通过串口实时监控系统运行状态。
总结
通过本文的步骤,我们成功完善了FreeRTOS工程,添加了:
- 完整的FreeRTOSConfig.h配置文件
- 串口通信功能
- printf调试输出功能
- 更规范的中断处理方式
这些改进使得我们的FreeRTOS工程更加健壮和实用,为后续开发复杂应用奠定了良好基础。
📚 获取完整代码和更多示例
完整的工程代码、配置文件以及更多示例请访问我的GitHub仓库:https://github.com/Despacito0o/FreeRTOS如果这篇文章对你有帮助,请给我的GitHub仓库点个Star!你的支持是我持续更新的动力。