一、FreeRTOS移植文件
FreeRTOS官方网站freertos.org,官网下载是从github下载,外网连接有问题基本上不容易下载,库文件使用的是开发板提供的FreeRTOSv9.0.0。
库文件包包括两个文件夹FreeRTOS核心库和FreeRTOS-Plus附加功能库。
移植文件包括include文件夹全部,MemMang文件夹全部,RVDS中的对应内核文件夹,Source根目录下的所有源文件以及Demo文件夹中例程所带的FreeRTOSConfig.h头文件。
二、Keil开发移植过程
复制文件到项目文件夹
创建一个FreeRTOS文件夹
在FreeRTOS文件夹内创建一个src文件夹和一个port文件夹(include文件夹可以直接从官方源文件中复制过来)。
复制官方源码中的include文件夹。
复制内核接口源文件以及内存管理文件到port文件夹中。
复制源码库中的源文件到src文件夹中。
复制FreeRTOSConfig.h文件到项目用户文件夹中。
添加分组和文件
在创建好的项目文件中添加分组,并在分组中添加源文件等。
创建两个分组Freertos/src和FreeRTOS/port,如图。
添加编译头文件路径
添加的路径包括include和对应内核文件夹,如图。
三、代码部分
包含的头文件
#include "FreeRTOS.h" // 必须在其他几个头文件之前
#include "queue.h" // 消息队列
#include "task.h" // 任务
#include "semphr.h" // 信号
#include "event_groups.h" // 事件组
定义变量
1、任务句柄
static TaskHandle_t demo_TaskHandle; //任务句柄
...
2、消息队列
QueueHandle_t demo_QueueHandle; //消息队列句柄
uint8_t demoQueueLength = 8; //消息队列长度
uint32_t demoQueueSize = 4; //消息队列单个数据大小
3、信号量
SemaphoreHandle_t demo_SemphrHandle; //信号量句柄
4、事件组EventGroup
static EventGroupHandle_t Event_Handle = NULL;
5、任务通知TaskNotify
任务通知不需要定义句柄,直接使用的是任务句柄。
任务通知可以替代二值信号量,计数信号量,1字消息队列,事件组。
接口函数
1、任务句柄
2、消息队列
3、信号量
4、事件组EventGroup
xEventGroupCreate(); // 事件创建函数
vEventGroupDelete(); // 事件删除函数
xEventGroupSetBits(); // 事件组置位函数
xEventGroupSetBitsFromISR(); // 事件组置位函数
xEventGroupWaitBits(); // 等待事件函数
xEventGroupClearBits(); // 返回值是没有被清除之前的值
xEventGroupClearBitsFromISR(); // 返回值是没有被清除之前的值
5、任务通知TaskNotify
// 发送任务通知函数
xTaskGenericNotify(); // 发送任务通知函数
xTaskNotifyGive();
vTaskNotifyGiveFromISR();
xTaskNotify();
xTaskNotifyFromISR();
xTaskNotifyAndQuery();
xTaskNotifyAndQueryFromISR();
// 获取任务通知函数
ulTaskNotifyTake(); // 作为信号量获取快速
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t *pulNotificationValue,
TickType_t xTicksToWait );
创建任务例程
注意创建任务有两种方法,一种是先创建完所有任务后再启动调度器;另外一种是先创建一个任务后启动调度器,在任务中创建其他任务后没用的任务删除掉;
任务优先级数字越大优先级越高,和uCOS相反。
#include "stm32f10x.h"
#include "string.h"
#include "bsp_gpio.h"
#include "bsp_led.h"
#include "FreeRTOS.h" // 必须在其他几个头文件之前
#include "queue.h" // 消息队列
#include "task.h" // 任务
#include "semphr.h" // 信号
#include "event_groups.h" // 事件组
static void BSP_Init(void);
static TaskHandle_t demo_TaskHandle = NULL;
static TaskHandle_t Task1_Handle = NULL, Task2_Handle = NULL;
QueueHandle_t demo_QueueHandle; //消息队列句柄
uint8_t demoQueueLength = 8; //消息队列长度
uint32_t demoQueueSize = 4; //消息队列单个数据大小
SemaphoreHandle_t demo_SemphrHandle; //信号量句柄
static void Task1_Entry(void *arg)
{
BaseType_t xReturn = pdTRUE;
for (;;)
{
xReturn = xSemaphoreGive(demo_SemphrHandle); // 释放信号量,二值置1,计数+1。
vTaskDelay(100); // 阻塞100个时钟周期
}
}
static uint32_t ulTestData = 0x01010101;
static void Task2_Entry(void *arg)
{
BaseType_t xReturn = pdTRUE;
for (;;)
{
xSemaphoreTake(demo_SemphrHandle, portMAX_DELAY); // 等待信号量,一直阻塞
xReturn = xQueueSend(demo_QueueHandle, &ulTestData , 0); // 发送ulTestData到消息队列
if (xReturn == pdTRUE)
{
printf("接收消息成功\r\n");
}
LED2_TOGGLE;
}
}
uint32_t ulQueueRxBuf;
static void Demo_TaskEntry(void *arg)
{
BaseType_t xReturn = pdTRUE;
for (;;)
{
xReturn = xQueueReceive(demo_QueueHandle, &ulQueueRxBuf, portMAX_DELAY); // 接收消息队列,使用portMAX_DELAY如果没有消息则一直阻塞
if (xReturn == pdTRUE)
{
printf("接收消息成功\r\n");
}
LED1_TOGGLE; // LED切换一次
}
}
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
BaseType_t ucTaskState = pdTRUE;
BSP_Init(); // 外设初始化
taskENTER_CRITICAL(); // 进入临界区
demo_QueueHandle = xQueueCreate(demoQueueLength, demoQueueSize); // 创建消息队列
demo_SemphrHandle = xSemaphoreCreateBinary(); // 创建二值信号量
// demo_SemphrHandle = xSemaphoreCreateCounting(12, 12); // 创建计数信号量,第一个形参是计数信号量最大值,第二个是初始值。
// TestSemphrHandle = xSemaphoreCreateMutex(); // 创建互斥信号量
xTaskCreate(Task1_Entry, "Task1", 512, NULL, 2, &Task1_Handle);
xTaskCreate(Task2_Entry, "Task2", 512, NULL, 3, &Task2_Handle);
ucTaskState = xTaskCreate((TaskFunction_t)Demo_TaskEntry, "DemoTask", 512, NULL, 3, &demo_TaskHandle); // 创建任务
taskEXIT_CRITICAL(); // 退出临界区
if (ucTaskState == pdTRUE)
{
vTaskStartScheduler(); // 开始任务调度
}
else
{
printf("Create Task error!!!\r\n");
}
while (1)
{
}
}
static void BSP_Init(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
LED_GPIO_Config();
USART_Config();
KEY_GPIO_Init();
}