目录
1. 模版准备
1.1 STM32模版准备
首先,我们需要找一个模版,这里我以江科大的工程模版为例,我将工程模版文件重命名了一下:
我给它设了0积分,但是有时会跳,可以直接去江协的B站下面链接去下载:
1.2 FreeRTOS模版准备
可参考:
这个下载文件不好附链接,以上链接的“1.3 FreeRTOS资料获取”末尾讲了原因,文件太多了,上传和下载特别慢,并且下载完解压也不好解压,要解压的话可能要喜提360全家桶了,我们这里主要学习FreeRTOS的编程思路,以STM32为例,可以先将不需要的文件移除出去,文末会放一个移植好的链接。
想要自己移植也可以,我给上传到百度网盘可自行提取下载:
链接: https://pan.baidu.com/s/1iWVua_87k73eg2RbYMIHow?pwd=y7c6
提取码: y7c6
2. Source文件移植
首先,我们现在STM32的工程模版文件夹下,创建一个新的文件夹FreeRTOS用于存放FreeRTOS相关文件:
找到FreeRTOS官方源码文件:
点击,找到“FreeRTOS”文件:
点击,找到“Source”文件:
点击,将该文件目录下的所有文件全部复制到自己刚刚创建的“FreeRTOS”文件目录下:
找到自己的工程模版,点击“portable”文件:
找到“Keil”,“MemMang”,“RVDS”除了这三个文件,将该文件夹下所有文件全部删除掉:
(PS:“portable”文件,其是针对不同芯片,不同端口的一些文件,这里是根据使用Keil的环境进行选择的,若是其他环境,需要根据自己使用环境进行更改环境进行配置)
3. 添加文件组
移植完后,返回打开工程:
此时并没有FreeRTOS的工程文件:
需要手动添加,如下图③中命名可随意,按照自己命名习惯进行命名:
4. 添加源码文件
如图操作进行添加:
除去文件夹文件,将.c文件全部选中,点击“Add”:
点击“OK”:
可以看到添加完成:
5. 添加接口文件
如下图,进行添加接口文件
找到“FreeRTOS”文件夹:
点击,找到“portable”文件夹:
点击,找到“MemMang”文件夹:
点击,找到“heap_4.c”文件,点击“Add”:
返回上一个文件夹,找到“RVDS”文件夹:
点击,根据自己使用的芯片内核挑选相应的内核文件,这里我使用的是STM32F103C8T6是M3内核的所以选择“ARM_CM3”:
点击,添加:
点击OK:
可以看出添加完成:
6. 添加路径
如图所示步骤,添加头文件目录“include”:
添加ARM_CM3(因为使用的是STM32F103C8T6是M3内核的,如果是其他内核的这里自行更改内核):
7. 添加头文件
完成以上步骤,点击编译会发现,报错显示没有FreeRTOS的头文件:
此时需要找到官方源文件下的Demo文件夹:
点击找到“CORTEX_STM32F103_Keil”:
点击找到“FreeRTOSConfig.h”:
将其复制粘贴到,我们自己创建的模版FreeRTOS文件夹下,include文件夹内:
此时在编译不会在发生报错:
这里有一点,需要注意的是Stm32F103C8T6的SRAM仅有20KB,而我们移植的FreeRTOS默认占用了17KB来作为自己的堆,所以我们写不了多少程序就会出现内存超出无法编译的情况。
解决方法将17改为10:
8. 中断文件修改
在FreeRTOSConfig.h代码中添加如下三行代码:
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define xPortSysTickHandler SysTick_Handler
此时编译会发现与stm32f10x_it.c的函数声明冲突了:
在找到stm32f10x_it.c文件,找到如下三个函数:
void SVC_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
全部注释掉:
此时在编译,没有报错:
9. 代码测试
9.1 FreeRTOS基本操作的头文件
#include "freertos.h"
#include "task.h"
#include "timers.h"
9.2 初始化GPIO
void Led_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
9.3 任务函数
只是一个简单的任务函数:
void Led_Task(void *pvParams)
{
Led_Init();
while(1)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
vTaskDelay(500);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
vTaskDelay(500);
}
}
9.4 主函数
创建任务并启动调度:
int main(void)
{
xTaskCreate(Led_Task,"ledtask",128,NULL,12,NULL);
vTaskStartScheduler();
}
9.5 完整代码
main.c完整代码:
#include "stm32f10x.h" // Device header
#include "freertos.h"
#include "task.h"
#include "timers.h"
void Led_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void Led_Task(void *pvParams)
{
Led_Init();
while(1)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
vTaskDelay(500);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
vTaskDelay(500);
}
}
int main(void)
{
xTaskCreate(Led_Task,"ledtask",128,NULL,12,NULL);
vTaskStartScheduler();
}
功能为PA0的LED灯闪烁。
完整工程代码: