STM32F103C8T6单片机开发:简单说说单片机的外部GPIO中断(标准库)

news2025/4/18 21:30:33

目录

前言

如何使用STM32F1系列的标准库完成外部中断的抽象

初始化我们的GPIO为输入的一个模式

初识GPIO复用,开启GPIO的复用功能时钟

GPIO_EXTILineConfig和EXTI_Init配置外部中断参数

插入一个小知识——如何正确的配置结构体?

初始化中断:NVIC注册

处理中断回调函数

本篇的实验代码


前言

在之前,我们就详细的讨论过了最简单的GPIO设备的驱动和使用,但是如你所见,这些调用都是同步,即我们程序主动的去设置和读取GPIO的状态。这很正常——我们只有在想要主动出击的时候,比如说点亮LED电平,查询按钮的状态的时候,我们主动的申请和读取结果。这是很正常的事情。

但是仍然有一些场景,我们实际上并不是这样的,甚至完全与此相反。举个例子,一些事情我们更希望是外部来告知我们发生了。举个例子,一个经典的场景就是——我们希望在按键嗯下的时候,我们来做一部分事情,比如说后面我们切换LCD界面啊等等的事情。按照我们之前的方法,那就是:

while(1)
{
    if(isKeyPressed()){
        do_things();
    }else{
        do_other_things();
    }
    ...
}

这个的问题看起来不大,但是实际上你仔细思考一下,问题很大。在我们上一个小节中,我们做一个改动,您可以尝试一下:

while(1)
{
    if(isKeyPressed()){
        reverse_gpio_status(&led0);
    }else{
        system_clock_delay_ms(1000);    // delay for 1 seconds
    }
    ...
}

你会发现一个致命的问题,整个系统罢工了,为什么,我们仔细看看这个代码——我们在一瞬间检查完Key没有按下之后,整个系统直接挂起来1秒钟,如果我们之后写更加庞大的项目的时候,问题还能更加尖锐(比如说使用ESP8266等待网络请求,那可就是一个等待就是好几秒),这下你的客户如果发了疯的按按钮就会发现根本不起作用的时候,你的好日子也就到头了。那咋办?

仔细想下,我们的逻辑是不是有点问题——分明是我们想要“按下按钮的时候,我们才会翻转LED的电平。”,整个程序的逻辑是——询问一下按钮按下了嘛?有则处理按钮按下的逻辑,没有处理其他程序。这不对的。

问题就在于,我们需要把逻辑颠倒过来!一个事件发生了,我们需要如何处理这个事情。而不是反复的询问这个事情有没有发生。因此,我们就需要一个机制,这个机制,就是外部中断,外部中断按照一种通知的方式,通知我们的单片机一个抽象的事件发生了。

一个光传感器察觉到了一个光亮度的变化的时候,光传感器发送了一个电平脉冲。与其一直轮循电平的变化,不如直接让我们的GPIO处于一个中断的前端,让接受到电平变化的引脚申请我们的单片机触发一个中断,极其短暂的打断我们的程序执行,跳转道一个新的处理流处理我们的电平变化的事件。比如说,光暗了,我们需要开灯,这个时候,我们处理光传感器发过来的“光暗下去了”的信号,处理的程序就是打开一个LED灯。你看,简单吧!

因此,按照这种方式,我们就可以摆脱我们的轮循式的询问,转向语义更好的“中断事件通知了”。

关于中断的本质和STM32的中断,我们放到旋转编码器和光传感器的之后作为一个硬核原理篇章,仔细的介绍其根本原理,这里,我们仍然只是保留到会用即可的水平。

下面,我们就来聊一聊,标准库是如何使用外部中断来完成我们的事情的。

如何使用STM32F1系列的标准库完成外部中断的抽象

标准库已经给我们提供好了脚手架了,只需要我们按照步骤进行配置即可。简单的说,就是做这些事情

  • 初始化我们的GPIO为输入的一个模式

  • 初始化GPIO外部中断的资源寄存器

  • 使能我们的外部中断

这需要我们一步步来看。

初始化我们的GPIO为输入的一个模式

为什么是输入模式呢?你想想,我们接受外部的中断是不是需要从外界获取信息?是的,这就是我们的GPIO中断模式本质上需要以输入模式进行配置的原因,如果你还看笔者的HAL库教程,你就会知道,HAL库直接封装好了体系,将输入模式中的一部分特化出来了外部中断,合并了我们标准库的配置,标准库比较原始,因此我们需要做的事情就是将这些步骤正确的组合起来。

关于输入模式的配置,这里我们不再重复谈论了,实在乏味。我们马上进入下一个阶段,配置外部中断的GPIO引脚资源。

初识GPIO复用,开启GPIO的复用功能时钟

关于复用的底层原理,一并合并到我们的GPIO中断中讨论,这里,你只需要知道的是:GPIO现在具备了片上外设和外部设备的沟通能力,在这里,就是我们的中断控制器现在可以监控我们的外部设备的电平变化了,我们这一步就是做这个事情。

开启GPIO的AF时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

开启这个时钟,我们的片上外设复用就变得可用,下一步,就是提交我们要监察的外部中断是如何的。

GPIO_EXTILineConfig和EXTI_Init配置外部中断参数

使用的函数是GPIO_EXTILineConfig来注册EXTI中断控制子系统,连接GPIO和外部中断线,进而再EXTI_Init函数来初始化。

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);

EXTI_InitTypeDef里,提供的就是我们写的参数了

typedef struct
{
  uint32_t EXTI_Line;               /*!< Specifies the EXTI lines to be enabled or disabled.
                                         This parameter can be any combination of @ref EXTI_Lines */
   
  EXTIMode_TypeDef EXTI_Mode;       /*!< Specifies the mode for the EXTI lines.
                                         This parameter can be a value of @ref EXTIMode_TypeDef */
​
    // 笔者注释:之前的版本中这里的注释类型写错了
  EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines.
                                         This parameter can be a value of @ref EXTITrigger_TypeDef */
​
  FunctionalState EXTI_LineCmd;     /*!< Specifies the new state of the selected EXTI lines.
                                         This parameter can be set either to ENABLE or DISABLE */ 
}EXTI_InitTypeDef;
插入一个小知识——如何正确的配置结构体?

我发现,大部分嵌入式的人,不太会查看手册/查看注释来进行学习。你看,我们的标准库实际上已经把事情说的很明白了,我们这里实际上需要填写的参数

第一个蚕食,人家的说法是任意组合的EXTI_Line,我们一看,嗯很,没有具体说明,一个最快速的办法就是看注释,EXTI_LINE的一个组合,这也就说明了,直接全局搜索一个EXTI_LINE,这里的EXTI_Mode对应的就是对应的GPIO_Pin所在的EXTI线,举个例子,GPIO_Pin_0对应的就是EXTI_Line0,GPIO_Pin_1对应的就是EXTI_Line1,类推!

#define EXTI_Line0       ((uint32_t)0x00001)  /*!< External interrupt line 0 */
#define EXTI_Line1       ((uint32_t)0x00002)  /*!< External interrupt line 1 */
#define EXTI_Line2       ((uint32_t)0x00004)  /*!< External interrupt line 2 */
#define EXTI_Line3       ((uint32_t)0x00008)  /*!< External interrupt line 3 */
#define EXTI_Line4       ((uint32_t)0x00010)  /*!< External interrupt line 4 */
#define EXTI_Line5       ((uint32_t)0x00020)  /*!< External interrupt line 5 */
#define EXTI_Line6       ((uint32_t)0x00040)  /*!< External interrupt line 6 */
#define EXTI_Line7       ((uint32_t)0x00080)  /*!< External interrupt line 7 */
#define EXTI_Line8       ((uint32_t)0x00100)  /*!< External interrupt line 8 */
#define EXTI_Line9       ((uint32_t)0x00200)  /*!< External interrupt line 9 */
#define EXTI_Line10      ((uint32_t)0x00400)  /*!< External interrupt line 10 */
#define EXTI_Line11      ((uint32_t)0x00800)  /*!< External interrupt line 11 */
#define EXTI_Line12      ((uint32_t)0x01000)  /*!< External interrupt line 12 */
#define EXTI_Line13      ((uint32_t)0x02000)  /*!< External interrupt line 13 */
#define EXTI_Line14      ((uint32_t)0x04000)  /*!< External interrupt line 14 */
#define EXTI_Line15      ((uint32_t)0x08000)  /*!< External interrupt line 15 */

EXTI_Mode是一个enum枚举类型

typedef enum
{
  EXTI_Mode_Interrupt = 0x00,
  EXTI_Mode_Event = 0x04
}EXTIMode_TypeDef;

这里有两个参数,我们理解和学习的是中断,很显然是EXTI_Mode_Interrupt,但是这里笔者还是要简单的说明一下这两个参数有什么区别。

特性EXTI_Mode_Interrupt (中断模式)EXTI_Mode_Event (事件模式)
是否触发中断✔️ (调用我们处理的回调函数)❌ (仅硬件事件)
是否唤醒 CPU✔️
CPU 参与需要 CPU 处理中断无需 CPU 干预
典型应用紧急任务(如按键、故障检测)硬件触发(如 DMA、ADC)

EXTI_Mode_Event不是我们这里可以管的,因此,等到我们谈论到了DMA,ADC等概念的时候,我们会回来学习事件模式的。

EXTITrigger_TypeDef说明我们如何触发这个中断。

typedef enum
{
  EXTI_Trigger_Rising = 0x08,
  EXTI_Trigger_Falling = 0x0C,  
  EXTI_Trigger_Rising_Falling = 0x10
}EXTITrigger_TypeDef;

嗯,上升?下降?上升下降?这些是什么东西啊?别急,我们来仔细思考一下。一个很自然的疑问,举个例子:我们如何认为外部的GPIO中断道来了呢?你可能会说这是我关心的嘛?你需要关心!,这需要你仔细阅读器件的手册,举一个例子,笔者的光传感器,查看手册后,可以做出这样的一个时序图。

我们看到,这个器件的特性是阈值触发类型的传感器,也就是扫描过一次阈值,就会触发一次信号。可以看到,我们触发一次,我们的光传感器就会快速向外发射一个低电平,因此,我们只需要检测低电平,就能捕捉到我们的光强变化事件了!

仔细看看下面的这个图,思考一下上面的三个枚举,你认为,这三个枚举,想要监控的是哪些电平变化呢?答案如下!

现在我们很清楚了,对于我们的器件,如果你的手册上说:光强变化给一个下降触发的时候,你就需要配置成Falling了。

剩下的Cmd实际上就是Enable,没啥好说的。这就是使能的意思。

很好,我们申请GPIO中断的第一个子步骤,是注册GPIO的中断Pin线,使用的函数是

/**
  * @brief  Selects the GPIO pin used as EXTI Line.
  * @param  GPIO_PortSource: selects the GPIO port to be used as source for EXTI lines.
  *   This parameter can be GPIO_PortSourceGPIOx where x can be (A..G).
  * @param  GPIO_PinSource: specifies the EXTI line to be configured.
  *   This parameter can be GPIO_PinSourcex where x can be (0..15).
  * @retval None
  */
  void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)

比如说,我们想要给GPIOB注册中断,办法就是提供:GPIO_PortSourceGPIOB和GPIO_PinSource0。这个时候,使用这个函数的后,我们的GPIO_Pin就能根我们的外部中断线连接起来,下一步只需要把中断使能起来,就可以使用外部中断来监控事件了。

初始化中断:NVIC注册

NVIC是啥呢?NVIC的全称是Nested vectored interrupt controller,即嵌套向量中断控制器。关于通用的中断,我们需要做的理解就是跟上面说的一致——是事件(中断也可以来自内部,但对于最核心的CPU而言,你认为他们都是外部好像毛病也不大,总而言之,就是一些事件需要触发我们的处理器暂停手下的活来处理通知的中断事件,这里的嵌套你可以认为中断是可以嵌套的)

如果感觉中断不好理解,笔者在手搓操作系统的博客中有打过这样的比喻:

现实生活中,我们可能往往会被任何啥东西打断,比如说,此时此刻我正在写一个阐述中断的博客,我的一个好朋友突然给我发QQ,向我抱怨该死的爬虫实在是太慢了,需要优化一下并发的结构。这个时候,我就跑去回应他,刚准备打几个字,我的母上大人着急的找我问点事情,我又抛下对这个哥们的回复,冲过去回复我母上大人的问题,之后再回复我兄弟的抱怨,最后回来,继续抓耳挠腮的写下这段话。

从0开始的操作系统手搓教程11:为底层添砖加瓦:中断_intr指令-CSDN博客

Charliechen114514/CCOperateSystem: A Tutorial Trying teach you how to make an os in modern tools with gcc, nasm and bochs!

理解好中断之后,我们继续说明我们的配置。STM32对我们的中断管理非常的细致,将中断分组,其描述优先级的位实际上非常了两个比较大的部分。如下所示

  • 抢占优先级(Preemption Priority):决定中断是否可以打断正在执行的其他中断

  • 子优先级(Sub-Priority):当多个挂起中断具有相同抢占优先级时,决定它们的执行顺序

换而言之,回复我母上大人的消息的抢占优先级是1,回复我兄弟的抱怨抢占优先级是2的时候,我显然会先处理母上大人的事情,这个时候,尽管我正在回复我的兄弟,我也会让他靠边站!,这就是抢占优先级的效果。

那子优先级呢?答案是当我们没有发生中断的时候,或者说发生的是同级优先级的中断的时候(可以认为是特殊的“没有中断发生”),我们决定先处理谁。举个例子,我跟好朋友A和好朋友B中,我更喜欢跟A相处的时候,我优先回复A的消息,完事了之后回复B的消息。因此,在存在多个中断配置的时候,我们需要牢记好,谁会霸道的优先发生,这样,在处理中断的时候,就会理清楚基本的思路。

来,举个例子,我们的Systicks更新中断总是放到优先级的最后,这个时候,如果你在高优先级的中断中,调用了跟Systicks相关的系统中断,你知道会发生什么的。那就是你希望Systicks更新,好衡量给定的毫秒数,但是你又在高优先级中断中,没办法执行Systicks更新的回调函数,导致Systicks又不更新,这个事情在HAL中就会非常明显,HAL库就是一个强依赖软件更新的时钟基础系统,因此,这个时候调用基于这个时钟的延时,都会导致矛盾:希望Systicks中断正常工作触发软件定时器更新,但是你处于高优先级中断中无法打断此时此刻的中断去更新软件定时器。导致系统直接死机。

配置上,对于STM32F103C8T6而言,就是这样了。

分组抢占优先级位数子优先级位数抢占优先级范围子优先级范围
Group00位4位00-15
Group11位3位0-10-7
Group22位2位0-30-3
Group33位1位0-70-1
Group44位0位0-150

这个中断,就对应了如下的结构体的NVIC_IRQChannelPreemptionPriority参数和NVIC_IRQChannelSubPriority参数,我们依次对应了抢占优先级和子优先级:

typedef struct
{
  uint8_t NVIC_IRQChannel;                    /*!< Specifies the IRQ channel to be enabled or disabled.
                                                   This parameter can be a value of @ref IRQn_Type 
                                                   (For the complete STM32 Devices IRQ Channels list, please
                                                    refer to stm32f10x.h file) */
​
  uint8_t NVIC_IRQChannelPreemptionPriority;  /*!< Specifies the pre-emption priority for the IRQ channel
                                                   specified in NVIC_IRQChannel. This parameter can be a value
                                                   between 0 and 15 as described in the table @ref NVIC_Priority_Table */
​
  uint8_t NVIC_IRQChannelSubPriority;         /*!< Specifies the subpriority level for the IRQ channel specified
                                                   in NVIC_IRQChannel. This parameter can be a value
                                                   between 0 and 15 as described in the table @ref NVIC_Priority_Table */
​
  FunctionalState NVIC_IRQChannelCmd;         /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
                                                   will be enabled or disabled. 
                                                   This parameter can be set either to ENABLE or DISABLE */   
} NVIC_InitTypeDef;

剩下的NVIC_IRQChannelCmd我们直接填写enable即可。那NVIC_IRQChannel说明什么呢?答案是——标识使能哪一个中断。中断也是需要使能的,牢记一句话——我们的一切电子设备几乎都是依靠时钟才能进行节拍有序的工作,没有基准时钟,所有的器件没有了节拍,自然也就黯淡失色

随后,我们把这个结构体提交给NVIC_Init函数即可。

处理中断回调函数

剩下的发生的事情,那就是交给单片机了,他经过一系列复杂的机制,终于到达了ST工程师们预设的中断,对于PB0(举个例子),这个IRQ_Handler是谁呢?EXTI0_IRQHandler。是随便起的名字嘛?不是。请看汇编——

g_pfnVectors:
​
  .word _estack
  .word Reset_Handler
  ......
  .word EXTI0_IRQHandler
  .word EXTI1_IRQHandler
  .word EXTI2_IRQHandler
  .word EXTI3_IRQHandler
  .word EXTI4_IRQHandler
  ......
  .word EXTI9_5_IRQHandler
  ......
  .word EXTI15_10_IRQHandler
  ......

在这一串代码里,我们很快找到了几个我们看起来很熟悉的东西,对的,就是这些,你会发现这些就是著名的IRQHandler,也就是中断处理回调函数,对于应用层次,你只需要理解的是发生了这个中断,就会触发回调(回调回调,回来调用)函数,来执行你的处理逻辑。

PB0对应的外部中断线是EXTI0线,也就是EXTI0_IRQn,触发的函数回调就是EXTI0_IRQHandler。因此,我们只需要在EXTI0_IRQHandler写上我们的处理逻辑即可。

需要注意的是,中断处理结束后,需要清理标置位,这个东西相当于我们的中断是否发生的标志,只有标志为——处理结束,没有发生了之后,我们才会理回新的中断!

本篇的实验代码

出于篇幅原因,这里不再粘贴代码,地址在这里:

BetterATK/103c8t6/standard/3_GPIO_EXIT at STM32F1 · Charliechen114514/BetterATKhttps://github.com/Charliechen114514/BetterATK/tree/STM32F1/103c8t6/standard/3_GPIO_EXIT

这里需要注意的是——我们引入了一个新的器件就是OLED器件,关于OLED器件的编程属于额外的内容,你需要做的就是将SCL接到PB8,SDA接到PB9,笔者写的CCGraphic框架会自动的在你的OLED屏上展示内容。具体的原理需要等待你掌握IIC协议和SPI协议之后,我们才能开始真正的修改内部的代码。

现象如下

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

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

相关文章

docker的安装使用0废话版本自学软硬件工程师778天

见字如面&#xff0c; 这里是AIGC创意人_竹相左边 上一篇 因为 自己开发客户系统&#xff0c;为了解决一键启动 前端后端&#xff0c;涉及到了docker-compose 在新的电脑上安装docker 有各种问题这里再次记录下&#xff0c;既是笔记也是分享。 我先用自己的话说一遍&#xff0…

探秘 Svelte+Vite+TS+Melt - UI 框架搭建,开启高效开发

框架太“重”了&#xff1a;通常一个小型项目只由少数几个简单页面构成&#xff0c;如果使用 Vue 或者 React 这些框架来研发的话&#xff0c;有点“大材小用”了。构建的产物中包含了不少框架运行时代码(虚拟 DOM、响应式、状态管理等)&#xff0c;这些代码对于小型项目而言是…

vscode 连不上 Ubuntu 18 server 的解决方案

下载 vscode 历史版本 18.5&#xff08;windows请装在 系统盘 C 盘&#xff09; 打开 vdcode&#xff0c;将 自动更新 设置为 None &#xff08;很关键&#xff0c;否则容易前功尽弃&#xff09; 重命名&#xff08;删除&#xff09; 服务器上的 .vscode-server 文件夹 重新…

云原生运维在 2025 年的发展蓝图

随着云计算技术的不断发展和普及&#xff0c;云原生已经成为了现代应用开发和运维的主流趋势。云原生运维是指在云原生环境下&#xff0c;对应用进行部署、监控、管理和优化的过程。在 2025 年&#xff0c;云原生运维将迎来更加广阔的发展前景&#xff0c;同时也将面临着一系列…

Redis进阶--哨兵

目录 一、引言 二、介绍 三、哨兵的核心功能 四、使用docker进行单个主机redis主从复制哨兵操作 五、哨兵重新选取主节点的流程 1.主观下线 2.客观下线 3.主节点挂了 4.挑选新主节点 六、总结 一、引言 如果主从复制中&#xff0c;主节点挂了&#xff0c;从节点会迷茫…

Franka 机器人x Dexterity Gen引领遥操作精细任务新时代

教授机器人工具灵活操作难题 在教授机器人灵活使用工具方面&#xff0c;目前主要有两种策略&#xff1a;一是人类遥控&#xff08;用于模仿学习&#xff09;&#xff0c;二是模拟到现实的强化学习。然而&#xff0c;这两种方法均存在明显的局限性。 1、人类遥控&#xff08;用…

专题|MATLAB-R语言Logistic逻辑回归增长模型在互联网金融共生及移动通信客户流失分析实例合集

全文链接&#xff1a;https://tecdat.cn/?p41343 作为数据科学家&#xff0c;我们始终关注如何通过模型创新揭示复杂系统的动态规律。本专题合集聚焦两大核心应用场景&#xff0c;通过 Logistic 增长模型与逻辑回归技术&#xff0c;为互联网金融共生演化与移动通信客户流失预警…

【学生管理系统升级版】

学生管理系统升级版 需求分析&#xff1a;注册功能:登录功能&#xff1a;验证码规则&#xff1a;忘记密码&#xff1a; 实操&#xff1a;系统主页面注册功能登录功能忘记密码效果演示 需求 为学生管理系统书写一个登陆、注册、忘记密码的功能。     只有用户登录成功之后&…

Web3 的云基础设施正在成型,Polkadot 2.0 用三项技术改写“上链成本”

在Web3基础设施内卷加剧的今天&#xff0c;“如何以更低成本、更大灵活性部署一条高性能应用链”正成为开发者们最关心的问题。而刚刚走出“技术慢热”误区的Polkadot&#xff0c;正在用一套名为 Polkadot 2.0 的架构升级方案&#xff0c;重新定义这一问题的解法。 这套升级最…

机器学习——ROC曲线、PR曲线

一、ROC曲线简介 1.1 ROC曲线的构成 1.横轴&#xff08;假正率&#xff0c;FPR&#xff09;&#xff1a; 表示负样本被错误分类为正的比例&#xff08;越小越好&#xff09; 2.纵轴&#xff08;真正率&#xff0c;TPR&#xff0c;即召回率&#xff09;&#xff1a; 表示正样…

