FreeRTOS的一些知识点

一、临界区

  1. 临界区是指一段代码,在执行过程中不允许被中断(例如:任务切换或硬件中断)。
  2. 临界区的作用是确保对共享资源的操作是原子性的,避免多个任务或中断同时操作共享资源导致数据错误。
  3. 对于实时系统来说,进入临界区时需要快速完成操作,以免影响系统的实时性。
  4. 在 FreeRTOS 中,可以通过以下方式进入和退出临界区:
    - 进入临界区:使用 taskENTER_CRITICAL() 函数,FreeRTOS 会关闭所有中断,暂停任务调度。这确保在临界区内的代码执行过程中,不会有其他任务或中断打断当前的任务。
    - 退出临界区:使用 taskEXIT_CRITICAL() 函数恢复中断和任务调度。
  5. 注意: 在临界区内应避免进行长时间的操作,尤其是像延时、等待等操作,因为这可能会影响系统的实时性能。理想情况下,进入临界区后,应尽快完成任务并退出临界区。
  6. 中断中进入临界区
    • 中断中也可以使用临界区来保证原子操作
UBaseType_t uxSavedInterruptStatus;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); // 关闭中断
// 临界区代码
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus); // 恢复中断
- 举例说明
int __io_putchar(int ch)
{UBaseType_t uxSavedInterruptStatus;uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1);portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);return ch;
}

二、时间管理

  1. FreeRTOS 的时间管理基于硬件定时器 SysTick,这是一个硬件定时器,它每隔 1 毫秒产生一次中断,用来增加系统的时间计数 ticks。
  2. 获取当前时间
    • xTaskGetTickCount():用于普通任务获取当前系统的 tick 计数,即系统启动后经过的时间(以 tick 为单位)。1 个 tick 通常等于 1 毫秒,具体取决于配置。
    • xTaskGetTickCountFromISR():在中断服务程序(ISR)中使用的版本,用来获取当前 tick 值。
  3. 任务睡眠
    • FreeRTOS 提供了 osDelay() 函数,可以让任务暂停执行一段时间
    • 但是,osDelay() 可能不够精确,因为它会让任务在执行完工作后再睡眠指定时间,导致延迟时间包括了任务执行时间。
  4. 更精确的延时
    • FreeRTOS 提供了 vTaskDelayUntil() 函数,它可以保证任务每隔固定时间间隔执行
TickType_t lastWakeTime = xTaskGetTickCount();
for (;;)
{do_something();vTaskDelayUntil(&lastWakeTime, 500); // 保证每隔 500 ticks 执行一次
}vTaskDelayUntil() 基于上一次唤醒时间来计算下次睡眠的时长,因此能保证任务周期精确,而不会受任务处理时间的影响。

三、堆栈管理

  1. 在嵌入式系统中,内存分为多个区域,包括代码段、全局变量区、堆区和栈区。
  • 栈:用于存储局部变量、函数参数、返回地址等。栈的空间是有限的。
  • 堆:用于动态分配的内存,例如通过 malloc() 分配的空间。
  1. 在裸机开发中(没有操作系统的情况下),堆和栈是共享的。在 FreeRTOS 中,每个任务都有自己独立的堆栈空间,而这些堆栈空间是从系统的堆中分配的。
  2. freeRTOS的栈空间 从堆区分配
  3. 栈: 自动从heap分配,自动释放不需要我们关心
  4. 在 STM32 开发中,使用 CubeIDE 配置 FreeRTOS 堆大小。可以通过以下路径设置堆大小:
CubeIDE(硬件配置界面) -> System View -> Middleware -> FreeRTOS -> Config Parameters -> TOTAL_HEAP_SIZE
要填入一个完整的数,不要 +-*/ ,而且要随机一点,不要 是512的整数倍
  1. 动态内存分配策略
  • FreeRTOS 提供了四种内存分配策略,常用的是带有碎片整理功能的动态分配策略。即 FreeRTOS 提供了 pvPortMalloc() 和 vPortFree() 这两个函数,类似于标准 C 的 malloc() 和 free(),用来动态分配和释放内存。
  1. 如何检查剩余堆内存
    • 可以使用 xPortGetMinimumEverFreeHeapSize() 函数来获取最小时刻的堆剩余空间。如果堆内存过小,说明系统内存分配有风险,可能需要调整配置。

