freertos学习01-移植到gd32

1、freertos简介

1、freertos顾名思义最大的特点就是免费,已经有越来越多的厂商的示例代码都是用freertos,比如st。
2、其次,freertos的文件数量很少,较为精简。
3、freertos经过多年的发展,其市场占有率移植位居前列,稳定性已经得到了市场的认可

1、1 freertos特点

freertos是一个可以裁剪的小型实时操作系统。其重要的特点简述如下:

  • 内核支持抢占式,合作式和时间片调度,一般选择为抢占式
  • 任务数量不限
  • 任务优先级不限
  • 高效的软件定时器,这个用起来很爽
  • 堆栈溢出检测功能
  • 任务间通信方式为:信号量,互斥量,队列,数据流,消息等几种方式

2、freertos官网介绍

官网地址:https://freertos.org/
在这里插入图片描述
这个新页面比之前老的现代化不少了。
在这里插入图片描述
下载上面的最新版就行了,下面的长期支持版,里面加了很多aiot的组件,学习的话,先用上面的版本,较为简单纯粹。
在这里插入图片描述
下载完成后解压,目录如上图,其中需要用的是FreeRTOS这个文件夹,-plus的这里面实际上也是freertos增加了一些第三方组件。FreeRTOS这个文件夹下就是淡出的内核,使用这个文件夹就行了。

打开文件夹
在这里插入图片描述
可以看到source文件下放的就是内核源码。include这里面明显是头文件,接下来看下portable文件夹下的内容。
在这里插入图片描述
这里面存放的是与编译器以及硬件相关的一些内容。由于我用的是keil编译器,所以需要用到上述三个文件夹

Keil :与keil相关的
MemMang:存放的是内存管理相关的代码
RVDS:存放的是与mcu内核相关的内容

在这里插入图片描述
具体可以看到keil文件夹下就只有一句话,叫我们看RVDS文件,RVDS文件夹下面存放mcu内核相关,看的cm3 cm4是不是很熟悉,stm32f1,stm32f4。

大致的freertos相关介绍就简单介绍到这里,下面开始移植操作。

2、移植freertos

我目前用到的是gd32f107(stm32太贵了,都切国产芯片了,用起来都差不多)。下面就以gd32f107为例
前期准备:

1.keil 工程文件
2.freertos源码,就是上文介绍的

2.1 新建freertos目录

打开功能目录,新建一个freertos文件夹
在这里插入图片描述

2.2拷贝源码

间源码FreeRTOS文件夹下面的Source文件夹下的文件全部拷贝到2.1工程目录下面新建的freertos文件夹
在这里插入图片描述

2.3删除多余文件

打开工程目录下的freertos文件下的portable,只保留Keil ,MenmMang,RVDS文件夹,其他文件夹全部删除。由于keil文件下就一句话,我就没有保留keil文件夹。删除后的文件夹目录如下图;
在这里插入图片描述
下面就要打开工程文件进行操作。

2.4配置工程

打开工程文件。
在这里插入图片描述
在工程下面新建两个组,Freertos,Freertos_PORTABLE。
双击Freertos组,添加文件,如下图操作。
在这里插入图片描述
双击Freertos_PORTABLE添加文件
添加内存管理:
在这里插入图片描述
定位到MenMang文件夹,添加heap_4。基本能满足部分情况下的使用需求,具体却别见https://www.freertos.org/a00111.html介绍
在这里插入图片描述
heap4支持动态和静态内存分配堆内存。
注意:要在FreeRTOSConfig.h,打开configAPPLICATION_ALLOCATED_HEAP宏定义,才能使能动态内存分配

添加port文件:
由于我用的gd32f107所以添加的CM3中的port,其他内核要添加对应文件夹下面的port.c
定位到RVDS->ARM_CM3文件夹,添加port.c
在这里插入图片描述
添加索引,按下图操作,添加项目目录下的Freertos\include,Freertos\portable\RVDS\ARM_CM3
在这里插入图片描述
到这里源码移植就完成了,现在不要想着编译,编译出来会报错错误的,还需要对源码进行一些调整。

2.5源码调整

2.4中提到了FreeRTOSConfig.h文件,这个文件在源码中是没有的,需要使用者自己创建,这个头文件的作用是对freertos进行剪裁,确定需要使用哪些功能。
哪里能找到现成的呢,在源码目录FreeRTOS\Demo下面放着的都是各个芯片的示例工程
在这里插入图片描述
打开其中的stm32f103_keil目录,这里面就有FreeRTOSConfig.h文件,接下来我们将这个文件拷贝到工程目录的include文件夹,(这个头文件可以放到其他地方,看个人喜好,为了便于管理,将其放到了Freertos文件下的include文件夹)
在这里插入图片描述

3、编译

上述步骤完成后,编译发现存在错误,显示INCLUDE_xTaskGetCurrentTaskHandle未定义
在这里插入图片描述
这就需要在FreeRTOSConfig.h中使能该功能

#define configUSE_MUTEXES						1 

添加上面的宏定义即可编译成功
在这里插入图片描述
虽然这个时候是编译成功了,但是freertos并没有运行。Freertos这些操作系统都系统时钟提供节拍,所以还需要对项目进行调整。

