RTOS 低功耗设计原理及实现
RTOS 低功耗设计原理及实现
文章目录
- RTOS 低功耗设计原理及实现
- 👨🏫前言
- 👨🔬Tickless Idle Mode 的原理及实现
- 👨🚀Tickless Idle Mode 的软件设计原理
- 👨💻Tickless Idle Mode 的实现
- 👨⚖️结尾
👨🏫前言
目前, 越来越多的嵌入式产品在开发中使用 RTOS 作为软件平台, 同时,开发中对低功耗的要求也越来越高, 本文会讨论一下如何在 RTOS 中处理微控制器的低功耗特性。
应用中使用的 RTOS 一般采用基于时间片轮转的抢占式任务调度机制,一般的低功耗设计思路如下:
- 当 Idle 任务运行时,进入低功耗模式;
- 在适当的条件下,通过中断或者外部事件唤醒 MCU
但是, 从第二点可以看出,每次当 OS 系统定时器产生中断时,也会将 MCU 从低功耗模式中唤醒,而频繁的进入低功耗模式/从低功耗模式中唤醒会使得 MCU 无法进入深度睡眠,对低功耗设计而言也是不合理的。
在 FreeRTOS 中给出了一种低功耗设计模式 —— Tickless Idle Mode, 这个方法可以让 MCU 更长的时间处于低功耗模式。
👨🔬Tickless Idle Mode 的原理及实现

上图是任务调度示意图,横轴是时间轴, T1, T2, T3, T4 是 RTOS 的时间片基准,有四个任务分别是 TaskA,TaskB,TaskC,TaskD:
- Task A,周期性任务
- Task B, 周期性任务
- Task C,突发性任务
- Task D,周期性任务
从图中可以看出在四个任务进行调度之间,会有四次空闲期间(此时 RTOS 会调度 Idle 任务运行, 软件设计的目标应该是尽可能使 MCU 在 Idle 任务运行时处于低功耗模式)。
1️⃣Idle1
Idle 任务运行期间,会产生一次系统时钟滴答,此时会唤醒 MCU,唤醒后 MCU 又会进入低功耗模式, 这次唤醒是无意义的。期望使 MCU 在 Idle1 期间一直处于低功耗模式, 因此适当调整系统定时器中断使得 T1 时不触发系统时钟中断, 中断触发点设置为 Task B 到来时。
2️⃣Idle2
Task C 在系统滴答到达前唤醒 MCU(外部事件),MCU 可以在 Idle2 中可以一直处于低功耗模式;
3️⃣Idle3
与 Idle2 情况相同,但 Idle3 时间很短,如果这个时间很短,那么进入低功耗模式的意义并不大,因此在进入低功耗模式时软件应该添加策略;
4️⃣Idle4
与 Idle1 情况相同。
👨🚀Tickless Idle Mode 的软件设计原理
Tickless Idle Mode 的设计思想在于尽可能地在 MCU 空闲时使其进入低功耗模式。从上述情景中可以看出软件设计需要解决的问题有:
- 合理地进入低功耗模式(避免频繁使 MCU 在低功耗模式和运行模式下进行不必要的切换);RTOS 的系统时钟源于硬件的某个周期性定时器(Cortex-M 系列内核多数采用 SysTick),RTOS 的任务调度器可以预期到下一个周期性任务(或者定时器任务) 的触发时间,如上文所述,调整系统时钟定时器中断触发时间,可以避免 RTOS 进入不必要的时间中断,从而更长的时间停留在低功耗模式中,此时 RTOS 的时钟不再是周期的而是动态的(在原有的时钟基准时将不再产生中断,即 Tickless)。
- 当 MCU 被唤醒时,通过某种方式为系统时钟提供补偿。MCU 可能被两种情况所唤醒,动态调整过的系统时钟中断或者突发性的外部事件,无论是哪一种情况,都可以通过运行在低功耗模式下的某种定时器来计算出 MCU 处于低功耗模式下的时间,在 MCU 唤醒后对系统时间进行软件补偿;
- 软件实现时,要根据具体的应用情景和 MCU 低功耗特性来处理问题。尤其是 MCU 的低功耗特性,不同 MCU 处于不同的低功耗模式下所能使用的外设(主要是定时器) 是不同的, RTOS 的系统时钟可以进行适当的调整。
👨💻Tickless Idle Mode 的实现
这里以 STM32F407 系列的 MCU 为例, 首先需要明确的是 MCU 的低功耗模式, F407 有 3 种低功耗模式:Sleep,Stop, Standby, 在 RTOS 平台时, SRAM 和寄存器的数据不应丢失, 此外需要一个定时器为 RTOS 提供系统时钟, 这里选择 Sleep 模式下进行实现。

1. 使能
#define configUSE_TICKLESS_IDLE 1
2. 空闲任务(RTOS 空闲时自动调用)
/* Idle 任务 */
void prvIdleTask( void *pvParameters )
{for( ; ; ){...#if ( configUSE_TICKLESS_IDLE != 0 ){TickType_t xExpectedIdleTime;/* 用户策略以决定是否需要进入 Tickless Mode */xExpectedIdleTime = prvGetExpectedIdleTime();if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ){vTaskSuspendAll(); // 挂起调度器{configASSERT( xNextTaskUnblockTime >= xTickCount );xExpectedIdleTime = prvGetExpectedIdleTime();if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ){/* 用户函数接口 *//* 1. 进入低功耗模式和如何退出低功耗模式 *//* 2. 系统时间补偿 */portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );}} (void) xTaskResumeAll(); // 恢复调度器}}#endif /* configUSE_TICKLESS_IDLE */...}
}
3. 低功耗模式处理(根据 MCU 的低功耗模式编写代码)
void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime )
{unsigned long ulReloadValue, ulCompleteTickPeriods,ulCompletedSysTickDecrements;portTickType xModifiableIdleTime;/* 最长睡眠时间不可以超过定时器的最大定时值 *//* 通过调整定时器的时间基准可以获得更理想的最大定时值 */if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ){xExpectedIdleTime = xMaximumPossibleSuppressedTicks;}/* 停止 SysTick */portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT |portNVIC_SYSTICK_INT_BIT;/* 计算唤醒时的系统时间,用于唤醒后的系统时间补偿 */ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );if( ulReloadValue > ulStoppedTimerCompensation ){ulReloadValue -= ulStoppedTimerCompensation;}__disable_interrupt();/* 确认下是否可以进入低功耗模式 */if( eTaskConfirmSleepModeStatus() == eAbortSleep ){/* 不可以,重新启动系统定时器 */portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT |portNVIC_SYSTICK_INT_BIT |portNVIC_SYSTICK_ENABLE_BIT;portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;__enable_interrupt();}else{/* 可以进入低功耗模式 *//* 保存时间补偿,重启系统定时器 */portNVIC_SYSTICK_LOAD_REG = ulReloadValue;portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT |portNVIC_SYSTICK_INT_BIT |portNVIC_SYSTICK_ENABLE_BIT;/* 进入低功耗模式,可以通过 configPRE_SLEEP_PROCESSING 函数进行低功耗模式下时钟及外设的配置*/xModifiableIdleTime = xExpectedIdleTime;configPRE_SLEEP_PROCESSING( xModifiableIdleTime );if( xModifiableIdleTime > 0 ){__DSB();__WFI();__ISB();}/* 退出低功耗模式 */configPOST_SLEEP_PROCESSING( xExpectedIdleTime );portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT |portNVIC_SYSTICK_INT_BIT;__disable_interrupt()__enable_interrupt();/*唤醒有两种情况:系统定时器或者外部事件(中断) */if((portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT) != 0){/* 系统定时器唤醒,时间补偿 */unsigned long ulCalculatedLoadValue;ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) – ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ){ulCalculatedLoadValue = (ulTimerCountsForOneTick - 1UL);}portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;ulCompleteTickPeriods = xExpectedIdleTime - 1UL;}else{/* 外部事件(中断)唤醒 */ulCompletedSysTickDecrements = ( xExpectedIdleTime *ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;ulCompleteTickPeriods = ulCompletedSysTickDecrements /ulTimerCountsForOneTick;portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) *ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;}/* 重启 Systick,调整系统定时器中断为正常值 */portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;portENTER_CRITICAL();{portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT |portNVIC_SYSTICK_INT_BIT |portNVIC_SYSTICK_ENABLE_BIT;vTaskStepTick( ulCompleteTickPeriods );portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;}portEXIT_CRITICAL();}
}
👨⚖️结尾
STM32 家族中拥有不同的系列,特别是专为低功耗应用设计的 L 系列,为其设计 RTOS 低功耗特性实现时可以有更多的实现方式(例,某种模式下内核停止运行, 此时可以使用外部定时器或者 RTC 来代替 Systick 作为系统定时器)。

相关文章:
RTOS 低功耗设计原理及实现
RTOS 低功耗设计原理及实现 文章目录 RTOS 低功耗设计原理及实现👨🏫前言👨🔬Tickless Idle Mode 的原理及实现👨🚀Tickless Idle Mode 的软件设计原理👨💻Tickless Idle Mo…...
PaddleOCR C++编译出错解决方案
文章目录 前言一、环境准备1、主要环境2、源码下载3、C推理库下载 二、报错信息1.静态库调用错误2.ld returned 1 exit status 总结 前言 最近,想尝试下PaddleOCR的C推理,但是过程不如人所愿,除了很多问题,这里捡重点的说下吧&…...
89、简述RabbitMQ的架构设计
简述RabbitMQ的架构设计 BrokerQueueExchangeRoutingKeyBinding信道架构设计图Broker RabbitMQ的服务节点 Queue 队列,是RabbitMQ的内部对象,用于存储消息。RabbitMQ中消息只能存储在队列中。生产者投递消息到队列,消费者从队列中获取消息并消费。多个消费者可以订阅同一…...
63 | 图像处理
文章目录 Python图像处理什么是图像处理?Python图像处理库安装Pillow库加载和显示图像调整图像大小裁剪图像调整图像亮度、对比度和色彩平衡应用滤镜练习题Python图像处理 什么是图像处理? 图像处理是指使用计算机算法来改变图像的外观或特征。它可以用于许多不同的应用程序…...
Stable Diffusion - 扩展 Roop 换脸 (Face Swapping) 插件的配置与使用
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/131856141 官网:GitHub - roop,参考论文:RobustSwap: A Simple yet Robust Face Swapping Model against Attr…...
opencv实现替换证件照颜色
程序可以实现蓝色底片变为红色底片(但有点小bug) 修改自:opencv:HSV颜色模型_opencv hsv_君浪的博客-CSDN博客 相关文章:OpenCV Mat数据类型指针ptr的使用_cv::mat ptr_AoboSir的博客-CSDN博客 【OpenCV】HSV颜色识…...
Elasticsearch【全文检索、倒排索引、应用场景、对比Solr、数据结构】(一)-全面详解(学习总结---从入门到深化)
目录 Elasticsearch介绍_全文检索 Elasticsearch介绍_倒排索引 Elasticsearch介绍_Elasticsearch的出现 Elasticsearch介绍_Elasticsearch应用场景 Elasticsearch介绍_Elasticsearch对比Solr Elasticsearch介绍_Elasticsearch数据结构 Elasticsearch介绍_全文检索 Elasti…...
了解 3DS MAX 3D摄像机跟踪设置:第 2 部分
推荐: NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 项目设置 步骤 1 打开“后效”。 打开后效果 步骤 2 转到合成>新合成以创建新合成。 将“宽度”和“高度”值分别设置为 1280 和 720。将帧速率设置为 25,将持续时间设置为 12 秒。单…...
MySQL 判断 JSON 数组是否相等
文章目录 1.问题2.使用 JSON_CONTAINS 与 JSON_LENGTH参考文献 1.问题 JSON(JavaScript Object Notation)是流行的互联网应用服务之间的数据交换格式。 MySQL 从 5.7 版本开始支持 RFC 7159 定义的 JSON 规范,主要有 JSON 对象 和 JSON 数组…...
uni-app个人中心
一. 介绍uni-app: uni-app 是基于Vue.js框架开发的一个跨平台移动应用开发框架,可以同时支持多个平台(如iOS、Android、Web等)的应用开发。采用了统一的语法和组件规范,可以大大简化跨平台开发的工作,提高…...
只需3步,使用Stable Diffusion无限生产AI数字人视频
效果演示 先看效果,感兴趣的可以继续读下去。 没有找到可以上传视频的地方,大家打开这个网盘链接观看:https://www.aliyundrive.com/s/CRBm5NL3xAE 基本方法 搞一张照片,搞一段语音,合成照片和语音,同…...
Mysql执行计划字段解释
文章目录 一、前言二、如何查看执行计划三、执行计划各字段解释四、select_type4.1、SIMPLE(简单查询)4.1.1、简单的单表查询4.1.2、多表连接查询 4.2、PRIMARY(主查询)4.2.1、包含复杂子查询的外层查询4.2.2、UNION语句中的第一个…...
Linux -- 线程
文章目录 1. 线程概念1.1 概念1.2 理解(Linux OS角度)1.3 见一见 2. 线程优缺点3. 线程使用3.1 认识线程库3.2 使用3.2.1 线程创建3.2.2 线程等待3.2.3 线程退出3.2.4 线程取消3.2.5 获取线程id3.2.6 线程分离 3.3 理解线程库3.4 证明线程栈3.5 线程局部…...
Android:实时更新时间
心想着也就是更新精确到分钟,不用精确到秒,定时器就没有必要,系统是有广播Intent.ACTION_TIME_TICK可以直接用 动态注册广播 主方法里面调用一下 //要先设置一下当前时间,不然刷新时间会等到1分钟后再刷新 tv_HM.setText(getHM…...
24 鼠标常用事件
鼠标进入:enterEvent鼠标离开:leaveEvent鼠标按下:mousePressEvent鼠标释放:mouseRelaseEvent鼠标移动:mouseMoveEvent 提升为自定义控件MyLabel 代码: //mylabel.h #ifndef MYLABEL_H #define MYLABEL_H#…...
了解 3DS MAX 3D摄像机跟踪设置:第 4 部分
推荐: NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 项目设置 步骤 1 打开“后效”。 打开后效果 步骤 2 转到合成>新合成以创建新合成。 将“宽度”和“高度”值分别设置为 1280 和 720。将帧速率设置为 25,将持续时间设置为 12 秒。单…...
nginx吞吐量调优
调整worker_processes和worker_connections: worker_processes:设置为服务器的CPU核心数或更高。例如,如果服务器有8个CPU核心,可以将worker_processes设置为8。worker_connections:设置每个worker进程所能处理的最大连…...
Python操作Excel文件,修改Excel样式(openpyxl)
秋风阁-北溪入江流 文章目录 安装依赖库openpyxlopenpyxl的操作加载文件,获取sheet加载文件load_workbook获取sheet 遍历单元格迭代遍历索引遍历 单元格行高和列宽的修改Excel列号与字母的转换Excel行高修改Excel列宽修改 Excel表格文字对齐属性设置修改单元格框线保…...
AutoSAR系列讲解(实践篇)7.6-实验:配置SWCRTE(下)
阅读建议: 实验篇是重点,有条件的同学最好跟着做一遍,然后回头对照着AutoSAR系列讲解(实践篇)7.5-OS原理进阶_ManGo CHEN的博客-CSDN博客理解其配置的目的和意义。本篇是接着AutoSAR系列讲解(实践篇)7.4-实验:配置SWC&RTE_ManGo CHEN的博客-CSDN博客的实验篇接着做…...
【node】使用express+gitee搭建图床,并解决防盗链问题
首先创建一个gitee的项目,详细步骤我就不一一说明 注解:大家记得将这个项目开源,还有记得获取自己的私钥,私钥操作如下: node依赖下载: "axios": "cors": "express"…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...

