ARM32开发--外部中断EXTI

news2025/1/14 18:40:53

知不足而奋进 望远山而前行


目录

文章目录

前言

目标

内容

外部中断概念

中断触发机制

中断触发源

硬件外部中断

需求

开发流程

关心的内容

完整代码

软件外部中断

需求

开发流程

关心的内容

完整代码

中断消抖处理

系统计数模块

自定义计数器

systick完成代码

消抖完整逻辑

总结


前言

在许多嵌入式系统中,包括STM32和GD32等,EXTI模块通常由多个输入线、边沿检测电路、触发选择寄存器、软件中断事件寄存器、请求挂起寄存器、中断屏蔽寄存器、事件屏蔽寄存器等部分组成,可以实现对外部中断和事件的高效检测和处理。


目标

  1. 掌握外部中断开发流程
  2. 理解中断触发机制
  3. 掌握硬件触发机制实现
  4. 掌握软件触发机制实现
  5. 掌握中断消抖处理方式

内容

外部中断概念

外部中断,英文缩写为EXTI,全称为External Interrupt的缩写,直译过来就是是外部的中断。它是指在嵌入式系统中负责检测和处理外部中断和事件的模块。它通过检测外部信号的电平变化或边沿触发,生成对应的中断或事件,并将其送到中断控制器或事件屏蔽控制器进行处理。

在许多嵌入式系统中,包括STM32和GD32等,EXTI模块通常由多个输入线、边沿检测电路、触发选择寄存器、软件中断事件寄存器、请求挂起寄存器、中断屏蔽寄存器、事件屏蔽寄存器等部分组成,可以实现对外部中断和事件的高效检测和处理。

EXTI(中断/事件控制器)包括 23 个相互独立的边沿检测电路并且能够向处理器内核产生中断 请求或唤醒事件。

中断触发机制

外部中断触发机制,分为两种:

  • 硬件触发
  • 软件触发

硬件触发机制主要是针对外部触发了芯片的引脚,造成引脚的电平发生变化,从而导致中断产生。

硬件触发机制支持三种触发类型:上升沿触发、下降沿触发和任意沿触发。

上升沿:之前是低电平,突然变成高电平了,这个数瞬间,我们称之为触发了上升沿

上升沿:之前是高电平,突然变成低电平了,这个数瞬间,我们称之为触发了下降沿

硬件触发外部中断,简单的理解就是,如果我配置了某个引脚外部中断功能,那么当这个引脚的电平发生变化时,就会触发中断机制,代码层级就会调用到我的中断函数。

软件触发机制,主要针对的是业务逻辑中,需要手动的触发中断事件,去执行中断逻辑而去设计的。他不需要对引脚做任何处理,也可以触发。

中断触发源

引脚的外部中断总共有15个,对于同一个PIN,例如PA0和PB0是不可以同时触发的。

硬件外部中断

需求

  • 按键按下时,打印日志
  • 按键抬起时,打印日志
  • 不通过键盘扫描实现,通过中断实现
开发流程
  1. 依赖添加

添加gd32f4xx_exti.c

添加gd32f4xx_syscfg.c

  1. 外部中断初始化
static void EXTI_config() {
    /********************* GPIO config *********************/
    // 时钟初始化
    rcu_periph_clock_enable(RCU_GPIOA);
    // 配置GPIO模式
    gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_0);

    /********************* EXTI config *********************/
    // 时钟配置
    rcu_periph_clock_enable(RCU_SYSCFG);
    // 配置中断源
    syscfg_exti_line_config(EXTI_SOURCE_GPIOA, EXTI_SOURCE_PIN0);
    // 中断初始化
    exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_BOTH);
    // 配置中断优先级
    nvic_irq_enable(EXTI0_IRQn, 1, 1);
    // 使能中断
    exti_interrupt_enable(EXTI_0);
    // 清除中断标志位
    exti_interrupt_flag_clear(EXTI_0);
}

初始化流程:

    1. GPIO初始化
    2. 外部中断初始化
  1. 外部中断函数
void EXTI0_IRQHandler(void)
{
    // 判断中断中断触发
    if(SET == exti_interrupt_flag_get(EXTI_0)) {
        if(gpio_input_bit_get(GPIOA, GPIO_PIN_0) == SET) {
            printf("down \r\n");
        } else {
            printf("up \r\n");
        }
    }
    // 清除中断标志位
    exti_interrupt_flag_clear(EXTI_0);
}

中断执行函数流程:

    1. 判断中断是否触发
    2. 清除中断标记
关心的内容
static void EXTI_config() {
    uint32_t extix = EXTI_0; // 哪个中断
    uint32_t extix_irq = EXTI0_IRQn;
    uint32_t extix_trig = EXTI_TRIG_BOTH; // 中断触发条件

    uint32_t extix_src_port = EXTI_SOURCE_GPIOA; // 中断触发源,哪个引脚
    uint32_t extix_src_pin = EXTI_SOURCE_PIN0;

    uint32_t extix_io_rcu = RCU_GPIOA;
    uint32_t extix_io_port = GPIOA;
    uint32_t extix_io_pin = GPIO_PIN_0;

    /********************* GPIO config *********************/
    // 时钟初始化
    rcu_periph_clock_enable(extix_io_rcu);
    // 配置GPIO模式
    gpio_mode_set(extix_io_port, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, extix_io_pin);

    /********************* EXTI config *********************/
    // 时钟配置
    rcu_periph_clock_enable(RCU_SYSCFG);
    // 配置中断源
    syscfg_exti_line_config(extix_src_port, extix_src_pin);
    // 中断初始化
    exti_init(extix, EXTI_INTERRUPT, extix_trig);
    // 配置中断优先级
    nvic_irq_enable(extix_irq, 1, 1);
    // 使能中断
    exti_interrupt_enable(extix);
    // 清除中断标志位
    exti_interrupt_flag_clear(extix);
}

总结起来,关心的内容:

  • 中断源,是哪个,EXTI_x
  • 引脚,是哪个硬件触发的。
  • 触发的条件,是高电平触发还是低电平触发
完整代码
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "Usart0.h"


void Usart0_recv(uint8_t *data, uint32_t len) {
    printf("recv: %s\r\n", data);
}

static void EXTI_config() {
    uint32_t extix = EXTI_0; // 哪个中断
    uint32_t extix_irq = EXTI0_IRQn;
    uint32_t extix_trig = EXTI_TRIG_BOTH; // 中断触发条件

    uint32_t extix_src_port = EXTI_SOURCE_GPIOA; // 中断触发源,哪个引脚
    uint32_t extix_src_pin = EXTI_SOURCE_PIN0;

    uint32_t extix_io_rcu = RCU_GPIOA;
    uint32_t extix_io_port = GPIOA;
    uint32_t extix_io_pin = GPIO_PIN_0;

    /********************* GPIO config *********************/
    // 时钟初始化
    rcu_periph_clock_enable(extix_io_rcu);
    // 配置GPIO模式
    gpio_mode_set(extix_io_port, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, extix_io_pin);

    /********************* EXTI config *********************/
    // 时钟配置
    rcu_periph_clock_enable(RCU_SYSCFG);
    // 配置中断源
    syscfg_exti_line_config(extix_src_port, extix_src_pin);
    // 中断初始化
    exti_init(extix, EXTI_INTERRUPT, extix_trig);
    // 配置中断优先级
    nvic_irq_enable(extix_irq, 1, 1);
    // 使能中断
    exti_interrupt_enable(extix);
    // 清除中断标志位
    exti_interrupt_flag_clear(extix);
}

// 中断函数
void EXTI0_IRQHandler(void)
{
    if(SET == exti_interrupt_flag_get(EXTI_0)) {
        if(gpio_input_bit_get(GPIOA, GPIO_PIN_0) == SET) {
            printf("down \r\n");
        } else {
            printf("up \r\n");
        }
        // 清除中断标志位
        exti_interrupt_flag_clear(EXTI_0);
    }
}


int main(void)
{
    systick_config();
    Usart0_init();
    EXTI_config();

    while(1) {
    }
}

软件外部中断

需求

接收串口消息,手动触发中断事件

开发流程
  1. 添加必要的依赖
  2. 外部中断初始化
static void EXTI_config() {
    uint32_t extix = EXTI_0; // 哪个中断
    uint32_t extix_irq = EXTI0_IRQn;

    /********************* EXTI config *********************/
    // 时钟配置
    rcu_periph_clock_enable(RCU_SYSCFG);
    // 中断初始化
    exti_init(extix, EXTI_INTERRUPT, EXTI_TRIG_NONE);
    // 配置中断优先级
    nvic_irq_enable(extix_irq, 1, 1);
    // 使能中断
	exti_interrupt_enable(extix);
    // 清除中断标志位
    exti_interrupt_flag_clear(extix);
}
  1. 外部中断函数
void EXTI0_IRQHandler(void)
{
    printf("IRQ \r\n");

    if(SET == exti_interrupt_flag_get(EXTI_0)) {
        printf("exti 0 \r\n");
            
        // 清除中断标志位
        exti_interrupt_flag_clear(EXTI_0);
    }
}
  1. 手动触发逻辑
void Usart0_recv(uint8_t *data, uint32_t len) {
    printf("recv: %s\r\n", data);

    exti_software_interrupt_enable(EXTI_0);
}
关心的内容

哪个中断源。EXTI_x,x为0到22

完整代码
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "Usart0.h"


void Usart0_recv(uint8_t *data, uint32_t len) {
    printf("recv: %s\r\n", data);

    exti_software_interrupt_enable(EXTI_0);
}

static void EXTI_config() {
    uint32_t extix = EXTI_0; // 哪个中断
    uint32_t extix_irq = EXTI0_IRQn;

    /********************* EXTI config *********************/
    // 时钟配置
    rcu_periph_clock_enable(RCU_SYSCFG);
    // 中断初始化
    exti_init(extix, EXTI_INTERRUPT, EXTI_TRIG_NONE);
    // 配置中断优先级
    nvic_irq_enable(extix_irq, 1, 1);
    // 使能中断
    exti_interrupt_enable(extix);
    // 清除中断标志位
    exti_interrupt_flag_clear(extix);
}

// 中断函数
void EXTI0_IRQHandler(void)
{
    printf("IRQ \r\n");

    if(SET == exti_interrupt_flag_get(EXTI_0)) {
        printf("exti 0 \r\n");
        // 清除中断标志位
        exti_interrupt_flag_clear(EXTI_0);
    }
}


int main(void)
{
    systick_config();
    Usart0_init();
    EXTI_config();

    while(1) {
    }
}

中断消抖处理

消抖方式:

  • 硬件消抖

  • 软件消抖

在按键操作过程中,如果我们采用的是扫描方式实现,消抖的处理方式通常为:

  1. 降低扫描频率。通常我们delay个20ms,也就是1秒扫50次,人的手速是到不了的,比较符合逻辑。
  2. 状态比较。比较本次和上次的状态,从而确定是否触发,降低触发误操作。

理论上我们可以将这种行为使用到中断处理方式中,但是,我们需要明确一点,中断中不可以睡眠时间过长。会影响其他任务执行。

我们可以通过以下两种方式间隔进行判断:

  1. 在定时器的中断函数里,按照指定间隔时间进行判断,这种需要占用一个Timer的中断函数。
  2. 通过时间差决定是否进行按键判定,即本次外部中断发生和上次中断发生的时间差。时间差就需要有时间计数概念,那么我们如何获得时间计数,可以利用System Tick。

系统计数模块

通常我们称之为System Tick,System Tick 不是基于标准定时器(Timer)实现的,而是使用了专门的 SysTick 定时器模块。SysTick 定时器是一个专用的计数器,用于实现系统的计时和调度。

SysTick 定时器是一个 24 位的递减计数器,其工作与标准定时器(Timer)不同。它的时钟源通常是系统时钟(CPU 时钟),并且它是硬件级别的计时器,专门用于实现系统级别的计时和调度功能,比如操作系统的任务调度、延时等。

我们的代码中其实已经使用到了,观察systick.hsystick.c,这个就是采用系统级别的计数器实现的。

计数器初始化逻辑如下:

计数器中断函数在gd32f4xx_it.c中:

这里每调用一次,就是一个时钟计数。同时也会调用到delay_decrement:

进行简单的总结:

整个系统在启动时,配置了时钟计数,SystemCoreClock / 1000000U),这里的意思是每秒钟调用delay_decrement()函数1000000次。

自定义计数器
volatile static uint32_t tick;
...
tick = 0

每次tick的时候,进行自增长,这样就相当于记录了时间:

void delay_decrement(void)
{
    if(0U != delay) {
        delay--;
    }
    tick++;
}

再将这个tick时间对外,外面使用者就可以获得时间计数了

uint32_t get_tick() {
    return tick;
}
systick完成代码
/*!
    \file    systick.h
    \brief   the header file of systick

    \version 2016-08-15, V1.0.0, firmware for GD32F4xx
    \version 2018-12-12, V2.0.0, firmware for GD32F4xx
    \version 2020-09-30, V2.1.0, firmware for GD32F4xx
    \version 2022-03-09, V3.0.0, firmware for GD32F4xx
*/

/*
    Copyright (c) 2022, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors
       may be used to endorse or promote products derived from this software without
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

#ifndef SYS_TICK_H
#define SYS_TICK_H

#include <stdint.h>

/* configure systick */
void systick_config(void);
/* delay a time in milliseconds */
void delay_1ms(uint32_t count);
/* delay decrement */
void delay_decrement(void);

void delay_1us(uint32_t count);
uint32_t get_tick();

#endif /* SYS_TICK_H */
/*!
    \file    systick.c
    \brief   the systick configuration file

    \version 2016-08-15, V1.0.0, firmware for GD32F4xx
    \version 2018-12-12, V2.0.0, firmware for GD32F4xx
    \version 2020-09-30, V2.1.0, firmware for GD32F4xx
    \version 2022-03-09, V3.0.0, firmware for GD32F4xx
*/

/*
    Copyright (c) 2022, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors
       may be used to endorse or promote products derived from this software without
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

#include "gd32f4xx.h"
#include "systick.h"

volatile static uint32_t delay;
volatile static uint32_t tick;

/*!
    \brief    configure systick
    \param[in]  none
    \param[out] none
    \retval     none
*/
void systick_config(void)
{
		tick = 0;
    /* setup systick timer for 1000000Hz interrupts */
    if(SysTick_Config(SystemCoreClock / 1000000U)) {
        /* capture error */
        while(1) {
        }
    }
    /* configure the systick handler priority */
    NVIC_SetPriority(SysTick_IRQn, 0x00U);
}

/*!
    \brief    delay a time in milliseconds
    \param[in]  count: count in milliseconds
    \param[out] none
    \retval     none
*/
void delay_1ms(uint32_t count)
{
    delay = count * 1000;

    while(0U != delay) {
    }
}

/*!
    \brief    delay decrement
    \param[in]  none
    \param[out] none
    \retval     none
*/
void delay_decrement(void)
{
    if(0U != delay) {
        delay--;
    }
		tick++;
}

void delay_1us(uint32_t count)
{
    delay = count;

    while(0U != delay) {
    }
}

uint32_t get_tick() {
		return tick;
}
消抖完整逻辑
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "Usart0.h"

#define SCAN_DELAY	1000
static uint32_t last_tick = 0;

static FlagStatus pre_state;

void Usart0_recv(uint8_t *data, uint32_t len) {
    printf("recv: %s\r\n", data);
}

static void EXTI_config() {
    uint32_t extix = EXTI_0; // 哪个中断
    uint32_t extix_irq = EXTI0_IRQn;
    uint32_t extix_trig = EXTI_TRIG_BOTH; // 中断触发条件

    uint32_t extix_src_port = EXTI_SOURCE_GPIOA; // 中断触发源,哪个引脚
    uint32_t extix_src_pin = EXTI_SOURCE_PIN0;

    uint32_t extix_io_rcu = RCU_GPIOA;
    uint32_t extix_io_port = GPIOA;
    uint32_t extix_io_pin = GPIO_PIN_0;

    /********************* GPIO config *********************/
    // 时钟初始化
    rcu_periph_clock_enable(extix_io_rcu);
    // 配置GPIO模式
    gpio_mode_set(extix_io_port, GPIO_MODE_INPUT, GPIO_PUPD_NONE, extix_io_pin);

    /********************* EXTI config *********************/
    // 时钟配置
    rcu_periph_clock_enable(RCU_SYSCFG);
    // 配置中断源
    syscfg_exti_line_config(extix_src_port, extix_src_pin);
    // 中断初始化
    exti_init(extix, EXTI_INTERRUPT, extix_trig);
    // 配置中断优先级
    nvic_irq_enable(extix_irq, 1, 1);
    // 使能中断
    exti_interrupt_enable(extix);
    // 清除中断标志位
    exti_interrupt_flag_clear(extix);
}

// 中断函数
void EXTI0_IRQHandler(void)
{
    if(SET == exti_interrupt_flag_get(EXTI_0)) {
        uint32_t current_tick = get_tick();
        if(current_tick - last_tick > SCAN_DELAY) {
            last_tick = current_tick;

            FlagStatus state = gpio_input_bit_get(GPIOA, GPIO_PIN_0);
            if(SET == state && RESET == pre_state) {
                // 如果当前为高电平,上一次为低电平,按下
                pre_state = state;
                printf("down \r\n");
            } else if(RESET == state && SET == pre_state) {
                // 如果当前为低电平,上一次为高电平,抬起
                pre_state = state;
                printf("up \r\n");
            }
        }
    }
    // 清除中断标志位
    exti_interrupt_flag_clear(EXTI_0);
}


int main(void)
{
    systick_config();
    Usart0_init();
    EXTI_config();

    pre_state = RESET;

    while(1) {
    }
}

总结

外部中断触发机制,分为两种:

  • 硬件触发
  • 软件触发

硬件触发机制主要是针对外部触发了芯片的引脚,造成引脚的电平发生变化,从而导致中断产生。

硬件触发机制支持三种触发类型:上升沿触发、下降沿触发和任意沿触发。

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

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

相关文章

LCD屏的价格和显示区的尺寸有关

LCD屏的价格和显示区的尺寸有关&#xff0c;和外尺寸无关。 下面通过12864点阵屏&#xff0c;对不同尺寸的屏&#xff0c;进行价格比较&#xff0c;就可以发现&#xff1a;LCD屏的价格和显示区的尺寸有关&#xff1b; 同点阵的屏&#xff0c;显示区域太小&#xff0c;显示12*1…

AMD在行动:揭示应用程序跟踪和性能分析的力量

AMD in Action: Unveiling the Power of Application Tracing and Profiling — ROCm Blogs 导言 Rocprof是一款强大的工具&#xff0c;设计用于分析和优化基于AMD ROCm平台上运行的HIP程序的性能&#xff0c;帮助开发者找出并解决性能瓶颈。Rocprof提供了多种性能数据&#x…

8.11 矢量图层线要素单一符号使用六(光栅线)

文章目录 前言光栅线&#xff08;Raster Line&#xff09;QGis设置线符号为光栅线&#xff08;Raster Line&#xff09;二次开发代码实现光栅线&#xff08;Raster Line&#xff09; 总结 前言 本章介绍矢量图层线要素单一符号中光栅线&#xff08;Raster Line&#xff09;的使…

【三维重建】增量SFM系统

在学习完鲁鹏老师的三维重建基础后&#xff0c;打算用C代码复现一下增量SFM系统&#xff08;https://github.com/ldx-star/SFM&#xff09;。 本项目的最终目标就是通过相机拍摄的多视角视图获取三维点云。由于资金有效&#xff0c;博主使用的是相机是小米12。 先来看一下最终…

Linux 安装ab测试工具

yum -y install httpd-tools ab -help #10个并发连接&#xff0c;100个请求 ab -n 200 -c 100 http://www.baidu.com/

算法之分治

分而治之 分治法所能解决的问题一般具有以下几个特征&#xff1a; 1) 该问题的规模缩小到一定的程度就可以容易地解决 2) 该问题可以分解为若干个规模较小的子问题&#xff0c;即该问题具有最优子结构性质 3) 利用该问题分解出的子问题的解可以合并为该问题的解 4) 该问题所分…

动态内存管理学不懂,小代老师带你深入理解动态内存管理(下卷)

动态内存管理学不懂&#xff0c;小代老师带你深入理解动态内存管理&#xff08;下卷 柔性数组6.1 柔性数组的特点&#xff1a;6.2 柔性数组的使用 7. 总结C/C中程序内存区域划分 柔性数组 也许你从来没有听说过柔性数组&#xff08;flexible array&#xff09;这个概念&#x…

探索C++ STL的设计方式:将算法与数据结构分离

STL的设计 一、简介二、STL容器三、C数组四、用户定义的集合4.1、使用标准集合的typedef4.2、重用标准迭代器4.3、实现自己的迭代器 五、总结 一、简介 本文介绍STL的设计方式&#xff0c;以及如何设计自己的组件&#xff0c;使其能够充分利用STL的功能。 STL的设计旨在将算法…

Golang | Leetcode Golang题解之第135题分发糖果

题目&#xff1a; 题解&#xff1a; func candy(ratings []int) int {n : len(ratings)ans, inc, dec, pre : 1, 1, 0, 1for i : 1; i < n; i {if ratings[i] > ratings[i-1] {dec 0if ratings[i] ratings[i-1] {pre 1} else {pre}ans preinc pre} else {decif dec…

【权威发布】2024年新能源与人工智能国际会议(ICNEAI 2024)

2024年新能源与人工智能国际会议 2024 International Conference on New Energy and Artificial Intelligence 会议简介 2024年新能源与人工智能国际会议是一场聚焦新能源与人工智能交叉领域前沿科技探讨的盛会。此次会议汇集了全球能源、环保和人工智能领域的专家学者、科技人…

WT32-ETH01作为TCP Server进行通讯

目录 模块简介WT32-ETH01作为TCP Server设置W5500作为TCP Client设置连接并进行通讯总结 模块简介 WT32-ETH01网关主要功能特点: 采用双核Xtensa⑧32-bit LX6 MCU.集成SPI flash 32Mbit\ SRAM 520KB 支持TCP Server. TCP Client, UDP Server. UDP Client工作模式 支持串口、wi…

服务部署:解决Docker容器与虚拟机主机之间MySql连接访问问题

一、场景&#xff1a; 虚拟机上Ubuntu系统安装了Mysql&#xff0c;现在有一个服务应用需要使用docker来部署&#xff0c;服务应用需要连接mysql做数据库基础使用&#xff0c;配置文件中配置了虚拟主机的IP和端口&#xff0c;但是还是无法连接到Mysql&#xff0c;报错无法连接超…

零基础直接上手java跨平台桌面程序,使用javafx(四)用Apache POI读取excel文件。

Apache POI这个库&#xff0c;可能是JAVA平台最好操作excel文件的库了。怎么才能使用呢&#xff1f; 1、下载Apache POI&#xff0c;本来是个很简单的事情&#xff0c;但是也有坑。这也就是我一直不敢用java的原因之一&#xff0c;这些莫名其妙的坑&#xff0c;总是让人烦躁。…

MAC安装idea教程

https://blog.csdn.net/qq_41810415/article/details/131649541 JDK安装 https://blog.csdn.net/dddebug/article/details/121713633 2、编辑.bash_profile文件 vim .bash_profile 进入编辑模式后 按 i 开始添加内容 结束编辑模式按 ESC 结束后保存输入 :wq! 不保存输入 :q! 检…

Apple - IOKit Fundamentals

本文翻译整理自&#xff1a;IOKit Fundamentals &#xff08;Updated: 2014-04-09 https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/Introduction/Introduction.html 文章目录 一、I/O Kit 基础知识简介1、谁应该阅读本…

vue2插槽

本节目标 默认插槽后备内容具名插槽作用域插槽案例-商品列表 默认插槽 让组件内部的一些结构 支持自定义 步骤 组件内需要定制的结构, 使用<slot></slot>占位 使用组件时, 传入结构替换slot的位置 后备内容 封装组件时, 可以为预留的<slot>插槽提供默认内…

Nacos长轮询底层是怎么实现的?

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案…

【perl】环境搭建

1、Vscode Strawberry Perl 此过程与tcl环境搭建很类似&#xff0c;请参考我的这篇文章&#xff1a; 【vscode】 与 【tclsh】 联合搭建tcl开发环境_tclsh软件-CSDN博客 perl语言的解释器可以选择&#xff0c;strawberry perl。Strawberry Perl for Windows - Releases。 …

一次性全部给你,这4款名不见经传的精品软件,用了就放不下

Geek Geek是个电脑卸载软件神器。 Geek 电脑空间不够了&#xff0c;想卸点应用来腾地方&#xff0c;但总是遇到各种问题&#xff0c;要么卸不干净&#xff0c;留下一些乱七八糟的文件&#xff0c;要么就是那些流氓软件&#xff0c;怎么卸都卸不掉&#xff0c;简直让人崩溃&am…

如何格式化U盘?4个正确方法,记得收藏好!

“我的u盘不知道是中病毒还是什么原因&#xff0c;现在没法使用了&#xff0c;我想将它进行格式化操作&#xff0c;想问问大家应该如何格式化u盘呢&#xff1f;请帮帮我&#xff01;” U盘作为我们日常生活中不可或缺的存储设备&#xff0c;常常用于传输和保存各种重要数据。然…