当前位置: 首页 > news >正文

009 - STM32学习笔记 - 中断

009 - STM32学习笔记 - 中断

这节的内容,野火的官方视频我反复看了好几次,但是感觉火哥在这块讲解的特别绕,理解起来很吃力,后来在看了一下其他老师的视频,结合一些书本资料和官方手册,才搞清楚STM32中断该怎么使用。

1、中断概念

什么是中断?主线程序正常运行过程中,当中断信号产生时,系统先暂停主线程序,转去执行中断程序,当中断程序执行完后,在转回主线程序继续运行。

举个比较通俗的例子来说,加入一个人正在田里干活,家里人过来喊吃中午饭,此人就将手里的活放下回家吃饭,等吃完饭后在回来继续劳作。这里面田里干活就是主线程序,回家吃饭就是中断程序,而对应的家里人过来喊的这个动作,就是中断信号。

所以主线程序我们可以认为是正常运行的程序,中间插入的一些事情我们认为是突发的异常,只不过异常产生的时间不确定而已,那么在正常运行的程序过程中,可能会产生很多突发异常,可能有些异常是同时产生的,那么当出现多个同时产生的异常时,系统该如何处理呢?

用上一个例子来说明,正在田里干活,突然觉得肚子不舒服急需解手(例子而已,请勿介意),而此时家里人过来喊吃饭,那么该优先做那件事呢?当然是优先解手,等完事后再去吃饭(毕竟吃饭可以晚一会再去,肚子不舒服当然先解决咯)。那么事情就可以理顺了,先解手,在吃饭,吃完饭后再下地干活(解手后记得洗手哈!)。

所以这里就引出来一个概念,优先,当多个中断同时出现时,优先处理哪件事,就需要确定这些事的优先级

看一下STM32中提供出来的中断,这里将stm32提供的中断打断分为两部分说明,如下表:

系统异常(内核)

位置优先级优先级 类型名称说明地址
---保留0x0000 0000
-3固定Reset复位0x0000 0004
-2固定NMI不可屏蔽中断,时钟安全系统0x0000 0008
-1固定HardFault所有类型的错误0x0000 000C
0固定MemManageMPU 不匹配0x0000 0010
1可设置BusFault预取指失败,存储器访问失败0x0000 0014
2可设置UsageFault未定义的指令或非法状态0x0000 0018
---保留0x0000 001C - 0x0000 002B
3可设置SVCall通过 SWI 指令调用的系统服务0x0000 002C
4可设置Debug Monitor调试监控器0x0000 0030
--保留0x0000 0034
5可设置PendSV可挂起的系统服务0x0000 0038
6可设置Systick系统嘀嗒定时器0x0000 003C

外部中断(外设)

位置优先级优先级 类型名称说明地址
07可设置WWDG窗口看门狗中断0x0000 0040
18可设置PVD连接到 EXTI 线的可编程电压检测 (PVD) 中断0x0000 0044
29可设置TAMP_STAMP连接到 EXTI 线的入侵和时间戳中断0x0000 0048
310可设置RTC_WKUP连接到 EXTI 线的 RTC 唤醒中断0x0000 004C
411可设置FLASHFlash 全局中断0x0000 0050
512可设置RCCRCC 全局中断0x0000 0054
613可设置EXTI0EXTI 线 0 中断0x0000 0058
714可设置EXTI1EXTI 线 1 中断0x0000 005C
815可设置EXTI2EXTI 线 2 中断0x0000 0060
916可设置EXTI3EXTI 线 3 中断0x0000 0064
1017可设置EXTI4EXTI 线 4 中断0x0000 0068
1118可设置DMA1_Stream0DMA1 流 0 全局中断0x0000 006C
1219可设置DMA1_Stream1DMA1 流 1 全局中断0x0000 0070
1320可设置DMA1_Stream2DMA1 流 2 全局中断0x0000 0074
1421可设置DMA1_Stream3DMA1 流 3 全局中断0x0000 0078
1522可设置DMA1_Stream4DMA1 流 4 全局中断0x0000 007C
1623可设置DMA1_Stream5DMA1 流 5 全局中断0x0000 0080
1724可设置DMA1_Stream6DMA1 流 6 全局中断0x0000 0084
1825可设置ADCADC1、 ADC2 和 ADC3 全局中断0x0000 0088
1926可设置CAN1_TXCAN1 TX 中断0x0000 008C
2027可设置CAN1_RX0CAN1 RX0 中断0x0000 0090
2128可设置CAN1_RX1CAN1 RX1 中断0x0000 0094
2229可设置CAN1_SCECAN1 SCE 中断0x0000 0098
2330可设置EXTI9_5EXTI 线 [9:5] 中断0x0000 009C
2431可设置TIM1_BRK_TIM9TIM1 刹车中断和 TIM9 全局中断0x0000 00A0
2532可设置TIM1_UP_TIM10TIM1 更新中断和 TIM10 全局中断0x0000 00A4
2633可设置TIM1_TRG_COM_TIM11TIM1 触发和换相中断与 TIM11 全局 中断0x0000 00A8
2734可设置TIM1_CCTIM1 捕获比较中断0x0000 00AC
2835可设置TIM2TIM2 全局中断0x0000 00B0
2936可设置TIM3TIM3 全局中断0x0000 00B4
3037可设置TIM4TIM4 全局中断0x0000 00B8
3138可设置I2C1_EVI2C1 事件中断0x0000 00BC
3239可设置I2C1_ERI2C1 错误中断0x0000 00C0
3340可设置I2C2_EVI2C2 事件中断0x0000 00C4
3441可设置I2C2_ERI2C2 错误中断0x0000 00C8
3542可设置SPI1SPI1 全局中断0x0000 00CC
3643可设置SPI2SPI2 全局中断0x0000 00D0
3744可设置USART1USART1 全局中断0x0000 00D4
3845可设置USART2USART2 全局中断0x0000 00D8
3946可设置USART3USART3 全局中断0x0000 00DC
4047可设置EXTI15_10EXTI 线 [15:10] 中断0x0000 00E0
4148可设置RTC_Alarm连接到 EXTI 线的 RTC 闹钟( A 和 B) 中断0x0000 00E4
4249可设置OTG_FS WKUP连接到 EXTI 线的 USB On-The-Go FS 唤醒中断0x0000 00E8
4350可设置TIM8_BRK_TIM12TIM8 刹车中断和 TIM12 全局中断0x0000 00EC
4451可设置TIM8_UP_TIM13TIM8 更新中断和 TIM13 全局中断0x0000 00F0
4552可设置TIM8_TRG_COM_TIM14TIM8 触发和换相中断与 TIM14 全局 中断0x0000 00F4
4653可设置TIM8_CCTIM8 捕获比较中断0x0000 00F8
4754可设置DMA1_Stream7DMA1 流 7 全局中断0x0000 00FC
4855可设置FSMCFSMC 全局中断0x0000 0100
4956可设置SDIOSDIO 全局中断0x0000 0104
5057可设置TIM5TIM5 全局中断0x0000 0108
5158可设置SPI3SPI3 全局中断0x0000 010C
5259可设置UART4UART4 全局中断0x0000 0110
5360可设置UART5UART5 全局中断0x0000 0114
5461可设置TIM6_DACTIM6 全局中断, DAC1 和 DAC2 下溢错误中断0x0000 0118
5562可设置TIM7TIM7 全局中断0x0000 011C
5663可设置DMA2_Stream0DMA2 流 0 全局中断0x0000 0120
5764可设置DMA2_Stream1DMA2 流 1 全局中断0x0000 0124
5865可设置DMA2_Stream2DMA2 流 2 全局中断0x0000 0128
5966可设置DMA2_Stream3DMA2 流 3 全局中断0x0000 012C
6067可设置DMA2_Stream4DMA2 流 4 全局中断0x0000 0130
6168可设置ETH以太网全局中断0x0000 0134
6269可设置ETH_WKUP连接到 EXTI 线的以太网唤醒中断0x0000 0138
6370可设置CAN2_TXCAN2 TX 中断0x0000 013C
6471可设置CAN2_RX0CAN2 RX0 中断0x0000 0140
6572可设置CAN2_RX1CAN2 RX1 中断0x0000 0144
6673可设置CAN2_SCECAN2 SCE 中断0x0000 0148
6774可设置OTG_FSUSB On The Go FS 全局中断0x0000 014C
6875可设置DMA2_Stream5DMA2 流 5 全局中断0x0000 0150
6976可设置DMA2_Stream6DMA2 流 6 全局中断0x0000 0154
7077可设置DMA2_Stream7DMA2 流 7 全局中断0x0000 0158
7178可设置USART6USART6 全局中断0x0000 015C
7279可设置I2C3_EVI2C3 事件中断0x0000 0160
7380可设置I2C3_ERI2C3 错误中断0x0000 0164
7481可设置OTG_HS_EP1_OUTUSB On The Go HS 端点 1 输出全局 中断0x0000 0168
7582可设置OTG_HS_EP1_INUSB On The Go HS 端点 1 输入全局 中断0x0000 016C
7683可设置OTG_HS_WKUP连接到 EXTI 的 USB On The Go HS  唤醒中断0x0000 0170
7784可设置OTG_HSUSB On The Go HS 全局中断0x0000 0174
7885可设置DCMIDCMI 全局中断0x0000 0178
7986可设置CRYPCRYP 加密全局中断0x0000 017C
8087可设置HASH_RNG哈希和随机数发生器全局中断0x0000 0180
8188可设置FPUFPU 全局中断0x0000 0184
8289可设置UART7UART 7 全局中断0x0000 0188
8390可设置UART8UART 8 全局中断0x0000 018C
8491可设置SPI4SPI 4 全局中断0x0000 0190
8592可设置SPI5SPI 5 全局中断0x0000 0194
8693可设置SPI6SPI 6 全局中断0x0000 0198
a、优先级

