【GD32】FreeRTOS实时操作系统移植(GD32F470ZGT6)

news2024/9/20 14:31:15

1. 简介

        在日常的应用开发项目中,常常需要单片机具有处理多种任务的需求,如果使用裸机开发那么肯定是不现实的,因为受限于IO与处理器的巨大速度差异,在裸机下处理器常常要等待当前IO操作完成才能进行下一个任务,效率大打折扣。

        因此使用实时操作系统成为首选,市面上比较火的的实时操作系统有很多,像这里要介绍的FreeRTOS就是其中之一。FreeRTOS可以说是非常老牌的实时操作系统了,发布至今已经有十几年了,但受欢迎程度至今依然非常高,可以说是初学者必学的第一个RTOS系统。

        FreeRTOS目前是被亚马逊收购了,收购后主要的改变就是加入了亚马逊的AWS物联网框架,不过我们只需要移植内核就够了。更多的文档可以在FreeRTOS官网上找到。

2. 移植

        移植的FreeRTOS版本为FreeRTOS 202406.01 LTS

2.1 添加文件

        下载源码后解压,进入“FreeRTOS-Kernel”这个文件夹,里面就是内核源码,把它复制到项目的根目录下。

        之后在Keil中添加对应的文件。首先是导入源码根目录的所有.c文件;然后进入portable ->MemMang这个文件夹,里面存放的是一些内存管理相关的代码,每一个文件代表了一种内存管理方式,所以并不是全部都要导入,一般来说导入heap_4.c,这个文件代表使用硬件堆内存进行内存管理,如果你使用的是外部RAM,那么应该导入heap_5.c,它可以允许外部RAM分配。最后,如果你的使用AC5编译器,那么下一步要导入RVDS -> ARM_CM4F中的.c文件;如果你使用的是AC6编译器,那么导入GCC -> ARM_CM4F中的.c文件

        所有导入的文件如下所示。

        当然还要添加头文件路径,我使用的是AC6编译器,所以路径添加如下。

        FreeRTOS提供了丰富的选项给用户进行内核的裁切,在examples -> template_configuration下的FreeRTOSConfig.h文件中。里面的配置有大几百项,都有详细的说明,只不过是全英文的,所以下面给一个我使用的精简版带中文注释的配置文件。

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#include "gd32f4xx.h"

#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
    #include <stdint.h>
    extern uint32_t SystemCoreClock;
#endif

/* 断言 */
#include <stdio.h>
#define vAssertCalled(char, int)                    printf("Error:%s,%d\r\n", char, int)
#define configASSERT(x) if((x)==0)                  vAssertCalled(__FILE__, __LINE__)

#define configUSE_PREEMPTION                        1

/* 使用时间片调度 */
#define configUSE_TIME_SLICING                      1		
/* 优化的任务调度算法 */
#define configUSE_PORT_OPTIMISED_TASK_SELECTION	    1                       
/* 低功耗内核定时器 */
#define configUSE_TICKLESS_IDLE                     0   
/* 处理器时钟频率 */
#define configCPU_CLOCK_HZ                          (SystemCoreClock)
/* 每秒TICK数 */
#define configTICK_RATE_HZ                          (( TickType_t )1000)
/* 最大优先级数 */
#define configMAX_PRIORITIES                        (32)
/* 最小任务栈空间 */
#define configMINIMAL_STACK_SIZE                    ((unsigned short)128)
/* 最大任务名长度 */
#define configMAX_TASK_NAME_LEN                     (16)
/* 定时器宽度 */
#define configTICK_TYPE_WIDTH_IN_BITS               TICK_TYPE_WIDTH_32_BITS
/* 空闲任务让度 */
#define configIDLE_SHOULD_YIELD                     0
/* 使用任务队列 */
#define configUSE_QUEUE_SETS                        0    
/* 使用任务通知 */
#define configUSE_TASK_NOTIFICATIONS                1   
/* 使用互斥量 */
#define configUSE_MUTEXES						    0    
/* 使用递归互斥量 */
#define configUSE_RECURSIVE_MUTEXES                 0   
/* 使用计数信号量 */
#define configUSE_COUNTING_SEMAPHORES               0
/* 使用应用任务标签 */
#define configUSE_APPLICATION_TASK_TAG              0
                      
/* 使用动态任务创建 */
#define configSUPPORT_DYNAMIC_ALLOCATION            1    
/* 使用静态任务创建 */
#define configSUPPORT_STATIC_ALLOCATION             0					
/* 堆空间大小 */
#define configTOTAL_HEAP_SIZE                       ((size_t)(36*1024))    

