基于 SysTick 定时器实现任务轮询调度器
文章目录
- 前言
- 一、SysTick 定时器介绍
- 二、SysTick 驱动设计
- 1. 初始化方法
- 2. SysTick 中断函数
- 3. 时间类 API
- 三、任务调度器设计
- 1. 任务结构体
- 2. 任务初始化
- 3. 主调度器
- 4. 调度器更新
- 四、任务函数实现
- 五、总结
- 1. 优缺点分析
- 2. 扩展建议
前言
在嵌入式系统中,对于资源受限、实时性要求较强的小型项目,使用一个轻量级的 轮询调度器(Polling Scheduler) 往往是比使用完整 RTOS 更合适的选择。本文将介绍如何基于 SysTick 定时器,构建一个简单、可配置、易于维护的任务轮询调度框架。
轮询调度器是一种按照固定频率循环调用多个任务的调度方式。与传统的 RTOS 使用任务优先级和时间片管理不同,轮询调度器结构简单,没有上下文切换开销,适用于嵌入式裸机系统。
SysTick 是 Cortex-M 内核自带的一个 24-bit 的定时器,非常适合实现毫秒级的系统节拍(系统心跳),可以定期触发中断来增加系统“时钟节拍数”。
一、SysTick 定时器介绍
SysTick 是 Cortex-M3/M4/M7 系列核内部自带的一个定时器,有如下特点:
-
可以设置一个重装值,到值时触发一次中断
-
可以选择不同的时钟源(如 HCLK/无分频或 HCLK/8)
-
通常用于 RTOS 的时钟引擎,也可用于实时延时
在本组件中,我们把 SysTick 设置为 10kHz 高精度定时器,即 0.1ms 一次中断
二、SysTick 驱动设计
1. 初始化方法
void drv_systick_init(void)
{crm_clocks_freq_type clocks_struct;systick_clock_source_config(SYSTICK_CLOCK_SOURCE_AHBCLK_NODIV); // 使用 AHB 时钟crm_clocks_freq_get(&clocks_struct);uint32_t tick_cnt = clocks_struct.ahb_freq / SYSTICK_FREQUENCE;systick_interrupt_config(tick_cnt);
}
根据当前 AHB 主时钟,计算定时轮被动进制值,定时频率为 SYSTICK_FREQUENCE = 10000 即 10kHz。
2. SysTick 中断函数
void SysTick_Handler(void)
{++systick_count;
}
每 0.1ms 一次,代表一个精度较高的 “系统时钟基准” 增加。
3. 时间类 API
uint32_t get_systick_count(void)
{return systick_count;
}uint32_t get_systick_ms(void)
{return (uint32_t)((float)systick_count / ((float)SYSTICK_FREQUENCE * 0.001f));
}uint32_t get_systick_s(void)
{return (uint32_t)((float)systick_count / (float)SYSTICK_FREQUENCE);
}void delay_ms(uint32_t ms)
{uint32_t start_cnt = get_systick_count();while ( (get_systick_count() - start_cnt) < ms * SYSTICK_FREQUENCE * 0.001f) {}
}void delay_s(uint32_t s)
{uint32_t start_cnt = get_systick_count();while ( (get_systick_count() - start_cnt) < s * SYSTICK_FREQUENCE) {}
}
-
get_systick_count():返回自己滴答数 -
get_systick_ms():系统运行时间,单位ms -
delay_ms():延时操作,单位ms
三、任务调度器设计
核心思想: 每个任务记录上次执行时间 last_tick,按照预设频率 frequence 判断是否超时,如果是,就执行任务函数。
1. 任务结构体
struct loop_task_info {char *name;void (*function)(void); // 任务函数指针uint32_t frequence; // 任务执行频率(Hz)uint32_t tick; // 已执行次数uint32_t last_tick; // 上次执行时的系统节拍数
};
所有任务被组织在一个静态数组 task_info[] 中。
2. 任务初始化
INIT_LOOP_TAST(task_info[LOOP_TASK_A], "Task A", task_a, 10000, 0, 0); // 10000Hz
INIT_LOOP_TAST(task_info[LOOP_TASK_B], "Task B", task_b, 500, 0, 0); // 500Hz
3. 主调度器
主循环不断轮询所有任务:
void loop_task_ontick(void)
{while (1) {for (i = 0; i < LOOP_TASK_MAX; ++i)loop_task_updata(&task_info[i]);}
}
4. 调度器更新
static void loop_task_updata(struct loop_task_info *loop_task)
{uint32_t tick_interval = get_systick_count() - loop_task->last_tick;if (tick_interval >= (get_systick_frequence() / loop_task->frequence)) {loop_task->last_tick = get_systick_count();++loop_task->tick;if(loop_task->function != NULL)loop_task->function();}
}
四、任务函数实现
任务函数内部可以再细分子任务,如在 Task A 中实现 10KHz、1KHz、1Hz 的子任务:
void task_a(void)
{if (get_loop_task_tick(LOOP_TASK_A) % (get_loop_task_frequence(LOOP_TASK_A) / 10000) == 0) {// 10000Hz 执行}if (get_loop_task_tick(LOOP_TASK_A) % (get_loop_task_frequence(LOOP_TASK_A) / 1000) == 0) {// 1000Hz 执行}if (get_loop_task_tick(LOOP_TASK_A) % (get_loop_task_frequence(LOOP_TASK_A) / 1) == 0) {// 1Hz 执行}
}
通过tick计数除以频率的方式,在一个任务函数中实现多频率分支处理,非常适合多粒度控制。
五、总结
1. 优缺点分析
优点:
-
结构简单:无需操作系统,适合裸机项目。
-
执行频率可控:每个任务可单独配置运行频率。
-
任务切换无上下文开销:极大节省系统资源。
缺点:
-
不适合实时性要求极高的任务:任务间是串行执行,容易被阻塞。
-
不支持任务优先级:所有任务平等轮询。
-
没有“抢占机制”:任务函数内部不能阻塞太久,否则影响整体调度精度。
2. 扩展建议
-
支持任务优先级(按优先级或 deadline 排序执行)
-
增加任务 Watchdog 功能,防止任务异常长时间卡死
-
动态添加、删除任务支持
-
基于时间轮的调度器优化版
相关文章:
基于 SysTick 定时器实现任务轮询调度器
文章目录 前言一、SysTick 定时器介绍二、SysTick 驱动设计1. 初始化方法2. SysTick 中断函数3. 时间类 API 三、任务调度器设计1. 任务结构体2. 任务初始化3. 主调度器4. 调度器更新 四、任务函数实现五、总结1. 优缺点分析2. 扩展建议 前言 在嵌入式系统中,对于资…...
【STM32】综合练习——智能风扇系统
目录 0 前言 1 硬件准备 2 功能介绍 3 前置配置 3.1 时钟配置 3.2 文件配置 4 功能实现 4.1 按键功能 4.2 屏幕功能 4.3 调速功能 4.4 倒计时功能 4.5 摇头功能 4.6 测距待机功能 0 前言 由于时间关系,暂停详细更新,本文章中,…...
MyBatis 动态 SQL 使用详解
🌟 一、什么是动态 SQL? 动态 SQL 是指根据传入参数,动态拼接生成 SQL 语句,不需要写多个 SQL 方法。MyBatis 提供了 <if>、<choose>、<foreach>、<where> 等标签来实现这类操作 ✅ 二、动态 SQL 的优点…...
【重装系统】大白菜自制U盘装机,备份C盘数据,解决电脑启动黑屏/蓝屏
1. 准备 U 盘 U 盘容量至少 8G,备份 U 盘的数据(后期会格式化) 2. 从微软官网下载操作系统镜像 https://www.microsoft.com/zh-cn/software-download/windows11 3. 下载安装大白菜 https://www.alipan.com/s/33RVnKayUfY 4. 插入 U 盘&#…...
vue实现目录锚点且滚动到指定区域时锚点自动回显——双向锚点
最近在用vue写官网,别问我为什么用vue写官网,问就是不会jq。。。。vue都出现11年了。。。 左侧目录:点击时,右侧区域可以自动滚动到指定的位置。 右侧区域手动滚动时,左侧锚点可以自动切换到对应的目录上 从而实现…...
python——正则表达式
一、简介 在 Python 中,正则表达式主要通过 re 模块实现,用于字符串的匹配、查找、替换等操作。 二、Python的re模块 使用前需要导入: import re 三、常用方法 方法描述re.match(pattern, string)从字符串开头匹配,返回第一个匹…...
Flutter Invalid constant value.
0x00 问题 参数传入变量,报错! 代码 const Padding(padding: EdgeInsets.all(20),child: GradientProgressIndicator(value: _progress), ),_progress 参数报错:Invalid constant value. 0x01 原因 这种情况,多发生于ÿ…...
libev实现Io复用及定时器事件服务器
客户端和服务器都绑定在了enp2s0网卡,需要SERVER_IP和SERVER_PORT改为其ip,注意不能是127.0.0.1,因为这个是lo虚拟网口。 安装libev sudo apt-get install libev-dev客户端: #include <iostream> #include <string>…...
【精品PPT】2025固态电池知识体系及最佳实践PPT合集(36份).zip
精品推荐,2025固态电池知识体系及最佳实践PPT合集,共36份。供大家学习参考。 1、中科院化学所郭玉国研究员:固态金属锂电池及其关键材料.pdf 2、中科院物理所-李泓固态电池.pdf 3、全固态电池技术研究进展.pdf 4、全固态电池生产工艺.pdf 5、…...
如何计算设备电池工作时长?
目录 【mAh(毫安时)计算方法】 【Wh(瓦时)计算方法】 【为什么仅用电流(mA)和时间(h)就能计算电池使用时长(mAh)?】 1. mAh 的本质是“电荷量…...
抽象类及其特性
目录 1、概念2、语法3、特性4、作用 1、概念 在面向对象中,所有对象都是通过类来描述的,但是并不是所有的类都可以用来描述对象。比如下述例子中的 Animal 类,Dog 类和 Cat 类是 Animal 类的子类,可以分别描述小狗和小猫…...
【教程】xrdp修改远程桌面环境为xfce4
转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 目录 xfce4 vs GNOME对比 配置教程 1. 安装 xfce4 桌面环境 2. 安装 xrdp 3. 配置 xrdp 使用 xfce4 4. 重启 xrdp 服务 5. 配置防火墙ÿ…...
利用python从零实现Byte Pair Encoding(BPE):NLP 中的“变形金刚”
BPE:NLP 界的“变形金刚”,从零开始的奇幻之旅 在自然语言处理(NLP)的世界里,有一个古老而神秘的传说,讲述着一种强大的魔法——Byte Pair Encoding(BPE)。它能够将普通的文本“变形…...
部署redis cluster
一。在所有的主机里面设置密码和文件地址 vi /etc/redis/6379.conf 注释:登陆则要使用auth 123456才可以进入redis 配置文件地址和超时时间 二。创建集群:上面主机为master,下面为slave,master和slave会随机分配 先写主节点&…...
Android 11 (API 30) 及更高版本中,查询的特定应用商店包,无需动态请求权限处理
在 Android 11 (API 30) 及更高版本中,通过在 AndroidManifest.xml 中添加 <queries> 元素声明需要查询的特定应用商店包名后: 1. 不需要额外请求权限 (如 QUERY_ALL_PACKAGES )即可查询这些应用的安装状态 2. 这是 Googl…...
基于springboot钻孔数据管理系统的设计与实现(源码+lw+部署文档+讲解),源码可白嫖!
摘要 本钻孔数据管理系统采用B/S架构,数据库是MySQL,网站的搭建与开发采用了先进的Java语言、Hadoop、数据可视化技术进行编写,使用了Spring Boot框架。该系统从两个对象:由管理员和用户来对系统进行设计构建。用户主要功能包括&…...
SpringBoot和微服务学习记录Day2
微服务 微服务将单体应用分割成更小的的独立服务,部署在不同的服务器上。服务间的关联通过暴露的api接口来实现 优点:高内聚低耦合,一个模块有问题不影响整个应用,增加可靠性,更新技术方便 缺点:增加运维…...
4.9复习记
1.地宫取宝--记忆化搜索,可以先写void dfs,然后在改成ll 形式的,边界条件return 0/1; 记忆化数组与dfs元素保持一致,记得记忆化剪枝 这个题特殊在value可能是0,不取的时候应该记为-1 https://mpbeta.cs…...
LinuxSocket套接字编程
1.介绍函数使用 1.创建套接字 int socket(int domain, int type, int protocol); domain:指定协议族,如AF_INET(IPv4)或AF_INET6(IPv6)。 type:指定套接字类型,如SOCK_DGRAM&#…...
动态科技感html导航网站源码
源码介绍 动态科技感html导航网站源码,这个设计完美呈现了科幻电影中的未来科技界面效果,适合展示技术类项目或作为个人作品集的入口页面,自适应手机。 修改卡片中的链接指向你实际的HTML文件可以根据需要调整卡片内容、图标和颜色要添加更…...
Java进阶版线程池(超详细 )
线程池 线程池工具类 Executors Executors 是 Java 提供的一个工具类,它包含了多个静态方法,能够方便地创建不同类型的线程池。 newFixedThreadPool 创建一个固定大小的线程池,线程池中的线程数量固定,当有新任务提…...
每日算法:洛谷U535992 J-C 小梦的宝石收集(双指针、二分)
题目描述 小梦有 n 颗能量宝石,其中第 i 颗的能量为 ai,但这些能量宝石十分不稳定,随时有可能发生崩坏,导致他们全部消失! 小梦想要留住宝石们,不希望他们发生崩坏,同时他发现:如…...
YOLOv11训练中精准率召回率与mAP@0.5的动态变化分析
目标检测模型的训练过程涉及多个关键性能指标和损失函数的变化,这些数据能够直观反映模型的收敛速度、最终精度以及改进效果。本文旨在通过绘制YOLOv11模型在训练过程中的精准率(Precision)、召回率(Recall)、mAP0.5 、…...
Java常用工具算法-6--秘钥托管云服务AWS KMS
前言: 之前我们介绍了一些常用的加密算法(如:对称加密AES,非对称加密RSA,ECC等),不论是哪一种都需要涉及到秘钥的管理。通常的做法都是把秘钥放到配置文件中进行配置,但是对于一些高…...
11. Langchain输出解析(Output Parsers):从自由文本到结构化数据
引言:从"自由发挥"到"规整输出" 2025年某金融机构的合同分析系统升级前,AI生成的合同摘要需人工二次处理达47分钟/份。引入LangChain结构化解析后,处理时间缩短至3分钟。本文将详解如何用LangChain的解析器,…...
docker stack常用命令
1、Docker Stack介绍 Docker Stack管理swarm堆栈与Swarm协调器配合使用,是Docker Swarm环境中用于管理一组相关服务的工具。它使得在Swarm集群中部署、管理和扩展一组相互关联的服务变得简单。主要用于定义和编排容器化应用的多个服务。以下是Docker Stack的一些关…...
python reportlab模块----操作PDF文件
reportlab模块----操作PDF文件 一. 安装模块二. reportlab相关介绍三. 扩展canvas类四. 水平写入完整代码五. 垂直写入完整代码 一. 安装模块 pip install reportlab二. reportlab相关介绍 # 1. letter 生成A4纸张尺寸 from reportlab.lib.pagesizes import letter print(let…...
解锁基因密码之重测序(从测序到分析)
在生命科学的奇妙世界中,基因恰似一本记录着生命奥秘的“天书”,它承载着生物体生长、发育、衰老乃至疾病等一切生命现象的关键信息。而重测序技术,则是开启基因“天书”奥秘的一把神奇钥匙。 试想,你手中有一本经典书籍的通用版…...
TQTT_KU5P开发板教程---QSFP25G光口回环测试
文档实现功能介绍 本文档通过一个叫做ibert的IP,实现25G光口回环测试例子。工程新建方法请参考文档《流水灯》,其中只是将文件名进行修改。 Vivado 起始页(或 file-->Project-->New 创建新工程(Create New Project) 向导起始页面 点…...
JVM虚拟机篇(七):JVM垃圾回收器全面解析与G1深度探秘及四种引用详解
JVM垃圾回收器全面解析与G1深度探秘及四种引用详解 JVM虚拟机(七):JVM垃圾回收器全面解析与G1深度探秘及四种引用详解一、JVM有哪些垃圾回收器1. Serial回收器2. ParNew回收器3. Parallel Scavenge回收器4. Serial Old回收器5. Parallel Old回…...
