本文目标:移植freertos到N32G430开发板上,并实现一个LED闪烁的基本例程
1.FreeRTOS介绍
RTOS全称为 Real Time Operation System,即实时操作系统。RTOS强调的是实时性,又分为硬实时和软实时。硬实时要求在规定的时间内必须完成操作,不允许超时;而软实时里对处理过程超时的要求则没有很严格。
FreeRTOS是RTOS的一种,尺寸非常小,可运行于微控制器上。微控制器是尺寸小,资源受限的处理器,它在单个芯片上包含了处理器本身、用于保存要执行的程序的只读存储器(ROM或Flash)、所执行程序需要的随机存取存储器(RAM),一般情况下程序直接从只读存储器执行微控制器用于深度嵌入式应用,一般都有非常明确、专门的工作。
2 FreeRTOS资料与源码下载
FreeRTOS的官网是www.freertos.org。
进入 FreeRTOS 首页,就会看到download下载链接,进入后下载“FreeRTOS 202212.00”文件,下载完成后双击运行,下载源码到指定目录。
加压之后源码文件夹,可以看到有两个文件夹,4 个 HTML 格式的网页和2个 txt 文档,HTML 网页和 txt 文档就不用介绍了,另外两个文件夹:FreeRTOS 和 FreeRTOS-Plus,这两个文件夹里面的东西就是 FreeRTOS 的源码
FreeRTOS
打开FreeRTOS 目录,可以看到有个三个文件夹,Demo里面放到的是针对不同MCU提供的相关例程,License 文件夹里面放的是相关的许可证,做产品的要仔细看看。Source 文件夹里面的就是FreeRTOS的源码文件了。
打开Source 文件夹,介绍一下portable这个文件夹,FreeRTOS 是个系统,它需要和硬件联系在一起,软件到硬件中间必须有一个桥梁,portable 文件夹里面的东西就是 FreeRTOS系统和具体的硬件之间的连接桥梁!不同的编译环境,不同的 MCU,其桥梁应该是不同的,打开 portable 文件夹,如下图所示:
MemMang 这个文件夹是跟内存管理相关的,我们移植的时候是必须的。Keil
文件夹里面的东西肯定也是必须的,但是我们打开Keil文件夹以后里面只有一个文件:See-also-the-RVDS-directory.txt,意思就是参考RVDS文件夹里面的东西!
RVDS 文件夹针对不同的架构的 MCU 做了详细的分类,N32G430就参考 ARM_CM4F,打开 ARM_CM4F 文件夹,里面有两个文件,这两个文件就是我们移植的时候所需要的!
3 移植freertos到N32G430开发板
3.1创建工程
1、新建一个文件夹,用于存放工程,文件夹下新建FreeRTOS、MDK-ARM、User三个文件夹,分别用于存放freertos的系统文件、MDK工程项目文件、用户文件。
2、拷贝厂商提供的firmware文件夹到工程目录下面:
3、新建工程到MDK目录下面,并按图示的建立相关引用以后头文件的位置设置:
3、添加文件到工程
3.2添加代码
LED 硬件图
开发板主MCU 芯片型号为N32G430CBL7,LQFP48 管脚封装。开发板上板载有3个LED灯。这里实现一个线程控制D1闪烁,该LED灯由PA1管脚控制。
任务创建osThreadNew()函数
先需要了解xTaskCreate()和xTaskCreateStatic()这两个更加基本的任务创建函数。
xTaskCreate();//位置task.c
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION;
#endif
- pvTaskCode 这是一个函数指针,指向执行任务的函数。
- pcName 任务的描述名称,方便调试,不用的话可以设为Null。
- usStackDepth 每个任务有自己的栈空间,这里根据任务占用需求设置栈空间的大小。
- pvParameters 用于传递给任务的参数,不用的话可以设为Null。
- uxPriority 设置任务的优先级,范围由0到(configMAX_PRIORITIES – 1)。数值越大,等级越高。
- pxCreatedTask 任务的句柄(handle),通过句柄可以对任务进行设置,比如改变任务优先级等,不用可以设为Null。
函数的返回值有两个pdPass和pdFail,pdPass表示任务创建成功,相反pdFail表示创建失败,创建失败的原因大多是因为系统没有足够的堆空间来保存任务的数据。
xTaskCreateStatic();//位置tasks.c
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION;
#endif
xTaskCreate()与 xTaskCreateStatic()的区别:
xTaskCreate是操作系统自动分配内存,xTaskCreateStatic是需要程序员手动定义内存。
- xTaskCreate适用于项目开发中内存余量比较充足的项目,只是简单的分配大小就可以了;
- xTaskCreateStatic适用于项目开发中内存比较紧张的项目,事先定义好内存大小并占用内存空间,这样在系统编译的时候就可以确定总内存大小,也不会出现系统运行到当前任务时内存不足而出现崩溃的情况。
- 使用动态方法创建任务(xTaskCreate)的时候需要将宏 configSUPPORT_DYNAMIC_ALLOCATION 设置为 1
- ·使用静态方法创建任务(xTaskCreateStatic)的时候需要将宏 configSUPPORT_STATIC_ALLOCATION 设为1宏定义位置Core/Inc/ FreeRTOSConfig.h
使用osThreadNew()创建一个进程
void MX_FREERTOS_Init(void) {
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
}
void MX_FREERTOS_Init(void) {
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
}
完整main.c
#include "main.h"
#include "bsp_led.h"
#include "cmsis_os.h"
void MX_FREERTOS_Init(void);
int main(void)
{
LED_Initialize(LED1_GPIO_PORT, LED1_GPIO_PIN );
osKernelInitialize();
MX_FREERTOS_Init();
osKernelStart();
while(1)
{
}
}
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
void StartDefaultTask(void *argument);
void MX_FREERTOS_Init(void);
void MX_FREERTOS_Init(void) {
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
}
void StartDefaultTask(void *argument)
{
for(;;)
{
osDelay(500);
LED_Toggle(LED1_GPIO_PORT, LED1_GPIO_PIN);
}
}
4 下载与演示
配置好下载器参数,添加flash,选择下载后自动运行。
下载后演示视频如下: