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

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

目录

前言

如何使用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, pleaserefer to stm32f10x.h file) */
​uint8_t NVIC_IRQChannelPreemptionPriority;  /*!< Specifies the pre-emption priority for the IRQ channelspecified in NVIC_IRQChannel. This parameter can be a valuebetween 0 and 15 as described in the table @ref NVIC_Priority_Table */
​uint8_t NVIC_IRQChannelSubPriority;         /*!< Specifies the subpriority level for the IRQ channel specifiedin NVIC_IRQChannel. This parameter can be a valuebetween 0 and 15 as described in the table @ref NVIC_Priority_Table */
​FunctionalState NVIC_IRQChannelCmd;         /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannelwill 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协议之后,我们才能开始真正的修改内部的代码。

现象如下

相关文章:

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

目录 前言 如何使用STM32F1系列的标准库完成外部中断的抽象 初始化我们的GPIO为输入的一个模式 初识GPIO复用&#xff0c;开启GPIO的复用功能时钟 GPIO_EXTILineConfig和EXTI_Init配置外部中断参数 插入一个小知识——如何正确的配置结构体&#xff1f; 初始化中断&#…...

Python urllib3 全面指南:从基础到实战应用

欢迎来到涛涛的频道&#xff0c;今天用到了urllib3&#xff0c;和大家分享下。 1、介绍 urllib3 urllib3 是 Python 中一个功能强大且用户友好的 HTTP 客户端库&#xff0c;它提供了许多标准库 urllib 所不具备的高级特性。作为 Python 生态中最受欢迎的 HTTP 库之一&#xf…...

25.5 GLM-4优化RAG实战:0.1%参数实现准确率飙升30%,成本直降90%!

