电控---中断

news2025/2/5 9:09:47

中断

1.处理器系统在执行代码的时候,会从存储器依次取出指令和数据,这种能力需要在处理器里保存一个存储器地址,就是所谓的程序计数器(Program Counter,PC),也叫程序指针
2.当外部中断(Extern Interrupt,EXTI)事件发生的时候,单片机有一定的策略保护好当前执行的状态,将PC跳转到中断服务函数(即回调函数),然后执行相应的用户自定义编写的处理策略
3.完成中断后,恢复原有执行
上述过程依赖嵌套中断向量控制器(Nested Vectored Interrupt Controller,NVIC)

中断事件有两类优先级

  • 抢占优先级:高的可以直接中断掉低优先级的中断服务函数直接处理
  • 子优先级:在多中断事件发生时 ,高的可以插队到低的前面先处理

虚函数

函数声明的前缀有_weak,表示该函数是虚函数

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	UNUSED(GPIO_Pin);
}

_weak
本质上是一个宏定义,实际上的文本对应的是编译指令_attribute((weak))

  • 虚函数
    • 有虚函数指令——weak的函数声明
    • 虚函数可以有很多个
  • 实函数
    • 没有虚函数指令_weak的函数声明,也就是普通的函数,都是实函数
    • 实函数至多只有一个,多了会编译报错(如果是C++可以兼容函数重载)
    • 如果实函数不存在,则随机选取一个幸运的虚函数(对我们而言是随机的。但对编译器而言有一定的选取规则)

工程配置

1.根据原理图或者PCB图,找到开发板上按键开关对应的单片机引脚。
2.将单片机开关引脚设置为外部中断0号通道
3.检测模式选择下降沿
4.输入模式选择上拉输入,用于维持平时的高电平
5.使能嵌套中断向量控制器
6.中断的两种优先级默认配置即可

在这里插入图片描述
it.c文件里就是各种各样的中断
在这里插入图片描述
HAL_GPIO_EXTI_IRQHandler(GPIOI_PIN_0);
go to defination
在这里插入图片描述
发现当触发中断时调用回调函数HAL_GPIO_EXTI_Callback(GPIO_Pin);
而这个函数是虚函数,所以我们在main中定义该函数,再次调用的时候就是调用我们自己定义的函数了。(实函数的优先级大于虚函数)

按键消抖方法:

1.通过延迟10ms,略过了不稳定的时间,等稳定下来之后再检测状态
缺点:不能同时调用多个,否则会事与愿违;
2.硬件上再按键两端并联一个电容器,滤除高频率的杂波
缺点:要重新设计电路板
3.不用外部中断,定时直接读取引脚信息,用定时器中断(充分利用了人类的反应时间比计算机慢得多的特点。只需要十几毫秒查询一次即可,同样节省了计算性能)


中断机制补充

在STM32工程中,即使main函数中没有直接调用中断函数,中断条件触发时仍会调用中断函数,这是由单片机的硬件和中断机制决定的。以下是对这一现象的解释以及单片机执行代码的顺序:

  1. 中断函数的调用原理

    • 中断向量表:STM32 微控制器内部有一个中断向量表,其中包含了各种中断类型及其对应的中断服务程序(ISR)的地址。当中断条件触发时,硬件会自动根据中断类型从中断向量表中查找并跳转到相应的 ISR 去执行。
    • 中断优先级:STM32 支持中断优先级设置,高优先级的中断可以打断低优先级的中断执行。当多个中断同时触发时,硬件会根据优先级来决定先处理哪个中断。
    • 自动调用机制:一旦中断条件满足,硬件会自动保存当前 CPU 的执行状态,然后跳转到对应的中断服务程序入口处开始执行,不需要在 main 函数中手动调用。
  2. 单片机执行代码的顺序

    • 上电或复位:系统上电或复位后,PC 指针指向固化在 FLASH 中的启动代码,开始执行初始化操作,如设置堆栈指针、初始化时钟等。
    • 进入 main 函数:启动代码执行完毕后,跳转到用户编写的 main 函数开始执行应用程序的主体代码。
    • 中断触发与响应:在 main 函数执行过程中,如果发生了中断条件触发,CPU 会暂停当前的代码执行,自动保存现场环境(如寄存器的值等),并根据中断向量表找到对应的中断服务程序入口地址,然后跳转去执行中断服务程序。
    • 中断返回:中断服务程序执行完成后,CPU 会恢复之前保存的现场环境,继续执行被中断的 main 函数中的代码,就好像中断从未发生过一样。

综上所述,STM32 微控制器通过中断向量表和硬件自动调用机制实现了中断函数的调用,而无需在 main 函数中显式地调用它们。同时,单片机执行代码的顺序是固定的,从上电或复位开始,经过启动代码的执行,最终进入 main 函数,并在需要时响应中断。这种机制确保了单片机能够高效、可靠地处理各种外部事件和异常情况。

NVIC补充讲解

嵌套中断向量控制器(Nested Vectored Interrupt Controller, NVIC)是 ARM Cortex-M 系列处理器的核心组件,负责管理中断和异常的优先级、嵌套和调度。其设计目标是实现低延迟、高灵活性的中断处理,满足实时系统的需求。以下从架构、寄存器、优先级机制、中断处理流程及优化技术等方面进行专业级分析。

1. NVIC 架构与核心特性

(1) 硬件架构
  • 集成于 Cortex-M 内核:与处理器紧耦合,直接控制中断响应逻辑。
  • 向量中断机制:每个中断/异常有唯一的向量地址(存储在向量表中),支持快速跳转。
  • 优先级动态配置:支持软件实时修改中断优先级。
  • 抢占与尾链优化:硬件自动处理中断嵌套时的现场保存与恢复,减少延迟。
(2) 关键特性
  • 支持 1~240 个外部中断(具体数量由芯片厂商定义)。
  • 4~256 级可编程优先级(优先级位数由芯片实现决定,如 Cortex-M3/M4 支持 8 级优先级,即 3 位)。
  • 优先级分组:将优先级分为抢占优先级(Preemption)和子优先级(Subpriority)。
  • 中断屏蔽:通过 PRIMASKFAULTMASKBASEPRI 寄存器实现中断全局或条件屏蔽。

2. NVIC 寄存器详解

NVIC 通过内存映射寄存器配置,关键寄存器如下(以 Cortex-M3/M4 为例):

(1) 中断使能寄存器
  • ISERx (Interrupt Set Enable Register):写 1 到某位使能对应中断。
  • ICERx (Interrupt Clear Enable Register):写 1 到某位禁用对应中断。
(2) 中断挂起寄存器
  • ISPRx (Interrupt Set Pending Register):手动触发中断挂起。
  • ICPRx (Interrupt Clear Pending Register):清除挂起状态。
(3) 优先级寄存器
  • IPRx (Interrupt Priority Register):配置中断优先级,每个中断占用 8 位(实际使用位数由芯片决定)。
    示例:若使用 4 位优先级(高 4 位有效),优先级字段格式为:
    Priority = (Preemption Priority << (8 - Priority_Width)) | Subpriority
(4) 系统异常寄存器
  • SHPRx (System Handler Priority Register):配置系统异常(如 SysTick、PendSV)的优先级。

3. 优先级分组与抢占机制

(1) 优先级分组寄存器 (AIRCR)
  • AIRCR[10:8] (PRIGROUP):定义优先级分组方式,将优先级位划分为抢占和子优先级。
    分组规则:
    抢占优先级位数 = PRIGROUP[2:0]
    子优先级位数 = Total_Priority_Bits - 抢占优先级位数

    示例:若总优先级位数为 4(即 16 级优先级),设置 PRIGROUP=5(二进制101),则:
    抢占优先级位数 = 3(高3位为抢占优先级),
    子优先级位数 = 1(低1位为子优先级)。

(2) 抢占规则
  • 若新中断的抢占优先级高于当前执行中断的抢占优先级,则发生抢占。
  • 子优先级仅在多个中断同时挂起且抢占优先级相同时决定执行顺序。

4. 中断处理流程

(1) 中断触发
  1. 中断源激活:外设触发中断信号(如定时器溢出)。
  2. 挂起状态设置:NVIC 将中断标记为挂起(Pending)。
  3. 优先级裁决:NVIC 比较当前执行任务的优先级与新中断的抢占优先级。
(2) 响应阶段
  1. 抢占判断:若允许抢占,CPU 暂停当前任务,保存现场(自动压栈:PC, PSR, R0-R3, R12, LR)。
  2. 向量表跳转:根据中断号从向量表获取 ISR 入口地址。
  3. ISR 执行:执行用户编写的中断服务程序。
(3) 中断返回
  1. 尾链优化 (Tail-Chaining):若挂起中断的优先级高于当前 ISR,直接跳转到新 ISR,跳过恢复现场。
  2. 现场恢复:通过 BX LRPOP {PC} 指令触发异常返回,硬件自动恢复现场。

5. 中断延迟与优化

(1) 关键延迟指标
  • 中断响应时间:从中断触发到 ISR 第一条指令执行的时间(Cortex-M 典型值为 12 周期)。
  • 上下文切换时间:现场保存/恢复的周期数(通常 12~20 周期)。
(2) 优化技术
  • 尾链优化:避免不必要的现场恢复/保存,减少连续中断的延迟。
  • 晚到中断处理 (Late Arrival):高优先级中断在保存现场期间到达时,优先处理高优先级中断。
  • 优先级压缩:合理分配优先级,避免过多抢占导致堆栈溢出。

6. 高级功能

(1) 动态优先级修改
  • 通过写 NVIC_IPRx 寄存器实时修改中断优先级。
  • 应用场景:动态调整任务重要性(如实时任务优先级提升)。
(2) 中断屏蔽
  • PRIMASK:全局关闭中断(CPSID I)。
  • BASEPRI:屏蔽优先级低于某阈值的中断(如 BASEPRI = 0x40 屏蔽优先级 ≥ 4 的中断)。
(3) 软件触发中断
  • 通过写 NVIC_STIR 寄存器(Software Trigger Interrupt Register)触发中断。

7. 调试与问题排查

(1) 常见问题
  • 优先级配置错误:导致预期外的中断嵌套或阻塞。
  • 中断服务程序过长:引发其他高优先级中断的响应延迟。
  • 共享资源冲突:未使用临界区保护导致数据竞争。
(2) 调试工具
  • CMSIS-Core 函数:如 __get_IPSR() 获取当前中断号。
  • 调试器监控:通过 IDE 查看 NVIC 寄存器状态和中断挂起情况。

8. 实际代码示例(基于寄存器操作)

(1) 配置外部中断 EXTI0
// 使能 EXTI0 中断(假设 EXTI0 对应中断号 6)
NVIC_ISER0 |= (1 << 6); // ISER0 对应中断 0-31

// 设置优先级(抢占优先级 2,子优先级 1,优先级位数为 4)
uint8_t priority = (2 << (8 - 4)) | 1; // 假设优先级位数为 4
NVIC_IPR6 = priority << 4; // IPR6 对应中断号 6,优先级值左移 4 位(高4位有效)

// 设置优先级分组(抢占3位,子1位)
SCB->AIRCR = (0x5FA << 16) | (0x5 << 8); // PRIGROUP=5
(2) 临界区保护
#define ENTER_CRITICAL()  __asm volatile ("cpsid i")
#define EXIT_CRITICAL()   __asm volatile ("cpsie i")

NVIC 是 Cortex-M 实时性的核心保障,其设计在硬件层面实现了:

  • 低延迟中断响应:通过向量化跳转和尾链优化。
  • 灵活的优先级管理:支持动态调整和分组配置。
  • 安全的嵌套机制:硬件自动处理现场保存与恢复。

深入掌握 NVIC 需结合芯片手册(如 STM32 参考手册)和 ARMv7-M 架构文档,重点关注寄存器操作、优先级策略及调试技巧。


定时器

