【STM32】SysTick操作系统延时函数的讲解,手撸带操作系统的延时函数

1. 流水灯模拟多线程
用一个流水灯小实验学习systick,模拟多线程

1.1 main.c
先看main.c文件,main函数中实现两个灯进行不同的任务
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "tasks.h"

int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init(); /* 初始化LED灯 */

while(1)
{
task1();
task2();
// led1_on();
// led2_off();
// delay_ms(500);
// led1_off();
// led2_on();
// delay_ms(500);
}
}

AI写代码
cpp
运行

HAL_Init()中:使用systick作为时基源,并默认配置1ms滴答(重置后的默认时钟为HSI)

即1ms中断一次

然后就只需要在中断服务函数中实现功能就好了

但是中断服务函数中最好不要写很长,最好把线程写在一个文件中,于是有了task.c

1.2 重点task.c
重点是task.c,要在这里实现多线程,main主函数里的task1()和task2()正是在这里实现

systick模拟多线程实验时,为什么两个小灯不同频率闪烁的代码写在中断服务函数里,就能实现功能呢?

答:SysTick 通常配置为每 1ms 产生一次中断

每次中断时,这个函数自动被调用,执行完中断程序再回到断点

函数内部维护两个任务的计时器,实现:

任务1:每秒执行一次(1000ms)
任务2:每0.5秒执行一次(500ms)
在main函数的HAL_Init()函数中默认设置的是每过1ms调用一下中断函数systick_isr(),相当于每过1ms都会检测task1和task2的cnt计数情况。就是每过1ms调用一次中断函数systick_isr(),这1ms后就实现systick_isr()中1000ms的led1和500ms的led2闪烁

#include "tasks.h"
#include "led.h"

uint32_t task1_cnt = 0;
uint32_t task2_cnt = 0;

uint8_t task1_flag = 0;
uint8_t task2_flag = 0;

void systick_isr(void)
{
if (task1_cnt < 1000)
task1_cnt++;
else
{
task1_flag = 1;
task1_cnt = 0;
}

if (task2_cnt < 500)
task2_cnt++;
else
{
task2_flag = 1;
task2_cnt = 0;
}
}

void task1(void)
{
if(task1_flag == 0)
return;

task1_flag = 0;

led1_toggle();
}

void task2(void)
{
if(task2_flag == 0)
return;

task2_flag = 0;

led2_toggle();
}
AI写代码
cpp
运行

在main函数中一直调用task1和task2,如果task1_flag == 0,即task1还没记完数,就return继续运行;否则,跳过return执行task1_flag = 0(没记完数时都为0,现在否则了,说明task1_flag = 1,所以需要重新置零,不能让它后面一直都是1进不去循环了); led1_toggle()(翻转灯);

别忘了中断函数再调用void systick_isr(void)
别忘了在.h文件中补充函数声明
1.3 老演员led.c
#include "led.h"
#include "sys.h"

//初始化GPIO函数
void led_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//打开时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟

//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_8 | GPIO_PIN_9; // 两个LED对应的引脚
gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
HAL_GPIO_Init(GPIOB, &gpio_initstruct);
//关闭LED
led1_off();
led2_off();
}

//点亮LED1的函数
void led1_on(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET); // 拉低LED1引脚,点亮LED1
}

//熄灭LED1的函数
void led1_off(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET); // 拉高LED1引脚,熄灭LED1
}

//翻转LED1状态的函数
void led1_toggle(void)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
}

//点亮LED2的函数
void led2_on(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET); // 拉低LED2引脚,点亮LED2
}

//熄灭LED2的函数
void led2_off(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET); // 拉高LED2引脚,熄灭LED2
}

//翻转LED2状态的函数
void led2_toggle(void)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_9);
}
AI写代码
cpp
运行

实现的是led1和led2不一样频率的闪烁,led1以1000ms闪烁,led2以500ms闪烁。

2. 什么是SysTick?
Systick,即滴答定时器,是内核中的一个特殊定时器,用于提供系统级的定时服务。该定时器是一个24位的递减计数器,具有自动重载值寄存器的功能。当计数器到达自动重载值时,它会自动重新加载并开始新的计数周期。
在使用Systick定时器进行延时操作时,可以设定初值并使能后,每经过一个系统时钟周期,计数值就减1。当计数到0时,Systick计数器自动重装初值并继续计数,同时内部的COUNTFLAG标志会置位,触发中断 (如果中断使能)。这样,可以在中断处理函数中实现特定的延时逻辑。

3. 手撸带操作系统的延时函数


根据流程图看懂以下代码不难