我为女儿开发了一个游戏网站

大家好&#xff0c;我是星河。 自从协助妻子为女儿开发了算数射击游戏后&#xff0c;星河就一直有个想法&#xff1a;为女儿打造一个专属的学习游戏网站。之前的射击游戏虽然有趣&#xff0c;但缺乏难度分级&#xff0c;无法根据女儿的学习进度灵活调整。而且&#xff0c;仅仅…

【Spring Cloud Netflix】GateWay服务网关

1.基本概述 GateWay用于在微服务架构中提供统一的入口点&#xff0c;对请求进行路由&#xff0c;过滤和处理。它就像是整个微服务系统的大门&#xff0c;所有外部请求都要通过它才能访问到后端的各个微服务。 2.核心概念 2.1路由(Route) 路由是Spring Cloud gateWay中最基本…

Docker部署Jenkins服务

文章目录 1.下载Jenkins服务2.部署Java21&#xff08;可选&#xff09;2.1 安装Java21 3.Maven3.9.9安装4.启动Jenkins5.初始化Jenkins5.1 入门5.2 安装推荐的插件5.3 创建第一个管理员用户5.4 实例配置5.5 Jenkins已就绪5.6 开始使用Jenkins5.7 重启Jenkins 6.配置Jenkins6.1 …

[ctfshow web入门] web40

信息收集 怎么一下子多这么多过滤啊&#xff0c;我以为跳过了好几题 这又能eval了&#xff0c;但是连$也不能用了 不能用. * ?&#xff0c;所以打不出fla*或者fla?????了 不能用/&#xff0c;构造不出日志注入和伪协议包含 仔细观察&#xff0c;禁的是中文的括号&#x…

蓝桥杯c ++笔记(含算法 贪心+动态规划+dp+进制转化+便利等)

蓝桥杯 #include <iostream> #include <vector> #include <algorithm> #include <string> using namespace std; //常使用的头文件动态规划 小蓝在黑板上连续写下从 11 到 20232023 之间所有的整数&#xff0c;得到了一个数字序列&#xff1a; S12345…

Qt问题之 告别软件因系统默认中文输入法导致错误退出的烦恼

1. 问题 使用Qt进行研发时&#xff0c;遇到一个问题&#xff0c;当在系统默认输入法中文&#xff08;英文输入法或者搜狗就不会触发闪退&#xff09;的情况下&#xff0c;选中QTableWidget控件&#xff08;QTableWidgetItem有焦点&#xff0c;但是不双击&#xff09;&#xff…

AlDente Pro for Mac电脑 充电限制保护工具

AlDente Pro for Mac电脑 充电限制保护工具 一、介绍 AlDente Pro for Mac&#xff0c;是一款充电限制保护工具&#xff0c;是可以限制最大充电百分比来保护电池的工具。锂离子和聚合物电池&#xff08;如 MacBook 中的电池&#xff09;在40&#xff05; 至 80&#xff05; 之…

算法训练之动态规划(一)

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…

Navicat连接远程PostGreSQL失败

问题描述 使用本地Navicat连接Windows远程服务器上部署的PostGreSQL数据库时,出现以下错误: 解决方案 出现以上报错信息,是因为PostGreSQL数据库服务尚未设置允许客户端建立远程连接。可做如下配置, 1. 找到PostGreSQL数据库安装目录下的data子文件夹,重点关注:postgres…

新一代达梦官方管理工具SQLark:可视化建表操作指南

在数据库管理工作中&#xff0c;新建表是一项基础且频繁的操作。SQLark 的可视化建表功能为我们提供了一种高效、便捷且丝滑流畅的建表新体验。一起来了解下吧。 SQLark 官方下载链接&#xff1a;www.sqlark.com 新建表作为常见的功能&#xff0c;相比其他管理工具&#xff0c;…