四. 调度策略

  1. FreeRTOS 采用的是 抢占式调度 和 时间片轮转 的结合:
  • 抢占式:只要有更高优先级的任务,系统会立即中断当前任务,执行高优先级任务。
  • 时间片轮转:当多个任务的优先级相同时,系统会给每个任务分配一个固定的时间片,轮流执行。
  1. 任务的切换时机: 通常在中断发生时,系统会检查是否有更高优先级的任务需要运行,如果有则进行任务切换。

五、FreeRTOS调试

  1. volatile 修饰共享变量:如果多个任务共享某个变量,为了确保每次都从内存中读取最新的值,而不是使用缓存,应该使用 volatile 关键字修饰变量。
  2. 中断优先级的设置:使用 FreeRTOS 时,中断的优先级需要降低到一定范围内,否则可能与 FreeRTOS 的调度机制产生冲突。可以在 CubeIDE 中配置中断优先级。
  3. 初始化顺序:在 main() 函数中,初始化各个模块时要注意顺序。例如,FreeRTOS 的启动必须在所有硬件初始化完成后进行。
  4. 中断中的 API 调用:在中断服务程序中调用 FreeRTOS 的 API 时,要使用以 FromISR 结尾的函数,例如 xQueueSendFromISR() 等。
  5. 断言与错误处理:FreeRTOS 提供了一个断言机制,可以在出现错误时触发断言。例如,在 FreeRTOSConfig.h 中定义:
#define configASSERT(x) if ((x) == 0) { taskDISABLE_INTERRUPTS(); printf("%s-%d\r\n", __func__, __LINE__); for (;;); }当系统检测到错误时,会进入断言并输出错误信息,帮助定位问题
  1. 栈和堆溢出检测
  • 栈溢出检测: FreeRTOS 提供了栈溢出检测功能,当某个任务的栈溢出时,会调用栈溢出钩子函数:
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{printf("Stack overflow in task: %s\r\n", pcTaskName);// 这里可以添加处理代码,例如重启系统或停止任务
}要启用栈溢出检测功能,需要设置 configCHECK_FOR_STACK_OVERFLOW = 2。
cubide->middleware-->config parameter--> configCHECK_FOR_STACK_OVERFLOW -->option 2
  • FreeRTOS 也支持堆溢出检测。当内存分配失败时,系统会调用堆溢出钩子函数
void vApplicationMallocFailedHook(void)
{printf("Heap memory allocation failed!\r\n");// 这里可以添加处理代码
}
启用堆溢出检测
configUSE_MALLOC_FAILED_HOOK=1
方法:cubide->middleware-->config parameter-->configUSE_MALLOC_FAILED_HOOK=1

六、异常处理

  1. 在 FreeRTOS 和嵌入式系统中,异常(如中断错误、数据异常、硬件异常等)是不可避免的。为了方便调试和快速定位问题,我们可以在常见的异常处理函数中加上打印日志。
  2. STM32 的异常处理函数通常实现在 core/stm32f1xx_it.c 文件中,包括以下几个关键函数:
    • HardFault_Handler:处理硬件错误(例如非法内存访问)。
    • MemManage_Handler:内存管理错误(例如堆栈溢出)。
    • UsageFault_Handler:处理非法指令、未对齐的内存访问等错误。
    • DebugMon_Handler:用于监控调试事件。
  3. 为了调试这些异常,可以在每个处理函数中添加调试打印,以便在异常发生时输出详细的错误信息,例如当前的函数名和出错的位置。
void HardFault_Handler(void)
{printf("HardFault occurred!\n");while (1); // 陷入死循环,方便调试
}void MemManage_Handler(void)
{printf("Memory management fault!\n");while (1);
}void UsageFault_Handler(void)
{printf("Usage fault!\n");while (1);
}

七、堆栈信息打印

  1. 在 FreeRTOS 中,每个任务都有其独立的栈空间。如果某个任务的栈空间不足,会引发栈溢出,导致系统崩溃。因此,监控任务的栈使用情况非常重要。
  2. 步骤1:获取任务栈的剩余大小
    • 可以使用 uxTaskGetStackHighWaterMark() 函数获取某个任务的栈剩余量,单位是 4 字节。这个函数会返回任务曾经使用过的最小栈空间,即可以用来评估是否需要调整任务的栈大小。
UBaseType_t freestacksz;
freestacksz = uxTaskGetStackHighWaterMark(task1Handle); // 获取任务1的剩余栈大小
printf("Task1 remaining stack: %lu bytes\n", freestacksz * 4);默认情况下,这个功能是关闭的。可以通过 CubeIDE 打开:
CubeIDE -> Middleware -> FreeRTOS -> Config Parameters -> Include uxTaskGetStackHighWaterMark
  1. 步骤2:任务栈分配调整
  • 创建任务时,建议给任务分配稍大的栈空间,初始值可以是 128 * 3(表示 128 字×3),并通过 uxTaskGetStackHighWaterMark() 动态调整,确保每个任务有足够的栈空间。

