【理解ARM架构】中断处理 | CPU模式

🐱作者:一只大喵咪1201
🐱专栏:《理解ARM架构》
🔥格言:你只管努力,剩下的交给时间!
图

目录

  • 🍜中断
    • 🍨GPIO中断
      • 代码实现
  • 🍜CPU
    • 🍨CONTROL寄存器
    • 🍨模式
      • 代码
    • 🍨提升访问等级
    • 🍨EXC_RETURN
  • 🍜总结

🍜中断

图
如上图,在上篇文章中本喵主要介绍的是右侧框中的异常,这里开始介绍一下左边框里的中断,中断主要由三部分组成:

  • 中断源:

    • 中断源多种多样,比如GPIO、定时器、UART、DMA等等。
    • 它们都有自己的寄存器,可以进行相关设置:使能中断、中断状态、中断类型等等。
  • 中断控制器,在STM32F103中被叫做NVICNested vectored interrupt controller(嵌套向量中断控制器)

    • 各种中断源发出的中断信号,汇聚到中断控制器。
    • 可以在中断控制器中设置各个中断的优先级。
    • 中断控制器会向CPU发出中断信号,CPU可以读取中断控制器的寄存器,判断当前处理的是哪个中断。
  • CPU:

    • CPU每执行完一条指令,都会判断一下是否有中断发生了。
    • CPU也有自己的寄存器,可以设置它来使能/禁止中断,这是中断处理的总开关。

🍨GPIO中断

就以本喵用的STM32F103ZET6的GPIO中断为例来讲解,配置PA0为中断输入引脚:

tu
如上图所示中断体系结构图,对于GPIO中断,STM32F103又引入了External interrupt/event controller (EXTI)用来设置GPIO的中断类型。

EXTI可以给NVIC提供16个中断信号:EXTI0~EXTI15。某个EXTIx来自哪个GPIO需要设置GPIO控制器。

  • 每一个中断源都有自己的寄存器来配置自己的中断类型。
  • 中断源将自己的中断信号给到中断控制器(NVIC),GPIO的中断信号先给到EXTI,再由EXTI给到中断控制器。
  • 中断控制器再比较不同中断的优先级,将某一个中断信号送给CPU。

当CPU检测到来自NVIC的中断信号时,如果该中断没有被屏蔽,就会跳转到向量表中执行相应的外部中断处理函数。

tu
如上图所示是向量表,下面的蓝色框就是中断的入口函数,CPU的处理流程和异常一模一样,也是先保护现场,分辨中断源并处理,最后恢复现场。


按照上面框图来配置一下GPIO中断,也就是我们常用的按键中断。

GPIO控制器:

图
如上图所示的寄存器,STM32F103的GPIO控制器中有AFIO_EXTICR1~AFIO_EXTICR4一共4个寄存器,名为:External interrupt configuration register,外部中断配置寄存器,用来选择某个外部中断EXTIx的中断源。

tu
如上图所示AFIO模块的基地址是0x40010000

图
从上图可知,EXTI0只能从PA0、……、PG0中选择一个,这也意味着PA0、……、PG0中只有一个引脚可以用于中断。这跟其他芯片不一样,很多芯片的任一GPIO引脚都可以同时用于中断。

EXTI:

图
EXTI框图所示,这个用来设置中断的触发方式,如高电平触发、低电平触发、上升沿触发、下降沿触发等等。

图
如上图,该模块的基地址是0x40010400

沿着上面框图中的红线,我们要设置:

  • Falling trigger selection register:是否选择下降沿触发

图
如上图所示EXTI_FTSR寄存器,bit0~bit19设置19个外部中断源的下降沿触发,将对应EXTIx的比特位置一就是使能,置为0就是不使能。

  • Rising trigger selection register:是否选择上升沿触发

图
如上图所示EXTI_RTSR寄存器,bit0~bit19设置19个外部中断源的上升沿触发,将对应EXTIx的比特位置一就是使能,置为0就是不使能。

  • Interrupt mask register:是否屏蔽中断

图
如上图所示EXTI_IMR寄存器,bit0~bit19设置19个外部中断源是否被屏蔽,将对应EXTIx的比特位置一就是不屏蔽,置为0就是屏蔽。

当发生中断时,可以读取下面寄存器判断是否发生了中断、发生了哪个中断:

图
如上图所示EXTI_PR寄存器,bit0~bit19对应19个外部中断源的发生情况,对应EXTIx的比特位为一就是发生中断,为0就是没有发生中断。

  • EXTI中配置完外部中断的触发方式以后,要解除相应中断源的屏蔽,也就是将中断开关打开,方便中断信号到达NVIC。

NVIC:

多个中断源汇聚到NVIC,NVIC的职责就是从多个中断源中取出优先级最高的中断,向CPU发出中断信号。

  • 处理中断时,程序要写NVIC的寄存器,清除中断标志。

tu
如上图所示NVIC涉及到的寄存器,我们暂时只需要关注:ISER(中断设置使能寄存器)、ICPR(中断清除挂起寄存器)、中断优先级寄存器(设置中断优先级,该寄存器是8位)。

tu
如上图所示中断使能和清除寄存器,这些寄存器有很多个,比如ISER0ISER1等等,里面的每一位对应一个中断。

  • 描述中的中断编号就是中断/异常处理函数在向量表中的位置,如中断#0就等于异常#16,因为中断也属于异常。
  • 中断处理入口有单独从0开始的一套编号,也和异常一起的一套编号。

tu
如上图所示,向量表,我们设置的PA0对应的中断编号是6,所以设置ISER0ICER0中的bit6即可。

对于中断优先级设置寄存器,每一个中断在NVIC中都有一个8位的寄存器来设置它的优先级,用这8位来表示中断的抢占优先级和子优先级,具体规则本喵就不再介绍了。

CPU:

cortex M3/M4处理器内部有这几个寄存器:

  • PRIMASK

tu
如上图所示PRIMASK寄存器, 把bit0设置为1,就可以屏蔽所有优先级可配置的中断。

可以使用这些指令来设置它:

CPSIE I  ; 清除PRIMASK,使能中断
CPSID I  ; 设置PRIMASK,禁止中断

或者:
MOV R0, #1
MSR  PRIMASK, R0  ; 将1写入PRIMASK禁止所有中断

MOV R0, #0
MSR PRIMASK, R0  ; 将0写入PRIMASK使能所有中断

因为这是CPU的寄存器,属于特殊寄存器,必须按照这几条指令以及规则修改寄存器。

  • FAULTMASK

图
如上图所示,FAULTMASKPRIMASK很像,它更进一步,除了一般的中断外,把HardFault都禁止了,只有NMI可以发生。该寄存器我们一般不会去设置它。

可以使用这些指令来设置它:

CPSIE F  ; 清除FAULTMASK
CPSID F  ; 设置FAULTMASK

或者:
MOV R0, #1
MSR  FAULTMASK R0  ; 将1写入FAULTMASK禁止中断

MOV R0, #0
MSR FAULTMASK, R0  ; 将0写入FAULTMASK使能中断
  • BASEPRI

图
如上图,BASEPRI用来屏蔽这些中断:它们的优先级的值大于或等于BASEPRI。比如设置将BASEPRI设置为0x60,那么优先级低于0x60的所有中断CPU都屏蔽掉了,不会去处理,只有优先级为0x00~0x60的中断CPU才会去处理。

可以使用这些指令来设置它:

MOVS R0, #0x60
MSR BASEPRI, R0   ; 禁止优先级在0x60~0xFF间的中断

MRS R0, BASEPRI   ; 读取BASEPRI

MOVS R0, #0
MSR BASEPRI, R0    ; 取消BASEPRI屏蔽

代码实现

图
如上图,为了访问寄存器方便,将AFIO定义成一个结构体,成员包含该模块中的所有寄存器。

图
如上图代码所示,定义key_init按键初始化函数,函数中,对于PA0引脚配置成输入在前面的文章中本喵讲解过,这里直接使用,重要的第二步中,将PA0映射到EXTI0上,让PA0成为中断源。

tu
如上图代码所示,将EXTI模块用结构体描述出来,然后定义exti_init初始化函数,设置为双边沿触发方式,并且使能中断,也就是不进行屏蔽,让EXTI能够向NVIC发生中断信号。

tu
如上图代码所示,同样将NVIC模块用结构体描述出来,并且定义nvic_init函数初始化NVIC,这里仅使能了EXTI0中断。

还定义了清除中断标志位的函数nvic_clear_int,在函数内将ICPR[0]bit6置一。

所有的配置完毕以后,就可以实现中断处理函数了,当PA0产生中断以后,会自动跳转到向量表中,从EXTI0_IRQHandler处理入口处执行中断服务函数。

图
如上图所示,在中断服务函数中,读取PA0的IDR寄存器值,当该值为0,说明按键被按下,否则按键没有按键,并且打印不同状态下的字符串。在中断函数的最后清除EXTINVIC中的重点标志位,方便下一次中断产生。

tu
如上图,使用软件仿真,勾选PA0引脚模拟中断产生,在串口中可以看到按键按下和松开的字符串,说明我们的中断功能配置成功。


默认情况下,CPU是会处理所有来自NVIC的中断的,如果将所有中断在CPU这里都屏蔽掉呢?

tu

如上图所示,在启动文件中,调用mymain函数之前,给PRIMASK特殊寄存器写1,屏蔽掉所有中断,此时程序运行起来后无论怎么点击PA0都不会有字符串显示,因为CPU此时不处理任何一个中断。

虽然默认情况下CPU是不屏蔽任何一个中断的,但是保险起见,还是在启动文件中使用CPSIE I指令,使能所有中断,让CPU处理所有NVIC送过来的中断。

🍜CPU

CPU有不同的工作模式,状态,以及可以使用不同的栈寄存器。

ARM芯片支持Thumb指令集、ARM指令集,处理器运行Thumb指令时处于Thumb状态,运行ARM指令时处于ARM状态。

CortexM3/M4只支持Thumb指令集,所以处理器运行时只有Thumb状态。除此之外,还有一个调试状态:比如通过调试器或触发断点后,处理器就会进入调试状态并停止指令执行。这里本喵不涉及调试状态,所以处理器只处于Thumb状态。

🍨CONTROL寄存器

tu

如上图所示CONTROL寄存器,这是一个特殊寄存器,是属于CPU的,影响着CPU的一些特定功能。不同类型的内核该寄存器使用的位数不同,这里本喵仅讲解Cortex-M3/M4内核时的该寄存器。

图
如上图所示CONTROL不同位的作用。

  • SPSEL:用来选择线程模式使用的是MSP还是PSP。
  • nPRIV:用来设置线程模式的访问等级(特权/非特权)。

🍨模式

图

如上图所示,CortexM3/M4处理器有两种模式:

  • 处理模式:执行中断服务程序等异常处理,在处理模式下,处理器有最大权限(具有特权访问等级)。
  • 线程模式:执行普通程序,这时处理器可以处于特权访问等级,也可以处于非特权访问等级。

不同模式下,处理权限可能不同,但是最大的不同就是:栈寄存器可能也不同


访问等级有两种:

  • 特权访问等级:可以访问所有寄存器、所有存储器。
  • 非特权访问等级:无法访问某些寄存器,比如无法访问NVIC寄存器(嵌套向量中断控制器)。

在一般的单片机系统中,RTOS和各类应用之间是无法隔离的,某个应用程序崩溃了,整个系统也就崩溃了。如果能让RTOS和各类应用程序彼此之间隔离开,那么可以增强系统的健壮性。这需要硬件的支持,比如需要有MPU(Memory Protection Unit)。

  • 没有MPU时,访问等级的用处不大,只能用来限制应用程序无法访问某些寄存器。

ARM处理器的通用寄存器有R0、R1、……、R15,其中的R13也被称为SP,即栈寄存器。对于SP,它有两个实体:MSP(Main SP)、PSP(Process SP)。

栈寄存器的选择:

  • ① 启动时,CONTROL寄存器的SPSEL等于0,默认使用MSP。注意:启动时是线程模式,使用的仍然是MSP
  • ② 程序可以修改CONTROL寄存器让SPSEL等于1,以使用PSP
  • ③ 发生异常时,异常处理函数中使用的必定是MSP
  • ④ 异常返回时,可以控制返回之后使用MSP还是PSP
  • 在处理模式下,使用MSP,也就是说指令中使用SP时,它对应的物理寄存器是MSP。
  • 在线程模式下,根据CONTROL寄存器的设置,处理器可能用的是MSP,也可能用的是PSP。
  • 处理模式下,使用的栈必然是MSP

代码

MRS r0, CONTROL  ; 将CONTROL寄存器的值读入R0
MSR CONTROL, r0  ; 将R0写入CONTROL寄存器

读写CONTROL特殊寄存器,必须使用上面的指令。

模式:

图
如上图,将前面GPIO中断的代码拿来仿真运行,查看寄存器时可以看到,Mode = Thread,表示此时是线程模式,Privilege = Privileged,表示此时是特权访问等级,Stack = MSP,表示此时使用的是MSP栈。

这是时CONTROL寄存器中的值都是默认值,本喵没有做任何改动,所以说默认情况下,使用的是特权访问等级和MSP

图
如上图所示,在按键中断处理函数中打一个断点,让程序运行到中断函数中停下来,此时Mode = Handler,表示此时处于处理模式,优先级和栈类型都没有改变。

  • 在处理异常或者中断时,CPU必定处于处理模式,其他情况处于线程模式,包括上电时。

访问等级:

下面本喵来改变一下CONTROL中的值:

tu
如上图,将CONTROL中的bit0置一,此时CPU处于线程模式,所以访问等级就是非特权访问等级。

tu

如上图,在线程模式的非特权访问等级下,调用mymain函数,在该函数中会访问NVIC,所以在访问的时候就会产生HardFault_Handler硬件异常,更进一步说明,非特权访问等级无法访问NVIC

tu

如上图,将访问NVIC的代码放在将访问等级改为非特权访问等级之前,此时就可以正常执行了。此时CPU处于线程模式非特权访问等级

tu
如上图,当执行中断服务函数的时候,CPU就自动变为处理模式特权访问等级了。

  • 处理中断和异常时,CPU必定处于特权访问等级,也就是处理模式时,CPU必定处于特权访问等级。
  • 只有线程模式时,CPU才存在不同的访问等级。

PSP/MSP:

tu

如上图所示,在CPU仍然是特权访问等级时,将栈设置为PSP,在将访问等级设置为非特权访问等级后,CPU处于线程模式,非特权访问等级,使用的是PSP。

  • 非特权访问等级无法访问CONTROL寄存器。

图
如上图,当CPU在处理中断服务函数时,自动恢复成了处理模式,特权访问等级,使用MSP,不再使用PSP

  • 在处理中断异常时,CPU必定使用MSP

图

如上图,从中断服务函数中退出以后,就会恢复到进入之前的状态,恢复成线程模式,特权访问等级,使用PSP


TU
如上图所示,PSPMSP是两个不同栈顶指针,默认情况下SP寄存器就是指MSP

给MSP赋值0x20010000,给PSP赋值0x20008000,让PSP挨着放在MSP的下面。

  • 一般使用了RTOS时,任务会使用PSP。裸机程序中仅使用MSP即可。
  • 在中断和异常中使用MSP是为了让程序更加高效,使用独立的栈,减少了硬件在线程保护和恢复时的工作量。

🍨提升访问等级

tu

如上图所示,在非特权访问等级下无法访问CONTROL寄存器,所以也就无法将访问等级提升为特权访问等级。

在前面我们看到,CPU在处理中断或者异常时,会变成处理模式,特权访问等级,以及使用MSP

图
所以可以按照上图所示的流程,在异常或者中断中,将CONTROL寄存器的bit0设置为0,让CPU从此变成特权访问模式。

tu
如上图,定义一个SetPrivileged函数,在函数内使用汇编代码块asm {}产生SVC异常,此时CPU就会执行SVC_Handler异常处理函数,此时CPU就会处于特权访问状态。

在异常处理函数中,将CONTROL寄存器的bit0清零,让CPU变成特权访问等级,之后在执行完异常处理函数以后,CPU就一直都是特权访问等级了,如此就成功的修改了CPU的访问等级。

tu
如上图所示,在执行SetPrivileged函数之前,处于非特权访问等级,在执行完毕后,处于特权访问等级,此时就成功的修改了访问等级。

🍨EXC_RETURN

在线程模式中,CPU是非特权访问等级,使用的是PSP栈,在处理模式时,是特权访问等级,使用的是MSP栈,在处理完中断或异常后,由处理模式变为线程模式时,会恢复对应的访问等级和使用的栈。

  • 这是怎么做到的呢?在哪里记录着前一个模式的CONTROL寄存器中的值?

在介绍异常和中断时,本喵就讲解过,调用异常和中断处理函数进行线程保护时,LR寄存器会被赋予一个特殊的值,该值就是EXC_RETIRN

tu
如上图所示,不考虑浮点单元使用,当LR中的值是0xFFFFFFF1时,CPU在处理完异常或者中断后,返回的是处理模式,并且使用主栈MSP

LR中的值是0xFFFFFFF9时,返回的是线程模式,并且使用的是主栈MSP

LR中的值是0xFFFFFFFD时,返回的是线程模式,并且使用的是进程栈PSP

图
如上图所示,使用前面的代码,在线程模式中使用的是PSP,在SVC_Handler异常处理函数中,使用的是MSP,可以看到LR寄存器中的值是0xFFFFFFFD

对照EXC_RETURN的合法值表中可以知道,在执行完SVC异常处理函数以后,返回线程处理模式,并使用PSP

🍜总结

中断的处理和异常处理非常的相似,都是由硬件去向量表中找到对应的处理入口,并执行处理函数。在调用处理函数之前,由硬件进行现场保护,中断源分辨,在执行完处理函数返回时,由软件触发现场恢复机制,由硬件完成现场恢复工作。

  • 所有中断都要经过中断控制器NVIC。

CPU有两种工作模式,处理模式和现场模式,处理模式对应的访问等级是特权访问等级,使用的是主栈MSP,在处理中断或者异常时,必然处于处理模式。

在线程模式时,访问等级和使用的栈都可以根据CONTROL去修改,有四种组合:

图

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java 数据结构篇-用链表、数组实现队列(数组实现:循环队列)

🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 队列的说明 1.1 队列的几种常用操作 2.0 使用链表实现队列说明 2.1 链表实现队列 2.2 链表实现队列 - 入栈操作 2.3 链表实现队列 - 出栈操作 2.4 链表实现队列 …

机器学习笔记 - 什么是3D语义场景完成/补全?

一、什么是3D语义场景补全? 3D 语义场景完成(Semantic Scene Completion)是一种机器学习任务,涉及以体素化形式预测给定环境的完整3D场景(完成3D形状的同时推断场景的 3D 语义分割的任务)。这是通过使用深度图和为场景提供上下文的可选 RGB 图像来完成的。目标是以一种可轻…

2023年腾讯云双12优惠活动整理汇总

2023年双12腾讯云推出了年末感恩回馈活动,年度爆款2核2G4M云服务器118元/年,新老用户同享,还可领取总面值2000元代金券,老用户服务器续费4折起。本文为大家整理汇总腾讯云双12优惠活动。 活动地址: 点此直达腾讯云双1…

linux常用命令-find命令与scp命令详解(超详细)

文章目录 前言一、find命令介绍1. find命令简介2. find命令的基本语法3. 常用的find命令选项和表达式 二、find命令示例用法1. 按照名称进行搜索2. 按照类型进行搜索3. 按照修改时间进行搜索4. 按照文件大小进行搜索5. 对搜索到的文件执行指定的命令6. 删除搜索到的文件 三、sc…

23种设计模式之C++实践(二)

23种设计模式之C++实践 3. 设计模式(二)组合型模式7. 适配器模式——不兼容结构的协调7.2:类适配器模式7.3:双向适配器模式适配器模式总结8.桥接模式——处理多维度变化桥接模式总结9. 组合模式——树形结构的处理9.2 透明组合模式9.3 安全组合模式组合模式总结10. 装饰模式…

yolov5 7.0版本部署手机端。通过pnnx导出ncnn。

yolov5 7.0版本部署手机端。通过pnnx导出ncnn。 流程配置ncnn android yolov5导出自己模型的ncnn修改yolo.py文件导出TorchScript文件pnnx转torchscript为ncnn 安卓运行权重路径输入输出anchors 大小类别名generate_proposals方法修改 结果 流程 网络yolov5 的部署已经有很多了…

分享一个国内可用的免费GPT4-AI提问AI绘画网站工具

一、前言 ChatGPT GPT4.0,Midjourney绘画,相信对大家应该不感到陌生吧?简单来说,GPT-4技术比之前的GPT-3.5相对来说更加智能,会根据用户的要求生成多种内容甚至也可以和用户进行创作交流。 然而,GPT-4对普…

Elasticsearch 优化查询中获取字段内容的方式,性能提升5倍!

1、背景 集群配置为:8 个 node 节点,16 核 32G,索引 4 分片 1 副本。应用程序的查询逻辑是按经纬度排序后找前 200 条文档。 1、应用对查询要求比较高,search 没有慢查询的状态。 2、集群压测性能不能上去,cpu 使用未打…

mybatis的一级缓存和二级缓存

mybatis的一级缓存和二级缓存 mybatis设计两级缓存来提高查询效率。 一级缓存是SqlSession级别,每个会话都需要创建一个sqlsession,避免同一个用户在多次查询中每次都去查询数据库就把查询结果做了缓存 二级缓存 跨SqlSession的缓存,以及缓存…

C#——Delegate(委托)与Event(事件)

C#——Delegate(委托)与Event(事件) 前言一、Delegate(委托)1.是什么?2.怎么用?Example 1:无输入无返回值Example 2:有输入Example 3:有返回值Exa…

抖音外卖商品模型

目录 一、抖音外卖商品模型 二、商家运营流程 (一)商家入驻流程 (二)商品发布流程 三、推广带货流程 (一)短视频带货 (二)直播视频带货 【直播工具】 【直播流程】 直播前…

SQL Server 数据库,创建数据表(使用T-SQL语句)

2.3表的基本概念 表是包含数据库中所有数据的数据库对象。数据在表中的组织方式与在电子表格中相似,都是 按行和列的格式组织的,每行代表一条唯一的记录,每列代表记录中的一个字段.例如,在包含公 司员工信息的表中,每行…

数据结构:图文详解双向链表的各种操作(头插法,尾插法,任意位置插入,查询节点,删除节点,求链表的长度... ...)

目录 一.双向链表的概念 二.双向链表的数据结构 三.双向链表的实现 节点的插入 头插法 尾插法 任意位置插入 节点的删除 删除链表中第一次出现的目标节点 删除链表中所有与关键字相同的节点 节点的查找 链表的清空 链表的长度 四.模拟实现链表的完整代码 前言&am…

初探Java之旅:探寻Java的奥秘

✨个人主页:全栈程序猿的CSDN博客 💨系列专栏:Java从入门到精通 ✌座右铭:编码如诗,Bug似流星,持续追求优雅的代码,解决问题如同星辰般自如 在计算机编程的世界中,有一门被誉为“千变…

位图布隆过滤器(附面试题)

文章目录 目录 文章目录 前言 一 . 位图 1.1 面试题 1.2 位图概念 1.3 位图的实现 1.4 位图的应用 二 . 布隆过滤器 2.1 布隆过滤器提出 2.2布隆过滤器概念 2.3 布隆过滤器的查找 2.4 实现 2.5 布隆过滤器删除 2.6 布隆过滤器优点 2.7 布隆过滤器缺陷 2.8 布隆过滤器使用场景 三…

面试官:说说Vue中Proxy与Object.defineProperty的用法与区别

前言 面试时,我们说完Vue响应式原理,或者Vue2和Vue3的区别时,通常会引出Vue3使用了Proxy来优化响应式,而面试官会继续深挖:说说Proxy与Object.defineProperty的区别。 我们不能只说Proxy直接代理一个对象&#xff0c…

【java毕业设计源码】基于SSM框架的在线智能题库管理系统设计与实现

该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等学习内容。 目录 一、项目介绍: 二、文档学习资料: 三、模块截图: 四、开发技术与运行环境: 五、代码展示: 六、数据库表截图&#xff1a…

【论文阅读 + 核心代码定位解读】(2023 AAAI)HiCLR

Hierarchical Consistent Contrastive Learning for Skeleton-Based Action Recognition with Growing Augmentations Contribution 直接使用 strong augmentations 会导致图片/骨架点序列的结构变形和语义信息损失,从而导致训练过程的不稳定。于是本文提出了一种逐…

Java Servlet

请求 请求行 方式 uri http/1.1 请求头 请求体 form表单标签提交Get请求时,参数以键值对形式放在url后,不放在请求体里,Get方式的请求也是可以有请求体的 Post请求时,放在请求头里面 Servlet (server applet) 是运行在服务端…

curl --compressed报错,此版本不支持此命令

出现这个问题是因为微软windows自带的curl不支持这个选项,验证如下 执行where curl 时,可以看到输出为 C:\Windows\System32\curl.ee 解决方法是使用其它curl,下载地址如下 curl for Windows https://curl.se/windows/ 然后把安装目录的bin目录放到path环境变量里最开始, 让…