嵌入式学习——ARM学习(2)——汇编学习

2024-08-30 09:52
文章标签 学习 嵌入式 arm 汇编

本文主要是介绍嵌入式学习——ARM学习(2)——汇编学习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

工具:Keil-uVision5

1、汇编

1.1 汇编的组成

指令:汇编语言的核心部分,表示 CPU 可以执行的操作,如数据传输、算术运算、逻辑运算等。

操作数:指令中用于指定操作对象的数据,可以是寄存器、内存地址或立即数。

标签:用于标识代码中的特定位置,通常用于跳转和循环控制。

伪指令:不直接对应于机器指令的指令,用于控制汇编过程,如 .data、.text、.global 等。

注释:用于解释代码,通常以特定符号(如 ;、@)开头和/* */,汇编器在处理时会忽略这些内容。

段:汇编程序通常分为不同的段,如代码段(.text)、数据段(.data)和堆栈段(.bss),每个段有不同的用途。

宏:一种用于简化代码的工具,可以定义一组指令并在需要时调用。

这些组成部分共同构成了汇编语言,使得程序员能够以更接近人类理解的方式编写与机器语言相对应的代码

1.2 汇编指令格式

1. **标签(可选)**:
   - 用于标识指令的位置,后面跟一个冒号(`:`)。
   - 例如:`loop_start:`

2. **操作码(Opcode)**:
   - 指令的名称,表示要执行的操作。
   - 例如:`MOV`、`ADD`、`SUB`。

3. **操作数**:
   - 指令的参数,指定操作的对象,可以是寄存器、立即数或内存地址。
   - 例如:`R0`、`R1`、`#5`。

4. **条件码(可选)**:
   - 用于指定指令的执行条件,通常放在操作码前。
   - 例如:`EQ`(相等)、`NE`(不相等)。

5. **注释(可选)**:
   - 用于解释指令的功能,通常以 `@` 开头,汇编器会忽略这些内容。
   - 例如:`@ 这是一个注释`。

### 示例格式:
```assembly
label:   opcode   operand1, operand2  @ 注释
```

### 示例指令:
```assembly
loop_start:   MOV     R0, #5          ; 将 5 移动到 R0 寄存器
               ADD     R1, R0, #10    ; 将 R0 和 10 相加,结果存储到 R1
```

在这个示例中:
- `loop_start` 是标签。
- `MOV` 和 `ADD` 是操作码。
- `R0`、`R1` 和 `#10` 是操作数。
- 注释解释了每条指令的功能。

2、汇编指令

2.1 数据搬移指令

2.1.1 MOV指令

格式:

        mov{条件码} 目标寄存器,操作数

解释:

        条件码可有可无,当存在条件码时,如果条件满足,则将操作数数值搬移到目标寄存器

主要功能:

        1、将数据从一个寄存器传送到另一个寄存器。

        2、将一个常数值传送到寄存器中。

        3、当 PC( R15)用做目的寄存器时,可以实现程序跳转。如“ MOV PC, LR”,所以这种跳转可以实现子程序调用及从子程序返回,代替指令“ B, BL”。       

        4、当 PC 作为目标寄存器且指令中 S 位被设置时,指令在执行跳转操作的同时,将当前处理器模式的 SPSR 寄存器的内容复制到 CPSR 中。这种指令“ MOVS PC LR”可以实现从某些异常中断中返回。

eg:

        MOV R0, #5      ; 将立即数 5 移动到 R0

2.1.2 MVN 指令

格式:

         mvn{条件码} 目标寄存器,操作数

解释:

        将操作数按位取反后的结果搬移到目标寄存器中

主要功能:

        1、MVN 是反相传送( Move Negative)指令。它将操作数的反码传送到目的寄存器。

        2、MVN 指令多用于向寄存器传送一个负数或生成位掩码。

        3、MVN 指令将 shifter_operand 表示的数据的反码传送到目的寄存器 Rd,并根据操作结果更新 CPSR 中相应的条件标志位。

主要作用:

        1、向寄存器中传送一个负数。

        2、生成位掩码( Bit Mask)。

        3、求一个数的反码。

eg:

        MVN R0, #0xfffffffe     ; 把0x00000001  移动到 R0

2.1.3立即数

在 ARM 汇编语言中,立即数(Immediate Value)是指在指令中直接给出的常量值,而不是存储在寄存器或内存中的值。立即数通常用于算术运算、逻辑运算和数据传输等操作。

数据的处理方式

假设存在立即数x,将x循环右移偶数位y,将会得到一个0-255内的数据z.此时,就说明x是一个立即数,当x当作指令的一部分执行时,实际保存到指令空间的时数据y和数据z,在指令空间的[7:0]保存的是数据z,[11:8]保存的是数据(32-y)/2.

立即数的特点

1. 直接使用:立即数可以直接在指令中使用,无需先加载到寄存器。

2. 范围限制:在 ARM 中,立即数的表示通常有范围限制,具体取决于指令的类型。例如,某些指令的立即数可以是 8 位、12 位或 16 位。

3. 前缀:在 ARM 汇编中,立即数通常以 # 符号开头。

立即数的判断:

1.直接写完编译,出错就不是立即数

2.判断一个数据是不是立即数时,只需要判断这个数据或者它的取反值能不能循环右移偶数位得到一个0-255内的数据,如果能吗,这个数据就是一个立即数

如果想要将一个非立即数放到寄存器中,可以使用一个伪指令LDR

格式:ldr 目标寄存器,=数据

eg: LDR R0,=0X12345678

2.2 移位运算指令

2.2.1 LSL 逻辑左移

解释:

        一个32位数据进行逻辑左移,最高位移出,最低位补0

格式:

        lsl{条件码} 目标寄存器,第一操作寄存器,第二操作数

eg:

        MOV R0, #0XFF

        LSL R1, R0, #0X4        @0xFF0

C语言语法也可以

        LSL R1, R0, #(0x1<<2)        @0xFF0

2.2.2 LSR 逻辑右移

解释:

        一个32位的数据进行逻辑右移,最低位移出,最高位补0

格式:

        lsr{条件码} 目标寄存器,第一操作寄存器,第二操作数

eg:

        MOV R0, #0XFF

        LSR R1, R0, #0X4        @0xF

2.2.3 ASR 算数右移

解释:

        一个32位的数据进行逻辑右移,最低位移出,最高位(30)补0(31符号位不变)

格式:

        asr{条件码} 目标寄存器,第一操作寄存器,第二操作数

2.2.4 ROR 循环右移

解释:

        一个32位的数据进行循环右移,最低位移出,补到最高位

格式:

        ror{条件码} 目标寄存器,第一操作寄存器,第二操作数

eg:

        MOV R0, #0XFF

        ROR R1, R0, #0X4        @0xF000000F

2.3 位运算指令

2.3.1 and 与运算

解释:

        将第一操作寄存器的数据和第二操作数进行与运算,得到的结果保存到目标寄存器中

格式:

        and{条件码} 目标寄存器,第一操作寄存器,第二操作数

eg:

        and r2,r1,r3 ;r2 = r1&r3

2.3.2 orr 或运算

解释:

        将第一操作寄存器的数据和第二操作数进行或运算,得到的结果保存到目标寄存器中

格式:

        orr{条件码} 目标寄存器,第一操作寄存器,第二操作数

eg:

        orr r2,r1,r3 ;r2 = r1 | r3

2.3.3 eor 异或运算

解释:

        将第一操作寄存器的数据和第二操作数进行异或运算,得到的结果保存到目标寄存器中

格式:

        eor{条件码} 目标寄存器,第一操作寄存器,第二操作数

eg:

        eor r2,r1,r3 ;r2 = r1 ^ r3