TIM定时器分类:

  • 基本定时器:
    • 预分频、自动装载值、自定义计数方向、自定义触发事件
    • 单个脉冲输出
    • 可以产生DMA请求定期搬运数据
  • 通用定时器:
    • 具有基本定时器的全部功能
    • 四个独立的GPIO通道可以进行输入捕获、输出比较、PWM生成、编码模式等
  • 高级定时器
    • 通用定时器的全部功能
    • 八个GPIO通道可以支持反向或互补PWM输出
    • 一个GPIO通道可以支持外部输入信号引入刹车重启等功能

CubeMX配置

在这里插入图片描述
使能内部时钟
在这里插入图片描述

  • Prescaler(PSC,预分频):定时器输入频率从时钟树的APB总线获取,但定时器本身可能不需要太高的频率,因此需要对定时器输入频率进行分频,得到定时器的主频
  • Counter Mode(计数模式)
    • 定时器有个计数器(Counter,CNT),根据其主频没产生一次脉冲,计数器改变1
    • Up(向上计数):+1
    • Down(向下计数):-1
    • Center Aligned model(中心对齐模式,双向计数):既可以+1也可以-1
      • Center Aligned model1 (中心对齐模式 1):计数器交替地向上和向下计数,输出比较中断标志位只在计数器 向下计数时被设置。
      • Center Aligned model2 (中心对齐模式 2):计数器交替地向上和向下计数,输出比较中断标志位只在计数器向上计数时被设置。
      • Center Aligned model3(中心对齐模式 3):计数器交替地向上和向下计数,输出比较中断标志位在计数器向下和向上计数时均被设置。
  • Counter Period(Auto Reload Register,ARR,自动装载值):
    • 定时器的计数器只能在0到ARR之间变动
    • 向上计数,从0到ARR,然后再开启一轮循环
    • 向下计数,从ARR到0,然后再开启一轮循环
    • 双向计数(中心对齐),从0到ARR-1,然后再从ARR计数到1,然后再开启一轮循环
    • 当计数器向上到达ARR或向下到达0时,下一个定时器主频周期会产生溢出中断。
  • Internal Clock Division(内部时钟分频)
    • 内部时钟分频是指对定时器的输入时钟源进行分频,以得到定时器计数器所使用的时钟信号频率。通过设置不同的分频系数,可以改变定时器的计数速度和时间基准。
    • 根据设置的分频系数,将定时器的输入时钟源进行相应的分频。例如,如果设置不分频,则定时器计数器的时钟信号频率等于输入时钟源的频率;如果设置为分频 2,则定时器计数器的时钟信号频率为输入时钟源频率的一半。
  • auto-reload preload(自动装载预装载)
    • Enable:新的自动重载值不会立即生效,而是先被写入预装载寄存器。此时计数器会继续按照原来旧的重载值进行计数,直到发生更新事件(如计数器溢出)。
    • Disable: 如果当前正在计数,写入的新值会立刻成为当前计数周期的重载值,计数器将按照新的重载值重新开始计数。
      在这里插入图片描述
      在这里插入图片描述
      HAL_TIM_Base_Start_IT开始TIM中断检测
      在这里插入图片描述
      重定义TIM中断虚函数

Prescaler(TIM定时器的预分频)

  1. 基本概念

    • 定义:预分频器是一种用于对输入的时钟信号进行分频的电路或功能模块。在STM32的TIM定时器中,它位于时钟源与计数器之间,通过对时钟源输出的时钟进行分频,得到定时器的计数时钟。例如,如果时钟源的频率为72MHz,通过预分频器设置为0(即不分频),则定时器的计数时钟频率就是72MHz;若设置为71(实际分频系数为72),则定时器的计数时钟频率为1MHz。
    • 作用:由于微控制器的系统时钟通常较高,而某些应用场景可能不需要如此高的频率来进行定时操作,预分频器可以将高频的时钟信号降低到合适的频率,以满足不同的定时需求。比如在一些需要较长定时间隔的场景中,通过预分频可以得到较低的定时器时钟频率,从而实现更长时间的定时[1]。
  2. 工作原理

    • 计数与更新:定时器时钟源每来一个脉冲(即tick一次),预分频器的计数值就会加1。当预分频器的计数值达到预设的值(即预分频器的设定值,范围通常是0至65535)时,预分频器会将计数值重置为0,并输出一个脉冲信号给计数器,使计数器的值加1。这个过程不断重复,从而实现了对时钟源的分频。
    • 示例:假设预分频器的值为71,那么时钟源需要72个脉冲后,预分频器才会完成一次计数周期并复位,同时计数器的值加1。这意味着定时器的计数时钟频率变为了原来的1/72。
  3. 相关寄存器

    • TIMx_PSC:这是预分频器的寄存器,用来设置预分频器的值。它是一个16位的寄存器,可设置的范围为0至65535,对应的分频系数实际上是1至65536。例如,如果要将定时器时钟频率除以8,就需要将TIMx_PSC的值设置为7。
    • 影子寄存器:TIMx_PSC寄存器存在影子寄存器(官方翻译为缓冲功能)。当定时器启动后更改TIMx_PSC的值并不会立即影响当前定时器的时钟频率,要等到下一个更新事件(UEV)发生时才会生效。更新事件由TIMx_CR1寄存器中的UDIS位控制,可通过计数器上溢或手动将TIMx_EGR寄存器中的UG位设置为1来触发。
  4. 应用场景举例

    • 精确定时:在一些需要精确控制时间间隔的应用中,如精确的数据采集、通信协议的实现等,可以通过合理设置预分频器的值来获得所需的定时精度。例如,若要实现每隔1ms产生一次中断,当系统时钟为72MHz时,可将预分频器设置为71,这样定时器的计数时钟频率为1MHz,每次计数1000个周期即为1ms。
    • 节能控制:在低功耗应用中,当不需要频繁地进行定时操作时,可以通过增大预分频器的值来降低定时器的时钟频率,从而减少芯片的功耗。例如,在待机状态下,将预分频器设置为较大的值,使定时器的计数时钟频率降低,减少不必要的时钟切换和动态功耗。

Internal Clock Division(内部时钟分频)

  1. 基本概念

    • 定义:在 STM32 的定时器模块中,内部时钟分频是指对定时器的输入时钟源进行分频,以得到定时器计数器所使用的时钟信号频率。通过设置不同的分频系数,可以改变定时器的计数速度和时间基准。
    • 相关寄存器:主要涉及到 TIMx_CR1 寄存器中的 CKD 位字段,用于设置定时器时钟(CK_INT)频率与数字滤波器(ETR、TIx)使用的采样时钟之间的分频比。
  2. 工作原理

    • 分频操作:根据设置的分频系数,将定时器的输入时钟源进行相应的分频。例如,如果设置不分频,则定时器计数器的时钟信号频率等于输入时钟源的频率;如果设置为分频 2,则定时器计数器的时钟信号频率为输入时钟源频率的一半。
    • 与数字滤波器的关系:在一些应用场景中,如定时器的输入捕获功能,内部时钟分频会影响数字滤波器的采样频率。数字滤波器用于对输入信号进行滤波处理,去除高频干扰等。通过合理设置内部时钟分频,可以调整数字滤波器的采样频率,从而更好地实现对输入信号的准确采集和处理。
  3. 应用场景举例

    • 输入捕获:在测量外部信号的频率、占空比或脉宽等参数时,需要使用定时器的输入捕获功能。通过合理设置内部时钟分频,可以使数字滤波器以合适的采样频率对输入信号进行采样,从而准确地检测到信号的有效电平变化。例如,在测量一个频率较高的脉冲信号时,可以选择较小的分频系数,使数字滤波器的采样频率较高,以便更精确地捕捉到脉冲信号的变化。
    • 按键消抖:在检测按键按下和松开的过程中,由于机械结构的原因,会产生抖动现象,即按键信号会出现短暂的不稳定状态。利用定时器的输入捕获功能和内部时钟分频,可以设置合适的采样频率和滤波参数,过滤掉按键抖动产生的干扰信号,从而准确地判断按键的有效按下和松开动作。

