前言
学习RTOS之前最重要的就是要学会将系统移植到单片机中,这里可以直接使用cubemx生成移植好的工程,也可以下载库来进行自己移植,这里我选择下载库来自己移植,因为这样可以配合Linux开发stm32单片机程序。
一、下载系统代码
首先打开FreeRTOS的官网这个是中文站点,所以速度很快,然后点击下载:
在下载里面不要最新的系统,这里我需要V9.0.0就可以了,因为高版本的增加了很多物联网相关的内容,对于我们现在的系统开发不太需要,所以这里点击更多下载
然后选择下面不带LTS的,LTS没有示例项目,有一些文件我们需要在示例工程中拿,然后需要转到github中去下载
来到GitHub中是最新版本,我们要找老版本需要点击Code
转去代码那里,然后找到V9.0.0的代码
来到了后在标签这找到V9.0.0
然后点击下载zip格式的文件
下载完成后就可以解压,解压完成就是下面这几个软件
可以看到有两个文件夹,一个是FreeRTOS
,另一个是FreeRTOS-Plus
,这两个是有区别的,第一个是内核,是我们需要的,第二个Plus的是在内核的基础上增加了一系列扩展组件和工具,提供了更丰富的功能和更高层次的抽象,例如,包含文件系统、TCP/IP 协议栈、USB 主机 / 设备栈、安全功能(如加密库)、图形用户界面(GUI)库等。如果做一些高级的东西可以用这个,但我们现在只是学习,选择第一个基础的就可以了。
打开第一个文件夹后会有三个文件夹,我们先看Source
文件夹,在Source
文件夹中存放的是内核源代码和对应的头文件
在Source
文件夹中有一个portable
这个是内核文件,其中内核文件是分平台的,这个平台是编译器的平台,比如我们用Keil,那就在这个文件夹中找到Keil进行移植就可以了,但是这里不能直接把Keil文件夹直接拿过去用,原因在移植的时候会说
然后在include
文件夹中存放的是对应的头文件
回到上一层,有一个Demo
文件夹,这个文件夹就是每个芯片所对应的示例工程,有一些文件我们需要在这个示例文件中
然后我们就可以开始工程的移植了。
二、移植工程
这里需要拿之前做好的标准库工程来进行改,只需要在做好的工程来新增文件就可以了,打开工程后点击这个三个正方形设置文件
在这里面新建一个freeRTOS
文件夹,在里面添加一下的.c
文件,我这为了工程的干净,不增加.h
文件了
然后点击Options
中点击C/C++
点击Include Paths
中的三个点,增加一下编译文件目录
需要添加的文件目录如下:
然后在main.c
中增加两个头文件,并且添加一个测试的内容,这里使用的是最小系统上的测试灯,所以需要进行一下初始化
然后编写一下控制函数
编写一下任务函数,记得这个任务函数的格式是void TaskName(void*)
然后在main.c
中创建任务并且进行任务的调度:
int main(){NVIC_SetPriorityGrouping(NVIC_PriorityGroup_4); // 设置中断优先级分组为第四组 这个是为了后面的定时器需要增加的Init_Led();xTaskCreate(LED_Test, "LED_Test", 128, NULL, 1, NULL); // 创建任务vTaskStartScheduler(); // 调度任务while(1){}
}
作为上面的操作后还不能进行测试,如果这样测试的话会导致在vTaskStartScheduler()
函数的位置卡死,因为还没有移植成功,需要先在freeRTOSConfig.h
文件中的最后面添加这三个宏定义:
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
#define vPortSVCHandler SVC_Handler
然后在stm32f10x_it.c
中需要注释一下这三个回调函数,因为这三个回调函数在系统中是进行了一下实现的,如果还没有,那会重复定义:
这样就可以编译并且运行测试了,可以看到LED灯在闪烁。
三、完整代码
#include "stm32f10x.h" // Device header
#include "freertos.h"
#include "task.h"void Init_Led(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);
}void LED_Cmd(uint8_t bit)
{if (bit == 1){GPIO_ResetBits(GPIOA, GPIO_Pin_5);}else if (bit == 0){GPIO_SetBits(GPIOA, GPIO_Pin_5);}
}void LED_Test(void* param)
{while(1){LED_Cmd(1);vTaskDelay(500);LED_Cmd(0);vTaskDelay(500);}
}int main(){NVIC_SetPriorityGrouping(NVIC_PriorityGroup_4); // 设置中断优先级分组为第四组Init_Led();xTaskCreate(LED_Test, "LED_Test", 128, NULL, 1, NULL); // 创建任务vTaskStartScheduler(); // 调度任务while(1){}
}
总结
这是一小步,但是系统学习和高级功能实现的一大步,好好搞一下就ok了。