2.3.4 mvn取反运算

查看2.1.2

2.3.5 bic 按位清零(遇1清0)

解释:

        将第一操作寄存器的数据和第二操作数进行按位清零运算,得到的结果保存到目标寄存器

格式:

        BIC{条件码} 目标寄存器,第一操作寄存器,第二操作数

eg:

        bic r0, r0, #0x1011 ;清除r0中的位12、 4和0位,保持其余的不变

        bic r1, r2, r3 ;将 r3 和 r2 做“逻辑与”操作,结果保存到 r1 中

2.4 算数运算指令

2.4.1 add 加法

解释:

        将第一操作寄存器的数值+第二操作数,结果保存到目标寄存器中,如果+s,运算结果会影响到CPSR条件位

格式:

        add{条件码}{s} 目标寄存器,第一操作寄存器,第二操作数

2.4.1.1 adc 加法

解释:

        目标寄存器 = 第一操作寄存器 + 第二操作数 + cpsr的c位数值

格式:

        adc{条件码} 目标寄存器,第一操作寄存器,第二操作数

2.4.2 sub 减法

解释:

        将第一操作寄存器的数值-第二操作数,结果保存到目标寄存器中,如果+s,运算结果会影响到CPSR条件位

格式:

        sub{条件码}{s} 目标寄存器,第一操作寄存器,第二操作数

2.4.2.1 sbc 减法

解释:

        目标寄存器 = 第一操作寄存器 - 第二操作数 - cpsr的c位的取反值

格式:

       sbc{条件码} 目标寄存器,第一操作寄存器,第二操作数

2.4.3 rsb 翻转减

解释:

        将第二操作数-第一操作寄存器的数值,结果保存到目标寄存器中,如果+s,运算结果会影响到CPSR条件位

格式:

        rsb{条件码}{s} 目标寄存器,第一操作寄存器,第二操作数

2.4.4 mul 乘法

解释:

        将第二操作数*第一操作寄存器的数值,结果保存到目标寄存器中

格式:

        mul{条件码}{s} 目标寄存器,第一操作寄存器,第二操作数

2.5 比较指令

cmp 比较

解释:

        将第一操作寄存器的数值和第二操作数进行比较 比较指令的本质是比较的两个数据进行减法运算,并且运算的结果会影响到CPSR寄存器的条件位

格式:

        cmp 第一操作寄存器,第二操作数

注意:

        比较指令经常和条件码一起使用,即先比较两个数的大小,再下面执行的指令后加上条件码,根据条件码 对应的条件是否满足决定这条指令是否执行

图表:

2.6 跳转指令

2.6.1 b

解释:

        跳转到指定的标签下执行,当程序发生跳转时lr不保存程序的返回地址

格式:

        b 标签

2.6.2 bl

解释:

        跳转到指定的标签下执行,当程序发生跳转时lr保存程序的返回地址

格式:

        bl 标签

2.7 内存读写指令

通过指令将一个寄存器的数据向内存中写或者从内存中读取数据保存到一个寄存器中

2.7.1 单寄存器内存读写指令 STR / LDR

向内存中写 str

        1、str 目标寄存器,[保存目标地址的寄存器] @将目标寄存器4字节数据写入到目标地址对应的内存中

        2、strh 目标寄存器,[保存目标地址的寄存器] @将目标寄存器2字节数据写入到目标地址对应的内存中

        3、strb 目标寄存器,[保存目标地址的寄存器] @将目标寄存器1字节数据写入到目标地址对应的内存中

从内存中读 ldr 

        1、ldr 目标寄存器,[保存目标地址的寄存器] @从目标地址对应的内存中读取4字节数据写入到目标寄存器

        2、ldrh 目标寄存器,[保存目标地址的寄存器] @从目标地址对应的内存中读取2字节数据写入到目标寄存器

        3、ldrb 目标寄存器,[保存目标地址的寄存器] @从目标地址对应的内存中读取1字节数据写入到目标寄存器