Auto Reload Register(自动重装载寄存器)

  1. 基本概念

    • 定义:在STM32等微控制器的定时器中,自动重装载寄存器用于设置定时器的自动重装载值,从而决定定时器的计数周期。它是一个16位的寄存器,里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就会产生溢出中断。
    • 相关寄存器:在物理上,自动重装载寄存器对应两个寄存器,一个是程序员可以写入或读出的预装载寄存器(preload register),另一个是程序员看不见的、但在操作中真正起作用的影子寄存器(shadow register)。根据TIMx_CR1寄存器中ARPE位的设置,预装载寄存器的内容可以随时传送到影子寄存器,即两者是连通的(permanently),或者在每一次更新事件(UEV)时才把预装载寄存器的内容传送到影子寄存器。
  2. 工作原理

    • 计数模式
      • 向上计数模式:定时器从0开始计数,当计数值达到自动重装载寄存器的值时,定时器会产生一个溢出事件,并将计数值重置为0,然后重新开始计数。
      • 向下计数模式:定时器从自动重装载寄存器的值开始计数,当计数值减到0时,定时器会产生一个溢出事件,并将计数值重置为自动重装载寄存器的值,然后重新开始计数。
    • 更新事件:当计数器的值达到自动重装载寄存器的值时,会产生一个更新事件(UEV)。如果此时TIMx_CR1寄存器中的UDIS位等于0,更新事件会被发送。此外,也可以通过软件主动生成更新事件。
  3. 配置方法

    • 禁用预装载寄存器:修改自动重装载寄存器的值会直接操作影子寄存器,新的值将立即生效。例如,使用TIM_ARRPreloadConfig(TIM4, DISABLE);函数可以禁用TIM4的预装载寄存器。
    • 使能预装载寄存器:修改自动重装载寄存器的值会先操作预装载寄存器,直到下一次更新事件后,预装载寄存器的值才会被拷贝到影子寄存器中。例如,使用TIM_ARRPreloadConfig(TIM4, ENABLE);函数可以启用TIM4的预装载寄存器。

Auto Reload Preload(自动重装载预加载)

  1. 基本概念

    • 定义:在 STM32 的 TIM 定时器中,自动重装载寄存器(TIMx_ARR)用于设置定时器的计数周期。而自动重装载预加载功能则是对该寄存器的一种操作模式控制,它可以决定写入新的自动重载值后何时生效。
    • 相关寄存器:主要涉及到 TIMx_CR1 寄存器中的 ARPE 位。当 ARPE 位设置为 0 时,表示禁用自动重装载预加载功能;当 ARPE 位设置为 1 时,表示启用自动重装载预加载功能。
  2. 工作原理

    • 禁用预加载(ARPE=0)
      • 当 ARPE 位为 0 时,对 TIMx_ARR 寄存器进行写操作,新的自动重载值会立即生效。也就是说,如果当前正在计数,写入的新值会立刻成为当前计数周期的重载值,计数器将按照新的重载值重新开始计数。
      • 例如,假设定时器正在从 0 开始向上计数,当前计数值为 50,此时如果将 TIMx_ARR 的值从 100 修改为 80,并且 ARPE 位为 0,那么计数器会立即停止当前的计数,以 80 作为新的计数上限重新开始计数。
    • 启用预加载(ARPE=1)
      • 当 ARPE 位为 1 时,对 TIMx_ARR 寄存器进行写操作,新的自动重载值不会立即生效,而是先被写入预装载寄存器。此时计数器会继续按照原来旧的重载值进行计数,直到发生更新事件(如计数器溢出)。
      • 当更新事件发生时,预装载寄存器中的新值才会被传送到影子寄存器,从而成为下一个计数周期的重载值。这样可以确保在更新事件产生后再开始新的计数周期,保护了原来的计数周期不受影响。
      • 例如,同样在定时器从 0 开始向上计数,当前计数值为 50,将 TIMx_ARR 的值从 100 修改为 80,且 ARPE 位为 1,那么计数器会继续按照 100 进行计数,直到计数到 100 发生溢出事件后,下一个计数周期才会以 80 作为计数上限。
  3. 应用场景

    • 多定时器同步输出:在多个定时器同时输出信号的场景中,自动重装载预加载功能非常有用。通过设置相同的更新事件和预加载值,可以确保多个定时器的输出信号在同一个时刻发生变化,实现同步输出。这对于一些需要精确时序控制的应用场景,如通信协议中的时钟同步、多个外设的协同工作等,具有重要意义。
    • 避免计数周期干扰:在一些实时性要求较高的应用中,可能需要在定时器运行过程中动态地改变计数周期。如果直接修改 TIMx_ARR 的值可能会导致当前计数周期的混乱,影响系统的正常运行。而启用自动重装载预加载功能后,可以在不影响当前计数周期的情况下,安全地更新计数周期,避免了计数周期的干扰和异常。

日落山水静,为君起松声。 —王勃

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

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

相关文章

动态规划DP 背包问题 多重背包问题(朴素版+二进制优化+单调队列)

概览检索 动态规划DP 概览&#xff08;点击链接跳转&#xff09; 动态规划DP 背包问题 概览&#xff08;点击链接跳转&#xff09; 多重背包问题1 原题链接 AcWiing 4. 多重背包问题1 题目描述 有 N种物品和一个容量是 V的背包。 第 i 种物品最多有 si件&#xff0c;每件体…

Golang 并发机制-5:详解syn包同步原语

并发性是现代软件开发的一个基本方面&#xff0c;Go&#xff08;也称为Golang&#xff09;为并发编程提供了一组健壮的工具。Go语言中用于管理并发性的重要包之一是“sync”包。在本文中&#xff0c;我们将概述“sync”包&#xff0c;并深入研究其最重要的同步原语之一&#xf…

排序算法与查找算法

1.十大经典排序算法 我们希望数据以一种有序的形式组织起来&#xff0c;无序的数据我们要尽量将其变得有序 一般说来有10种比较经典的排序算法 简单记忆为Miss D----D小姐 时间复杂度 &#xff1a;红色<绿色<蓝色 空间复杂度&#xff1a;圆越大越占空间 稳定性&…

数据结构课程设计(三)构建决策树

3 决策树 3.1 需求规格说明 【问题描述】 ID3算法是一种贪心算法&#xff0c;用来构造决策树。ID3算法起源于概念学习系统&#xff08;CLS&#xff09;&#xff0c;以信息熵的下降速度为选取测试属性的标准&#xff0c;即在每个节点选取还尚未被用来划分的具有最高信息增益的…

python-leetcode-二叉树的层序遍历

102. 二叉树的层序遍历 - 力扣&#xff08;LeetCode&#xff09; # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right right from coll…

毕业设计:基于深度学习的高压线周边障碍物自动识别与监测系统

目录 前言 课题背景和意义 实现技术思路 一、算法理论基础 1.1 卷积神经网络 1.2 目标检测算法 1.3 注意力机制 二、 数据集 2.1 数据采集 2.2 数据标注 三、实验及结果分析 3.1 实验环境搭建 3.2 模型训练 3.2 结果分析 最后 前言 &#x1f4c5;大四是整个大学…

【Hadoop】Hadoop的HDFS

这里写目录标题 HDFS概述HDFS产出背景及定义HDFS产生背景HDFS定义 HDFS优缺点HDFS优点HDFS缺点 HDFS组成架构HDFS文件块大小 HDFS的Shell操作常用命令实操准备工作上传下载HDFS直接操作 HDFS的API操作客户端环境准备HDFS的API案例实操HDFS文件上传HDFS文件下载HDFS文件更名和移…

C++ Primer 迭代器

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

简单介绍一下什么是OpenFeign

OpenFeign是什么&#xff1f; OpenFeign是一个声明式的Http客户端&#xff0c;它可以用来发起Http请求 它主要用于SpringCloud微服务之间的通讯&#xff0c;让调用另一个服务的Java方法和调用本地方法一样快速和便捷 之前我们是用RestTemplate写一大堆东西发起Http请求远程调…

力扣动态规划-20【算法学习day.114】

前言 ###我做这类文章一个重要的目的还是记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&#xff01;&#xff01;&#xff01; 习题 1.网格中的最小路径代价 题目链接…

Codeforces Round 1002 (Div. 2)(部分题解)

补题链接 A. Milya and Two Arrays 思路&#xff1a;题意还是比较好理解&#xff0c;分析的话我加了一点猜的成分&#xff0c;对a&#xff0c;b数组的种类和相加小于4就不行&#xff0c;蒋老师的乘完后小于等于2也合理。 AC代码&#xff1a; #include <bits/stdc.h> u…

在线销售数据集分析:基于Python的RFM数据分析方法实操训练

一、前言 个人练习&#xff0c;文章用于记录自己的学习练习过程&#xff0c;分享出来和大家一起学习。 数据集&#xff1a;在线销售数据集 分析方法&#xff1a;RFM分析方法 二、过程 1.1 库的导入与一些必要的初始设置 import pandas as pd import datetime import matplo…

小程序设计和开发:要如何明确目标和探索用户需求?

一、明确小程序的目标 确定业务目标 首先&#xff0c;需要明确小程序所服务的业务领域和目标。例如&#xff0c;是一个电商小程序&#xff0c;旨在促进商品销售&#xff1b;还是一个服务预约小程序&#xff0c;方便用户预订各类服务。明确业务目标有助于确定小程序的核心功能和…

【C语言深入探索】:指针高级应用与极致技巧(二)

目录 一、指针与数组 1.1. 数组指针 1.2. 指向多维数组的指针 1.2.1. 指向多维数组元素的指针 1.2.2. 指向多维数组行的指针 1.3. 动态分配多维数组 1.4. 小结 二、指针与字符串 2.1. 字符串表示 2.2. 字符串处理函数 2.3. 代码示例 2.4. 注意事项 三、指针与文件…

手写MVVM框架-构建虚拟dom树

MVVM的核心之一就是虚拟dom树&#xff0c;我们这一章节就先构建一个虚拟dom树 首先我们需要创建一个VNode的类 // 当前类的位置是src/vnode/index.js export default class VNode{constructor(tag, // 标签名称&#xff08;英文大写&#xff09;ele, // 对应真实节点children,…

【Blazor学习笔记】.NET Blazor学习笔记

我是大标题 我学习Blazor的顺序是基于Blazor University&#xff0c;然后实际内容不完全基于它&#xff0c;因为它的例子还是基于.NET Core 3.1做的&#xff0c;距离现在很遥远了。 截至本文撰写的时间&#xff0c;2025年&#xff0c;最新的.NET是.NET9了都&#xff0c;可能1…

C++11中的bind

官方文档对于bind接口的概述解释&#xff1a;Bind function arguments 在C11中&#xff0c;std::bind 是一个非常有用的工具&#xff0c;用于将函数、成员函数或函数对象与特定的参数绑定在一起&#xff0c;生成一个新的可调用对象。std::bind 可以用于部分应用函数参数、改变…

鼠标拖尾特效

文章目录 鼠标拖尾特效一、引言二、实现原理1、监听鼠标移动事件2、生成拖尾元素3、控制元素生命周期 三、代码实现四、使用示例五、总结 鼠标拖尾特效 一、引言 鼠标拖尾特效是一种非常酷炫的前端交互效果&#xff0c;能够为网页增添独特的视觉体验。它通常通过JavaScript和C…

金山打字游戏2010绿色版,Win7-11可用DxWnd完美运行

金山打字游戏2010绿色版&#xff0c;Win7-11可用DxWnd完美运行 链接&#xff1a;https://pan.xunlei.com/s/VOIAYCzmkbDfdASGJa_uLjquA1?pwd67vw# 进入游戏后&#xff0c;如果输入不了英文字母&#xff08;很可能是中文输入状态&#xff09;&#xff0c;就按一下“Shift”键…

爬虫学习笔记之Robots协议相关整理

定义 Robots协议也称作爬虫协议、机器人协议&#xff0c;全名为网络爬虫排除标准&#xff0c;用来告诉爬虫和搜索引擎哪些页面可以爬取、哪些不可以。它通常是一个叫做robots.txt的文本文件&#xff0c;一般放在网站的根目录下。 robots.txt文件的样例 对有所爬虫均生效&#…