/* 使用空闲钩子 */
#define configUSE_IDLE_HOOK                         0      
/* 使用tick钩子 */
#define configUSE_TICK_HOOK                         0           
/* 使用内存空间分配失败钩子 */
#define configUSE_MALLOC_FAILED_HOOK                0 
/* 堆溢出检查 */
#define configCHECK_FOR_STACK_OVERFLOW              0   

/* 创建运行状态 */
#define configGENERATE_RUN_TIME_STATS               0             
/* 使用跟踪功能 */
#define configUSE_TRACE_FACILITY                    0
/* 使用状态格式化函数 */
#define configUSE_STATS_FORMATTING_FUNCTIONS        0

#if ( configUSE_TRACE_FACILITY == 1 )
#include "trcRecorder.h"
#endif

/* 使用协程 */                                                                        
#define configUSE_CO_ROUTINES                       0                 
/* 协程任务优先级 */
#define configMAX_CO_ROUTINE_PRIORITIES             ( 2 )                   

/* 使用定时器 */
#define configUSE_TIMERS				            0                              
/* 定时器任务优先级 */
#define configTIMER_TASK_PRIORITY                   (configMAX_PRIORITIES-1)        
/* 定时器队列长度 */
#define configTIMER_QUEUE_LENGTH                    10                               
/* 定时器任务栈空间 */
#define configTIMER_TASK_STACK_DEPTH                (configMINIMAL_STACK_SIZE*2)    

/* 获取任务状态函数 */
#define INCLUDE_xTaskGetSchedulerState              1
#define INCLUDE_eTaskGetState                       1
/* 设置任务优先级函数 */
#define INCLUDE_vTaskPrioritySet                    1
/* 获取任务优先级函数 */
#define INCLUDE_uxTaskPriorityGet                   1
/* 删除任务函数 */
#define INCLUDE_vTaskDelete                         1
/* 资源释放函数 */
#define INCLUDE_vTaskCleanUpResources               1
/* 任务挂起函数 */
#define INCLUDE_vTaskSuspend                        1
/* 延时函数 */
#define INCLUDE_vTaskDelayUntil                     1
#define INCLUDE_vTaskDelay                          1
/*  */
#define INCLUDE_xTimerPendFunctionCall              0
/* 获取当前任务句柄函数 */
#define INCLUDE_xTaskGetCurrentTaskHandle           1
/*  */
#define INCLUDE_uxTaskGetStackHighWaterMark         0
/* 获取空闲任务句柄 */
#define INCLUDE_xTaskGetIdleTaskHandle              0

/* 任务优先级宽度 */
#ifdef __NVIC_PRIO_BITS
	#define configPRIO_BITS                         __NVIC_PRIO_BITS
#else
	#define configPRIO_BITS                         4                  
#endif
/* 内核优先级数 */
#define configKERNEL_INTERRUPT_PRIORITY             ( 15 << (8 - configPRIO_BITS) )	/* 240 */
/* 系统优先级数 */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY        ( 5 << (8 - configPRIO_BITS) )  /* 80 */

/* 系统中断移植 */
#define xPortPendSVHandler                          PendSV_Handler
#define vPortSVCHandler                             SVC_Handler

#endif /* FREERTOS_CONFIG_H */

2.2 代码移植

        导入文件后,还需要对原来的代码进行一些调整。

        首先,以前我们需要自己实现SysTick定时,但FreeRTOS内部已经帮我们实现了,所以SysTick的中断需改写成下面。

extern void xPortSysTickHandler(void);
void SysTick_Handler(void)
{	
    #if (INCLUDE_xTaskGetSchedulerState  == 1 )
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
    {
    #endif  /* INCLUDE_xTaskGetSchedulerState */  
        xPortSysTickHandler();
    #if (INCLUDE_xTaskGetSchedulerState  == 1 )
    }
    #endif  /* INCLUDE_xTaskGetSchedulerState */
}

        另外,实时操作系统的运行是依靠PendSV和SVC这两个中断的,FreeRTOS内部有对应的代码实现,因此我们需要在之前的文件中注释掉这两个中断的实现。

        做完这些步骤以后,项目正常来说就能编译成功了。

2.3 测试例程

        简单写一个点灯例程测试FreeRTOS的运行。

static void led_init(void)
{
	rcu_periph_clock_enable(RCU_GPIOE);
	gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
	gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
}

static void led_task(void* args)
{
    led_init();
    
	for(;;)
	{
		gpio_bit_set(GPIOE, GPIO_PIN_3);
		printf("LED OFF\n");
		vTaskDelay(1000 / portTICK_PERIOD_MS);
		gpio_bit_reset(GPIOE, GPIO_PIN_3);
		printf("LED ON\n");
		vTaskDelay(1000 / portTICK_PERIOD_MS);
	}
}

