本文为使用汇编开发STM32系列文章之----基础知识篇,全部文章目录点此跳转。

目录

  • 一、STM32F1内核基础知识
    • 1.Cortex-M3 内核结构
    • 2.Cortex-M3 内核的指令
    • 3.Cortex-M3 内核的寄存器组
      • 3.1 堆栈指针寄存器(MSP和PSP)
      • 3.2 连接寄存器(LR)
      • 3.3 程序计数器(PC)
      • 3.4 特殊功能寄存器
        • 3.4.1 程序状态寄存器(xPSR或PSR)
        • 3.4.2 中断屏蔽寄存器
        • 3.4.3 控制寄存器(CONTROL)
    • 4.Cortex‐M3 内核的操作模式
    • 5.Cortex‐M3 内核的异常
  • 二、STM32F1基础外设知识
    • 1.内存分布
    • 2.启动配置
    • 3.时钟树与系统结构
    • 4.GPIO
  • 三、ARM汇编指令
    • 1.ARM汇编语言基础语法
    • 2.Thumb-2 常用指令
    • 3.常用伪指令
      • 3.1 Thumb的伪指令
      • 3.2 ARMCC编译器的伪指令
  • 四、参考文献

★说明★:本文暂不深究其中的原理,仅描述与汇编相关的简要知识点,相关细节将会在后续文章使用到时详细说明。

一、STM32F1内核基础知识

1.Cortex-M3 内核结构

  STM32F1使用的是属于ARMv7-M架构的ARM Cortex-M3 内核 ,是一个32位的处理器内核,其内部的数据路径是32位的、寄存器是32位的以及存储器接口也是32位的。并且使用了哈佛结构,拥有独立的指令总线和数据总线为数字信号的处理提供了较高的性能。下方是Cortex-M3 内核的简略图。

2.Cortex-M3 内核的指令

  Cortex-M3 内核只使用Thumb‐2 指令集,其中既包括16位的指令,又包括32位的指令,这使得在编程时不必再像从前一样去手动切换指令状态(32 位的ARM 状态和 16 位的 Thumb 状态,切换时会消耗额外的切换时间),即可达到性能和存储之间的平横。因为在32位指令下,性能极高;而在16位指令下,代码密度提高了一倍,可以在相同的内存和缓存中存放更多的指令。
  为了使芯片结构保持简单情况下进一步提升系统的运行效率,Cortex-M3 内核采用简单的3级流水线。每个指令的执行分为三个步骤:取指令、译码和执行。"取指令"时需要通过指令总线读取存储器中的对应指令,此操作会占用指令总线;"译码"时将指令转换为具体的控制信号,不占用任何总线;"执行"时进行读取寄存器堆栈、操作数在通信移位器中移位、ALU产生相应的运算结果并写到目的寄存器中并根据需求更改状态寄存器条件位,此时占用数据总线。
  因为Cortex-M3 内核使用的是哈弗结构,具有单独的数据总线和指令总线,所以在组成3级流水线时,这三个操作并不会相互影响,从而将单个指令的执行时间为3周期,但在单周期内可以有1个指令的吞吐率。单周期指令的3级流水线如下如图所示。

3.Cortex-M3 内核的寄存器组

  Cortex-M3内核拥有通用寄存器 R0‐R15 以及一些特殊功能寄存器,其中R0-R12属于通用寄存器,但是大多数的16位指令只能使用R0‐R7(低组寄存器),而 32 位的指令则可以访问所有通用寄存器。特殊功能寄存器有预定义的功能,而且必须通过专用的指令来访问。寄存器组如下图所示。

3.1 堆栈指针寄存器(MSP和PSP)

  R13是堆栈指针寄存器,且Cortex-M3 内核中共有两个堆栈指针,分别是主堆栈指针(MSP)和进程堆栈指针(PSP)。主堆栈指针(MSP)是缺省的堆栈指针,它由 OS 内核、异常服务例程以及所有需要特权访问的应用程序代码来使用。进程堆栈指针(PSP),用于常规的应用程序代码(不处于异常服用例程中时)。因为有两个堆栈指针,所以Cortex-M3 内核也就支持两个堆栈。当引用 R13(或写作SP)时,你引用到的是当前正在使用的那一个,另一个必须用特殊的指令来访问(MRS,MSR 指令)。而且堆栈指针的最低两位永远是 0,这意味着堆栈总是 4 字节对齐的。
注:在 ARM 编程领域中,凡是打断程序顺序执行的事件,都被称为异常(exception)。在不严格的上下文中,异常与中断也可以混用。