使用 GLM-4 优化 RAG 程序:基于标注数据的 Adapter 训练实战 关键词:GLM-4 优化, RAG 增强, 数据标注, Adapter 训练, 检索增强生成 1. RAG 系统的核心挑战与优化方向 传统 RAG(Retrieval-Augmented Generation)系统常面临以下瓶颈: graph LR A[用户提问] --> B[检…...

OrangePi入门教程(待更新)

快速上手指南 https://www.hiascend.com/developer/techArticles/20240301-1?envFlag1 教学课程(含开发板配置和推理应用开发) https://www.hiascend.com/developer/devboard 开发推理应用 https://www.hiascend.com/developer/techArticles/20240326-1?envFlag1...

基于SpringBoot+Vue实现的二手交易市场平台功能一

一、前言介绍&#xff1a; 1.1 项目摘要 随着社会的发展和人们生活水平的提高&#xff0c;消费者购买能力的提升导致产生了大量的闲置物品&#xff0c;这些闲置物品具有一定的经济价值。特别是在高校环境中&#xff0c;学生群体作为一个具有一定消费水平的群体&#xff0c;每…...

TC3xx芯片的UCB介绍

文章目录 前言一、UCB的定义及其功能简介二、UCB_BMHDx_ORIG and UCB_BMHDx_COPY (x 0 - 3)2.1 BMHD(Boot Mode Head) 三、UCB_SSW四、UCB_PFLASH_ORIG and UCB_PFLASH_COPY4.1 Password4.2 UCB Confirmation 前言 缩写全称UCBUser Configuration BlockBMHDBoot Mode Headers…...

Airflow量化入门系列:第四章 A股数据处理与存储优化

Airflow量化入门系列&#xff1a;第四章 A股数据处理与存储优化 本教程系统性地讲解了 Apache Airflow 在 A 股量化交易中的应用&#xff0c;覆盖从基础安装到高级功能的完整知识体系。通过八章内容&#xff0c;读者将掌握 Airflow 的核心概念、任务调度、数据处理、技术指标计…...

《海空重力测量理论方法及应用》之一重力仪系统组成及工作原理(下)

2、三轴稳定平台型 稳定平台的作用是隔离测量载体角运动对重力观测量的影响&#xff0c;确保重力传感器的敏感轴方向始终与重向保持一致。 当前主流的海空重力仪使用的稳定平台方案主要有4种: ①双轴阻尼陀螺平台: ②)双轴惯导加捷联方位平台: ③三轴惯导平台; ④捷联惯导…...

C++模板递归结构详解和使用

示例代码 template<typename _SourceIterator, typename _DestT> struct convert_pointer {typedef typename convert_pointer<typename _SourceIterator::pointer, _DestT>::type type; };1. 模板参数 _SourceIterator 是输入的类型&#xff0c;通常表示迭代器类…...

(八)PMSM驱动控制学习---无感控制之滑膜观测器

在FOC矢量控制中&#xff0c;我们需要实时得到转子的转速和位置 &#xff0c;但在考虑到成本和使用场合的情况下&#xff0c;往往使用无感控制&#xff0c;因为无位置传感器克服了传统机械式传感器的很多缺点和不足。比如&#xff0c;机械式传感器对环境要求比较严格&#xff0…...

蓝桥杯真题-分糖果-题解

链接&#xff1a;https://www.lanqiao.cn/problems/4124/learning/ 题目 复述&#xff1a;两种糖果&#xff0c;分别有9和16&#xff0c;分给7人&#xff0c;每个人得到的最少2&#xff0c;最多5&#xff0c;必需全部分完&#xff0c;几种分法&#xff1f; 复习-深度优先搜索 …...

推荐系统(二十二):基于MaskNet和WideDeep的商品推荐CTR模型实现

在上一篇文章《推荐系统&#xff08;二十一&#xff09;&#xff1a;基于MaskNet的商品推荐CTR模型实现》中&#xff0c;笔者基于 MaskNet 构建了一个简单的模型。笔者所经历的工业级实践证明&#xff0c;将 MaskNet 和 Wide&Deep 结合应用&#xff0c;可以取得不错的效果&…...

辅助查询是根据查询到的文档片段再去生成新的查询问题

&#x1f4a1; 辅助查询是怎么来的&#xff1f; 它是基于你当前查询&#xff08;query&#xff09;检索到的某个文档片段&#xff08;chunk_result&#xff09;&#xff0c;再去“反推”出新的相关问题&#xff08;utility queries&#xff09;&#xff0c;这些问题的作用是&a…...

Spring Cloud 框架为什么能处理高并发

Spring Cloud框架能够有效处理高并发场景&#xff0c;核心在于其微服务架构设计及多组件的协同作用&#xff0c;具体机制如下&#xff1a; 一、分布式架构设计支撑高扩展性 服务拆分与集群部署 Spring Cloud通过微服务拆分将单体系统解耦为独立子服务&#xff0c;每个服务可独…...

Pseduo LiDAR(CVPR2019)

文章目录 AbstractIntroductionRelated WorkLiDAR-based 3D object detectionStereo- and monocular-based depth estimationImage-based 3D object detection MethodDepth estimationPseudo-LiDAR generationLiDAR vs. pseudo-LiDAR3D object detectionData representation ma…...

强化学习课程:stanford_cs234 学习笔记(3)introduction to RL

文章目录 前言7 markov 实践7.1 markov 过程再叙7.2 markov 奖励过程 MRP&#xff08;markov reward process&#xff09;7.3 markov 价值函数与贝尔曼方程7.4 markov 决策过程MDP&#xff08;markov decision process&#xff09;的 状态价值函数7.4.1 状态价值函数7.4.2 状态…...

前端精度计算:Decimal.js 基本用法与详解

一、Decimal.js 简介 decimal.js 是一个用于任意精度算术运算的 JavaScript 库&#xff0c;它可以完美解决浮点数计算中的精度丢失问题。 官方API文档&#xff1a;Decimal.js 特性&#xff1a; 任意精度计算&#xff1a;支持大数、小数的高精度运算。 链式调用&#xff1a;…...

来聊聊C++中的vector

一.vector简介 vector是什么 C 中的 vector 是一种序列容器&#xff0c;它允许你在运行时动态地插入和删除元素。 vector 是基于数组的数据结构&#xff0c;但它可以自动管理内存&#xff0c;这意味着你不需要手动分配和释放内存。 与 C 数组相比&#xff0c;vector 具有更多的…...

对比学习中的NCE(Noise-Contrastive Estimation)和InfoNCE(SimCLR)损失函数+案例(附SimSiam分析)

在对比学习&#xff08;Contrastive Learning&#xff09;中&#xff0c;NCE&#xff08;Noise-Contrastive Estimation&#xff09;和InfoNCE是两种常见的目标函数&#xff0c;它们都用于通过区分正样本和负样本来学习高质量的表示。 1. NCE&#xff08;Noise-Contrastive Est…...

基于FAN网络的图像识别系统设计与实现

基于FAN网络的图像识别系统设计与实现 一、系统概述 本系统旨在利用FAN(Fourier Analysis Networks)网络架构实现高效的图像识别功能,并通过Python语言设计一个直观的用户界面,方便用户操作与使用。FAN网络在处理周期性特征方面具有独特优势,有望提升图像识别在复杂场景…...

【瑞萨 RA-Eco-RA2E1-48PIN-V1.0 开发板测评】PWM

【瑞萨 RA-Eco-RA2E1-48PIN-V1.0 开发板测评】PWM 本文介绍了瑞萨 RA2E1 开发板使用内置时钟和定时器实现 PWM 输出以及呼吸灯的项目设计。 项目介绍 介绍了 PWM 和 RA2E1 的 PWM 资源。 PWM 脉冲宽度调制&#xff08;Pulse Width Modulation, PWM&#xff09;是一种对模拟…...

NDK开发:开发环境

NDK开发环境 一、NDK简介 1.1 什么是NDK NDK(Native Development Kit)是Android提供的一套工具集,允许开发者在Android应用中使用C/C++代码。它包含了: 交叉编译器构建工具调试器系统头文件和库示例代码和文档1.2 NDK的优势 性能优化:直接使用底层代码,提高性能代码保…...

设计模式简述(三)工厂模式

工厂模式 描述简单工厂&#xff08;静态工厂&#xff09;工厂方法模式 抽象工厂增加工厂管理类使用 描述 工厂模式用以封装复杂的实例初始化过程&#xff0c;供外部统一调用 简单工厂&#xff08;静态工厂&#xff09; 如果对象创建逻辑简单且一致&#xff0c;可以使用简单工…...

通过Postman和OAuth 2.0连接Dynamics 365 Online的详细步骤

&#x1f31f; 引言 在企业应用开发中&#xff0c;Dynamics 365 Online作为微软的核心CRM平台&#xff0c;提供了强大的Web API接口。本文将教你如何通过Postman和OAuth 2.0认证实现与Dynamics 365的安全连接&#xff0c;轻松调用数据接口。 &#x1f4dd; 准备工作 工具安装…...

LlamaIndex实现RAG增强:上下文增强检索/重排序

面向文档检索的上下文增强技术 文章目录 面向文档检索的上下文增强技术概述技术背景核心组件方法详解文档预处理向量存储创建上下文增强检索检索对比技术优势结论导入库和环境变量读取文档创建向量存储和检索器数据摄取管道使用句子分割器的摄取管道使用句子窗口的摄取管道查询…...

AI比人脑更强,因为被植入思维模型【43】蝴蝶效应思维模型

giszz的理解&#xff1a;蝴蝶效应我们都熟知&#xff0c;就是说一个微小的变化&#xff0c;能带动整个系统甚至系统的空间和时间的远端&#xff0c;产生巨大的链式反应。我学习后的启迪&#xff0c;简单的说&#xff0c;就是不要忽视任何微小的问题&#xff0c;更多时候&#x…...

程序化广告行业(62/89):DSP系统的媒体与PDB投放设置探秘

程序化广告行业&#xff08;62/89&#xff09;&#xff1a;DSP系统的媒体与PDB投放设置探秘 大家好&#xff01;在之前的学习中&#xff0c;我们对程序化广告的DSP系统有了一定了解。今天还是带着和大家共同进步的想法&#xff0c;深入探索DSP系统中媒体设置以及PDB投放设置的…...

Java项目之基于ssm的怀旧唱片售卖系统(源码+文档)

项目简介 怀旧唱片售卖系统实现了以下功能&#xff1a; 用户信息管理&#xff1a; 用户信息新增&#xff1a;添加新用户的信息。 用户信息修改&#xff1a;对现有用户信息进行修改。 商品信息管理&#xff1a; 商品信息添加&#xff1a;增加新的商品&#xff08;唱片&#x…...

程序化广告行业(61/89):DSP系统活动设置深度剖析

程序化广告行业&#xff08;61/89&#xff09;&#xff1a;DSP系统活动设置深度剖析 大家好&#xff01;在程序化广告的学习道路上&#xff0c;我们已经探索了不少重要内容。今天依旧本着和大家一起学习进步的想法&#xff0c;深入解析DSP系统中活动设置的相关知识。这部分内容…...

Altshuller矛盾矩阵查询:基于python和streamlit

基于python和streamlit实现的Altshuller矛盾矩阵查询 import streamlit as st import json# 加载数据 st.cache_resource def load_data():with open(parameter.json, encodingutf-8) as f:parameters json.load(f)with open(way.json, encodingutf-8) as f:contradictions …...

FreeRTOS的空闲任务

在 FreeRTOS 中&#xff0c;空闲任务&#xff08;Idle Task&#xff09; 是操作系统自动创建的一个特殊任务&#xff0c;其作用和管理方式如下&#xff1a; 1. 空闲任务创建 FreeRTOS 内核自动创建&#xff1a;当调用 vTaskStartScheduler() 启动调度器时&#xff0c;内核会自…...

【代码模板】如何用FILE操作符打开文件?fopen、fclose

#include "stdio.h" #include "unistd.h"int main(int argc, char *argv[]) {FILE *fp fopen("1.log", "wb");if (!fp) {perror("Failed open 1.log");return -1;}fclose(fp); }关于权限部分参考兄弟篇【代码模板】C语言中…...

[特殊字符] Pandas 常用操作对比:Python 运算符 vs Pandas 函数

在 Pandas 中&#xff0c;许多操作可以直接使用 Python 的比较运算符&#xff08;如 、!、>、< 等&#xff09;&#xff0c;而不需要调用 Pandas 的专门函数&#xff08;如 eq()、ne()、gt() 等&#xff09;。这些运算符在 Pandas 中已经被重载&#xff0c;代码更简洁。以…...

I.MX6ULL开发板与linux互传文件的方法--NFS,SCP,mount

1、内存卡或者U盘 方法比较简单&#xff0c;首先在linux系统中找到u盘对应的文件夹&#xff0c;随后使用cp指令将文件拷贝进u盘。 随后将u盘插入开发板中&#xff0c;找到u盘对应的设备文件。一般u盘对应的设备文件在/dev下&#xff0c;以sda开头&#xff0c;可以使用命令列出所…...

图解AUTOSAR_SWS_FlashEEPROMEmulation

AUTOSAR Flash EEPROM Emulation (FEE) 详解 基于AUTOSAR规范的Flash EEPROM Emulation模块分析 目录 1. 概述2. 架构设计 2.1 模块位置与接口2.2 内部状态管理2.3 配置结构3. API接口 3.1 接口功能分类3.2 错误管理4. 操作流程 4.1 写入操作序列5. 总结1. 概述 Flash EEPROM …...

Unity:Simple Follow Camera(简单相机跟随)

为什么需要Simple Follow Camera&#xff1f; 在游戏开发中&#xff0c;相机&#xff08;Camera&#xff09;是玩家的“眼睛”。它的作用是决定玩家看到游戏世界的哪一部分。很多游戏需要相机自动跟随玩家角色&#xff0c;让玩家始终可以看到角色及其周围的环境&#xff0c;而…...

[项目总结] 在线OJ刷题系统项目总结与分析(二): 技术应用(上)

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…...

针对Ansible执行脚本时报错“可执行文件格式错误”,以下是详细的解决步骤和示例

针对Ansible执行脚本时报错“可执行文件格式错误”&#xff0c;以下是详细的解决步骤和示例&#xff1a; 目录 一、错误原因分析二、解决方案1. 检查并添加可执行权限2. 修复Shebang行3. 转换文件格式&#xff08;Windows → Unix&#xff09;4. 检查脚本内容兼容性5. 显式指定…...

从 Dense LLM 到 MoE LLM:以 DeepSeek MoE 为例讲解 MoE 的基本原理

写在前面 大多数 LLM 均采用 Dense(密集) 架构。这意味着,在处理每一个输入 Token 时,模型所有的参数都会被激活和计算。想象一下,为了回答一个简单的问题,你需要阅读整部大英百科全书的每一个字——这显然效率低下。 为了突破 Dense 模型的瓶颈,一种名为 Mixture of …...

未来已来:探索AI驱动的HMI设计新方向

在科技浪潮的持续冲击下&#xff0c;人工智能&#xff08;AI&#xff09;正以势不可挡的姿态重塑各个领域的格局&#xff0c;其中人机交互&#xff08;HMI&#xff0c;Human - Machine Interaction&#xff09;设计领域深受其影响&#xff0c;正经历着深刻的变革。AI 技术的融入…...

5天速成ai agent智能体camel-ai之第1天:camel-ai安装和智能体交流消息讲解(附源码,零基础可学习运行)

嗨&#xff0c;朋友们&#xff01;&#x1f44b; 是不是感觉AI浪潮铺天盖地&#xff0c;身边的人都在谈论AI Agent、大模型&#xff0c;而你看着那些密密麻麻的代码&#xff0c;感觉像在读天书&#xff1f;&#x1f92f; 别焦虑&#xff01;你不是一个人。很多人都想抓住AI的风…...

Unity UGUI使用手册

概述 UGUI(Unity Graphical User Interface) :Unity 图像用户界面 在游戏开发中&#xff0c;我们经常需要搭建一些图形用户界面。Unity内置的UGUI可以帮助开发者可视化地拼接界面&#xff0c;提高开发效率。UGUI提供不同样式的UI组件&#xff0c;并且封装了对应功能的API&am…...

(二)输入输出处理——打造智能对话的灵魂

上一篇&#xff1a;&#xff08;一&#xff09;从零开始&#xff1a;用 LangChain 和 ZhipuAI 搭建简单对话 在上一篇文章中&#xff0c;我们成功搭建了一个基于 LangChain 和 ZhipuAI 的智能对话系统的基础环境。今天&#xff0c;我们将深入探讨输入输出处理的细节&#xff0…...

beego文件上传

1file.go 2html代码 3路由设置 beego.Router("/file/Upload", &controllers.FileUploadController{}, "post:Upload") 注意 1&#xff0c;得新建个upload文件夹 2&#xff0c;路由设置严格区分大小写。 biiego文件下载上传代码 github 觉得不错Star下...

代码随想录回溯算法01(递归)

回溯法也可以叫做回溯搜索法&#xff0c;它是一种搜索的方式。 回溯是递归的副产品&#xff0c;只要有递归就会有回溯。 所以以下讲解中&#xff0c;回溯函数也就是递归函数&#xff0c;指的都是一个函数。 组合问题&#xff1a;N个数里面按一定规则找出k个数的集合切割问题&am…...

分治-归并排序-逆序对问题

目录 1.升序&#xff08;以右边的合并组为基准&#xff09; 2.降序&#xff08;以左边的合并组为基准&#xff09; 3.逆对序--固定下标 1.升序&#xff08;以右边的合并组为基准&#xff09; 找出左边有多少个数比我(nums[right])大 应该在每一次合并之前&#xff0c;进行…...

mysql-getshell的几种方法

mysql_getshell的几种方法 mysql_getshell 一、mysql的–os-shell 利用原理 –os-shell就是使用udf提权获取WebShell。也是通过into oufile向服务器写入两个文件&#xff0c;一个可以直接执行系统命令&#xff0c;一个进行上传文件。此为sqlmap的一个命令&#xff0c;利用这…...

初阶数据结构--树

1. 树的概念与结构 树是⼀种⾮线性的数据结构&#xff0c;它是由 n&#xff08;n>0&#xff09; 个有限结点组成⼀个具有层次关系的集合。把它叫做 树是因为它看起来像⼀棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;⽽叶朝下的。 有⼀个特殊的结点&#xff0c;称…...

搭建redis主从同步实现读写分离(原理剖析)

搭建redis主从同步实现读写分离(原理剖析) 文章目录 搭建redis主从同步实现读写分离(原理剖析)前言一、搭建主从同步二、同步原理 前言 为什么要学习redis主从同步&#xff0c;实现读写分析。因为单机的redis虽然是基于内存&#xff0c;单机并发已经能支撑很高。但是随着业务量…...

Python3 学习笔记

Python3 简介 | 菜鸟教程 一 Python3 简介 Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性&#xff0c;相比其他语言经常使用英文关键字&#xff0c;其他语言的一些标点符号&#xff0c;它具有比其他语言更有特色…...