二、点亮希望之光:寄存器与库函数驱动 LED 灯
文章目录
- 一、寄存器
- 1、存储器映射
- 2、存储器映射表
- 3、寄存器
- 4、寄存器映射
- 5、寄存器重映射
- 6、总线基地址、外设基地址、外设寄存器地址
- 7、操作寄存器(以操作一个GPIO口为例)
- 1. 寄存器地址定义部分
- 2. `GPIOD_Configuration` 函数部分
- 3. `main` 函数部分
- 二、库函数
- 1、为什么要使用库函数
- 2、什么是库函数
- 3、库函数的详解(以GPIO为例)
- 4、如何操作库函数(以点亮LED连接到PD7为例)
- 三、寄存器和库函数的区别
- 1、寄存器与库函数的区别
- 2、寄存器操作的优势和劣势
- 3、库函数的优势和劣势
- 四、GD32F4xx 系列器件的存储器映射表
一、寄存器
- GD32F450ZG 单片机的寄存器是用于控制和配置芯片内部各种硬件资源的存储单元。它们就像是一组开关和控制器,通过对这些寄存器进行读写操作,可以实现对单片机的功能配置、数据传输、中断处理等多种操作。
1、存储器映射
- 概念:存储器映射是将芯片中的各种存储器(如闪存、SRAM等)和外设(如定时器、GPIO等)统一编址,把它们看成一个连续的地址空间。就好像一个大仓库,不同的区域存放着不同的东西,这个大仓库的每个存储单元都有一个唯一的地址。这样CPU可以通过这个统一的地址来访问不同的资源。
- 举例:在GD32F450ZG单片机中,整个存储区域可能从0x00000000开始,一直到某个较大的地址,其中不同的段分配给了不同的用途。例如,一部分地址范围是闪存(程序存储区),用来存放程序代码;另一部分是SRAM(数据存储区),用于存放程序运行时的数据。
2、存储器映射表
- 概念:存储器映射表是一张详细的“地图”,它记录了存储区域中每个地址段对应的具体资源。它告诉用户从哪个地址开始到哪个地址结束是闪存、从哪个地址开始是SRAM、哪个地址范围是某个外设(如UART、SPI等)的寄存器等信息。
- 用途:通过查看存储器映射表,开发者可以准确地找到想要访问的资源的地址范围。例如,在编写程序时,如果要访问某个外设的寄存器,就需要根据这个表来确定正确的地址。详细可见文章末尾存储器映射表。
3、寄存器
- 概念:寄存器是一种特殊的存储单元,它位于芯片内部,用于控制和监视芯片的各种功能。可以把寄存器想象成一个个小的“控制盒”,每个“控制盒”负责一个特定的功能。例如,对于GPIO(通用输入输出端口),有控制引脚方向(输入或输出)的寄存器、控制引脚输出电平(高或低)的寄存器等。
- 功能分类:
- 控制寄存器:用于控制外设的工作模式。比如,定时器的控制寄存器可以设置定时器的计数模式(向上计数、向下计数等)、是否使能定时器等。
- 状态寄存器:用于反映外设的当前状态。以UART为例,状态寄存器可以指示是否有数据接收完成、是否有数据发送缓冲区为空等状态。
- 数据寄存器:用于存储要发送或接收的数据。在SPI通信中,数据寄存器用于存放要发送出去的数据,或者读取接收到的数据。
4、寄存器映射
- 概念:寄存器映射是将寄存器的物理地址映射到一个便于编程访问的虚拟地址空间。这样,在编程时就可以通过简单的地址操作来访问寄存器,而不需要关心寄存器的实际物理位置。
- 举例:GD32F450ZG单片机可能将一些外设寄存器映射到特定的地址范围,比如将GPIOA的寄存器映射到从地址A开始的一段连续地址,这样在程序中通过访问这个地址范围就相当于访问GPIOA的寄存器。
5、寄存器重映射
- 概念:寄存器重映射是改变寄存器的默认映射地址,将其映射到另外一个地址空间。这样做的目的通常是为了方便布线、解决资源冲突或者满足特定的应用需求。
- 举例:在某些情况下,默认的GPIO引脚对应的寄存器地址可能在布线时不太方便访问,通过寄存器重映射,可以将这些寄存器映射到一个更容易访问的地址,从而方便对GPIO进行操作。
6、总线基地址、外设基地址、外设寄存器地址
- 总线基地址:它是整个存储系统中某条总线(如APB总线、AHB总线)的起始地址。就像一条街道的起点门牌号,所有连接在这条总线上的外设的地址都是基于这个总线基地址来确定的。
- 外设基地址:是某个外设在总线上的起始地址。例如,GPIOA这个外设在总线上有一个基地址,从这个地址开始的一段连续地址空间就是GPIOA的寄存器地址范围。
- 外设寄存器地址:是外设中每个具体寄存器的地址。以GPIOA为例,有控制引脚方向的寄存器地址、控制引脚输出电平的寄存器地址等,这些都是基于GPIOA的外设基地址来确定的。
7、操作寄存器(以操作一个GPIO口为例)
以下是基于GD32F450ZG芯片,通过操作寄存器的方式来控制GPIOD的第7引脚输出高电平以点亮LED的示例代码(假设LED阳极接该引脚,阴极接地这种常见连接方式),以下代码使用C语言编写,且是示意性代码,你可能需要根据实际的编译环境等做适当调整:
// 首先定义寄存器相关的地址,这些地址可以从芯片手册中获取对应的值
#define RCC_AHB1ENR (*(volatile unsigned int *)0x40023830) // 时钟使能寄存器地址
#define GPIOD_MODER (*(volatile unsigned int *)0x40020C00) // GPIOD 模式寄存器地址
#define GPIOD_OTYPER (*(volatile unsigned int *)0x40020C04) // GPIOD 输出类型寄存器地址
#define GPIOD_OSPEEDR (*(volatile unsigned int *)0x40020C08) // GPIOD 输出速度寄存器地址
#define GPIOD_PUPDR (*(volatile unsigned int *)0x40020C0C) // GPIOD 上拉下拉寄存器地址
#define GPIOD_ODR (*(volatile unsigned int *)0x40020C14) // GPIOD 输出数据寄存器地址// 函数用于初始化GPIOD的相关配置
void GPIOD_Configuration(void)
{// 使能GPIOD时钟,对应RCC_AHB1ENR寄存器中相关位设置为1RCC_AHB1ENR |= (1 << 3); // 配置GPIOD的第7引脚为通用输出模式(01),参考芯片手册对MODER寄存器的描述GPIOD_MODER &= ~(3 << 14); // 先清除原来的设置GPIOD_MODER |= (1 << 14); // 设置为输出模式// 设置输出类型为推挽输出(0),对应OTYPER寄存器设置,默认就是推挽输出,这里做下示意性设置GPIOD_OTYPER &= ~(1 << 7); // 设置输出速度,这里设置为高速(11),可根据实际需求调整,参考OSPEEDR寄存器说明GPIOD_OSPEEDR &= ~(3 << 14);GPIOD_OSPEEDR |= (3 << 14);// 设置上拉下拉电阻,这里设置为无上下拉(00),参考PUPDR寄存器GPIOD_PUPDR &= ~(3 << 14);
}int main()
{// 进行GPIOD引脚的初始化配置GPIOD_Configuration();// 将GPIOD的第7引脚输出数据寄存器对应位置1,输出高电平GPIOD_ODR |= (1 << 7); while(1){// 可以在这里添加其他需要循环执行的代码,如果不需要可以为空循环}
}
下面详细解释一下代码各部分的含义:
1. 寄存器地址定义部分
通过 #define
宏定义了一系列寄存器的地址,使用 volatile
关键字修饰是为了告诉编译器该变量(实际代表的寄存器内容)可能会被硬件等外部因素改变,编译器不要对其访问做优化,要每次都从实际的内存地址(寄存器所在地址)读取其值。
例如 RCC_AHB1ENR (*(volatile unsigned int *)0x40023830)
就定义了 RCC_AHB1ENR
这个寄存器对应的内存地址是 0x40023830
,后续可以通过对这个定义好的变量进行读写操作来操作对应寄存器。
2. GPIOD_Configuration
函数部分
-
时钟使能:
首先在函数内通过RCC_AHB1ENR |= (1 << 3);
操作RCC_AHB1ENR
寄存器来使能GPIOD的时钟。在芯片中,各个外设模块(比如这里的GPIOD端口)都需要时钟才能正常工作,将该寄存器对应位(第3位对应GPIOD的时钟使能位,具体参考芯片手册的寄存器说明)置1就是开启其时钟。
-
引脚模式配置:
- 对于
GPIOD_MODER
寄存器,它用来设置每个引脚的工作模式(比如输入、输出、复用功能等)。先通过GPIOD_MODER &= ~(3 << 14);
清除原来对应引脚(第7引脚,对应寄存器的位是从低位开始算,第7引脚对应的位在第14、15两位控制,因为每两位控制一个引脚的模式,所以左移14位)的模式设置,然后GPIOD_MODER |= (1 << 14);
将其设置为通用输出模式(01表示输出模式,参考芯片手册的模式编码定义)。
- 对于
-
输出类型配置:
GPIOD_OTYPER
寄存器用于设置引脚是推挽输出还是开漏输出,这里GPIOD_OTYPER &= ~(1 << 7);
表示将第7引脚设置为推挽输出(默认一般就是推挽输出,这里做明确设置),也就是可以输出高低电平且具有一定的驱动能力。
-
输出速度配置:
通过操作GPIOD_OSPEEDR
寄存器来设置引脚的输出速度,这里GPIOD_OSPEEDR &= ~(3 << 14);
先清除原来的速度设置,然后GPIOD_OSPEEDR |= (3 << 14);
将其设置为高速输出(速度等级的编码同样参考芯片手册定义,这里设置为11表示高速),根据实际电路和对速度的需求可以选择不同的速度等级。
-
上拉下拉电阻配置:
最后使用GPIOD_PUPDR
寄存器设置引脚的上拉下拉情况,GPIOD_PUPDR &= ~(3 << 14);
操作是将第7引脚设置为无上下拉状态(00表示无上下拉,不同编码对应不同的上拉下拉设置,参考芯片手册)。
3. main
函数部分
-
首先调用
GPIOD_Configuration
函数对GPIOD的第7引脚进行初始化配置,使其具备合适的输出条件。 -
然后通过
GPIOD_ODR |= (1 << 7);
操作GPIOD_ODR
寄存器,将第7引脚对应的位(第7位)置1,这样就使得该引脚输出高电平,从而如果连接的LED电路正确(阳极接该引脚,阴极接地),就可以点亮LED。 -
最后的
while(1)
循环可以根据实际需求添加其他要不断执行的代码逻辑,如果暂时不需要额外逻辑,空循环即可保证程序持续运行并维持引脚的输出电平状态。
请注意,以上代码只是基于芯片手册对寄存器操作的常规实现示例,实际应用中可能需要考虑更多如系统初始化等完整的环境搭建内容,并且要严格对照芯片手册确保寄存器地址、位操作等都符合芯片的具体规定。
二、库函数
1、为什么要使用库函数
- 提高开发效率:直接操作寄存器来控制芯片的功能是非常繁琐的。例如,配置一个通用输入输出(GPIO)引脚,需要对多个寄存器进行位操作,包括配置模式寄存器、输出数据寄存器等。使用库函数可以避免这些复杂的底层寄存器操作,减少代码编写量和出错的概率。
- 增强代码的可移植性:不同的芯片可能有不同的寄存器地址和操作方式。如果使用库函数,只要库函数的接口不变,在不同的同系列芯片或者经过适当修改的其他芯片之间移植代码会更加方便。
- 便于代码维护:库函数将复杂的硬件操作封装起来,使代码结构更加清晰。当需要修改功能时,例如改变GPIO引脚的功能或者更新芯片的某些配置,只需要调用相应的库函数或者修改库函数的参数,而不需要在大量的寄存器操作代码中寻找和修改。
2、什么是库函数
- 库函数是芯片厂商或者第三方为了方便开发者使用芯片的功能而编写的一组函数。这些函数封装了对芯片内部寄存器的操作,为开发者提供了一个更高级的编程接口。以GD32F450ZG为例,它的库函数可以实现诸如GPIO配置、定时器设置、中断处理等各种功能。库函数通常是基于芯片的硬件手册编写的,它准确地反映了芯片的功能和特性。
3、库函数的详解(以GPIO为例)
- 函数分类:
- 初始化函数:用于配置GPIO引脚的模式(输入、输出、复用等)、速度等参数。例如,
gpio_mode_set()
函数用于设置GPIO引脚的模式,它会根据传入的参数配置相应的寄存器。 - 读写函数:用于读取GPIO引脚的输入状态或者写入输出状态。像
gpio_output_bit_set()
和gpio_output_bit_reset()
函数可以分别设置和清除GPIO引脚的输出电平。
- 初始化函数:用于配置GPIO引脚的模式(输入、输出、复用等)、速度等参数。例如,
- 参数含义:
- 以
gpio_mode_set()
函数为例,它通常需要传入GPIO端口(如GPIOD
)、引脚号(如GPIO_PIN_7
)、模式(如GPIO_MODE_OUTPUT
)等参数。这些参数明确了要操作的具体引脚和要设置的功能。
- 以
4、如何操作库函数(以点亮LED连接到PD7为例)
- 步骤一:包含头文件
- 首先需要包含相关的头文件,这些头文件包含了库函数的声明。对于GD32F450ZG的GPIO操作,通常需要包含
gd32f4xx_gpio.h
头文件。在C语言中,使用#include "gd32f4xx_gpio.h"
语句将头文件包含到源文件中。
- 首先需要包含相关的头文件,这些头文件包含了库函数的声明。对于GD32F450ZG的GPIO操作,通常需要包含
- 步骤二:初始化GPIO时钟
- 芯片的GPIO模块需要时钟才能正常工作。可以使用
rcu_periph_clock_enable()
函数来使能GPIOD的时钟。例如:
- 芯片的GPIO模块需要时钟才能正常工作。可以使用
rcu_periph_clock_enable(RCU_GPIOD);
- 步骤三:配置GPIO引脚模式
- 使用
gpio_mode_set()
函数将PD7配置为输出模式。示例代码如下:
- 使用
gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
- 这里`GPIOD`表示要操作的是D端口,`GPIO_MODE_OUTPUT`表示设置为输出模式,- `GPIO_PUPD_NONE`表示不使用上下拉电阻,`GPIO_PIN_7`表示操作的是第7个引脚。
- 步骤四:点亮LED(设置高电平)
- 使用
gpio_output_bit_set()
函数将PD7引脚设置为高电平来点亮LED。代码如下:
- 使用
gpio_output_bit_set(GPIOD, GPIO_PIN_7);
- 完整示例代码如下:
#include "gd32f4xx.h"
#include "gd32f4xx_gpio.h"
int main()
{rcu_periph_clock_enable(RCU_GPIOD);gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);gpio_output_bit_set(GPIOD, GPIO_PIN_7);while (1);return 0;
}
- 在上述代码中,
while(1)
语句用于让程序保持运行状态,这样可以持续保持LED点亮。如果没有这个循环,程序执行完后可能会导致LED熄灭或者出现其他不可预期的行为。
请注意,以上代码可能需要根据具体的开发环境和工程配置进行适当的调整,如添加启动文件、正确配置链接脚本等。
三、寄存器和库函数的区别
1、寄存器与库函数的区别
- 操作层次不同
- 寄存器:是芯片内部的存储单元,直接与硬件电路相关联。例如,在GD32F450ZG芯片中,GPIO(通用输入输出)寄存器用于控制引脚的输入输出模式、电平状态等。每个寄存器都有特定的地址和位定义,开发者需要直接对这些寄存器进行读写操作来控制硬件。比如,通过向GPIO端口的控制寄存器写入特定的值来设置引脚为输入或输出模式。
- 库函数:是对寄存器操作的封装。它提供了一种更高级的编程接口,隐藏了寄存器操作的细节。例如,库函数内部会根据传入的参数(如设置引脚为输出模式)自动对相应的寄存器进行正确的读写操作,开发者只需要调用库函数并传入合适的参数,而不需要了解具体是哪个寄存器以及如何对其进行位操作。
- 代码形式不同
- 寄存器操作:代码通常涉及直接访问寄存器地址。在C语言中,可能会使用指针来访问寄存器。例如,
*(volatile uint32_t *)0x40021000 = 0x00000001;
(这只是一个简单示例,实际地址和值根据芯片手册确定),这里将值0x00000001
写入到地址为0x40021000
的寄存器中,这种代码比较底层,不易理解。 - 库函数调用:代码看起来更加简洁明了。以设置GPIO引脚模式为例,可能会有类似
gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
这样的函数调用。其中gpio_mode_set
是库函数,后面的参数用于指定端口、模式、上下拉电阻状态和引脚号等信息。
- 寄存器操作:代码通常涉及直接访问寄存器地址。在C语言中,可能会使用指针来访问寄存器。例如,
2、寄存器操作的优势和劣势
- 优势
- 高度灵活性:可以实现对芯片硬件的最精细控制。开发者能够根据自己的需求精确地设置每个寄存器位,以实现特殊的功能或者对硬件进行优化。例如,在某些低功耗应用中,可以通过对特定寄存器的位操作来精确控制芯片各个模块的功耗状态。
- 资源占用少:由于直接操作寄存器,没有额外的代码封装层,所以生成的代码体积可能相对较小。这在资源受限的嵌入式系统中,如一些小型的传感器节点或者简单的微控制器应用中,是一个重要的优势。
- 执行效率高:没有函数调用的开销,直接对寄存器进行读写,在一些对实时性要求极高的应用场景中,能够更快地响应硬件事件。例如,在高速数据采集系统中,直接操作寄存器可以更快地获取和处理数据。
- 劣势
- 开发难度大:需要开发者深入了解芯片的寄存器手册,包括寄存器的地址、位定义、复位值等信息。对于复杂的芯片,寄存器数量众多,操作起来容易出错。例如,在配置一个复杂的通信接口(如SPI或I2C)时,需要正确设置多个相关寄存器的多个位,这对开发者的硬件知识和耐心是一个很大的考验。
- 代码可读性差:直接操作寄存器的代码通常是一些十六进制或二进制的常量赋值,以及指针操作,这些代码对于其他开发者或者后期维护代码的人员来说,理解起来非常困难。而且,代码缺乏高层次的抽象,使得业务逻辑被底层硬件操作细节所掩盖。
- 可移植性差:不同芯片的寄存器布局和功能定义不同。如果要将基于某个芯片寄存器操作的代码移植到另一个芯片上,几乎需要重新编写大部分代码。例如,从GD32F450ZG移植到另一个型号的微控制器,由于寄存器地址和功能可能完全不同,原有的寄存器操作代码无法直接使用。
3、库函数的优势和劣势
- 优势
- 易于开发:降低了开发难度,开发者不需要深入了解芯片的每个寄存器细节。只需要熟悉库函数的接口和功能,就可以快速实现对芯片硬件的控制。例如,使用库函数来配置定时器,只需要按照函数的参数要求传入定时时间、计数模式等信息,就可以完成定时器的配置,而不需要了解定时器相关寄存器的具体操作。
- 代码可读性好:库函数的调用使得代码更具有逻辑性和可读性。代码能够清晰地表达其功能,例如
gpio_output_bit_set(GPIOD, GPIO_PIN_7);
很容易理解是设置GPIOD端口的第7引脚为输出高电平。这种高层次的抽象使得代码的维护和协作开发更加方便。 - 可移植性强:在同一系列芯片或者具有相似库函数接口的芯片之间,代码移植相对容易。只要库函数的接口和功能没有大的变化,就可以在不同芯片上使用相同的代码逻辑。例如,在GD32系列的不同型号芯片中,如果库函数接口保持一致,就可以方便地移植GPIO控制代码。
- 劣势
- 灵活性相对较低:库函数提供了一种标准化的操作方式,可能无法满足一些特殊的硬件控制需求。例如,在某些非常特殊的硬件调试或者优化场景下,需要对寄存器进行一些非标准的位操作,而库函数可能没有提供这样的功能接口。
- 资源占用可能较多:由于库函数是对寄存器操作的封装,内部可能会包含一些额外的代码来处理参数检查、错误处理等功能。这可能导致生成的代码体积比直接操作寄存器的代码要大,在资源受限的系统中可能会受到限制。
- 执行效率可能稍低:库函数调用会带来一定的函数调用开销,包括参数传递、栈操作等。在对性能要求极高的场景下,可能会影响系统的实时响应速度。不过,在大多数嵌入式应用中,这种效率损失通常是可以接受的。
四、GD32F4xx 系列器件的存储器映射表
相关文章:

二、点亮希望之光:寄存器与库函数驱动 LED 灯
文章目录 一、寄存器1、存储器映射2、存储器映射表3、寄存器4、寄存器映射5、寄存器重映射6、总线基地址、外设基地址、外设寄存器地址7、操作寄存器(以操作一个GPIO口为例)1. 寄存器地址定义部分2. GPIOD_Configuration 函数部分3. main 函数部分 二、库…...

Oracle 用户管理模式下的恢复案例-不完全恢复
1. 不完全恢复的几种常用方法 01. recover database using backup controlfile 如果丢失当前控制文件,用冷备份的控制文件恢复的时候,用来告诉 oracle,不要以 controlfile 中的 scn 作为恢复的终点; 02. recover database until …...

SharpDevelop IDE IViewContent.cs类
文件位置:IViewContent.cs /// <summary>/// IViewContent is the base interface for "windows" in the document area of SharpDevelop./// A view content is a view onto multiple files, or other content that opens like a document/// (e.…...

Unity RectTransUtility工具类
这个工具主要是用于动态生成UI的情况。项目中我们通过配置UI的锚点、位置以及大小(位置、大小都是通过蓝湖看到的),然后通过代码动态生成UI。 大部分情况下只要合理设置锚点,那么生成出来的UI就已经满足了适配的要求。 using UnityEngine;public static…...

React性能优化
三个可以优化的地方 避免过度多次渲染 组件会在以下情况下重新渲染 注意:例如组件组合的形式,<Test><Counter></Counter></Test>,即使Test发生了重新渲染,Counter也不会重新渲染。另外使用React这样的库或框架时&a…...

前端开发流程实操:从概念到上线
在前端开发这个充满创意与技术挑战的领域,一个清晰的开发流程是确保项目顺利进行并达到预期效果的关键。 下面就和大家分享一下前端开发的实操流程。 一、项目启动与需求分析 前端开发不是孤立的,它是整个项目的一部分,所以首先要与项目团…...

Metasploit使用
最近在学Metasploit,Metasploit是一个免费的、可下载的渗透测试框架,通过它可以很容易地获取、开发并对计算机软件漏洞实施攻击,是一个集成了渗透测试全流程的渗透工具。 图一 模块:模块组织按照不同的用途分为7种类型的模块 &am…...

Milvus向量数据库05-常见问题整理
Milvus向量数据库05-常见问题整理 1-什么是PipeLine 这张图展示了一个文档处理和搜索系统的架构,主要分为两个部分:Ingestion Pipeline(摄取管道)和 Search Pipeline(搜索管道)。下面是对图中各部分的详细…...

Ruby On Rails 笔记3——表的增删改查
1.Migration Migrations是一种便利的方法,能以重现的方式随时间推移改变数据库schema. 使用Ruby Domain Specific Language (DSL),因此你不用手写SQL,进而使你的schema和changes与数据库独立。 可以把每次migration看作是数据库的一个新“版本”。A schema开始时什么都没有…...

CSS3 动画详解,介绍、实现与应用场景详解
CSS3 动画概述 CSS3 动画是通过 CSS3 的新特性来实现元素的动态变化。与传统的 JavaScript 动画不同,CSS3 动画主要通过 CSS 属性的变化来实现动画效果,具有高效、轻量和易于实现的优点。CSS3 动画通常用于网页的动态交互效果、过渡效果、元素移动、缩放、旋转等场景。 一、…...

Winston-MySQL 使用文档
目录 简介 安装 配置 环境变量配置 日志级别和表配置 创建 Logger 实例 文件传输配置 控制台输出配置 完整代码 使用方法 记录信息日志 记录错误日志 记录警告日志 总结 简介 winston-mysql 是一个为 winston3.x 日志库设计的 MySQL 传输插件,允许你…...

java日期工具: 获取两个时间段的时间段值,Java获得两个日期之间的所有年、月份、日。
文章目录 日期字符串格式化获取两个日期之间的所有日期 (字符串格式)获取两个时间段的时间段值,Java获得两个日期之间的所有年、月份、日。生效时间需要大于当前时间结束时间的月份不能大于当前月份日期字符串格式化 /*** 日期字符串格式化** @param time* @param Format_int…...

【Rive】混合动画
1 混合动画简介 【Rive】动画 中介绍了 Rive 中动画的基础概念和一般动画的制作流程,本文将介绍混合动画的基础概念和一般制作流程。Unity 中混合动画介绍详见→ 【Unity3D】动画混合。 混合动画是指同一时刻多个动画按照一定比例同时执行,这些动画控制的…...

qt应用程序崩溃日志和转储dmp文件对于定位问题
qt应用程序崩溃日志和转储文件对于定位问题 一. DMP 文件包含的信息:二. 分析 DMP 文件的主要方法:三. 生成更详细的 DMP 文件:四. 分析 DMP 文件的注意事项:五. 实用建议:六. 实战 一. DMP 文件包含的信息:…...

Mysql架构
连接层 最上层是一些客户端和连接服务,负责客户端的连接,验证账号密码等授权认证 服务层 主要完成大多数的核心服务功能,对sql进行解析,优化,调用函数,如果是查询操作,有没有缓存等操作操作。所…...

杂发单的单据类型一个参数的逻辑
【核准中可改】被产线滥用了。它们可以这样做,开立一张杂发单,打印出来交领导层签名。单据要交财务做核算的。然后去修改杂发单的材料。以为可以瞒天过海。2个仓库,一个中掉坑里,一个发现了它们的拙劣的手段,上报之后没…...

Linux系统 vim 编辑文件搜索关键字用法
1、首先确保在normal模式下,按ESC后不在insert模式 输入 /test或?test 此时就会匹配 test 字符串,并且高亮显示 2、向前搜索 /字符串:按n匹配下一个目标,按N匹配上一个目标 3、向后搜索 ?字符串:按n匹配上一个目标…...

Vue智慧商城项目
创建项目 vue组件库 — vant-ui(常用于移动端) Vant 2 - 轻量、可靠的移动端组件库 安装vant npm i vantlatest-v2 -S 引入组件 按需导入和全部导入 全部导入 整个组件库的所有组件都导进来,缺点是增加了代码包体积 main.js import…...

Qt Window应用程序去掉控制台窗口
Qt Window应用程序去掉控制台窗口 方式一 set(PROJECT_SOURCESWIN32main.cppmainwindow.hpp )add_executable(Tool-V2${PROJECT_SOURCES} )方式二 set_target_properties(Tool-V2 PROPERTIESMACOSX_BUNDLE TRUEWIN32_EXECUTABLE TRUE )参考文献: cmake Qt 项目…...

软件测试最新项目合集【商城、外卖、银行、金融等等.......】
项目一:ShopNC商城 项目概况: ShopNC商城是一个电子商务B2C电商平台系统,功能强大,安全便捷。适合企业及个人快速构建个性化网上商城。 包含PCIOS客户端Adroid客户端微商城,系统PC后台是基于ThinkPHP MVC构架开发的跨…...

SAP SD学习笔记18 - 投诉处理4 - 请求书订正依赖,投诉处理流程的总结
上一章讲了 Credit/Debit Memo依赖,Credit/Debit Memo。Credit Memo依赖 本质上是一张受注票;Credit Memo 本质上是一张请求票。 SAP SD学习笔记17 - 投诉处理3 - Credit/Debit Memo依赖,Credit/Debit Memo-CSDN博客 本章继续讲本图中的内容…...

VBA批量提取PDF内容的程序
VBA批量提取PDF内容的程序 Sub ExtractPDFText()Dim pdfApp As Acrobat.AcroAppDim pdfDoc As Acrobat.CAcroPDDocDim pdfPage As Acrobat.AcroPDPageDim txtData As StringDim i As IntegerDim filePath As StringDim outputFolder As StringDim outputFileName As String 初…...

C++入门终
目录 一、引用 二、内联函数 三、auto关键字 四、指针空值nullptr 一、引用 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间 类型&引用变量名(对象名)…...

ubuntu下Qt5自动编译配置QtMqtt环境(10)
文章目录 [toc]1、概述2、下载QtMqtt源码3、编译4、验证5、参考6、视频 更多精彩内容👉内容导航 👈👉Qt网络编程 👈 1、概述 Qt默认是不包含mqtt库的,如果需要使用到mqtt库就只能自己编译配置; 网络所有的…...

Vulnhub DC-3靶机攻击实战(一)
导语 在之前的博客分享中,我们介绍了关于如何获取DC-1和DC-2机器的所有的Flag,下面我们来介绍一下如何对DC-3靶机进行渗透测试。 第一步、搭建靶机环境 下载靶机,并且将靶机导入到VMware环境中,如下所示。 第二步、收集服务器信息 进入到Kali攻击机之后,打开root权限…...

常用传感器介绍合集
SW-520D倾斜传感器 HX711模块:高精度称重的核心利器 GY302光照传感器模块详解 MLX90614红外测温传感器介绍 MAX30102心率血氧传感器模块:精准健康监测的利器 RGB颜色传感器简介 DS18B20温度传感器模块 人体红外传感器简介 FC-28土壤湿度传感器 …...

“为您的家电穿上防震铠甲:优质电器缓冲器
在地震频发地区或日常生活中,确保家电的安全和稳定至关重要。为了防止地震、意外碰撞或其他外力对家电造成损害,采用优质的电器缓冲器就像是为家电穿上了一层坚固的“防震铠甲”。这不仅能够有效减少因震动导致的损坏风险,还能显著延长家电的…...

Elasticsearch入门之HTTP高级查询操作
前言 上一篇博客我们学习了es的一些基础操作如下: 创建索引(创建表 create table)查看索引(查看表show tables)查看单个索引(查看单个表show create table)删除索引(删除表&#x…...

Java基础-异常
异常 什么是异常 在实际工作中,遇到的情况不可能是非常完美的。比如:你写一个模块,用户输入不一定符合你的要求、你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据库的数据,数据…...

鲲鹏麒麟使用Docker部署Redis5
本次部署采用Docker方式进行部署,服务器为鲲鹏服务器,CPU架构为ARM64,操作系统版本信息为 # cat /etc/kylin-release Kylin Linux Advanced Server release V10 (Tercel)镜像 下载镜像鲲鹏麒麟Redis5镜像包 部署 1、上传镜像到服务器 2、…...