3.2 连接寄存器(LR)

  R14是连接寄存器(LR),用于在调用子程序时存储返回地址。

3.3 程序计数器(PC)

  R15是程序计数器(PC),用于指示下次欲执行的指令的地址,因为 CM3 内部使用了指令流水线,读 PC 时返回的值是当前指令的地址+4。

3.4 特殊功能寄存器

  特殊功能寄存器包含三种功能的寄存器:程序状态寄存器(xPSR或PSR)、中断屏蔽寄存器和控制寄存器(CONTROLl)。他们只能用MSR和MRS指令访问,而且他们也没有寄存器地址。

3.4.1 程序状态寄存器(xPSR或PSR)

程序状态寄存器内部各位定义如下:

✦N:正负标志,N=1表示运算结果为负数,N=0表示运算结果为正数或者0。
✦Z:零标志,Z=1表示运算结果为0,Z=0表示运算结果为非0。
✦C:加法运算时表示进位标志,C=1表示产生进位,C=0表示未产生进位;减法运算时表示借位标志,C=0表示产生借位,C=1表示未产生借位;
✦V:溢出标志,V=1表示有溢出,V=0表示无溢出。
✦Q:表示增强的DSP指令是否发生溢出,在ARMv7-M架构的ARM Cortex-M3 内核无定义。
✦ICI/IT[26:25]:暂未找到解释,后期再补上。
✦T:暂未找到解释,后期再补上。
✦ICI/IT[15:10]:暂未找到解释,后期再补上。
✦Exception Number[8:0]:中断号。

3.4.2 中断屏蔽寄存器

  中断屏蔽寄存器包含三个寄存器,用于控制异常的使能和除能。只有在特权级下,才允许访问这 3 个寄存器。
  ✦PRIMASK:此寄存器只有一个位,设置为1时,会关闭所有的可屏蔽异常(中断),只有NMI和硬件异常(fault)可以相应。默认值0。
  ✦FAULTMASK:此寄存器只有一个位,设置为1时,只有NMI会响应,其他的所有异常(中断)和硬件异常(fault)全部关闭响应。默认值0。
  ✦BASEPRI:这个寄存器最多有 9 位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设成 0,则不关闭任何中断,0 也是默认值。

3.4.3 控制寄存器(CONTROL)

  控制寄存器用于定义特权级别,还用于选择当前使用哪个堆栈指针。

功能
CONTROL[1] 堆栈指针的选择;
0 = 选择主堆栈指针 MSP(复位后缺省值)
1 = 选择进程堆栈指针 PSP
在线程或基础级(没有在响应异常——译注),可以使用 PSP。
在 handler 模式下,只允许使用 MSP,所以此时不得往该位写 1。
CONTROL[0] 0 = 特权级的线程模式;
1 = 用户级的线程模式;
Handler模式永远都是特权级的。

4.Cortex‐M3 内核的操作模式

  Cortex‐M3 支持 2 个模式:处理者模式(handler模式)和线程模式(Thread模式),以及两个特权等级:特权级和用户级。当处理器处在线程状态下时,既可以使用特权级,也可以使用用户级;另一方面,处理者模式总是特权级的。在复位后,处理器进入线程模式+特权级。对应的模式和级别关系如下图所示。

. 特权级 用户级
异常时处理的代码 处理者模式 错误用法
主应用程序的代码 线程模式 线程模式

  在特权级下的代码可以通过置位 CONTROL[0]来进入用户级。而不管是任何原因产生了任何异常,处理器都将以特权级来运行其服务例程,异常返回后将回到产生异常之前的特权级。用户级下的代码不能再试图修改 CONTROL[0]来回到特权级。它必须通过一个异常 handler,由那个异常 handler 来修改 CONTROL[0],才能在返回到线程模式后拿到特权级。改变流程如下图所示。

5.Cortex‐M3 内核的异常

  Cortex‐M3 内核支持大量异常,包括 11 个系统异常和最多240个外部中断(IRQ),但是外部中断具体用多少个要看具体的MCU的设计。异常说明以及向量表偏移地址,如下表所示。其中异常标号用于分辨当先发生的异常类型,以及根据偏移地址计算中断回调函数的地址。异常编号可以在程序状态寄存器(xPSR或PSR)中获取到。