在上面的表中,需要注意的是,系统已经给各种中断(异常)给出了默认优先级,数字越小,优先级越高。而且再优先级类型中明确说明了哪些优先级可以设置,哪些优先级不可设置。也就是说,凡是标明了中断优先级类型为可设置的,则表明用户可以通过修改优先级级别,从而决定中断执行的先后顺序。

b、中断地址

当单片机产生中断信号的时候,系统需要响应这个中断,对应的在表中最后一栏,看到每个对应的中断均有一个地址,需要注意的是,这个地址不是绝对地址,而是偏移地址,这里牵扯到地址重映射,后面学到了在分享。

c、中断服务子程序

在启动代码那一节中提到中断服务程序,当启动代码执行后,会映射所有中断服务程序,即我们说的中断向量表,在向量表中包含了所有内核和外设的中断服务函数名,这里需要注意,后续在用到中断服务程序时,一定要确保编写的中断服务程序名和向量表中的程序名一致,否则程序不会报错,但是当中断产生时,并不会去执行写好的中断服务程序,而是执行系统默认的程序,而系统默认的为无限空循环,那程序就会死到那里,不会出现响应。

2、中断向量控制器(NVIC)

中断向量控制器(Nested vectored interrupt controller)属于内核外设,主要作用是管理包括内核和片上所有外设的中断相关功能。

使用到的两个库文件为:core_cm4.hmisc.h,NVIC寄存器位于core_cm4.h中,固件库中NVIC预留了很多位,我猜大概率时为了后期扩展使用,目前我用到的固件库版本还比较老,一共才90多个中断,有兴趣的话可以去找一找最新的固件库看一下。

typedef struct
{__IO uint32_t ISER[8];                 /*!< 偏移量: 0x000 (读/写)  中断使能寄存器 			*/uint32_t RESERVED0[24];__IO uint32_t ICER[8];                 /*!< 偏移量: 0x080 (读/写)  中断清除寄存器         	*/uint32_t RSERVED1[24];__IO uint32_t ISPR[8];                 /*!< 偏移量: 0x100 (读/写)  中断使能悬起寄存器		  */uint32_t RESERVED2[24];__IO uint32_t ICPR[8];                 /*!< 偏移量: 0x180 (读/写)  中断清除悬起寄存器         */uint32_t RESERVED3[24];__IO uint32_t IABR[8];                 /*!< 偏移量: 0x200 (读/写)  终端有效位寄存器           */uint32_t RESERVED4[56];__IO uint8_t  IP[240];                 /*!< 偏移量: 0x300 (读/写)  中断优先级寄存器           */uint32_t RESERVED5[644];__O  uint32_t STIR;                    /*!< 偏移量: 0xE00 (只 读)  软件触发中断寄存器         */
}  NVIC_Type;

这里学习一下几个常用的寄存器

中断优先级寄存器(NVIC_IPRx)

在这里插入图片描述

这个图中,按照中断优先级分为IP0-IP80(实际目前我使用的内核中断已经增加到93,看过野火官方出的教材上,中断源已经增加到97了),每个中断的IPx寄存器都有8位位宽,原则来说,每个中断的优先级可配置范围位0~255,其值越小,优先级越高,但是实际起到作用的只有4位。

在这里插入图片描述
此表中,可以看到实际起到作用的只有高4位,低4位并没有使用,STM32官方为了表示这4位,将优先级分为主(抢占)优先级和子优先级,两个中断同时触发时,主优先级高的先抢占执行权,主优先级相同时,则子优先级高的限制性,当然也可能存在主优先级和子优先级相同的情况,这个STM32官方也给出了解决办法,就是硬件编号越小的,优先级越高。

因此根据主优先级和子优先级的分类,STM32将优先级分为5组分别如下
在这里插入图片描述
可以用中标准库函数NVIC_PriorityGroupConfig() 来实现优先级的分组

3、EXTI外部中断/事件控制器

在STM32中还提供了一个EXTI外部中断/事件控制器,用于产生事件/中断请求的边沿检测,数量有23个,每个输入线都可以进行单独配置,可以通过寄存器选择中断/事件类型,和相应的触发条件(上升沿触发、下降沿触发和边沿触发),并且也可以根据需求单独进行屏蔽。
在这里插入图片描述

EXTI控制器框图
typedef struct
{uint32_t EXTI_Line;               /* 选择输入线 */EXTIMode_TypeDef EXTI_Mode;       /*!< 触发模式:可选为外部中断或者事件模式 */EXTITrigger_TypeDef EXTI_Trigger; /*!< 触发方式:上升沿、下降沿、边沿检测 */FunctionalState EXTI_LineCmd;     /*!< 使能位 */ 
}EXTI_InitTypeDef;

以中断触发按键检测为例,对EXTI进行分析:

a、EXTI_Line外部中断/事件线

F429中168个GPIO通过下面的方式连接到16个外部中断/事件控制器上

在这里插入图片描述
其中将GPIOA-GPIO中以引脚号从0-15分别挂在在EXTI0-EXIT15

我使用的开发板上,可以操作的按键电路GPIO有两个,分别为PA0和PC13,PA0是连接到EXTI0,PC13连接到EXTI13上,因此PA0的外部中断/事件线应该选择EXTI_Line0,而PC13则选择EXTI_Line13。

b、EXTI_Mode,外部中断/事件模式控制器
typedef enum
{EXTI_Mode_Interrupt = 0x00,	//中断模式EXTI_Mode_Event = 0x04		//事件模式
}EXTIMode_TypeDef;

这个直接选择中断模式EXTI_Mode_Interrupt就行。

c、EXTI_Trigger外部中断/事件触发方式
typedef enum
{EXTI_Trigger_Rising = 0x08,			//上升沿触发EXTI_Trigger_Falling = 0x0C,  		//下降沿触发EXTI_Trigger_Rising_Falling = 0x10	//边沿触发
}EXTITrigger_TypeDef;

这里我选择的是上升沿触发EXTI_Trigger_Rising

在将上面几个寄存器设置好后,就可以使用中断使能控制器``EXTI_LineCmd`对外部中断/事件进行使能。

下面将程序关键部分代码贴上来,里面详细的可以看一下注释,程序内容是:按键按下,触发中断,控制LED灯亮灭。

关于LED灯的配置和使用,可以看一下之前关于LED灯的文章,这里着重说一下按键中断的相关配置和程序。

创建bsp_exti_key.c和bsp_exti_key.h

bsp_exti_key.h

#ifndef __BSP_KEY_H__
#define __BSP_KEY_H__#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"#define KEY1_PORT               GPIOA					//宏定义KEY1按键端口
#define KEY1_PIN                GPIO_Pin_0				//宏定义KEY1按键引脚号
#define KEY1_CLK                RCC_AHB1Periph_GPIOA	 //宏定义KEY1时钟#define KEY1_EXTI_IRQ           EXTI0_IRQn				//配置KEY1中断源#define KEY2_PORT               GPIOC					//宏定义KEY1按键端口
#define KEY2_PIN                GPIO_Pin_13				//宏定义KEY1按键引脚号
#define KEY2_CLK                RCC_AHB1Periph_GPIOC	 //宏定义KEY1时钟#define KEY2_EXTI_IRQ           EXTI15_10_IRQn			//配置KEY2中断源#define KEY1_EXTI_PROTSOURCE    EXTI_PortSourceGPIOA	 //宏定义KEY1端口源
#define KEY1_EXTI_PINSOURCE     EXTI_PinSource0			//宏定义KEY1引脚源	
#define KEY1_EXTI_LINE          EXTI_Line0				//宏定义KEY1输入线#define KEY2_EXTI_PROTSOURCE    EXTI_PortSourceGPIOC	//宏定义KEY2端口源
#define KEY2_EXTI_PINSOURCE     EXTI_PinSource13		//宏定义KEY2引脚源	
#define KEY2_EXTI_LINE          EXTI_Line13				//宏定义KEY2输入线#define KEY1_Handler    EXTI0_IRQHandler				//宏定义KEY1中断服务函数#define KEY2_Handler    EXTI15_10_IRQHandler			//宏定义KEY2中断服务函数#define KEY_ON  1
#define KEY_OFF 0void EXTI_Key_Config(void);
uint8_t Key_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);#endif  /*__BSP_KEY_H__*/

这里需要注意的是在中断源的配置上,看到PA0的中断源是EXTI0_IRQn,而PC13的中断源配置为EXTI15_10_IRQn,这里可以看一下stm32f4xx.h中对于IRQn_Type结构体定义,这里就不大篇幅贴源码了。

bsp_exti_key.h

#include "bsp_exti_key.h"static void NVIC_Config(void)				//配置中断向量表
{/*创建NVIC_InitTypeDef结构体*/NVIC_InitTypeDef NVIC_InitStructure;/*设置NVIC为优先级组1*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);/*设置主优先级为1*/NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;/*设置子优先级为1*/NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;/*使能中断通道*/NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;/*配置中断源为按键1*/NVIC_InitStructure.NVIC_IRQChannel = KEY1_EXTI_IRQ;/*初始化中断*/NVIC_Init(&NVIC_InitStructure);/*配置中断源为按键2,其余沿用上面的配置*/NVIC_InitStructure.NVIC_IRQChannel = KEY2_EXTI_IRQ;/*初始化中断*/NVIC_Init(&NVIC_InitStructure);
}void EXTI_Key_Config(void)
{/*--------------------------------GPIO引脚功能配置--------------------------------------*/GPIO_InitTypeDef KEY_InitStruct;/* 定义EXTI结构体 */EXTI_InitTypeDef EXTI_InitStructure;RCC_AHB1PeriphClockCmd(KEY1_CLK|KEY2_CLK,ENABLE);KEY_InitStruct.GPIO_Mode = GPIO_Mode_IN;KEY_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;KEY_InitStruct.GPIO_Pin = KEY1_PIN;GPIO_Init(KEY1_PORT,&KEY_InitStruct);KEY_InitStruct.GPIO_Pin = KEY2_PIN;GPIO_Init(KEY2_PORT,&KEY_InitStruct);/************************************配置NVIC向量控制器*********************************/NVIC_Config();/******************************配置EXTI外部中断/事件控制器*******************************//*使能SYSCFG时钟,使用GPIO外部中断时,必须使能SYSCFG时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);/* 将EXTI连接到按键1引脚 */SYSCFG_EXTILineConfig(KEY1_EXTI_PROTSOURCE,KEY1_EXTI_PINSOURCE);/* 将EXTI连接到按键1引脚 */SYSCFG_EXTILineConfig(KEY2_EXTI_PROTSOURCE,KEY2_EXTI_PINSOURCE);/* 设置EXTI模式为外部中断模式 */EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;/* 设置EXTI触发模式为上升沿 */EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;/* 使能EXTI */EXTI_InitStructure.EXTI_LineCmd = ENABLE;/* 设置引脚为KEY1 */EXTI_InitStructure.EXTI_Line = KEY1_EXTI_LINE;/* 初始化KEY1 */EXTI_Init(&EXTI_InitStructure);/* 设置引脚为KEY1,其余沿用上面的配置*/EXTI_InitStructure.EXTI_Line = KEY2_EXTI_LINE;/* 初始化KEY1 */EXTI_Init(&EXTI_InitStructure);
}

在完成以上设置后,就可以写我们的中断服务函数了,中断服务函数是放在stm32f4xx_it.c中,具体实现如下:

/* 中断服务程序名需要和启动文件startup_stm32f429_439xx.s中中断向量表的中断服务程序名一致,否则系统会跑去执行默认的程序,即启动代码中的B .程序进入死循环,这里用宏定义将中断服务程序改为KEY1/KEY2_Handler,目的是为了方便看出来这个中断服务程序是用来做什么的 */
void KEY1_Handler(void)
{/* 当中断触发后,会将中断标志位状态置位,只需要读取中断标志位就可以知道终端是否触发 */if(EXTI_GetITStatus(KEY1_EXTI_LINE) != RESET){LED_G_TOGGLE;					//中断触发后,用户程序}/* 中断触发后,需要将中断标志位清除,后续会等待中断再次触发 */EXTI_ClearITPendingBit(KEY1_EXTI_LINE);
}
void KEY2_Handler(void)
{if(EXTI_GetITStatus(KEY2_EXTI_LINE) != RESET){LED_R_TOGGLE;}EXTI_ClearITPendingBit(KEY2_EXTI_LINE);
}

main.c

#include "stm32f4xx.h"
#include "bsp_led.h"
#include "bsp_exti_key.h"int main(void)
{LED_Config();				//初始化LEDEXTI_Key_Config();			//初始化GPIO、EXTI及NVIC,之后就是进入死循环等待中断触发并执行中断服务程序while(1){}
}

总结:

关于中断的使用,编程内容总结如下几个:

1、初始化用来产生中断的GPIO;

2、初始化EXTI外部中断/事件控制器;

3、配置NVIC中断向量表;

4、编写中断服务程序。

相关文章:

009 - STM32学习笔记 - 中断

009 - STM32学习笔记 - 中断 这节的内容&#xff0c;野火的官方视频我反复看了好几次&#xff0c;但是感觉火哥在这块讲解的特别绕&#xff0c;理解起来很吃力&#xff0c;后来在看了一下其他老师的视频&#xff0c;结合一些书本资料和官方手册&#xff0c;才搞清楚STM32中断该…...

分享几种js格式化金额的方法

一、使用 Intl.NumberFormat 构造函数 这是 JavaScript 中格式化金额的最常见方法。Intl.NumberFormat()构造函数接受两个参数&#xff1a;语言环境和选项。语言环境是为其格式化金额的语言和地区。选项是一组控制金额格式的属性。例如&#xff0c;可以使用样式属性来指定货币…...

圣墟传说H5手工端搭建架设教程

圣墟传说H5手工端搭建架设教程 大家好&#xff0c;我是艾西。今天给大家带来的游戏是由小说改编而来的大型玄幻MMORPG仙侠手游&#xff0c;也是比较老的游戏了虽然你可能没有怎么听过&#xff0c;但总会有一批喜欢的玩家热衷于它。 那么让我们直接进入正题开始操作&#xff1…...

编程(40)----------单例模式

在简单总结单例模式之前, 需要了解一下背景知识-----为何会有单例模式? 想象一个这样的场景, 打游戏的时候, 尝试很多次, 都未通关. 这种情况下是否会考虑查一下攻略? 一个好的攻略甚至可能连每一关的每一个场景由多少只怪物都说的清清楚楚. 再比如, 在以前上学的时候, 为了…...

Java开发 - 让你少走弯路的Redis主从实现单节点哨兵模式

前言 前一篇中&#xff0c;我们讲解了Redis主从的搭建方式&#xff0c;其实很简单呐有木有&#xff0c;都是配置&#xff0c;连句代码都没有&#xff0c;是不是感觉高估了Redis主从的搭建方式&#xff1f;哈哈&#xff0c;没关系&#xff0c;跟着博主&#xff0c;包你全会。今…...

Java的Atomic原子类

Java SDK 并发包里提供了丰富的原子类&#xff0c;我们可以将其分为五个类别&#xff0c;这五个类别提供的方法基本上是相似的&#xff0c;并且每个类别都有若干原子类。 对基本数据类型的变量值进行原子更新&#xff1b;对对象变量的指向进行原子更新&#xff1b;对数组里面的…...

离线语音控制新方案,NRK3303语音识别芯片在智能风扇的应用

随着科技的不断发展&#xff0c;智能家居已经成为人们日常生活中不可或缺的一部分&#xff0c;涌现出越来越多的智能设备&#xff0c;如智能门锁、智能灯泡、智能冰箱等&#xff0c;这些设备为人们的生活带来了更多的便利和创新。其中作为常见的风扇通过添加智能语音控制功能&a…...

在树莓派3B+上安装Pytorch1.7

在树莓派3B上安装Pytorch1.7(应该是最简单的方法了)_package libopenblas-dev has no installation cand_Chauncey_Wang的博客-CSDN博客由于项目要求&#xff0c;我需要在树莓派上安装pytorch这就有几个问题&#xff0c;首先吧&#xff0c;咱们和外面之间有一道长城&#xff0c…...

Java性能权威指南-总结4

Java性能权威指南-总结4 Java性能调优工具箱操作系统的工具和分析CPU运行队列磁盘使用率网络使用率 Java监控工具基本的VM信息 Java性能调优工具箱 操作系统的工具和分析 CPU运行队列 快速小结 检查应用性能时&#xff0c;首先应该审查CPU时间。优化代码的目的是提升而不是…...

c语言全局变量和局部变量问题汇总

✅作者简介&#xff1a;嵌入式领域优质创作者&#xff0c;博客专家 ✨个人主页&#xff1a;咸鱼弟 &#x1f525;系列专栏&#xff1a;单片机设计专栏 &#x1f4c3;推荐一款求职面试、刷题神器&#x1f449;注册免费刷题 1、关键字static的作用是什么&#xff1f; 定义静态变…...

14.3:给定一个由字符串组成的数组strs,必须把所有的字符串拼接起来,返回所有可能的拼接结果中字典序最小的结果

给定一个由字符串组成的数组strs&#xff0c;必须把所有的字符串拼接起来&#xff0c;返回所有可能的拼接结果中字典序最小的结果 贪心写法 首先注意的一点是&#xff1a;如果两个字符串的长度相同&#xff0c;“abc”&#xff0c;“abd”&#xff0c;肯定是“abc”的字典序最…...

C++ 项目实战:跨平台的文件与视频压缩解压工具的设计与实现

C实战&#xff1a;跨平台文件与视频压缩解压工具的设计与实现 一、引言&#xff08;Introduction&#xff09;1.1 项目背景与目标1.2 技术选型&#xff1a;C、FFmpeg、libarchive、libzip、QtCFFmpeglibarchivelibzipQt 二、设计思路与框架&#xff08;Design Philosophy and F…...

C和指针(二)数据

数据类型 1&#xff0c;C语言中仅有四种基本数据类型——整型、浮点型、指针、聚合类型&#xff08;数组、结构等&#xff09;。 2&#xff0c;整型包括字符、短整型、整型、长整型&#xff0c;且可以分为有符号和无符号两种版本。 1&#xff09;长整型至少和整型一样长&#…...

PyTorch基础学习(一)

一.简介 PyTorch是一个基于Python的开源机器学习框架&#xff0c;它提供了丰富的工具和接口&#xff0c;用于构建和训练深度学习模型。PyTorch的主要特点包括&#xff1a; 动态计算图&#xff1a; PyTorch使用动态计算图&#xff0c;这意味着在模型构建过程中可以实时地进行计…...

chatgpt赋能python:Python代做:让您的网站更友好的SEO利器

Python代做&#xff1a;让您的网站更友好的SEO利器 如果您是一位网站管理员或者SEO工程师&#xff0c;您一定知道SEO对于网站的重要性。那么在SEO中&#xff0c;Python代做可以为您提供什么&#xff1f;在本文中&#xff0c;我们将通过介绍Python代做的技术和方法&#xff0c;…...

2022年都快结束了,还有人不会安卓录屏?在安卓上录制屏幕的的实现方式

前言 在我之前的文章 《以不同的形式在安卓中创建GIF动图》 中&#xff0c;我挖了一个坑&#xff0c;可以通过录制屏幕后转为 GIF 的方式来创建 GIF。只是当时我只是提了这么一个思路&#xff0c;并没有给出录屏的方式&#xff0c;所以本文的内容就是教大家如何通过调用系统 A…...

px rem em rpx 区别 用法

任意浏览器的默认字体高都是16px。所有未经调整的浏览器都符合: 1em16px。那么12px0.75em,10px0.625em。为了简化font-size的换算&#xff0c;需要在css中的body选择器中声明Font-size62.5%&#xff0c;这就使em值变为 16px*62.5%10px, 这样12px1.2em, 10px1em, 也就是说只需要…...

忆享聚焦|ChatGPT、AI、网络数字、游戏……近期热点资讯一览

“忆享聚焦”栏目第十四期来啦&#xff01;本栏目汇集近期互联网最新资讯&#xff0c;聚焦前沿科技&#xff0c;关注行业发展动态&#xff0c;筛选高质量讯息&#xff0c;拓宽用户视野&#xff0c;让您以最低的时间成本获取最有价值的行业资讯。 目录 行业资讯 1.科技部部长王志…...

[Daimayuan] 树(C++,动态规划,01背包方案数)

有一棵 n n n 个节点的以 1 1 1 号点为根的有根树。现在可以对这棵树进行若干次操作&#xff0c;每一次操作可以选择树上的一个点然后删掉连接这个点和它的儿子的所有边。 现在我们想知道对于每一个 k k k ( 1 ≤ k ≤ n 1≤k≤n 1≤k≤n)&#xff0c;最少需要多少次操作能…...

如何选择源代码加密软件

&#xff08;SDC沙盒&#xff09;和DLP、文档加密、云桌面等&#xff0c;其优缺点做客观比较如下&#xff1a; 比较内容安全容器(SDC沙盒)DLP文档加密云桌面代表厂家*信达卖咖啡、赛门贴科亿*通、IP噶德、*盾、*途四杰、深*服设计理念以隔离容器加准入技术为基础&#xff0c;构…...

TO-B类软件产品差异化

产品差异化&#xff0c;是在市场众多同质化产品中&#xff0c;突出自身产品亮点的重要方式。对于客户来讲其选择是多种多样的&#xff0c;与其花费大量的时间研究每一家产品的特点&#xff0c;还不如直接选择品牌更大、价格更低的产品来的直接&#xff0c;因此显而易见的突出产…...

设计模式之美-实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?

领域驱动设计&#xff08;Domain Driven Design&#xff0c;简称DDD&#xff09;盛行之后&#xff0c;这种基于贫血模型的传统的开发模式就更加被人诟病。而基于充血模型的DDD开发模式越来越被人提倡。所以&#xff0c;我打算用两节课的时间&#xff0c;结合一个虚拟钱包系统的…...

ChatGPT如何训练自己的模型

ChatGPT是一种自然语言处理模型&#xff0c;它的任务是生成自然流畅的对话。如果想要训练自己的ChatGPT模型&#xff0c;需要进行大量的数据收集、预处理、配置训练环境、模型训练、模型评估等过程。本文将详细介绍这些过程&#xff0c;帮助读者了解如何训练一个高品质的ChatGP…...

springboot使用线程池的实际应用(一)

在实际Spring Boot项目中&#xff0c;我们可以使用Java的原生多线程或者使用Spring自带的线程池进行多线程编程。多线程的好处在于能够提高应用程序的运行效率&#xff0c;特别是在某些计算密集型场景下。以下是一些使用多线程的典型场景&#xff1a; 并发处理请求&#xff1a…...

ESP-8266学习笔记

1、学习地址 【XMF09F系列资源】基于MicroPython的ESP8266物联网应用开发-赛教资源目录汇总-小蜜蜂笔记 Quick reference for the ESP8266 — MicroPython latest documentation 2、MicroPython及相关开发资源 3、固件烧录与uPyLoader的使用 烧录教程参考: https://www.…...

Java泛型简单的使用

前言 Java里面的泛型在实际开发中运用的很多&#xff0c;学过C的同学一定知道C的模板&#xff0c;而Java中的泛型&#xff0c;一定程度上和它还是挺像的。 相信写Java的人&#xff0c;大都有用过List的实现类ArrayList。在Java没有泛型之前&#xff0c;它的内部是一个Object的…...

深度探索:Qt CMake工程编译后的自动打包策略

深度探索&#xff1a;Qt CMake工程编译后的自动打包策略 1. 引言&#xff08;Introduction&#xff09;1.1 Qt和CMake的基本概念&#xff08;Basic Concepts of Qt and CMake&#xff09;1.2 自动打包的重要性&#xff08;Importance of Automatic Packaging&#xff09; 2. Qt…...

2.7 编译型和解释型

2.7 编译型和解释型 前面我们使用java和javac命令把Hello&#xff0c;World&#xff01;在控制台输出。那为什么输出&#xff0c;这里我们需要掌握两个知识点。编译型语言和解释型语言。在计算机的高级编程语言就分为编译型语言和解释型语言。而我们的Java既有编译型的特点也有…...

校园网自动登陆(河南科技学院)

1. 介绍 河南科技学院校园网自动登陆&#xff08;新乡的很多系统相似&#xff0c;可能也可以用&#xff1f;&#xff09;&#xff0c;java版。可以实现电脑&#xff0c;路由器&#xff0c;软路由的自动认证wifi,后续会上传docker版本的。 源码地址 github&#xff1a;https://…...

C++11 override和final关键字

C11中的override和final关键字是为了增强代码的编译时类型检查和面向对象设计中的继承机制。 override关键字用于显示地表明派生类中的成员函数覆盖了基类中的虚函数。当派生类中的函数与基类中的虚函数签名不同或者没有使用override关键字时&#xff0c;编译器会给出警告或错…...