拓展:

        str 目标寄存器,[保存目标地址的寄存器,#操作数] @将目标寄存器的数据写入到目标地址+操作数为首地址的内存中

        ldr 目标寄存器,[保存目标地址的寄存器,#操作数] @从目标地址+操作数为首地址的内存中读取数据写入到目标寄存器

        str 目标寄存器,[保存目标地址的寄存器],#操作数 @将目标寄存器的数据写入到目标地址为首地址的内存中,然后保存目标地址的寄存器数值变为原来的数据+操作数大小

        ldr 目标寄存器,[保存目标地址的寄存器],#操作数 @从目标地址为首地址的内存中读取数据写入到目标寄存器,然后保存目标地址的寄存器数值变为原来的数据+操作数大小

2.7.2 批量寄存器内存读写指令  STM / LDM

写:将多个寄存器的数据写入到指定内存中

读:从指定的内存中读取数据写入到多个寄存器

2.7.2.1 stm / ldm

写:

        stm 保存目标地址的寄存器,{寄存器列表} @将寄存器列表中各个寄存器的数据写入到目标地址对应的内存中

读:

        ldm 保存目标地址的寄存器,{寄存器列表}  @从目标地址对应的内存中读取数据保存到寄存器列表中的各个寄存器中

注意:

        1.寄存器列表中寄存器编号如果连续,可以用-表示一个寄存器范围 {r1-r5} 如果寄存器编号散乱,则用 ,分隔每一个寄存器 {r1,r3,r5,r7} {r1-r3,r5,r7}

        2.无论寄存器列表中寄存器的顺序是什么样的,低内存地址始终和小编号寄存器对应

2.7.2.2 地址增长方式

当指定一个内存基地址后,我们对这个基地址内存进行读写操作,然后根据地址增长方式可以让我们操作的基地址发生变化

格式:

        stm{地址增长后缀} 保存目标地址的寄存器!,{寄存器列表}

解释:

        将寄存器列表中的寄存器数据写入到目标地址中时,保存目标地址的寄存器保存的目标地址会发生对应的改变

后缀:

        ia:先向目标地址对应的内存中写入数据,然后保存目标地址的寄存器保存的目标地址数值+4

        ib:先让保存目标地址的寄存器保存的地址+4,再向目标地址对应的内存中写入数据         da:先向目标地址对应的内存中写入数据,然后保存目标地址的寄存器保存的目标地址数值-4

        db:先让保存目标地址的寄存器保存的地址-4,再向目标地址对应的内存中写入数据

ldm同上

2.7.3 栈内存读写指令

操作栈内存需要知道栈顶的地址,而栈顶地址保存在SP寄存器中

栈类型

增栈:每次压栈结束后栈指针寄存器保存的栈顶地址往高地址方向增长

减栈:每次压栈结束后栈指针寄存器保存的栈顶地址往低地址方向增长

空栈:每次压栈结束后栈指针寄存器指向的栈顶空间没有保存的有效数据

满栈:每次压栈结束后栈指针寄存器指向的栈顶空间存在有效数据

栈可以分为空增栈(EA)、空减栈(ED)、满增栈(FA)、满减栈(FD)

ARMv7-a架构处理器默认使用满减栈实现压栈和出栈

压栈命令:

        push {寄存器列表} @将寄存器列表中每一个寄存器的数值进行压栈

出栈命令:

        pop {寄存器列表}

手动实现满减栈

方法1、db后缀压栈 ia后缀出栈

eg:

        

方法2、使用满减栈对应的后缀fd实现

eg:

        

2.8 状态寄存器传送指令 MRS / MSR

内核中存在一个寄存器CPSR,这个寄存器保存的是当前程序的状态,我们可以通过状态寄存器传送指令实现对当前程序状态的读取以及修改程序的状态

MRS 目标寄存器,CPSR 

        @读取CPSR保存的状态值到目标寄存器中

MSR CPSR,操作数

        @将操作数写入到CPSR寄存器中进而修改程序的状态

注意:

        在特权模式下可以通过修改cpsr寄存器的数值切换到USER模式

        但是USER模式下无法通过修改CPSR数值切换到特权模式

        想要在user模式下切换到其他模式,只要发生对应的事件后处理器自动进入对应的模式

2.9 软中断产生指令

2.9.1 软中断

swi 中断号

        @中断号是一个12位的立即数,不同的中断号用来标识不同的中断

2.9.2 异常模式和异常源

异常模式:当发生了异常之后处理器进入的工作模式就是异常模式

异常源:引发处理器进入异常模式的源头叫做异常源

5种异常模式和7种异常源

异常模式异常源
IRQ        

产生了一个IRQ中断

FIQ

产生了一个FIQ中断

UNDEF

处理器遇到未定义指令导致程序中止

SVC

复位

产生软中断

ABORT

存取数据异常导致程序中止

存取指令异常导致程序中止

2.9.3 异常向量表

在 ARM 架构中,异常向量表(Exception Vector Table)是一个特殊的内存区域,用于处理各种异常和中断。异常向量表的每个条目对应于特定类型的异常,指向处理该异常的代码(即异常处理程序)。

异常向量表的结构

在 ARM 体系结构中,异常向量表通常位于内存的起始地址(例如,地址 0x00000000)。每个异常向量的大小通常为 4 字节(32 位),因此每个异常向量表的条目可以容纳一个指向异常处理程序的地址。

地址异常进入模式
0x00000000复位管理模式
0x00000004未定义指令未定义模式
0x00000008软件中断管理模式
0x0000000C中止(预取)中止模式
0x00000010中止(数据)中止模式
0x00000014保留保留
0x00000018中断 IRQ中断模式
0x0000001C快中断 FIQ快中断模式

.section .vectors.word _reset_handler      ; 复位向量.word _undefined_handler   ; 未定义指令向量.word _swi_handler         ; 软件中断向量.word _prefetch_abort_handler ; 预取异常向量.word _data_abort_handler  ; 数据异常向量.word 0                    ; 保留.word _irq_handler         ; IRQ 向量.word _fiq_handler         ; FIQ 向量.section .text
_reset_handler:; 复位处理代码B main                    ; 跳转到主程序_undefined_handler:; 未定义指令处理代码B ._swi_handler:; 软件中断处理代码B ._prefetch_abort_handler:; 预取异常处理代码B ._data_abort_handler:; 数据异常处理代码B ._irq_handler:; IRQ 处理代码B ._fiq_handler:; FIQ 处理代码B .

2.9.4 异常处理流程(四大步,三小步)

1、保存程序当前的工作状态到对应的异常模式的SPSR寄存器中

2、修改SPSR

        1.修改程序的工作模式为对应的异常模式[4:0]

        2.修改程序的工作状态为ARM状态[5] @ARM为0,thumb为1

        3.根据当前异常的优先级设置程序合适的中断禁止[7:6] @1为忽略

3、将程序的返回地址保存到对应的异常模式的LR寄存器(L14)

4、修改PC寄存器的值为当前异常在异常向量表中的位置

注意:该步骤为处理器自动完成

2.9.5 异常返回工作

注意:该步骤为 程序员手动完成

1、恢复程序状态 SPSR => CPSR

2、返回主程序执行 LR => PC

2.9.6 测试代码

.text  
.global _start _start:
@初始化异常向量表b mainb .b do_swi  @产生软中断后跳到这里执行b .b .b .b .b .
main:
@初始化SVC模式下的栈ldr sp,=0X40000020@切换程序的工作模式到user模式MSR CPSR,#0x10@初始化user模式下的栈ldr sp,=0X40000020@主程序执行mov r1,#1mov r2,#2@产生一个软中断swi 1add r3,r1,r2b loop@软中断异常处理程序
do_swi:
@压栈保护现场stmfd sp!,{r1,r2,lr}mov r1,#3mov r2,#4mul r4,r1,r2ldmfd sp!,{r1,r2,pc}^  @异常返回loop:b loop
.end 

3、混合编程

要想实现C和汇编的混合编程必须遵循ATPCS规范。

ATPCS : ARM-Thumb Procedure Call Standard
 

int add(int i,int j) {return i+j;
}

将汇编的标签当作C语言的函数使用

将C语言的函数当作汇编的标签使用

函数参数的传递采用R0-R3进行传递,如果参数的个数大于4个通过压栈的方式进行传递

函数的返回值通过R0返回,如果函数的返回值大于4个字节通过r0-r1返回

ATPCS规范中规定ARM采用满减栈。

3.1 汇编调用C语言的函数 

#include <stdio.h>// 声明汇编函数
extern int add_func(int a, int b);int main() {int result = add_func(5, 10); // 调用汇编函数printf("Result: %d\n", result);return 0;
}
*****汇编文件**********
.text    
.global _start  _start: @ 1. 初始化栈指针,C代码运行必须有栈ldr sp, =0x40000820@ 2. 汇编调用c函数 @ 2.1 给C的函数传递实参值mov r0, #3   @ a = 3mov r1, #4   @ b = 4@ 2.2 汇编调用c的函数bl add_func@ 2.3 函数的返回通过r0返回,查看r0寄存器中的值loop:   b loop  .end

3.2 c语言调用汇编标签

.text    .globl _start  _start: @ 1. 初始化栈指针,C代码运行必须有栈ldr sp, =0x40000820@ 2. 汇编调用c,跳转到main函数b main.end
********c文件************
// 使用extern对函数进行声明
extern int add_func(int a, int b, int c, int d);int sum = 0;
int main()
{// 在c代码中调用汇编代码sum = add_func(1,2,3,4);while(1);return 0;
}
********汇编文件**********
.text 
.global add_func  @ 将add_func函数声明为全局add_func:add r0, r0, r1add r0, r0, r2add r0, r0, r3mov pc, lr
.end

3.3 c语言内联汇编

c语言中直接使用汇编的语法

通过asm关键字进行修饰

asm volatile("汇编指令\n\t"     //"\n\t"表示一条指令的结束.....:输出列表  //指令结果的输出值:输入列表  //指令的数据输入:破坏列表  //破坏列表指定我们当前被修改的资源 memory
);
********汇编启动文件*******
.text    
.globl _start  _start: @ 1. 初始化栈指针,C代码运行必须有栈ldr sp, =0x40000820@ 2. 汇编调用c,跳转到main函数b main
.end
**********c语言文件***********// 内联汇编 
int add_func2(int a, int b, int c, int d)
{int sum = 0;// 使用汇编实现求和asm volatile(  "add r0, r0, r1\n\t"  "add r0, r0, r2\n\t"  "add r0, r0, r3\n\t"  :"=r"(sum)  :"r"(a),"r"(b),"r"(c),"r"(d)  :"memory" );return sum;
}//"=r"(sum)表示输出从寄存器中放到变量sum中
// "r"(a) 指定输入从变量a中获取放到通用寄存器//"memory"声明使用内存// 使用extern对函数进行声明
extern int add_func(int a, int b, int c, int d);int sum = 0;
int main()
{// 调用内联汇编的函数 sum = add_func2(5,6,7,8);// 在c代码中调用汇编代码sum = add_func(1,2,3,4);while(1);return 0;
}*********汇编文件*************.text 
.global add_func  @ 将add_func函数声明为全局add_func:add r0, r0, r1add r0, r0, r2add r0, r0, r3mov pc, lr
.end

这篇关于嵌入式学习——ARM学习(2)——汇编学习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1120491

相关文章

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识