异常编号 类型 偏移地址 优先级 简介
0 N/A 0x00 N/A 异常编号为0表示此时无异常发生。
因为此时无异常,故向量表偏移地址0x00处无中断回调函数,所以此处用来存储MSP(主堆栈指针)的初始值。
1 复位 0x04 -3(最高) 复位中断,偏移地址0x04处存放复位中断回调函数地址。
特殊的,此处存储的地址在内核上电复位后自动赋值给PC(程序计数器指针),故程序会首先运行复位中断回调函数。
2 NMI 0x08 -2 不可屏蔽中断(来自外部 NMI 输入脚)。
3 硬件异常
(hard fault)
0x0C -1 当被失能的异常触发时将产生硬件异常(hard fault)。
4 存储器管理异常
(Mem Manage fault)
0x10 可编程 存储器管理异常。
MPU 访问犯规以及访问非法位置均可引发。企图在“非执行区”取指也会引发此 fault。
5 总线异常 0x14 可编程 从总线系统收到了错误响应,原因可以是预取流产(Abort)或数据流产,或者企图访问协处理器
6 用法异常 0x18 可编程 由于程序错误导致的异常。通常是使用了一条无效指令,或者是非法的状态转换,例如尝试切换到 ARM 状态。
7-10 保留 0x1C-0x28 N/A N/A
11 SVCall 0x2C 可编程 执行系统服务调用指令(SVC)引发的异常
12 调试监视器异常 0x30 可编程 调试监视器发起的请求产生的异常,包括设置的断点,数据观察点,或者是外部调试请求。(注意,异常并不一定是错误,所有打断正常循序执行的事件都称为异常)
13 保留 0x34 N/A N/A
14 PendSV 0x38 可编程 为系统设备而设的“可悬挂请求”(pendable request)
15 SysTick 0x3C 可编程 系统滴答定时器(周期性溢出的一个内核级别的定时器)
16-255 外部中断16-255 0x40-0x3FF 可编程 外部中断16 到 外部中断255
“外部”指 Cortex‐M3 内核的外部,与stm32的外部中断注意区分。

  在发生异常时,Cortex‐M3 内核会自动将寄存器中的值保存至栈中(俗称现场保护),再跳转至中断回调函数进行处理,处理完毕后自动将栈中的寄存器值还原到之前的寄存器,然后继续执行原先正在执行的程序。

二、STM32F1基础外设知识

1.内存分布

  STM32F103x的内存分布如下图所示。左侧部分是 Cortex‐M3 内核给出的可寻址的内存全部地址,框内的说明是STM32F1使用的情况,右侧引出的部分是本系列教程会涉及到的关键内容及地址。在后期文章实际用到时会详细说明。

2.启动配置

  在上面的内存分布小节的图中可以看到地址0x0000 0000 - 0x0007 FFFF处的内存作用是不定的,可以是Flash也可以是系统内存,并且被BOOT引脚设置。接下来将介绍这么做的原因。
  因为Cortex-M3内核在启动时始终从代码区0x0000 0000开始,导致在启动时只能从Cortex-M3内核设置的flash启动。而STM32F1系列单片机将开始的0x0000 0000 - 0x0007 FFFF地址空出来,并且通过后期映射的方法实现了从FLASH启动、系统存储器启动以及SRAM启动的功能。

  在STM32F10xxx里,可以通过BOOT[1:0]引脚选择三种不同启动模式,如下表所示。

启动模式选择引脚 启动模式 说明
BOOT1 BOOT0
X 0 FLASH FLASH被选为启动区域
0 1 系统存储器 系统存储器被选为启动区域
1 1 SRAM SRAM被选为启动区域

  根据选定的启动模式,FLASH、系统存储器或SRAM可以按照以下方式访问:

  ● 从FLASH启动:FLASH被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址(0x0800 0000)访问它,即FLASH的内容可以在两个地址区域访问,0x0000 0000或0x0800 0000。
  ● 从系统存储器启动:系统存储器被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址0x1FFF F000访问它。
  ● 从内置SRAM启动:只能在0x2000 0000开始的地址区访问SRAM。

3.时钟树与系统结构

  对于时钟树的理解其实是很简单的,只要下载个官方配置软件:STM32CubeMX,进入时钟配置界面,可以一目了然的看到各个时钟的走向,各种倍频分频可设置部分非常详尽,每个外设所挂载的总线很容易获取。下图是我翻译后的版本,图很高清,请点击打开后观看。


  在下方的STM32F1系统结构图中可以很清楚的看到各种外设、总线之间的关系,可以获取APB1总线和APB2总线下到底连接着哪些外设。

