热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【STM32H7教程】第70章STM32H7的内部Flash基础知识和HAL库API

完整教程下载地址:http:www.armbbs.cnforum.php?modviewthread&tid86980第70章STM32H7的内部Flash基础知识

完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980


第70章       STM32H7的内部Flash基础知识和HAL库API

本章节为大家讲解内部Flash的基础知识和对应的HAL库API。

目录

第70章       STM32H7的内部Flash基础知识和HAL库API

70.1 初学者重要提示

70.2 内部Flash基础知识

70.2.1 内部Flash的硬件框图

70.2.2 内部Flash框架

70.2.3 内部Flash读操作

70.2.4 内部Flash写入和擦除操作

70.2.5 内部Flash读保护

70.2.6 内部Flash选项字节

70.2.7 内部Flash的ECC校验

70.3 内部Flash的HAL库用法

70.3.1 内部Flash结构体FLASH_TypeDef

70.3.2 内部Flash擦除结构体FLASH_EraseInitTypeDef

70.3.3 内部Flash的操作总结

70.4 内部Flash源文件stm32h7xx_hal_flash.c

70.4.1 函数HAL_FLASH_Lock

70.4.2 函数HAL_FLASH_Unlock

70.4.3 函数HAL_FLASH_Program

70.4.4 函数HAL_FLASHEx_Erase

70.5 总结



 


70.1 初学者重要提示


  1.   本章2.5小节里面的Flash三级读保护是重点,务必要掌握明白。
  2.   STM32H743XI有两个独立的BANK,一个BANK的编程和擦除操作对另一个BANK没有任何影响。但是如果用户应用程序和要擦写的Flash扇区在同一个BANK,在执行擦写操作时,用户应用程序将停止运行,包括中断服务程序。
  3.   STM32H7的两个Flash BANK是256bit带宽,CPU访问是采用的两个64bit AXI总线。
  4.   HAL库的内部Flash编程函数HAL_FLASH_Program固定编写32字节数据。

70.2 内部Flash基础知识


70.2.1 内部Flash的硬件框图

认识一个外设,最好的方式就是看它的框图,方便我们快速的了解内部Flash的基本功能,然后再看手册了解细节。

通过这个框图,我们可以得到如下信息:


  •   sys_ck时钟输入

D1域总线时钟。


  •   po_rst输入

Power on reset 上电复位。


  •   d1_rst输入

D1域系统复位。


  •   flash_it输出

flash中断请求输出。

 

STM32H7的两个Flash BANK是独立的,读写和擦除互补影响,256bit带宽,CPU访问是采用的两个64bit AXI总线。


70.2.2 内部Flash框架

关于内部Flash的框架,了解以下几个知识点即可:


  •   256bit为单位,即32字节,并且每个单位配10bit的ECC校验位。正是这个原因要求大家对Flash进行编程时,必须以32字节为单位。
  •   两个独立的BANK,每个BANK有1MB容量。并且每个BANK的扇区大小固定为128KB,即8个扇区。

BANK1的地址范围:0x0800 0000到0x080F FFFF。

BANK2的地址范围:0x0810 0000到0x081F FFFF。


70.2.3 内部Flash读操作

STM32H7的内部Flash读操作跟内部RAM的读操作是一样的,支持64bit,32bit,16bt和8bit,使用比较简单。这里我们重点普及一个知识点,H7的内部Flash在不同主频下需要做的延迟参数:

 

对于上面的表格,大家可以看到,当延迟等待设置为0的时候,即无等待,单周期访问,速度可以做到70MHz。增加1个Flash周期后,访问速度可以做到140MHz。当增加到3个或4个Flash周期后,最高速度可以做到225MHz。

了解了这个知识点后,再来看下面的时序,非常具有参考意义:

注:ACLK、ARADDR、ARVALID、RDATA、RVALID 和RLAST是AXI总线信号。Flash读和Flash数据是 Flash 接口信号。

 