int main(void)
{	
    nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
	DEBUG_Init();
	xTaskCreate(led_task, "InitTask", 1024, NULL, 5, NULL);
	vTaskStartScheduler();
    while(1);
}

        首先把中断组设成4位抢占位,这个非常重要,不然在调用含ISP结尾的API时可能会出问题。

        调xTaskCreate创建任务,第一个参数是任务函数指针;第二个参数是任务的名字;第三个参数是任务栈空间,如果任务的调用深度越深和里面定义的变量越多,那么这个就要对应的设大点,不然会导致栈溢出;第四个参数是用户数据指针,如果要传数据给任务就可以设置;第五个参数是任务的优先级,数字越大优先级越高,这个跟单片机的优先级逻辑是相反的;第六个参数是任务句柄,如果不需要获取任务的句柄那么可以传空指针。

        调vTaskStartScheduler启动任务调度。

        一般来说,在led_task任务函数里面,先初始化LED灯,然后在死循环里面每隔一秒改变一次灯的状态,使用vTaskDelay函数进行延时,里面的数要除portTICK_PERIOD_MS这个宏转成毫秒值

2.4 运行效果

        下载后应该能看到板子上的灯闪烁,串口打印如下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2073304.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

亦菲喊你来学机器学习(11) --回归树算法

文章目录 回归树回归树结构回归树的工作原理优点与缺点构建回归树模型回归树模型参数介绍训练模型测试模型 总结 回归树 决策树是一种常用的机器学习算法&#xff0c;广泛应用于分类和回归任务中。当决策树用于回归任务时&#xff0c;我们称之为回归树&#xff08;Regression …

零基础5分钟上手亚马逊云科技 - 网络安全分析最佳实践

简介&#xff1a; 欢迎来到小李哥全新亚马逊云科技AWS云计算知识学习系列&#xff0c;适用于任何无云计算或者亚马逊云科技技术背景的开发者&#xff0c;通过这篇文章大家零基础5分钟就能完全学会亚马逊云科技一个经典的服务开发架构方案。 我会每天介绍一个基于亚马逊云科技…

【逐行注释】基于CV/CT模型的IMM|MATLAB程序|源代码复制后即可运行,无需下载

订阅专栏后可以直接查看完整的源代码(和注释),无需付费下载或其他的操作。代码复制到MATLAB上面可以得到和我一样的运行结果。 文章目录 程序概述完整代码与逐行注释运行结果解释按模块分析代码程序概述 基于EKF的多模型交互。以CV和CT两个模型进行交互,这里对代码进行逐…

Django后台管理Xadmin使用DjangoUeditor富文本编辑器

Django后台管理Xadmin使用DjangoUeditor富文本编辑器 一、下载 点击github下载 https://github.com/twz915/DjangoUeditor3 1、下载完后解压到跟xadmin同一层级目录: 2、解压后名称可能为DjangoUeditor3-master,需要改为DjangoUeditor 3、进入DjangoUeditor目录,把Djan…

Visiual Studio如何添加C语言的依赖和一些快捷键

Debug 和 Release 项目输出设置 Debug: 调试版本&#xff0c;包含调试信息&#xff0c;并且把进行任何优化&#xff0c;便于程序员调试。Debug模式下生成两个文件&#xff0c;除了 .exe 或者 .dll文件外&#xff0c;还有一个 .pdb 文件&#xff0c;这个文件记录了代码中断点等…

查找数学类文献的专业数据库有哪些 如何获取这些数据库资源

一、MathSciNet&#xff08;美国数学会《数学评论》&#xff09; MathSciNet数据库是美国数学学会出版的《数学评论》Mathematical Reviews和Current Mathematical Publications的网络版&#xff0c;包含《数学评论》自1940年出版以来的所有评论文章&#xff0c;包括期刊、图书…

【Node】【4】事件循环和EventEmitter类

事件循环 事件驱动&#xff1a;node中程序的执行是由事件的发生和相应的事件处理器&#xff08;eventHandler&#xff09;来驱动的编程范式。 程序监听并响应发生的事件。每个异步事件都生成一个事件观察者&#xff0c;在执行某个事件&#xff08;主题&#xff09;结束的时候…

SVN项目的文件泄露分析和漏洞修复

说明:本文仅是用于学习分析自己搭建的SVN漏洞内容和原理,请勿用在非法途径上,违者后果自负,与笔者无关;本文开始前请认真详细学习《‌中华人民共和国网络安全法》‌及其相关法规内容【学法时习之丨网络安全在身边一图了解网络安全法_中央网络安全和信息化委员会办公室】 …