4.GPIO

  GPIO全名叫做General-purpose input/output,即多功能(或通用)输入输出引脚,从名称即可知道GPIO口可以设置为多种模式。可设置的模式中共有三大种类:输出模式、输入模式和复用模式。而根据电路结构又可以分为上拉、下拉、浮空、推挽等模式。下表只描述常用功能,复用等其他特殊功能后期用到在详细说。

模式 结构 全称
输入 上拉 上拉输入
下拉 下拉输入
浮空 浮空输入
模拟 模拟输入
输出 推挽 推挽输出
开漏 开漏输出

  每个GPIO端口有7个32位的常用配置寄存器,例如GPIOA口的七个常用寄存器功能和地址如下表所示,其他端口除了地址不同外其他与此完全一致。

寄存器名称 地址 功能
GPIOA_CRL 0x4001 0600 端口配置低寄存器
设置GPIOA 0-7引脚的输入输出模式及IO翻转速度
GPIOA_CRH 0x4001 0620 端口配置高寄存器
设置GPIOA 8-15引脚的输入输出模式及IO翻转速度
GPIOA_IDR 0x4001 0640 端口输入数据寄存器
读取GPIOA 16个引脚的状态值
GPIOA_ODR 0x4001 0660 端口输出数据寄存器
控制GPIOA 16个引脚的输出高低电平,会一次性控制16个引脚状态
GPIOA_BSRR 0x4001 0680 端口位设置/清除寄存器
将GPIOA 16个引脚的某些引脚的输出设置为1清除为0,可单独操作某些引脚
GPIOA_BRR 0x4001 06A0 端口位清除寄存器
将GPIOA 16个引脚的某些引脚的输出清除为0,可单独操作某些引脚
GPIOA_LCKR 0x4001 06C0 端口配置锁定寄存器
该寄存器用来锁定端口位的配置,设置后在下次系统复位之前将不能再更改端口位的配置

三、ARM汇编指令

1.ARM汇编语言基础语法

  ARM汇编指令一般较为完整的书写格式如下所示:

{标号}
   操作码{执行条件}{S} 目的寄存器,操作数 1,操作数 2, …  {;注释}
注:{ }不包含在内,意思为{ }中的内容是可选的。

其中:
  ①标号是可选的,如果有,它必须顶格写。标号的作用是让汇编器来计算程序转移的地址,类似与C语言里的函数名。
  ②操作码是指令的助记符,也就是常写的汇编指令,它的前面必须有至少一个空白符,通常使用一个 “Tab” 键来产生。
  ③操作码紧跟的是执行条件后缀,要紧贴操作码写。可以空着不写,表示无条件执行本指令。执行条件往往配合比较指令来使用。执行条件如下表所示(稍微往后放一下,以防打乱阅读节奏)。
  ④执行条件后紧跟影响标志后缀:S,如果没有执行条件则紧贴操作码写。S可以空着不写,表示此指令执行的结果不影响程序状态寄存器(xPSR或PSR)的值。但是在使用比较指令时,无需加S即可改变程序状态寄存器(xPSR或PSR)的值。
  ⑤目的寄存器,指令执行后结果的存放寄存器。
  ⑥操作数往往会有若干个,不同指令需要不同数目的操作数,并且对操作数的语法要求也可以不同。

注:“x” 表示与之比较的值。

条件码助记符 含义 使用 程序状态寄存器(xPSR或PSR) 的相关位
EQ = x Z = 1
NE ≠ x Z = 0
CS 无符号数 ≥ x C = 1
CC 无符号数 < x C = 0
MI x 为负数 N = 1
PL x 为正数或0 N = 0
VS 溢出 V = 1
VC 未溢出 V = 0
HI 无符号数 > x C = 1 且 Z = 0
LS 无符号数 ≤ x C = 0 且 Z = 1
GE 有符号数 ≥ x N = V
LT 有符号数 < x N ≠ V
GT 有符号数 > x Z = 0 且 N = V
LE 有符号数 ≤ x Z = 1 或 N ≠ V
AL 无条件执行 忽略

  为了可以更好的理解,现举几个例子进行说明。其中MOV是数据传送指令,CMP是比较指令(比较指令无需加S后缀便可自动更新程序状态寄存器的标志位)。普通数值前加符号"#“表示为常数数值,在汇编语言中称为"立即数”。
注意:ARM汇编指令可以使用大写字母也可以小写字母,只要统一格式即可,只要有一处用大写字母就要全部用大写字母,反之全部用小写字母。