4、运行freertos

freertos运行要依靠mcu的系统时钟提供节拍,一般系统时钟周期设置为1ms。

4.1添加时钟节拍

在系统时钟中断函数中添加如下内容,对于gd32f107,其系统时钟定时器的中断函数位于gd32f107_it.c中
按照如下方式修改:

extern void xPortSysTickHandler( void );
void SysTick_Handler(void)
{
	if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
	{
	xPortSysTickHandler();
	}
    delay_decrement();
}

在FreeRTOSConfig.h添加

#define configUSE_TIMERS				        1                               //为1时启用软件定时器
#define configTIMER_TASK_PRIORITY		        (configMAX_PRIORITIES-1)        //软件定时器优先级
#define configTIMER_QUEUE_LENGTH		        5                               //软件定时器队列长度
#define configTIMER_TASK_STACK_DEPTH	        (configMINIMAL_STACK_SIZE*2)    //软件定时器任务堆栈大小

4.2设置异常处理

将gd32f107_it.c中的这两个异常处理函数屏蔽掉
//void PendSV_Handler(void)
//void SVC_Handler(void)
因为这两个异常处理函数在port.c中被重新定义了。

最后编译没有错误。

4.3测试

接下来添加一段测试代码,看下freertos的正常运行。
新建一个u_task.c文件,后续所有的测试问题都放到这里。
新建三个任务

  • 启动任务:负责启动其他所有任务后,删除掉自身
  • 任务1:控制led灯闪烁
  • 任务2:控制串口打印输出

代码如下

#include "FreeRTOS.h"
#include "task.h"
#include "usart.h"
#include "gpio.h"
#include "gd32f10x.h"
#include "stdio.h"
TaskHandle_t start_task_Handler;
void start_task(void *pvParameters);
TaskHandle_t task1_Handler;
void task1(void *pvParameters);

TaskHandle_t task2_Handler;
void task2(void *pvParameters);

TaskHandle_t task3_Handler;
void task3(void *pvParameters);
void start_os(void)
{
	xTaskCreate(start_task,"start_task",128,NULL,1,&start_task_Handler);
	vTaskStartScheduler();
}



void start_task(void *pvParameters)
{
	taskENTER_CRITICAL();
	xTaskCreate(task1,"task1",128,NULL,2,&task1_Handler);
	xTaskCreate(task2,"task2",128,NULL,3,&task2_Handler);
//	xTaskCreate(task3,"task3",128,NULL,4,&task3_Handler);
	vTaskDelete(start_task_Handler);
	taskEXIT_CRITICAL();
}

void task1(void *pvParameters)
{
	init_gpio();
	while(1)
	{
		gpio_bit_write(GPIOC,GPIO_PIN_5,gpio_output_bit_get(GPIOC,GPIO_PIN_5)?0:1);
		vTaskDelay(500);
	}
	
}


void task2(void *pvParameters)
{
	init_usart3();
	while(1)
	{
		printf("hello \r\n");
		vTaskDelay(500);
	}
	
}

在main.c中调用start_os()函数。

extern void start_os(void);

int main(void)
{
    systick_config();
	start_os();
}

编译下载运行,可以看到串口已经在输出了
在这里插入图片描述
运行正常。

4.4新建任务解析

新建步骤
1、先定义任务句柄

TaskHandle_t start_task_Handler

2、定义任务

void start_task(void *pvParameters)
{
	while(1)
	{
		
		vTaskDelay(500);
	}
}

每个任务都有一个while主循环,每个循环中要用vTaskDelay来确定任务的执行周期。vTaskDelay是相对定时,后面还有绝对定时函数,后面用到再进行说明。

3、创建任务

xTaskCreate(start_task,"start_task",128,NULL,2,&task1_Handler);

函数的原型如下:

    BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                            const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                            const configSTACK_DEPTH_TYPE usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask )

其中:

  • pxTaskCode:任务函数的名称
  • pcName:定义一个能看到的任务名称,为字符串,可以与任务函数不同。后续可以通过xTaskGetHandle()函数来获取到这个函数的句柄。长度定义在configMAX_TASK_NAME_LEN,默认是16字节
  • usStackDepth:定义栈空间大小,configSTACK_DEPTH_TYPE默认定义的是uint16_t,也就是说,当usStackDepth=100实际的堆栈空间大小为200字节。usStackDepth最小值为configMINIMAL_STACK_SIZE,默认定义是128。所以每个任务堆栈最小为256字节
  • pvParameters:传递给任务的参数
  • uxPriority:任务优先级,范围 0~ configMAX_PRIORITIES-1。
  • pxCreatedTask :任务句柄

返回值为

0:pdPASS创建成功
-1:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY堆内存不足

任务创建相关函数主要有4个

xTaskCreate() 动态创建一个任务
xTaskCreateStatic() 静态创建一个任务
xTaskCreateRestricted() 创建一个动态MPU(Memory Protection Unit),一般不使用
vTaskDelete() 删除任务

任务创建相关函数,一般使用xTaskCreate 和vTaskDelete函数,其他两个一般较少使用。后面示例主要以这两个函数为主。

  • 10
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值