八、系统任务状态打印

  • 可以打印系统中所有任务的运行状态,方便整体调试。
  • 获取所有任务的状态:使用 vTaskList() 函数可以获取当前系统中所有任务的运行信息,包括任务名、任务状态、任务优先级、剩余栈大小等。
char *pbuffer = (char *)calloc(1, 512); // 为任务信息分配内存
printf("\r\n-name---------stat---Priority--lastword---ID---\r\n");
vTaskList(pbuffer);  // 获取任务列表
printf("%s", pbuffer);  // 打印任务信息
printf("-X:run-B:block-R:ready-D:del-S:suspend-Heap mini %d-\r\n", xPortGetMinimumEverFreeHeapSize());
free(pbuffer);  // 释放内存//默认该函数关闭,使能  cubeied-middleware->config parameter->
configUSE_TRACE_FACILITY 和 configUSE_STATS_FORMATTING_FUNCTIONS 使能 示例输出
-name---------stat---Priority--lastword---ID---
taskPrint      	X	0	129	5
IDLE           	R	0	106	6
taskStackDetect	B	0	83	2
taskStackDetect	B	0	143	3
taskStackDetect	B	0	143	4
defaultTask    	B	3	97	1
-X:run-B:block-R:ready-D:del-S:suspend-Heap mini 3592-X 代表正在运行的任务
B 代表阻塞状态
R 代表就绪状态
S 代表挂起状态
D 代表删除的任务输出的堆内存剩余量可以通过 xPortGetMinimumEverFreeHeapSize() 获取,帮助我们监控系统堆的使用情况。

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

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

相关文章

在Ubuntu使用VScode配合GDB完成代码调试

想学一下Ubuntu下的vscode代码调试,在网上找了很多博客,发现根本不管用,而且很多都是在Windows下的,与我的需求(使用CMakeLists.txt)不同,根本不能用,研究了一下。并记录。 1.创建C…

浅谈人工智能之Java调用基于Ollama本地大模型

引言 随着人工智能技术的飞速发展,大型语言模型(Large Language Models, LLMs)已成为自然语言处理领域的研究热点。Ollama是一个强大的工具,它使得在本地部署和管理这些大型语言模型变得更加便捷。本文档旨在指导Java开发者如何在…

【C++ Primer Plus习题】16.7

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: #include <iostream> #include <vector> #include <…

I/O流(Java)

目录 1. IO概述 1.1 什么是IO 1.2 IO的分类 1.3 IO的流向说明图解 1.4 顶级父类 2. File类 2.1 概述 2.2 构造方法 2.3 常用方法 2.3.1 获取功能的方法 2.3.2 绝对路径和相对路径 2.3.3 判断功能的方法 2.3.4 创建删除功能的方法 2.3.5 目录的遍历 3. 字节流 3…

[Golang] Context

[Golang] Context 文章目录 [Golang] Context什么是context创建context创建根context创建context context的作用并发控制context.WithCancelcontext.WithDeadlinecontext.WithTimeoutcontext.WithValue 什么是context Golang在1.7版本中引入了一个标准库的接口context&#xf…

计算机毕业设计 办公用品管理系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

如何将扫码提交的数据直接推送到企业微信、钉钉、飞书群聊?详细教程

功能介绍 在草料制作的表单中&#xff0c;填表人扫码填写并提交数据后&#xff0c;这些信息可以立即通过企业微信、钉钉或飞书自动推送到相应的群聊中&#xff0c;实现即时共享和沟通&#xff0c;提升团队协作效率。 设置教程 企业微信 钉钉 飞书

蚂蚁在 RAG 与向量检索上的实践:技术应用与创新分析

引言 在AI技术迅猛发展的背景下&#xff0c;如何有效地处理海量数据成为了技术创新的关键问题。向量数据库和RAG&#xff08;Retrieval-Augmented Generation&#xff09;技术结合&#xff0c;为提升生成式AI应用的准确性和实时性提供了有效的解决方案。本文结合蚂蚁集团在向量…

国外创意二维码应用案例:韩国Cheil特别制作“希望胶带”,帮助寻找失踪儿童!

