#申请原创#@21小跑堂
引:
单片机上使用操作系统越来越普遍了,现在将FreeRTOS最简源码在单片机上的使用讲解一下,方便大家后续工作中的方便,这篇文章同时也适合在其它芯片上的应用。
一、下载最新版本的FreeRTOS
两个地址可以进行下载,其一为官网下载:
https://www.freertos.org/zh-cn-cmn-s/
另外一个是托管网站,托管网站的版本一般不是最新的:
https://sourceforge.net/projects/freertos/files/FreeRTOS/
二、下载之后的文件夹介绍
我们打开关注的FreeRTOS文件夹
打开Source文件夹
使用keil进行环境搭建,我们需要打开portable文件夹
重点关注MemMang(内存管理)
RVDS(内核选择)文件夹
三、提取最简源码到工程模板目录中
我们在工程模板里面创建一个FreeRTOS的文件夹
在文件夹中创建两个空的文件夹,命名为:src和port文件夹
src文件夹主要保存FreeRTOS中的核心源文件;
port文件夹中保存内存管理以及处理架构的文件;
将portable文件夹中的两个文件夹拷贝到port文件夹中。
最后拷贝include头文件到FreeRTOS文件夹中。
将FreeRTOSConfig.h文件拷贝到user文件夹中,这部分是需要进行更改的。
四、进行工程的MDK设置操作
在工程中增加刚刚拷贝到目录中的文件
分别是FreeRTOSConfig.h文件、croutine.c、event_groups.c、list.c、queue.c、stream_buffer.c、tasks.c、timers.c、port.c、heap_4.c文件,按照上面的形式进行排列。
指定头文件的路径
刚刚已经将源码添加在工程项目中了,编译的时候需要为这些源文件指定头文件的路径,不然编译会报错的。具有头文件的目录分别是user文件夹、include文件夹、ARM_CM3文件夹。进行MDK的设定即可完成。如下图片的操作即可。
五、修改FreeRTOSConfig.h文件
增加头文件的引用
#include "stm32f10x.h"
将FreeRTOS中的xPortPendSVHandler和单片机的PendSV_Handler对应起来。
将FreeRTOS中的vPortSVCHandler和单片机的SVC_Handler对应起来。进行如下定义:
#define xPortPendSVHandler PendSV_Handler#define vPortSVCHandler SVC_Handler
六、修改stm32f10x_it.c文件
将void SVC_Handler(void)函数屏蔽,因为在第五部分已经进行了关联。
将void PendSV_Handler(void)函数屏蔽,因为在第五部分已经进行了关联。
添加心跳函数,首先需要进行引用外部函数操作:
externvoidxPortSysTickHandler(void);
在如下部分进行定义即可。
voidSysTick_Handler(void)
{
#if (INCLUDE_xTaskGetSchedulerState == 1 )
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
#endif /* INCLUDE_xTaskGetSchedulerState */
xPortSysTickHandler();
#if (INCLUDE_xTaskGetSchedulerState == 1 )
}
#endif /* INCLUDE_xTaskGetSchedulerState */
}
至此,大部分工作就已经做完了,下面以简单的创建任务及软件仿真的形式展现出来,软件仿真,仍然使用的是MDK自带的示波器功能进行仿真操作。
七、创建简单的任务
voidTask1_Entry(void *p_arg)
{
for(;;)
{
flag1 =1;
delay(100);
flag1=0;
delay(100);
}
}
voidTask2_Entry(void *p_arg)
{
for(;;)
{
flag2 =1;
delay(100);
flag2=0;
delay(100);
}
}
将任务添加到主循环中,添加的方法如下:
xTaskCreate((TaskFunction_t )Task2_Entry,
(constchar* )"task2",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_TASK_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
xTaskCreate((TaskFunction_t )Task1_Entry,
(constchar* )"task1",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
这个时候,我们进行仿真,看看效果如何?
我们调用出Logic Analyzer,可以使用软件仿真的形式查看变量的变化情况,明显的看出来flag1和flag2在任务1完成之后,紧跟着完成任务2,以此循环往复的进行着。
我们也可以进行穿插进行,需要增加手动任务切换函数taskYIELD();在每个任务后面增加这个函数,代码如下,我们重新看一下效果。
voidTask1_Entry(void *p_arg)
{
for(;;)
{
flag1 =1;
delay(100);
flag1=0;
delay(100);
taskYIELD();
}
}
voidTask2_Entry(void *p_arg)
{
for(;;)
{
flag2 =1;
delay(100);
flag2=0;
delay(100);
taskYIELD();
}
}
八、实时任务的体现
我们可以看见flag1的上升沿和flag2的上升沿不是在同一时间,这部分就要创建空闲任务,再通过vTaskDelay()函数实现阻塞延迟的操作。
这里不再赘述了,一起学习一起研究。
结:
任何的操作系统都是工具,只是减少基础代码的编写,上层的逻辑代码的实现,还是无法节省的,而FreeRTOS只是将程序员的底层工作简化,更加专注于逻辑功能方面的实现。
|
手把手开始第一次FreeRTOS 的应用,整体过程详细,适合小白上手实操。