STM32 SysTick中断:嵌入式系统时间管理的核心原理与实战应用

news2026/5/22 7:16:32
1. 项目概述为什么SysTick中断是STM32开发的基石在STM32的嵌入式开发世界里无论你是刚入门的新手还是已经做过几个项目的熟手有一个功能你几乎无法绕开那就是SysTick——系统滴答定时器。你可能在HAL库的初始化代码里见过它也可能在RTOS实时操作系统的源码里频繁地与它打交道。但很多时候我们只是“拿来就用”对于它如何工作、特别是如何利用其中断来精准地管理时间却只知其然不知其所以然。这个项目标题“STM32 SysTick中断使用方法”看似聚焦于一个具体的“使用方法”但其背后涉及的是嵌入式系统最核心的“心跳”与“节拍”管理。SysTick中断绝不仅仅是让一个LED灯定时闪烁那么简单。它是实现精准延时、构建软件定时器框架、为RTOS提供任务调度时钟源乃至进行系统运行时间统计的关键。理解并熟练运用SysTick中断意味着你掌握了为你的STM32应用程序注入稳定“时间感知”能力的方法。这就像给一个机器人装上了精准的时钟它才能知道何时该动、何时该停、每个动作该持续多久。本文将从一个一线开发者的视角彻底拆解SysTick中断。我不会只给你几行干巴巴的初始化代码而是会带你理解ARM Cortex-M内核设计SysTick的初衷分析不同场景下的配置考量手把手演示从寄存器级到HAL库级的两种实现路径并分享在实际产品开发中围绕SysTick中断构建稳健时间管理框架的实战经验与那些容易踩坑的细节。无论你用的是STM32F1、F4还是H7系列其内核层面的原理都是相通的。2. SysTick核心原理与设计思路解析2.1 SysTick的定位来自ARM内核的“标配”定时器首先必须明确SysTick不是一个属于STM32外设如TIM、USART范畴的模块它是ARM Cortex-M处理器内核自带的一个简易定时器。这意味着所有基于Cortex-M内核的芯片包括STM32全系列都拥有它其编程模型是统一的。这种设计带来了巨大的便利性你的延时或操作系统移植代码在不同型号的STM32甚至不同品牌的Cortex-M芯片间移植性会非常好。SysTick的核心任务非常简单提供一个定期的、可预测的中断。它内部是一个24位的递减计数器从某个初始值减到0重载这个初始值计数器就会周而复始地运行。每次计数器减到0就会触发一次SysTick中断同时计数器会自动重载初始值开始下一轮计数。这个“初始值”就是我们配置的关键它直接决定了中断的周期。为什么是24位这是一个在成本和实用性之间的权衡。24位最大计数值约为1670万2^24在常见的系统时钟频率如72MHz、168MHz下足以配置出从微秒到数秒范围的中断周期满足绝大多数定时需求同时又比32位计数器节省硬件资源。2.2 中断周期计算频率、重载值与时间的三角关系这是理解SysTick配置的核心。三者关系如下中断周期秒 重载值 1 / 系统时钟频率Hz这里“1”是因为计数器从重载值递减到0总共经历了重载值1个时钟周期。例如我们常用的1ms中断是如何实现的假设系统时钟SYSCLK 72MHz。 我们想要T 1ms 0.001s。 那么重载值 T * SYSCLK - 1 0.001 * 72,000,000 - 1 72000 - 1 71999。计算时务必注意时钟频率的单位是Hz。在HAL库中提供了一个宏HAL_RCC_GetHCLKFreq()来获取当前的系统时钟频率这样我们的代码就可以适应不同的时钟配置增强可移植性。注意重载值Reload Value必须小于等于0xFFFFFF24位最大值。如果你的计算值超过这个数意味着你要求的中断周期太长单次计数无法实现。此时通常需要结合一个软件变量进行“分频”比如在中断服务函数里对一个静态变量计数每中断N次才执行一次实际操作。2.3 方案选型寄存器操作 vs HAL库如何抉择STM32开发中我们通常有两种方式来配置SysTick直接寄存器操作直接读写Cortex-M内核的系统控制块SCB中的相关寄存器。这种方式代码精简、执行效率最高你对整个过程有完全的控制权常见于早期标准外设库SPL或对体积和效率极其敏感的场景如Bootloader。使用HAL/LL库APISTM32CubeMX生成的代码默认使用HAL库的HAL_SYSTICK_Config()和HAL_SYSTICK_CLKSourceConfig()函数。这种方式屏蔽了底层寄存器细节代码更易读、易维护且与HAL库的其他部分如延时函数HAL_Delay()无缝集成。我的实战建议是对于大多数应用层开发优先使用HAL库方式。理由如下一致性与项目其他部分使用HAL库的风格统一。可维护性代码意图更清晰后续接手者容易理解。功能集成HAL_Delay()、HAL_GetTick()等便利函数都依赖于HAL库配置的SysTick。足够高效对于1ms的中断周期HAL库那一点点额外的调用开销完全可以忽略不计。当然如果你在编写极简的裸机框架或深入研究掌握寄存器操作仍是很有价值的。下文我将对两种方式都进行详解。3. 核心细节解析与实操要点3.1 时钟源选择内核时钟AHB还是二分频SysTick的时钟源可以配置这是一个容易被忽略但重要的细节。它有两个选择内核时钟AHB时钟HCLK这是默认也是推荐的选择。SysTick的时钟与内核主频一致计时最精准。AHB时钟的8分频在某些早期的Cortex-M3/M4设计或特定低功耗场景下可用。除非有特殊的低功耗或计时需求否则不要使用这个分频因为它会降低定时精度并且HAL库的延时函数HAL_Delay默认是基于内核时钟计算的如果时钟源不对会导致延时时间错误。在HAL库中通过HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK)来配置为内核时钟。通常在SystemClock_Config()函数中CubeMX已经帮我们生成并调用了这个配置。3.2 中断优先级配置并非越高越好SysTick中断作为系统心跳它的优先级设置需要慎重。在Cortex-M中中断优先级数值越小优先级越高。常见误区认为系统心跳中断优先级应该设到最高。这是错误的。正确实践SysTick中断的优先级通常应该设置为一个中等或较低的优先级。原因如下避免阻塞关键外部中断SysTick中断是定期发生的频率很高如1ms一次。如果它的优先级过高可能会阻塞那些需要快速响应的外部事件比如电机驱动的PWM捕获、通信接口的数据接收等导致数据丢失或控制失灵。为RTOS做准备许多RTOS如FreeRTOS、uC/OS会使用SysTick作为任务调度器Scheduler的时钟源。调度器中断的优先级通常不会设为最高以确保更紧急的硬件中断能得到响应。在HAL库初始化时SysTick中断优先级通常被设置为默认值。如果你想修改需要在HAL_Init()之后调用HAL_SYSTICK_Config()之前使用HAL_NVIC_SetPriority(SysTick_IRQn, ...)进行设置。一个典型的设置是比你的主要外设中断如USB、通信接口低但比一些非实时性任务高。3.3 中断服务函数ISR编写要点SysTick的中断服务函数名是固定的SysTick_Handler对于ARMCC、GCC编译器。在HAL库工程中你通常不需要自己实现这个函数因为HAL库已经在stm32fxxx_it.c文件中提供了它其内部会调用HAL_IncTick()函数来递增一个全局计数器uwTick这个计数器正是HAL_GetTick()和HAL_Delay()的基础。那么我们如何添加自己的中断处理逻辑呢你有两种主流且优雅的方式回调函数Callback模式这是最推荐的方式。不要在SysTick_Handler里直接写大量代码。而是建立一个自己的定时任务管理模块。在SysTick_Handler中或在其调用的HAL_IncTick()之后调用你自己模块的“定时任务巡检”函数。在这个巡检函数里基于HAL_GetTick()或你自己维护的更高精度的计时变量来执行那些需要定时发生的任务比如按键扫描、LED呼吸灯、传感器数据定时读取等。弱引用Weak重写HAL库定义的SysTick_Handler通常是弱符号__weak。理论上你可以在自己的主文件或某个模块中重新定义一个强符号的SysTick_Handler函数来覆盖它。但务必谨慎如果你重写了它必须确保在新函数里手动调用HAL_IncTick()否则HAL库的延时和计时功能将全部失效。我强烈建议新手不要这样做优先采用第一种回调模式。实操心得保持中断服务函数尽可能短小精悍是嵌入式开发的金科玉律。SysTick中断频率高更应如此。将具体的业务逻辑放到主循环或由SysTick触发的低优先级任务中执行是保证系统实时响应能力的关键。4. 实操过程与核心环节实现下面我将分别展示通过HAL库和直接操作寄存器两种方式配置一个1ms周期的SysTick中断并实现一个简单的毫秒级定时任务框架。4.1 基于HAL库的标准配置流程推荐假设你使用STM32CubeMX生成工程默认已经完成了SysTick的初始化。但我们还是从头梳理一遍关键步骤步骤1系统时钟配置在main.c的SystemClock_Config()函数中CubeMX已经设置了系统时钟如HSE→PLL→SYSCLK72MHz并隐含地调用了HAL_SYSTICK_Config()和HAL_SYSTICK_CLKSourceConfig()。你可以找到这行代码/* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);这里将SysTick中断优先级设置为0最高。根据我们之前的分析你可能需要根据项目实际情况调整这个优先级比如改为3或4。步骤2实现一个简单的定时任务管理器我们在main.c或单独的文件中创建以下代码// 定义任务结构体 typedef struct { uint32_t targetTick; // 任务执行的目标时间点 uint32_t interval; // 任务执行间隔毫秒 void (*taskFunc)(void); // 任务函数指针 uint8_t isActive; // 任务激活标志 } SysTick_Task_t; // 定义几个示例任务 #define MAX_TASKS 5 static SysTick_Task_t taskList[MAX_TASKS]; static uint8_t taskCount 0; // 添加任务的函数 uint8_t SysTick_AddTask(uint32_t interval_ms, void (*func)(void)) { if (taskCount MAX_TASKS) return 0; // 失败 taskList[taskCount].interval interval_ms; taskList[taskCount].taskFunc func; taskList[taskCount].isActive 1; // 设置第一次执行时间为当前时间 间隔 taskList[taskCount].targetTick HAL_GetTick() interval_ms; taskCount; return 1; // 成功 } // 任务巡检函数需要在某个地方被周期调用例如放在main循环中 void SysTick_TaskRunner(void) { uint32_t currentTick HAL_GetTick(); for (int i 0; i taskCount; i) { if (taskList[i].isActive) { // 使用差值比较处理uwTick溢出回绕的情况 if ((int32_t)(currentTick - taskList[i].targetTick) 0) { taskList[i].taskFunc(); // 执行任务 // 更新下一次执行时间 taskList[i].targetTick currentTick taskList[i].interval; } } } } // 示例任务函数1翻转LED void Task_BlinkLED(void) { HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); } // 示例任务函数2打印信息需实现串口发送 void Task_PrintInfo(void) { // uart_printf(SysTick is running.\r\n); }步骤3在主循环中集成在main()函数的while(1)循环中调用任务巡检函数。int main(void) { HAL_Init(); SystemClock_Config(); // ... 其他外设初始化 // 添加定时任务 SysTick_AddTask(500, Task_BlinkLED); // 每500ms闪烁LED SysTick_AddTask(1000, Task_PrintInfo); // 每1000ms打印信息 while (1) { SysTick_TaskRunner(); // 运行定时任务 // ... 其他主循环逻辑 } }这种方式所有的任务逻辑都在主循环中执行SysTick中断只负责精准地递增uwTick实现了中断与业务逻辑的解耦结构清晰且安全。4.2 直接寄存器配置方式深入了解为了理解本质我们看看如何不依赖HAL库手动配置SysTick。步骤1计算重载值如前所述假设SYSCLK 72MHz需要1ms中断则ReloadValue 72000000 / 1000 - 1 71999步骤2配置并启动SysTick我们需要操作三个寄存器SysTick-LOAD重载值寄存器。SysTick-VAL当前值寄存器写入任何值会清空它。SysTick-CTRL控制状态寄存器。#include core_cm3.h // 或对应内核的头文件它定义了SysTick的类型 void SysTick_Init_Direct(uint32_t ticks) { // 1. 设置重载值 SysTick-LOAD (ticks 0xFFFFFFUL) - 1UL; // 确保不超过24位 // 2. 清空当前计数器 SysTick-VAL 0UL; // 3. 配置控制寄存器 // - 使用内核时钟源 (CLKSOURCE 1) // - 使能SysTick中断 (TICKINT 1) // - 使能SysTick计数器 (ENABLE 1) SysTick-CTRL SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; } // 在main函数中调用 int main(void) { // ... 系统时钟初始化后 SysTick_Init_Direct(72000); // 传入的是‘ticks’即72000000/1000 // ... while(1); }步骤3实现中断服务函数你需要在自己工程的启动文件如startup_stm32fxxx.s所声明的中断向量表对应的位置实现SysTick_Handler函数。// 例如在 main.c 中 volatile uint32_t g_systick_counter 0; // 替代HAL的uwTick void SysTick_Handler(void) { g_systick_counter; // 这里可以添加非常简短、必须严格定时的代码 // 例如快速置位一个软件标志。 }然后你可以基于g_systick_counter来实现自己的GetTick()和Delay()函数。注意事项寄存器操作方式虽然高效但你需要自己处理所有细节包括中断优先级的NVIC配置通过NVIC_SetPriority(SysTick_IRQn, ...)并且要确保你的代码与可能使用的其他库如标准外设库的旧代码兼容。在复杂的项目或团队协作中这可能会增加维护成本。5. 构建稳健的毫秒延时与定时框架仅仅会触发中断还不够我们需要基于SysTick构建真正稳定可用的时间服务。HAL_Delay()是一个阻塞延时在很多时候并不适用因为它会独占CPU。我们需要非阻塞的定时判断。5.1 非阻塞延时与定时判断这是嵌入式编程的常用技巧核心就是比较当前“滴答数”和记录的起始“滴答数”。// 非阻塞延时函数查询方式 uint8_t Delay_NonBlocking(uint32_t *startTick, uint32_t delayMs) { if ((HAL_GetTick() - *startTick) delayMs) { *startTick HAL_GetTick(); // 可选自动重置起始点用于循环定时 return 1; // 时间到 } return 0; // 时间未到 } // 使用示例 uint32_t ledToggleTime 0; while (1) { // 其他任务... if (Delay_NonBlocking(ledToggleTime, 200)) { // 每200ms执行一次 HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // 注意这里我们没有在函数内重置startTick因为Delay_NonBlocking示例函数已经做了。 // 实际使用时根据函数设计决定是内部重置还是外部重置。 } // 更多其他任务... }5.2 处理uwTick溢出回绕问题HAL_GetTick()返回的uwTick是一个32位无符号整数大约每49.7天2^32 ms会溢出归零。上面的减法比较(HAL_GetTick() - startTick) delayMs在C语言中对于无符号数运算是安全的即使发生溢出只要时间间隔delayMs小于溢出周期的一半约24.8天计算结果在数学上仍然是正确的。这是嵌入式领域处理定时器溢出的经典且安全的方法。为了更清晰可以定义一个宏或内联函数#define TIME_AFTER(current, previous) ((int32_t)((current) - (previous)) 0) // 判断‘current’时刻是否在‘previous’时刻之后安全处理溢出 // 使用if (TIME_AFTER(HAL_GetTick(), startTime delay)) { ... }5.3 扩展至微秒级延时SysTick通常配置为1ms中断要实现微秒级延时单纯靠中断是不够的。常用的方法是使用一个高分辨率的定时器如基本定时器TIM或者采用DWT数据观察点与跟踪单元中的CYCCNT计数器这是一个内核级的、无中断的32位周期计数器。使用DWT实现微秒延时需芯片支持// 初始化DWT void DWT_Init(void) { CoreDebug-DEMCR | CoreDebug_DEMCR_TRCENA_Msk; // 使能跟踪 DWT-CYCCNT 0; // 清空计数器 DWT-CTRL | DWT_CTRL_CYCCNTENA_Msk; // 使能周期计数器 } // 微秒级延时阻塞式 void DWT_Delay_us(uint32_t us) { uint32_t startTick DWT-CYCCNT; // 将微秒转换为CPU周期数。SystemCoreClock是系统内核频率Hz。 uint32_t delayTicks us * (SystemCoreClock / 1000000); // 等待周期数达到 while ((DWT-CYCCNT - startTick) delayTicks); }这种方法精度非常高且不依赖中断但它是阻塞的。通常用于短时间的精确等待如驱动WS2812B灯珠、软件I2C的时序等。6. 常见问题与排查技巧实录在实际开发中SysTick看似简单却可能引发一些令人困惑的问题。6.1 问题速查表问题现象可能原因排查步骤与解决方案HAL_Delay()延时时间不对变快或变慢1. SysTick时钟源配置错误未使用内核时钟。2.HAL_SYSTICK_Config()传入的Ticks参数计算错误。3. 系统时钟SYSCLK频率与预期不符。1. 检查SystemClock_Config()中是否调用了HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK)。2. 检查HAL_SYSTICK_Config(SystemCoreClock / 1000)参数SystemCoreClock变量值是否正确。3. 使用调试器查看SystemCoreClock变量或检查RCC配置。SysTick中断根本不触发1. 中断未使能TICKINT位。2. 全局中断未开启。3. 重载值LOAD为0。4. 在调试模式下内核可能被挂起。1. 检查SysTick-CTRL寄存器的TICKINT位是否为1。2. 确保在main()早期调用了__enable_irq()或类似函数开启总中断。3. 检查LOAD寄存器值是否大于0。4. 检查调试器的相关设置如CubeIDE中暂停时是否“停止所有外设”。进入SysTick中断后其他中断响应变慢或丢失SysTick中断优先级设置过高。使用HAL_NVIC_SetPriority(SysTick_IRQn, x, y)降低其优先级增大数值x。使用自己的SysTick_Handler后HAL_Delay()卡死重写的中断服务函数中未调用HAL_IncTick()。在你自定义的SysTick_Handler函数开头务必调用HAL_IncTick()。定时任务偶尔会跳过一两次执行1. 中断服务函数执行时间过长导致丢失中断。2. 任务执行时间过长超过了任务间隔。3. 在比较时间时未正确处理uwTick溢出。1.黄金法则保持ISR短小只做标志位设置、计数器递增等简单操作。2. 优化任务函数或将长任务拆解。3. 确保使用(current - start) interval这种无符号减法进行比较。6.2 高级调试技巧测量中断执行时间与系统负载SysTick中断的频率是已知的我们可以利用它来粗略评估系统的繁忙程度。技巧在SysTick中断入口和出口翻转一个GPIO引脚然后用示波器观察该引脚的波形。引脚高电平的宽度就是SysTick中断服务函数包括所有被它调用的函数如HAL_IncTick()和你添加的代码的执行时间。观察如果这个高电平宽度接近甚至超过你的中断周期如1ms说明系统大部分时间都在处理中断负载过重必须优化。实现代码片段void SysTick_Handler(void) { HAL_GPIO_WritePin(PROBE_GPIO_Port, PROBE_Pin, GPIO_PIN_SET); // 入口置高 HAL_IncTick(); // ... 其他非常简短的代码 HAL_GPIO_WritePin(PROBE_GPIO_Port, PROBE_Pin, GPIO_PIN_RESET); // 出口拉低 }这是一个非常直观且强大的性能分析手段。6.3 与RTOS共存的注意事项当你引入RTOS如FreeRTOS时情况会发生变化。RTOS需要接管SysTick作为其心跳Tick源。通常做法RTOS的移植层文件如FreeRTOSConfig.h会要求你注释掉或处理原有的SysTick_Handler并定义RTOS自己的xPortSysTickHandler。RTOS会重新配置SysTick并管理uwTick。你的应用层代码此时你不应该再直接操作SysTick的寄存器或添加自己的中断处理逻辑。所有的定时、延时操作都应使用RTOS提供的API如vTaskDelay()、xTaskGetTickCount()等。HAL库延时HAL_Delay()在RTOS中通常会被重定向到一个基于RTOS Tick的非阻塞延时或者直接不建议使用因为它会阻塞整个任务。核心原则在裸机系统中SysTick是你的时间管家在RTOS系统中请把时间管理权交给操作系统遵循其规则来使用定时和延时功能。通过以上从原理到实践从配置到调试的完整拆解相信你已经对STM32的SysTick中断有了立体而深入的理解。它不仅仅是一个简单的定时器更是你构建稳定、可预测的嵌入式系统的时间基石。从精准的微秒级延时到复杂的多任务调度都离不开对这颗“心脏”的准确把握。下次当你使用HAL_Delay()或配置RTOS的心跳时你会清楚地知道这一切是如何从一次次的SysTick中断中构建起来的。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…