2.Thumb-2 常用指令

  下表仅列出Thumb-2 常用的一些指令,后期用到时再做详细使用说明。

指令助记符 描述 指令助记符 描述
ADC 带进位加法 LSR 逻辑右移
ADD 加法 MOV 数据传送
AND 逻辑与 MUL 乘法
ASR 算术右移 MVN 取反后的数据传送
B 分支指令 NEG 取反
BIC 逻辑位清除 ORR 逻辑或运算
POP 出栈 PUSH 压栈
BL 带链接的相对分支指令 BLX 带交换的分支指令
ROR 循环右移 CMN 相反数比较
SBC 带借位减法 CMP 比较指令
STM 多寄存器存储 EOR 逻辑异或
STR 单寄存器数据存储 LDM 多寄存器加载
SUB 减法 LDR 单寄存器加载
LSL 逻辑 左移 SWI 软中断
BKPT 断点指令 TST 位测试

3.常用伪指令

3.1 Thumb的伪指令

  Thumb的伪指令不是Thumb指令集中的指令,只是为了编程方便而定义的伪指令,使用时可以像其他的Thumb指令一样使用,但在编译的时候编译器会将其替换为Thumb存在的等效指令。Thumb的伪指令共有三个:ADR、LDR和NOP。其中LDR伪指令与Thumb中的LDR指令的区别是,LDR伪指令的参数中有等号:“=”。其他两个都是新符号。

伪指令助记符 格式 功能说明
ADR ADR 目标寄存器,地址表达式 获取地址值,可以是获取某标号处的地址值
注意:要获取的地址值相对程序计数器(PC)的地址之间的偏移量要为正数并小于1KB。
NOP NOP 空操作
会被替换为像如 "MOV R0,R0"这样的指令
LDR LDR 目标寄存器,=地址表达式 用于加载一个32位立即数或一个地址值到目标寄存器。
注意:如果要加载的常数超过MOV或MVN的范围,则会创建文字池,那么文字池地址值相对程序计数器(PC)的地址之间的偏移量要小于1KB。

3.2 ARMCC编译器的伪指令

  RAMCC编译器是Keil5软件带有的ARM编译器,RAMCC编译器的伪指令是用于告诉RAMCC编译器如何进行汇编的指令。暂时整理以下常用伪指令,后期有需要在添加和详细说明。

伪指令助记符 格式 功能说明
AREA AREA 段名 属性1,属性2… 定义一个代码段或者数据段
ENTRY ENTRY 汇编程序的入口点
END END 汇编程序的程序的结尾
EQU 常量名 EQU 常量数值 定义一个常量,相当于c语言中的 define
EXPORT EXPORT 标号 声明一个全局的标号,可以在其他文件使用声明的标号
IMPORT IMPORT 标号 通知编译器要使用一个在其他文件中定义的标号,相当于c语言中的 extern
DCD DCD 表达式 用于分配一片连续的字存储单元并用伪指令中指定的表达式初始化,表达式可以是程序标号或数字表达式
PROC PROC 表示一个汇编子程序的开始。相当于C语言中函数开始。
ENDP ENDP 表示一个汇编子程序的结束。相当于C语言中函数结束。

四、参考文献

[1]Cotex-M3权威指南(中文版),宋岩(译)
[2]汇编语言程序设计–基于ARM体系结构(第2版),北京航空航天大学出版社。
[3]STM32F103xCDE_DS_CH_V5.pdf

最后,由于本人水平有限,文中难免出现错误,敬请大家批评指正,感谢!

STM32涉及到的汇编基础知识相关推荐

  1. 汇编基础知识之输入输出

    最近在学习汇编程序,但输入输出是我遇到的第一个难题,这里就简单讲诉一些汇编的基本输出输出字符串.字符.输出数字等知识,仅供大家学习.这只是一些基础知识,汇编高手亦可以温习一些基础的输入输出知识. 一. ...

  2. 【STM32标准库】【基础知识】外部中断

    文章目录 外部中断 什么是外部中断 外部中断的触发 上升沿触发 下降沿触发 上升下降沿触发 外部中断初始化 初始化思路 1.初始化GPIO 2. 打开时钟 3.GPIO和外部中断的连接 4.外部中断初 ...

  3. STM32 电机教程 5 - 步进电机基础知识介绍

    前言 步进电机是一种专门用于速度及位置精确控制的特种电机,它旋转是以固定的角度〈俗称步距角〉一步一步运行的,故称为步进电机. ​ 步进电机有反应式 (VR).永磁式(PM).混合式(HB)三种类型.混 ...

  4. x86汇编-2(第五章)nasm汇编基础知识、指令、显存、bochs调试

    一. 汇编程序一般人为地分为代码段与数据段,不同的段的内存分配总是16字节的倍数,公式如下 设数据段或代码段为x字节,分配内存为:(x/16+x%16)*16字节 标号:标识当前位置的偏移地址,如果当 ...

  5. 【STM32标准库】【基础知识】时钟系统

    文章目录 时钟 时钟的作用 时钟的产生 F4系列的时钟系统 时钟源 总线 标准库的时钟设置 内部高速时钟设置 外部高速时钟设置 AHB时钟设置 APB1/2时钟设置 默认值 文章基于适用于STM32F ...

  6. mysql 访问寄存器_汇编寄存器(内存访问)基础知识之三---mov指令

    1 内存中字的存储 一个字型数据占2个内存单元,内存里面一个内存单元一个字节(8位),高地址单位放高8位,低地址单元放低8位. 注意:0号是地址单元,1是高地址单元(上是低地址,下面是高地址) (1) ...

  7. 2021-03-30 一笔记 STM32基础知识

    2021.3.30 第一次笔记 STM32的入门学习之基础知识 一 STM32的介绍 STM32是基于ARM内核的32位MCU系列---内核为ARM公司为要求高性能,低成本,低功耗的嵌入式应用专门设计 ...

  8. 【转贴】GCC内联汇编基础

    原文作者 Sandeep.S 英文原文 [https://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html] 本文将介绍GCC编译环境下 ...

  9. TCP短连接产生大量TIME_WAIT导致无法对外建立新TCP连接的原因及解决方法—基础知识篇...

    最近遇到一个线上报警:服务器出现大量TIME_WAIT导致其无法与下游模块建立新HTTP连接,在解决过程中,通过查阅经典教材和技术文章,加深了对TCP网络问题的理解.作为笔记,记录于此.       ...

  10. 学习编程基础知识,进阶成为更优秀的程序员

    "脚本小子"常常从某些网站上复制脚本代码,然后到处粘贴,却并不明白其中的方法与原理 ​​当你看到编程语言编进教材的时候,看到一个文科生也在编写Python程序进行数据分析的时候,你 ...

最新文章

  1. ppt生成器_WPS又有新动作!发布新款PPT快速生成器,职场办公必备
  2. python中回文设计_Python中的回文递归
  3. python ui自动化配置文件,Python+Selenium进行UI自动化测试项目中,常用的小技巧2:读取配置文件(configparser,.ini文件)...
  4. C++字节序反转的实现算法(附完整源码)
  5. ERROR: cannot launch node of type [turtlebot_teleop/turtlebot_teleop_key] 问题解决
  6. JSP + Struts + Hibernate + Spring+MySQL+Myeclipse实现固定资产管理系统
  7. Spark精华问答 | Spark和Hadoop的架构区别解读
  8. 鱼塘钓鱼(信息学奥赛一本通-T1373)
  9. 华为P50 Pro+最新渲染图曝光:双环形相机模组内有乾坤
  10. 爬虫登录获取cookie的难点
  11. mysql求和语句大全_sql查询语句大全
  12. SpringSecurity Filter顺序
  13. mac头和ip头部详解
  14. 【unity3d游戏源码及软件】部分展示之:超级马里奥unity源码,内附更多源码
  15. tl494cn逆变器电路图_TL494CN逆变器
  16. 三分钟带你快速了解网站开发的整个流程
  17. 《私募股权基金投资基础知识》---第七章
  18. 快排(基础详解入门)
  19. 海尔消费金融2019年业绩:营收13.89亿元,净利润2.05亿元
  20. C语言:指针的偏移步长、结构体成员的偏移量、嵌套结构体成员的偏移量、结构体的内存对齐

热门文章

  1. LTE中资源数量映射用到的PRB数量(TB,CQI,MCS,PRB)
  2. spyder 更改默认工作目录的最优方法
  3. [锁 Lock] Lock lock = new ReentrantLock()之自增序列号
  4. 装X神器--Hacker Typer
  5. 启用特殊池解读 0x000000c5 蓝屏
  6. RN通信底层原理 -- 总结篇
  7. 电线带电时先接零线还是火线
  8. 电类专业(自动化、电气、电子、电力、通信等)的大学四年应该怎么过呢_史蒂文森sun_新浪博客
  9. R语言-gsub替换字符工具
  10. 使用OLED屏显示汉字