void delay_us(uint32_t nus)
{
uint32_t ticks;
uint32_t tcnt = 0, told, tnow;
uint32_t reload = SysTick->LOAD; //重装载值

ticks = nus * 72; //需要计的节拍数
told = SysTick->VAL; //刚进入while循环时计数器的值

while(1)
{
tnow = SysTick->VAL;
if(tnow != told)
{
if(tnow < told)
tcnt += told - tnow;
else
tcnt += reload - (tnow -told);

told = tnow;//下次进入while循环时,当前VAL的值作为told

if(tcnt >= ticks)//已计的数超过/等于需要计的数时,退出循环
break;
}
}
}
AI写代码
cpp
运行

写在delay.c

学过C语言的都知道->是用指针访问结构体成员,systick是结构体指针,VAL是它访问的结构体成员,其实它是一个寄存器

4. systick寄存器
SysTick控制及状态寄存器(CTRL)

SysTick重装载数值寄存器(LOAD)

SysTick当前数值寄存器(VAL)

————————————————
版权声明:本文为CSDN博主「逆小舟」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/2301_76153977/article/details/154233968

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

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

相关文章

强烈安利8个AI论文网站,专科生毕业论文轻松搞定!

强烈安利8个AI论文网站&#xff0c;专科生毕业论文轻松搞定&#xff01; 专科生论文写作的救星&#xff0c;AI工具如何帮你轻松应对 对于许多专科生来说&#xff0c;毕业论文不仅是学业生涯中的一次重要考验&#xff0c;也是一场与时间、知识和压力的较量。而如今&#xff0c;随…

iOS App的tcp、udp数据包抓取在实际开发中的使用方式

我开始用数据流抓包的方式看 iOS 网络行为&#xff0c;是在一次很典型的场景里。 接口返回完全正常&#xff0c;日志也没有异常&#xff0c;但功能在真机上偶发失效。 代理抓包工具里&#xff0c;HTTPS 请求干净得不像是有问题的样子。先明确一件事&#xff1a;iOS 数据流抓包在…

医院智能随访管理系统,java版随访系统源码,符合三甲医院评审标准,能对接HIS等医疗系统

医院智能随访管理系统包括患者档案管理、随访呵护、随访登记、健康教育等功能&#xff0c;支持主动随访模式和被动随访模式&#xff0c;为随访工作人员提供管理信息和标准化随访依据&#xff0c;能够很好地辅助医院各科室的日常随访工作、规范随访的信息处理流程&#xff0c;提…

STM32F103步进电机S曲线加减速定位算法详解

stm32f103步进S曲线加减速定位算法在嵌入式开发中&#xff0c;步进电机的控制是一个常见的需求&#xff0c;尤其是在需要精确定位的场合。今天我们来聊聊如何在STM32F103上实现步进电机的S曲线加减速定位算法。这个算法不仅能让我们更平滑地控制电机&#xff0c;还能减少机械冲…

机器学习中的层次聚类(凝聚型)

摘要&#xff1a;层次聚类&#xff08;凝聚型&#xff09;是一种自底向上的无监督聚类算法&#xff0c;通过逐步合并最近邻簇构建层次结构。该算法首先将每个样本视为独立簇&#xff0c;然后基于距离度量&#xff08;如Ward法、单链接法等&#xff09;迭代合并簇&#xff0c;最…

34.方块定位

1.使用WhiteRec.CBD图片完成以下操作 ①测量每个图片上有多少个物料(白色方块),并显示在图片上 ②在图像上按从左到右,从上到下的顺序标记每颗物料的序号,序号显示在物料的中心附近 ③将料盘按照下图的样式划分,每个区域内一颗物料,并显示分割线。 ④在图像上找出每颗…

Cloudflare Workers 和 Pages 的本质区别:托管 vs 计算

Cloudflare Workers 和 Pages 经常一起被提,但它们解决的是两类完全不同的问题。可以一句话先分清: Pages 是“托管与发布”,Workers 是“计算与控制”。 下面我按定位 → 能力 → 典型场景 → 选型建议把差异说透。 一、核心定位差异(最重要) Cloudflare Pages 定位:前…

Qoder NEXT 来了:补全功能全新升级,AI 代码采纳率提升 65%

今天&#xff0c;Qoder 智能补全能力全面升级&#xff0c;并发布全新品牌 NEXT。Qoder NEXT 能主动感知整个代码库与编辑历史&#xff0c;在开发者完成一次修改后&#xff0c;立即推断出后续需要联动变更的位置&#xff0c;并提供精准的代码建议&#xff0c;让 AI 真正理解&quo…

黑客技术门槛有多高?普通人入局需谨慎!网安入行必看的 3 个事实