信息学奥赛初赛天天练-75-NOIP2016普及组-完善程序-二分答案、二分查找、贪心算法、贪心策略

文章PDF链接: https://pan.baidu.com/s/1SVcGU_rApvoUWrUoviPCiA?pwdht2j 提取码: ht2j 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 1 完善程序 (单选题 &#xff0c;每小题3分&#xff0c;共30分) 郊游活动 有 n名同学参加学校组织的郊游活动&#xff0c…

gateway的学习

1.网关的作用 1.负载均衡 2.过滤器的使用 1.通过配置文件实现的过滤器 2.代码逻辑层面实现全局过滤器 //全局过滤器代码逻辑实现 Component //Order(1):注解配置过滤器的执行顺序 public class GlobalFilter implements GatewayFilter, Ordered {/*** 处理当前请求&#xff0c;…

RocketMQ~高性能设计与实现(零拷贝技术)、多种集群模式

与Kafka类似&#xff0c;RocketMQ也使用了零拷贝技术、对于分区&#xff0c;其也有分队列的思维在。 零拷贝技术 传统的IO读写其实就是readwrite的操作&#xff0c;整个过程会分为如下几步 用户调用read()方法&#xff0c;开始读取数据&#xff0c;此时发生一次上下文从用户…

Storage:Keeping memories in the brain(存储:把记忆保存在大脑中)

Once you’ve encoded information, you now need to store it. Unfortunately, forgetting is a major part of how our brains work.Most of us can’t remember what we had for dinner Tuesday, three weeks ago.However, we can all remember our first kiss. 一旦完成了信…

工厂模式和策略模式的区别和各自的实现

工厂模式和策略模式是两种不同的设计模式&#xff0c;它们分别解决的是创建对象和定义算法家族的问题。 工厂模式 工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一&#xff0c;它提供了一种创建对象的方式&#xff0c;使得创建对象的过程与使…

如何发布年会通知?

在组织年会等重要活动时&#xff0c;确保每位参与者都能及时接收到通知至关重要。本文将指导您如何利用云分组平台发布年会通知&#xff0c;并通过查询功能为参与者提供座位号等信息。一、电脑端上传查询信息 1. 登录云分组官网 访问官网并通过微信扫码登录。2. 进入查询菜单 在…

通过因子分析识别消费者偏好的潜在因素的案例

因子分析是一种统计方法&#xff0c;用于研究变量之间的潜在关系。它是一种降维技术&#xff0c;通过识别较少数量的因子&#xff08;或称为维度、成分&#xff09;来解释多个观测变量之间的相关性。这些因子是不可观测的潜在变量&#xff0c;它们被认为是原始变量的潜在原因。…

厦门凯酷全科技有限公司抖音小店的新蓝海开启电商新篇章

在数字经济的浪潮中&#xff0c;电子商务以其独特的魅力和无限潜力&#xff0c;正以前所未有的速度改变着我们的消费方式和商业模式。作为这股浪潮中的佼佼者&#xff0c;厦门凯酷全科技有限公司凭借其敏锐的市场洞察力和前瞻性的战略布局&#xff0c;成功在抖音小店这一新兴平…

乐凡北斗卫星通信终端,多场景应用

北斗卫星通信终端在民生保障、抗险减灾、野外搜救、海洋渔业、交通运输、边境巡防等多个领域都有广阔的应用空间。在不同场景下&#xff0c;乐凡北斗卫星通信终端发挥着各自独特而关键的作用&#xff0c;其强大的定位功能和北斗三代短报文功能保障了信息的高效传递和任务的顺利…

Context-dependence:Why your environment matters(情境依赖:为什么环境很重要)

Consider an everyday situation:You get up from your desk to have a cup of tea.Once you arrive in the kitchen, you forget what you wanted.However, when you get back to your desk, you suddenly remember. 考虑一个日常会遇到的情况:你从桌旁起身想要倒杯茶&#xf…

内存管理篇-09伙伴系统初始化一:memblock管理

1.伙伴系统的初始化概述 硬件初始化&#xff1a;计算机加电后进行硬件检测。加载引导程序&#xff0c;将Linux内核加载到内存中。 内核初始化&#xff1a;内核被加载后开始初始化各个子系统。进行CPU架构相关的初始化。初始化内存控制器和其他设备驱动。 内存管理初始化&…

Chat App 项目之解析(四)

Chat App 项目介绍与解析&#xff08;一&#xff09;-CSDN博客文章浏览阅读76次。Chat App 是一个实时聊天应用程序&#xff0c;旨在为用户提供一个简单、直观的聊天平台。该应用程序不仅支持普通用户的注册和登录&#xff0c;还提供了管理员登录功能&#xff0c;以便管理员可以…