每年&#xff0c;在全世界都有大量的儿童失踪案件发生。对于父母来说&#xff0c;仅凭一张照片、一张海报要在茫茫人海里找到失踪的孩子&#xff0c;何其艰难&#xff1f; 2020年5月&#xff0c;韩国广告公司Cheil与韩国国家警察局宣布&#xff1a;为寻找长期失踪儿童&#xf…

9.18作业

提示并输入一个字符串&#xff0c;统计该字符串中字母、数字、空格、其他字符的个数并输出 代码展示 #include <iostream>using namespace std;int main() {string str;int countc 0; // 字母计数int countn 0; // 数字计数int count 0; // 空格计数int counto 0;…

面了智谱大模型算法岗,效率贼高!

最近这一两周不少互联网公司都已经开始秋招提前批面试了。不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些球友解…

Renesas R7FA8D1BH (Cortex®-M85)内部RTC的应用

目录 概述 1 软硬件 1.1 软硬件环境信息 1.2 开发板信息 1.3 调试器信息 2 FSP配置RTC 2.1 配置参数 2.2 RTC模块介绍 3 RTC相关函数 3.1 R_RTC_Open() 3.2 R_RTC_Close() 3.3 R_RTC_ClockSourceSet() 3.4 R_RTC_CalendarTimeSet() 3.5 R_RTC_CalendarTimeGet()…

workbench的使用

connection name 是可以任意取的 Hostname 是数据库的地址&#xff0c;本地的话就默认是127.0.0.1 port是端口 选择store in value来存储密码 点击测试连接test connection 单击就可以登录&#xff0c;如果需要编辑的话&#xff0c;右键选择edit connection 可以选择删除账…

C++_类和对象(下篇)—— 内部类、匿名对象、对象拷贝时的编译器优化

目录 四、类和对象&#xff08;下篇&#xff09; 5、内部类 6、匿名对象 7、对象拷贝时的编译器优化 四、类和对象&#xff08;下篇&#xff09; 5、内部类 如果⼀个类定义在另⼀个类的内部&#xff0c;这个内部类就叫做内部类。内部类是⼀个独立的类&#xff0c;跟定义…

【C语言】带你手把手拿捏指针(3)(含转移表)

文章目录 一、字符指针变量二、数组指针变量1.数组指针变量是什么2.数组指针变量的初始化 三、二维数组传参的本质四、函数指针变量1. 函数指针变量的创建2.函数指针的使用3.案例解析&#xff1a; 五、typedof关键字六、函数指针数组和转移表1.函数指针数组2.转移表 一、字符指…

问题:WINCC 7.5 结构变量只能是内部变量吗?

问题&#xff1a;WINCC 7.5 结构变量只能是内部变量吗&#xff1f; 答案&#xff1a;不是的呢&#xff0c;你创建结构的时候可以选择外部变量的 如图&#xff1a;工控人加入PLC工业自动化精英社群 #WINCC 7.5##变量##结构##西门子工业支持中心#

Spring Cloud Alibaba-(1)搭建项目环境

1.Spring Cloud Alibaba&#xff08;官网&#xff1a;https://sca.aliyun.com/&#xff09; Spring Cloud Alibaba 是阿里巴巴结合自身丰富的微服务实践而推出的微服务开发的一站式解决方案&#xff0c;是 Spring Cloud 第二代实现的主要组成部分。吸收了 Spring Cloud Netflix…

如何让源码加密后还能运行?五种企业源代码加密措施推荐

随着企业越来越依赖技术创新&#xff0c;保护源代码的安全变得尤为重要。源代码是企业的核心资产之一&#xff0c;包含了重要的业务逻辑和技术创新。未经授权的访问、篡改或泄露都可能给公司带来巨大的损失。因此&#xff0c;实施有效的源代码加密措施至关重要。本文将推荐五种…

龙海家园的免费停车点探寻

​第一次去龙海家园就把我羡慕到了&#xff0c;楼下就是鲤鱼门地铁&#xff0c;龙海家园底商的餐饮好吃又实惠&#xff0c;还有特别多的超市&#xff0c;空中花园也很大&#xff0c;还可以共享前海基金小镇的花园环境。虽然我看到很多车排队等进龙海家园&#xff0c;但是我还是…

传输层协议(TCP和UDP)

目录 一、UDP 1、UDPAPI 2、UDPAPI的使用 二、TCP 1、TCPAPI 2、TCP的相关特性 2.1 确认应答 2.2 超时重传 2.3 连接管理&#xff08;三次握手&#xff0c;四次挥手&#xff09; 2.4 滑动窗口 2.5 流量控制 2.6 拥塞控制 2.7 延时应答 2.8 捎带应答 2.9 面向字节…