经常能看到有人问 “零基础能学黑客技术吗&#xff1f;”“学网安真的能月入 20K 吗&#xff1f;”—— 作为从业多年的安全工程师&#xff0c;今天想从技术门槛、行业收益、职业路径三个维度&#xff0c;跟大家聊聊真实的网安行业&#xff0c;帮想入行的朋友避开 “脚本小子”…

双馈风力发电系统AC/DC/AC变流器的仿真模型 ,网侧变流器及转子侧变流器的控制方案,采用双...

双馈风力发电系统AC/DC/AC变流器的仿真模型 &#xff0c;网侧变流器及转子侧变流器的控制方案&#xff0c;采用双PWM控制&#xff0c;网侧采用定子电压定向&#xff0c;转子侧采用定子磁链定向&#xff0c;实现超同步及次同步时功率的双向流动。 还有20页的说明内容。双馈风机变…

用 Cloudflare D1 给 Pages/Functions 上数据库:一套“绑定式部署”的正确姿势

你现在的站点不是静态导出,而是 Next.js App Router 跑在 Cloudflare Pages 的 SSR/Functions 上。 这意味着:你的 API(例如 /api/footprints 留言)本质是 Cloudflare Worker 运行时,它拿数据库不是走“公网连接串”,而是走 Cloudflare 的 Binding 注入: 你在 Cloudflar…

京东蚂蚁领跑链上金融:香港RWA革命如何打通万亿级资产新通道?

引言&#xff1a;一场静默的金融革命正在东方之珠上演当华尔街的投行精英还在为传统证券代币化的合规框架争论不休时&#xff0c;香港维多利亚港的夜色中&#xff0c;一场以“现实资产代币化”&#xff08;RWA&#xff09;为核心的链上金融竞赛已悄然进入白热化阶段。京东科技在…

阿培利斯:一种具有潜力的癌症治疗药物

阿培利斯作为一款专注于癌症治疗的药物&#xff0c;在多种类型癌症的临床治疗探索中展现出显著的应用前景&#xff0c;为肿瘤治疗领域注入了新的活力。从药代动力学与药效学特征来看&#xff0c;该药物具备口服吸收效果更佳、半衰期更长的优势&#xff0c;这一特性使其能够支持…

DApp开发全周期革命:模式创新、模块化架构与合规化生存指南

引言&#xff1a;DApp&#xff0c;数字世界的“新宪法”截至2025年12月&#xff0c;全球DApp数量突破12万&#xff0c;覆盖金融、游戏、社交、供应链等30余个领域&#xff0c;用户总量突破5亿。从Curve Finance的800亿美元锁仓量到Axie Infinity单日300万活跃用户&#xff0c;D…

BC911:22V/3.5A 同步降压单节锂电池充电芯片

BC911是一款高集成度同步降压锂电池充电芯片&#xff0c;专为单节锂离子电池设计&#xff0c;输入电压范围4~22V&#xff0c;最大充电电流3.5A&#xff0c;适用于便携式媒体播放器、智能手机、PDA/DSC、手持设备及充电底座等场景。提供ESOP8与DFN10两种封装&#xff0c;工作结温…

nginx接口超时,增加接口超时时间

C:\tools\nginx-1.28.0\conf\nginx.conf文件&#xff0c;报错&#xff1a;2026/01/07 16:49:32 [error] 29844#25096: *8 upstream timed out (10060: A connection attempt failed because the connected party did not properly respond after a period of time, or establis…

全网干货!2026 转行网络安全:行业前景预判 + 工作内容详解 + 薪资水平参考

如果你计划在2026年转行到网络安全领域&#xff0c;以下是一些建议&#xff0c;可以帮助你顺利过渡并打下坚实的基础 1、薪资情况 初级职位&#xff08;0-3年经验&#xff09; 薪资范围&#xff1a;大约 8k-15k/月&#xff08;根据地区、公司规模和工作内容有所不同&#xff…

ROS-Industrial 安装及使用

ROS-Industrial相关组件信息。它们涵盖了运动规划、可达性分析、标定及系统桥接等关键任务&#xff0c;但各有不同的发布状态和安装方式。为了让你有一个清晰的整体概览&#xff0c;下表汇总了这些组件的核心信息&#xff1a;组件/包名主要功能描述支持的ROS版本 (Humble)推荐的…

UE5 C++(12):

&#xff08;54&#xff09; &#xff08;55&#xff09; 谢谢

低代码技术民主化:全民开发时代即将到来

数字化转型正在经历一场静默的革命。过去几年里&#xff0c;企业对软件的需求以每年两倍以上的速度增长&#xff0c;而专业开发者的供给年增长率不足5%。这道愈发扩大的裂缝&#xff0c;正在被低代码技术以一种近乎哲学的方式弥合——它不仅是工具的创新&#xff0c;更是生产关…