关于这个时序要要认识到以下几点:


  •   AXI总线发起读取信号后,Flash端等待了3个时钟周期(注意延迟三个周期,支持的Flash速度),之后连续读取了4个64bit数据。
  •   由于AXI总线是64bit的,所以1次读取就可以读出64bit数据,连续读取4次后,就是256bit,即Flash接口的一组数据,因为H7的Flash接口带宽是256bit的。
  •   如果不开Flash Cache的情况下,连续读可以提升性能。

 

下面是连续读取8个64bit数据的时序图,跟连续读取4个64bit数据基本是一样的,只是多读取了4组数据。

 


70.2.4 内部Flash写入和擦除操作

最重要的知识点放在开头说:STM32H7内部Flash的写操作地址必须是32字节对齐(此地址对32求余数为0),写入的数据量也必须是32字节整数倍,不足32字节整数倍,补0也要是整数倍。

这里我们重点了解Flash的写入和擦除流程。Flash的写入扇区流程如下:


  1. 先保证这块扇区空间之前已经擦除过了。
  2. 解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。
  3. 检查是否写保护,使能Flash可以编程,然后对其进行编程操作,编程完毕后,等待编程完成,然后禁止Flash编程位。具体操作可以通过HAL库的函数HAL_FLASH_Program实现。

 

Flash的擦除流程如下:


  1. 解锁Flash,通过HAL库的函数HAL_FLASH_Unlock实现。
  2. 如果是BANK1或者BANK2需要擦除,调用函数FLASH_MassErase,然后等待擦除完成,完成之后关闭BANK1和BANK2的擦除请求位BER1/BER2
  3. 如果是扇区擦除,调用函数FLASH_Erase_Sector,然后等待擦除完成,完成之后关闭扇区的擦除请求位SER。

70.2.5 内部Flash读保护

内部Flash支持三级读保护RDP(read out protection)。


  •   Level 0(无保护)

默认设置,所有读写和擦除操作都可以正常支持。


  •   Level 1 (Flash连接保护)
    •   可以防止连接调试器时读取Flash内容,或者RAM中存有恶意获取代码,也是禁止的。因此只要调试器连接芯片,或者从内部RAM启动运行代码,都是禁止访问内部Flash的。
    •   如果没有检测到从内部RAM启动和系统bootloader启动且没有连接调试器,对用户Flash的读写和擦除操作都是允许的,并且其它安全存储区也是可以访问的。否则是禁止访问的,一旦检测到对Flash的读请求,将产生总线错误。
    •   如果将Level 1切换到Level 0时,用户Flash区和安全区域将被擦除。
  •   Level 2(设备保护和自举保护)
    •   所有调试特性被关闭。
    •   禁止从RAM启动。
    •   除了选项字节里面的SWAP位可以配置,其它位都无法更改。
    •   禁止了调试功能,且禁止了从RAM和系统bootloader启动,用户Flash区是可以执行读写和擦除操作的,访问其它安全存储区也是可以的。

 

特别注意:Level2修改是永久性的,一旦配置为Level2将不再支持被修改。

如果大家要设置读保护的话,使用HAL的API可以设置,也可以使用STM32CubeProg设置:

 

 


70.2.6 内部Flash选项字节

Flash选项字节主要用于boot地址设置,安全保护,Flash扇区保护等,涉及到的选项比较多。如果大家打算了解这一部分的话,使用STM32CubeProg进行设置即可,也比较方便。

 


70.2.7 内部Flash的ECC校验

这里先说下为什么内部Flash要带ECC校验,因为随着芯片的制造工艺水平越高,带电粒子产生的位翻转就越多,此时的ECC是必须要有的,一般可以纠正1-2个bit,安全等级高的Flash类存储器和RAM类都是必须要带ECC的。

对于STM32H7带的ECC校验,一般不需要用户去管理。

 


  • ECC相关知识

关于ECC方面的知识,专门整理了一个帖子:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=86777


70.3 内部Flash的HAL库用法


70.3.1 内部Flash结构体FLASH_TypeDef

内部Flash相关的寄存器是通过HAL库中的结构体FLASH_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:

typedef struct
{__IO uint32_t ACR; __IO uint32_t KEYR1; __IO uint32_t OPTKEYR; __IO uint32_t CR1; __IO uint32_t SR1; __IO uint32_t CCR1; __IO uint32_t OPTCR; __IO uint32_t OPTSR_CUR; __IO uint32_t OPTSR_PRG; __IO uint32_t OPTCCR; __IO uint32_t PRAR_CUR1; __IO uint32_t PRAR_PRG1; __IO uint32_t SCAR_CUR1; __IO uint32_t SCAR_PRG1; __IO uint32_t WPSN_CUR1; __IO uint32_t WPSN_PRG1; __IO uint32_t BOOT_CUR; __IO uint32_t BOOT_PRG; uint32_t RESERVED0[2]; __IO uint32_t CRCCR1; __IO uint32_t CRCSADD1; __IO uint32_t CRCEADD1; __IO uint32_t CRCDATA; __IO uint32_t ECC_FA1; uint32_t RESERVED1[40]; __IO uint32_t KEYR2; uint32_t RESERVED2; __IO uint32_t CR2; __IO uint32_t SR2; __IO uint32_t CCR2; uint32_t RESERVED3[4]; __IO uint32_t PRAR_CUR2; __IO uint32_t PRAR_PRG2; __IO uint32_t SCAR_CUR2; __IO uint32_t SCAR_PRG2; __IO uint32_t WPSN_CUR2; __IO uint32_t WPSN_PRG2; uint32_t RESERVED4[4]; __IO uint32_t CRCCR2; __IO uint32_t CRCSADD2; __IO uint32_t CRCEADD2; __IO uint32_t CRCDATA2; __IO uint32_t ECC_FA2;
} FLASH_TypeDef;

 

这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。

__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:

#define __O volatile /*!#define __IO volatile /*!

 

下面我们看下Flash的定义,在stm32h743xx.h文件。

#define PERIPH_BASE (0x40000000UL)
#define D1_AHB1PERIPH_BASE (PERIPH_BASE + 0x12000000UL)
#define FLASH_R_BASE (D1_AHB1PERIPH_BASE + 0x2000UL)
#define FLASH ((FLASH_TypeDef *) FLASH_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52002000

 

我们访问Flash的CR1寄存器可以采用这种形式:FLASH->CR1 = 0。


70.3.2 内部Flash擦除结构体FLASH_EraseInitTypeDef

下面是做内部Flash擦除的结构体,用到的地方比较多:

typedef struct
{uint32_t TypeErase; uint32_t Banks; uint32_t Sector; uint32_t NbSectors; uint32_t VoltageRange;
} FLASH_EraseInitTypeDef;

 

下面将结构体成员逐一做个说明:


  •   TypeErase

用于选择BANK擦除还是扇区擦除,H743有两个BANK,每个BANK有个8个扇区,每个扇区128KB。具体支持的参数如下:

#define FLASH_TYPEERASE_SECTORS 0x00U /* 扇区方式擦除 */
#define FLASH_TYPEERASE_MASSERASE 0x01U /* BANK方式擦除 */

 


  •   Banks

用于选择要擦除的BANK,或者两个BANK都选择:

#define FLASH_BANK_1 0x01U /* Bank 1 */
#define FLASH_BANK_2 0x02U /* Bank 2 */
#define FLASH_BANK_BOTH (FLASH_BANK_1 | FLASH_BANK_2) /* Bank1 和 Bank2 */

 


  •   Sector

用于选择要擦除的扇区:

#define FLASH_SECTOR_0 0U /* Sector Number 0 */
#define FLASH_SECTOR_1 1U /* Sector Number 1 */
#define FLASH_SECTOR_2 2U /* Sector Number 2 */
#define FLASH_SECTOR_3 3U /* Sector Number 3 */
#define FLASH_SECTOR_4 4U /* Sector Number 4 */
#define FLASH_SECTOR_5 5U /* Sector Number 5 */
#define FLASH_SECTOR_6 6U /* Sector Number 6 */
#define FLASH_SECTOR_7 7U /* Sector Number 7 */

 


  •   NbSectors

用于设置要擦除的扇区个数,对于STM32H743来说,范围1到8。


  •   VoltageRange

用于设置编程的并行位数,电压不同,位数不同:

#define FLASH_VOLTAGE_RANGE_1 0x00000000U /* Flash program/erase by 8 bits */
#define FLASH_VOLTAGE_RANGE_2 FLASH_CR_PSIZE_0 /* Flash program/erase by 16 bits */
#define FLASH_VOLTAGE_RANGE_3 FLASH_CR_PSIZE_1 /* Flash program/erase by 32 bits */
#define FLASH_VOLTAGE_RANGE_4 FLASH_CR_PSIZE /* Flash program/erase by 64 bits */

 


70.3.3 内部Flash的操作总结

使用方法由HAL库提供:


  •   Flash编程函数操作流程
    •   Flash解锁函数HAL_FLASH_Unlock。
    •   Flash查询方式编程HAL_FLASH_Program。
    •   Flash中断方式编程HAL_FLASH_Program_IT。
    •   Flash上锁函数HAL_FLASH_Lock。
  •   选项字节编程流程
    •   选项字节解锁函数HAL_FLASH_OB_Unlock。
    •   选项字节加载函数HAL_FLASH_OB_Launch。
    •   选项字节编程函数HAL_FLASHEx_OBProgram。
    •   选项字节加锁函数HAL_FLASH_OB_Lock。
  •   Flash擦除流程
    •   Flash解锁函数HAL_FLASH_Unlock。
    •   Flash查询方式擦除HAL_FLASHEx_Erase。
    •   Flash中断方式擦除HAL_FLASHEx_Erase_IT。
    •   Flash上锁函数HAL_FLASH_Lock。

70.4 内部Flash源文件stm32h7xx_hal_flash.c

此文件涉及到的函数较多,这里把几个常用的函数做个说明:


  •   HAL_FLASH_Unlock
  •   HAL_FLASH_Lock
  •   HAL_FLASHEx_Erase
  •   HAL_FLASH_Program

70.4.1 函数HAL_FLASH_Lock

函数原型:

HAL_StatusTypeDef HAL_FLASH_Lock(void)
{
/* 设置FLASH Bank1控制寄存器Lock位,即禁止访问 */SET_BIT(FLASH->CR1, FLASH_CR_LOCK);/* 验证Flash Bank1是否已经被锁住 */if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) == 0U){return HAL_ERROR;}/* 设置FLASH Bank2控制寄存器Lock位,即禁止访问 */SET_BIT(FLASH->CR2, FLASH_CR_LOCK);/* 验证Flash Bank2是否已经被锁住 */if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) == 0U){return HAL_ERROR;}return HAL_OK;
}

 

函数描述:

用于Flash加锁,加锁后将不能对Flash进行编程和擦除。


70.4.2 函数HAL_FLASH_Unlock

函数原型:

HAL_StatusTypeDef HAL_FLASH_Unlock(void)
{if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U){/* 允许访问Flash Bank1 */WRITE_REG(FLASH->KEYR1, FLASH_KEY1);WRITE_REG(FLASH->KEYR1, FLASH_KEY2);/* 验证是否已经解锁 */if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U){return HAL_ERROR;}}if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U){/* 允许访问Flash Bank2 */WRITE_REG(FLASH->KEYR2, FLASH_KEY1);WRITE_REG(FLASH->KEYR2, FLASH_KEY2);/* 验证是否已经解锁 */if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U){return HAL_ERROR;}}return HAL_OK;
}

 

函数描述:

此函数用于Flash解锁,解锁后可以对Flash进行擦除和编程。


70.4.3 函数HAL_FLASH_Program

函数原型:

HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)
{HAL_StatusTypeDef status;__IO uint32_t *dest_addr = (__IO uint32_t *)FlashAddress;__IO uint32_t *src_addr = (__IO uint32_t*)DataAddress;uint32_t bank;uint8_t row_index = FLASH_NB_32BITWORD_IN_FLASHWORD;/* 检测参数 */assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));assert_param(IS_FLASH_PROGRAM_ADDRESS(FlashAddress));/* 上锁 */__HAL_LOCK(&pFlash);#if defined (FLASH_OPTCR_PG_OTP)if((IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress)) || (IS_FLASH_PROGRAM_ADDRESS_OTP(FlashAddress)))
#elseif(IS_FLASH_PROGRAM_ADDRESS_BANK1(FlashAddress))
#endif {bank = FLASH_BANK_1;}else{bank = FLASH_BANK_2;}/* 错误标识,无错误 */pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;/* 等待操作完成 */status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);if(status == HAL_OK){if(bank == FLASH_BANK_1){
#if defined (FLASH_OPTCR_PG_OTP)if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD){/* 设置OTP寄存器的PG位,使能可以编程 */SET_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);}else
#endif {/* 设置PG位,使能可编程 */SET_BIT(FLASH->CR1, FLASH_CR_PG);}}else{/* 设置PG位 */SET_BIT(FLASH->CR2, FLASH_CR_PG);}__ISB();__DSB();#if defined (FLASH_OPTCR_PG_OTP)if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD){/* 编程OTP(16 bits) */*(__IO uint16_t *)FlashAddress = *(__IO uint16_t*)DataAddress;}else
#endif {/* 对Flash进行编程 */do{*dest_addr = *src_addr;dest_addr++;src_addr++;row_index--;} while (row_index != 0U);}__ISB();__DSB();/* 等待最后一次操作完成 */status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, bank);#if defined (FLASH_OPTCR_PG_OTP)if (TypeProgram == FLASH_TYPEPROGRAM_OTPWORD){/* 如果编程操作完成,关闭OTP PG位 */CLEAR_BIT(FLASH->OPTCR, FLASH_OPTCR_PG_OTP);}else
#endif {if(bank == FLASH_BANK_1){/* 如果操作完成,关闭PG位 */CLEAR_BIT(FLASH->CR1, FLASH_CR_PG);}else{/* 如果操作完成,关闭PG位 */CLEAR_BIT(FLASH->CR2, FLASH_CR_PG);}}}/* 解锁 */__HAL_UNLOCK(&pFlash);return status;
}

 

函数描述:

此函数主要用于Flash编程,固定编程32个字节数据。

函数参数:


  •   第1个参数是要编程的Flash类型,支持两种参数:
    •   FLASH_TYPEPROGRAM_FLASHWORD,用于芯片内部Flash编程。
    •   FLASH_TYPEPROGRAM_OTPWORD,用于芯片内部OTP存储区编程,当前的H743并没有这个区域,所以可以忽略。
  •   第2个参数是要编程的Flash地址。
  •   第3个参数是要编程到Flash的数据地址。
  •   返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。

注意事项:


  •   第2个参数的Flash地址要是32字节对齐的,即此地址对32求余等于0。
  •   第3个参数务必要是32字节的整数倍。

70.4.4 函数HAL_FLASHEx_Erase

函数原型:

HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError)
{HAL_StatusTypeDef status = HAL_OK;uint32_t sector_index;/* 检查参数 */assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));assert_param(IS_FLASH_BANK(pEraseInit->Banks));/* 上锁 */__HAL_LOCK(&pFlash);/* 无错误 */pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;/* 等待BANK1的操作完成 */if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1){if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK){status = HAL_ERROR;}}/* 等待BANK2的操作完成 */if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2){if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK){status = HAL_ERROR;}}if(status == HAL_OK){if(pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE){/* 整个BANK1或者BANK2擦除 */FLASH_MassErase(pEraseInit->VoltageRange, pEraseInit->Banks);/* 等待操作完成 */if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1){if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1) != HAL_OK){status = HAL_ERROR;}/* 如果擦除完成,关闭BANK1的BER位 */FLASH->CR1 &= (~FLASH_CR_BER);}if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2){if(FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2) != HAL_OK){status = HAL_ERROR;}/* 如果擦除操作完成,关闭BANK2的BER位 */FLASH->CR2 &= (~FLASH_CR_BER);}}else{/* 初始化扇区错误码 */*SectorError = 0xFFFFFFFFU;/* 扇区方式擦除 */for(sector_index = pEraseInit->Sector; sector_index <(pEraseInit->NbSectors + pEraseInit->Sector);sector_index++){FLASH_Erase_Sector(sector_index, pEraseInit->Banks, pEraseInit->VoltageRange);if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1){/* 等待BANK1操作完成 */status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_1);/* 如果擦除操作完成,禁止SER位 */FLASH->CR1 &= (~(FLASH_CR_SER | FLASH_CR_SNB));}if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2){/* 等待BANK2操作完成 */status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE, FLASH_BANK_2);/* 如果擦除操作完成,禁止SER位 */FLASH->CR2 &= (~(FLASH_CR_SER | FLASH_CR_SNB));}if(status != HAL_OK){/* 如果擦除出错,停止后续擦除,返回擦除异常的扇区号 */*SectorError = sector_index;break;}}}}/* 解锁 */__HAL_UNLOCK(&pFlash);return status;
}

 

函数描述:

用于内部Flash的批量擦除(BANK擦除)和扇区方式擦除。

函数参数:


  •   第1个参数是FLASH_EraseInitTypeDef类型结构体指针变量。
  •   第2个参数是错误码返回,返回0xFFFFFFFF表示全部正确,返回其它值是擦除过程中的错误扇区。
  •   返回值,返回HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。

70.5 总结

本章节就为大家讲解这么多,对于内部Flash编程来说,掌握本章节的这些知识点就够用了,更多的知识点可以看STM32H7的参考手册学习。

 


推荐阅读
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • 显卡750ti价格(750ti显卡发行价格)
    |责编:林光楠在当前这个B2BB2C逐步取代传统卖场占据主导地位的时代,通过电商、淘宝平台直接购买电脑相信已经成了不少对DIY认识不太深入的主流用户首选的配机方案。相比线下购买,网 ... [详细]
  • c语言难在哪儿,c语言难学
    本文目录一览:1、C语言难在哪?2、学C语言难 ... [详细]
  • vc写入mysql数据库无效_VC连接mysql数据库错误:libmysql.lib : fatal error LNK1113: invalid machine 解决方法...
    VC连接MySQL的配置过程在上一篇博文中,不过当你设置好,以为万事大吉的时候,运行却出现这个错误:libmysql.lib:fatalerrorLNK1113:inval ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • LVS实现负载均衡的原理LVS负载均衡负载均衡集群是LoadBalance集群。是一种将网络上的访问流量分布于各个节点,以降低服务器压力,更好的向客户端 ... [详细]
  • 本文介绍了5个基本Linux命令行工具的现代化替代品,包括du、top和ncdu。这些替代品在功能上进行了改进,提高了可用性,并且适用于现代化系统。其中,ncdu是du的替代品,它提供了与du类似的结果,但在一个基于curses的交互式界面中,重点关注占用磁盘空间较多的目录。 ... [详细]
  • 第2讲 Android Camera Native Framework 初识cameraserver进程
    本讲是AndroidCameraNativeFramework专题的第2讲,我们初识CameraServer,包括如下内容:Camera ... [详细]
  • 2月4日每日安全热点节日期间某企远程办公遭XRed攻击 ... [详细]
author-avatar
唯依爱时尚服饰
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有