W25Q64(模拟SPI)读写数据的简单应用

文章目录

  • 一、W25Q64是什么?
  • 二、使用步骤
    • 1.硬件
      • 1.引脚说明
      • 2.硬件连接
      • 3.设备ID
      • 4.内部框架
      • 5.指令集
        • 指令集1
        • 指令集2
    • 2.软件
      • 1.W25Q64引脚定义代码如下(示例):
      • 2.W25Q64初始化代码如下(示例):
      • 3.W25Q64引脚配置代码如下(示例):
      • 4.SPI读取数据代码如下(示例):
      • 5.写使能/禁止写使能代码如下(示例):
      • 6. W25Q64 判断忙状态代码如下(示例):
      • 7. W25Q64 扇区/块/芯片擦除代码如下(示例):
        • 1.W25Q64 扇区擦除
        • 2.W25Q64 块擦除
        • 3.W25Q64 芯片擦除
      • 8.W25Q64页写操作代码如下(示例):
      • 9.W25Q64读数据代码如下(示例):
      • 10.W25Q64读取设备ID代码如下(示例):
      • 11.W25Q64测试代码如下(示例):
      • 12.W25Q64测试结果:
  • 三、总结


一、W25Q64是什么?

W25Q64是一种常见的串行闪存存储器,由Winbond公司生产。它的容量为64兆比特(8兆字节),采用SPI接口进行通信。

W25Q64主要特点包括:

1.容量大:W25Q64具有64兆比特(8兆字节)的存储容量,可以存储大量数据。

2.串行接口:W25Q64使用SPI(Serial Peripheral Interface)接口进行通信,它由四条线组成:时钟线(SCK)、数据输入线(MOSI)、数据输出线(MISO)和片选线(CS)。支持SPI模式0和模式3。在SPI模式0中,数据在时钟的下降沿采样,在上升沿传输;而在SPI模式3中,数据在时钟的上升沿采样,在下降沿传输。这两种模式的时序图可以在W25Q64的数据手册中找到。

3.高速读写:W25Q64的串行闪存存储器支持高速读取和写入操作,可达到快速的数据传输速度。

4.扇区擦除:W25Q64的存储空间被划分为多个扇区,每个扇区大小为4KB。可以通过扇区擦除来更新存储的数据。

5.低功耗:W25Q64具有低功耗特性,在待机模式下能够降低功耗,延长电池寿命。

在这里插入图片描述

二、使用步骤

1.硬件

1.引脚说明

在这里插入图片描述

引脚序号引脚名称引脚功能
1CS片选引脚,用于选择芯片进行通信。当该引脚被拉低时,表示选中W25Q64芯片。
2DO数据输出引脚,用于将数据从W25Q64芯片传输到主控芯片。
3WP写保护引脚,用于控制W25Q64芯片是否进入写保护状态。当WP引脚被拉低时,芯片进入写保护状态,禁止对芯片进行写操作。
4GND地引脚,用于接地。
5DI数据输入引脚,用于将数据从主控芯片传输到W25Q64芯片。
6CLK时钟引脚,用于同步数据传输的时钟信号。
7HOLDHOLD引脚用于暂停SPI通信,以便于主控芯片在需要时保持W25Q64芯片的状态。当HOLD引脚被拉低时,芯片会暂停当前的SPI通信操作,并保持之前的状态。当HOLD引脚恢复高电平时,SPI通信可以继续。
8VCC电源引脚,用于提供芯片的电源电压:2.7V~3.6V。

2.硬件连接

从上面的引脚说明,我们不需要使用WP引脚和HOLD引脚的功能,可以将它们直接连接到VCC电源引脚上。这样做可以确保这两个引脚保持在高电平状态,以便芯片正常工作。

连接WP和HOLD引脚到VCC上的好处是简化了连接和布线过程,节省了两个单片机IO口资源。
在这里插入图片描述

3.设备ID

W25Q64的芯片ID为0xEF4017。这个ID是由该芯片制造商Winbond公司指定的,用于标识该芯片型号的唯一性。

W25Q64的芯片ID是由3个字节组成,其中第1个字节为制造商ID,固定为0xEF,代表Winbond公司;第2个字节和第3个字节表示设备类型和密度,固定为0x40和0x17,分别代表64Mbit(8MB)的串行闪存存储器。因此,W25Q64的完整芯片ID为0xEF4017。

4.内部框架

存储结构:W25Q64通常以块(Block)、扇区(Sector)和页(Page)的形式组织存储数据。W25Q64一共有128块,每个块包含16个扇区,每个扇区包含16个页,每页最多256字节。

由此可知W25Q64容量的计算方式如下:
以1页/256字节,1扇区包含16页为基础,可以得到1扇区=16256Byte)=4096(Byte)=4KB;
又因1块包含16个扇区,可以得到1块=16
4096(Byte)=65536(Byte)=64KB;
最后总共128块,128*65536(Byte)=8388608(Byte)=8MB,所以
W25Q64寻址空间:0x000000~0x7FFFFF。

在这里插入图片描述

5.指令集

在这里插入图片描述

指令集1
//W25Q64指令表1
#define W25Q64_Write_Enable						          0x06
#define W25Q64_Write_Disable                              0x04
#define W25Q64_Read_Status_register_1				      0x05
#define W25Q64_Read_Status_register_2				      0x35
#define W25Q64_Write_Status_register				      0x01
#define W25Q64_Page_Program							      0x02
#define W25Q64_Quad_Page_Program				          0x32
#define W25Q64_Block_Erase_64KB						      0xD8
#define W25Q64_Block_Erase_32KB						      0x52
#define W25Q64_Sector_Erase_4KB						      0x20
#define W25Q64_Chip_Erase							      0xC7
#define W25Q64_Erase_Suspend					          0x75
#define W25Q64_Erase_Resume							      0x7A
#define W25Q64_Power_down							      0xB9
#define W25Q64_High_Performance_Mode				      0xA3
#define W25Q64_Continuous_Read_Mode_Reset			      0xFF
#define W25Q64_Release_Power_Down_HPM_Device_ID		      0xAB
#define W25Q64_Manufacturer_Device_ID				      0x90
#define W25Q64_Read_Uuique_ID						      0x4B
#define W25Q64_JEDEC_ID								      0x9F

在这里插入图片描述

指令集2
//W25Q64指令集表2(读指令)
#define W25Q64_Read_Data						          0x03
#define W25Q64_Fast_Read						          0x0B
#define W25Q64_Fast_Read_Dual_Output				      0x3B
#define W25Q64_Fast_Read_Dual_IO					      0xBB
#define W25Q64_Fast_Read_Quad_Output				      0x6B
#define W25Q64_Fast_Read_Quad_IO					      0xEB
#define W25Q64_Octal_Word_Read_Quad_IO				      0xE3

2.软件

1.W25Q64引脚定义代码如下(示例):

/* Defines ------------------------------------------------------------------*/
#define W25Q64_GPIO_RCC    RCC_APB2Periph_GPIOA
#define W25Q64_GPIO_Port   GPIOA
#define SPI_CS_Pin         GPIO_Pin_6//CS
#define SPI_DO_Pin         GPIO_Pin_5//MISO
#define SPI_SLK_Pin        GPIO_Pin_4//CLK
#define SPI_DI_Pin         GPIO_Pin_3//MOSI//根据实际的引脚修改

2.W25Q64初始化代码如下(示例):

当 CS 为高电平时,表示不选中该芯片,芯片将不会响应 SPI 总线上传来的数据。因此,为了确保在系统上电后不会意外触发芯片操作,一般会在初始化时将 CS 引脚设置为高电平状态。

/******************************************************************************** 函数名:User_W25Q64_Init* 描述  :W25Q64初始化* 输入  :void* 输出  :void* 调用  :初始化* 备注  :
*******************************************************************************/
void User_W25Q64_Init(void)
{W25Q64_GPIO_Init();	W25Q64_DATA_Init();		
}/******************************************************************************** 函数名:W25Q64_GPIO_Init* 描述  :W25Q64引脚初始化* 输入  :void* 输出  :void* 调用  :初始化* 备注  :
*******************************************************************************/
void W25Q64_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(W25Q64_GPIO_RCC, ENABLE);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = SPI_CS_Pin | SPI_DI_Pin | SPI_SLK_Pin;		GPIO_Init(W25Q64_GPIO_Port, &GPIO_InitStructure);	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   GPIO_InitStructure.GPIO_Pin = SPI_DO_Pin;			GPIO_Init(W25Q64_GPIO_Port, &GPIO_InitStructure);		
}/******************************************************************************** 函数名:W25Q64_DATA_Init* 描述  :W25Q64数据初始化* 输入  :void* 输出  :void* 调用  :初始化* 备注  :
*******************************************************************************/
void W25Q64_DATA_Init(void)
{SPI_CS_HIGH();	
}

3.W25Q64引脚配置代码如下(示例):

/******************************************************************************** 函数名:SPI_CS_HIGH* 描述  :CS输出高电平* 输入  :void* 输出  :void* 调用  :内部调用* 备注  :*******************************************************************************/
void SPI_CS_HIGH(void)
{GPIO_SetBits(W25Q64_GPIO_Port,SPI_CS_Pin);	
}/******************************************************************************** 函数名:SPI_CS_LOW* 描述  :CS输出低电平* 输入  :void* 输出  :void* 调用  :内部调用* 备注  :*******************************************************************************/
void SPI_CS_LOW(void)
{GPIO_ResetBits(W25Q64_GPIO_Port,SPI_CS_Pin);		
}/******************************************************************************** 函数名:SPI_SLK_HIGH* 描述  :SLK输出高电平* 输入  :void* 输出  :void* 调用  :内部调用* 备注  :*******************************************************************************/
void SPI_SLK_HIGH(void)
{GPIO_SetBits(W25Q64_GPIO_Port,SPI_SLK_Pin);	
}/******************************************************************************** 函数名:SPI_SLK_LOW* 描述  :SLK输出低电平* 输入  :void* 输出  :void* 调用  :内部调用* 备注  :*******************************************************************************/
void SPI_SLK_LOW(void)
{GPIO_ResetBits(W25Q64_GPIO_Port,SPI_SLK_Pin);		
}/******************************************************************************** 函数名:SPI_SLK_HIGH* 描述  :SI输出高电平* 输入  :void* 输出  :void* 调用  :内部调用* 备注  :*******************************************************************************/
void SPI_DI_HIGH(void)
{GPIO_SetBits(W25Q64_GPIO_Port,SPI_DI_Pin);	
}/******************************************************************************** 函数名:SPI_DI_LOW* 描述  :SI输出低电平* 输入  :void* 输出  :void* 调用  :内部调用* 备注  :*******************************************************************************/
void SPI_DI_LOW(void)
{GPIO_ResetBits(W25Q64_GPIO_Port,SPI_DI_Pin);		
}/******************************************************************************** 函数名:Read_DO_Level* 描述  :读取DO电平* 输入  :void* 输出  :void* 调用  :内部调用* 备注  :*******************************************************************************/
uint8_t Read_DO_Level(void)
{return GPIO_ReadInputDataBit(W25Q64_GPIO_Port,SPI_DO_Pin);
}

4.SPI读取数据代码如下(示例):

我这里SPI读数据是采用了SPI模式0的方式,在这种模式下,数据在时钟的下降沿进行采样,并且在时钟的上升沿进行传输,最后将数据保存到Outdata变量中。

SPI模式0是指在时钟空闲时,时钟线为低电平,在读取数据时,数据从MISO引脚上升沿进行采样,这是W25Q64芯片的SPI通信方式之一。

/******************************************************************************** 函数名:SPI_SendByte* 描述  :SPI读取数据* 输入  :data* 输出  :Outdata* 调用  :内部调用* 备注  :通过发送一个字节的数据并同时接收一个字节的数据,实现了数据的读取操作。*******************************************************************************/
uint8_t SPI_SendByte(uint8_t data)
{uint8_t i, Outdata = 0x00;	for (i = 0; i < 8; i ++){if(data & (0x80 >> i))//在下降沿,把数据移到MOSI总线上{SPI_DI_HIGH();}else{SPI_DI_LOW();}		SPI_SLK_HIGH();	// 上升沿读取数据if (Read_DO_Level()){Outdata |= (0x80 >> i);	//掩码提取数据}SPI_SLK_LOW();	// 下降沿}	return Outdata;
}

5.写使能/禁止写使能代码如下(示例):

在进行写入操作之前,需要先调用写使能命令来允许写入操作,写入完成后再调用禁止写使能命令来禁止写入操作。如果不调用禁止写使能命令,则W25Q64芯片仍然处于写入状态,可能会导致数据错误或者芯片损坏。

写使能/禁止写使能的时序图在规格书上有,这里就不贴出来了。


/******************************************************************************** 函数名:W25Q64_WriteEnable* 描述  :W25Q64发送写使能命令* 输入  :void* 输出  :void* 调用  :内部调用* 备注  :*******************************************************************************/
void W25Q64_WriteEnable(void)
{SPI_CS_LOW();SPI_SendByte(W25Q64_Write_Enable);SPI_CS_HIGH();
}/******************************************************************************** 函数名:W25Q64_WriteDisable* 描述  :W25Q64发送禁止写使能命令* 输入  :void* 输出  :void* 调用  :内部调用* 备注  :*******************************************************************************/
void W25Q64_WriteDisable(void)
{SPI_CS_LOW();SPI_SendByte(W25Q64_Write_Disable);SPI_CS_HIGH();
}

6. W25Q64 判断忙状态代码如下(示例):

该函数的作用是等待 W25Q64 芯片的忙状态结束。在进行一些与 Flash 写入相关的操作之前,需要检查 W25Q64 芯片是否处于忙状态,以确保写入操作的正确性。该函数使用 SPI 协议与 W25Q64 通信,读取状态寄存器中的信息,并检查其中的位 0 是否为 0。如果位 0 为 0,表示忙状态已经结束,函数退出;否则,继续等待。如果等待时间超过了设定的 Timeout 时间,函数将会输出错误信息并退出。

/******************************************************************************** 函数名:W25Q64_WaitForBusyStatus* 描述  :等待 W25Q64 芯片的忙状态结束* 输入  :void* 输出  :void* 调用  :内部调用* 备注  :*******************************************************************************/
void W25Q64_WaitForBusyStatus(void)
{uint16_t Timeout = 0xFFFF;SPI_CS_LOW();SPI_SendByte(W25Q64_Read_Status_register_1);    while (Timeout > 0){uint8_t status = SPI_SendByte(W25Q64_DUMMY_BYTE);if ((status & 0x01) == 0)// 检查忙状态是否结束{break;}    Timeout--;if (Timeout == 0){printf("W25Q64 ERROR \r\n");break;}}    SPI_CS_HIGH();
}

7. W25Q64 扇区/块/芯片擦除代码如下(示例):

1.W25Q64 扇区擦除

W25Q64 芯片的扇区大小为 4KB


/******************************************************************************** 函数名:W25Q64_SectorErase* 描述  :扇区擦除函数* 输入  :Sector_Address		* 输出  :void* 调用  :内部调用* 备注  :在执行写入操作前要进行擦除*******************************************************************************/
void W25Q64_SectorErase(uint32_t Sector_Address)
{W25Q64_WriteEnable();//W25Q64写使能	SPI_CS_LOW();	SPI_SendByte(W25Q64_Sector_Erase_4KB);	SPI_SendByte(Sector_Address >> 16);//24位扇区地址SPI_SendByte(Sector_Address >> 8);  SPI_SendByte(Sector_Address);		  SPI_CS_HIGH();W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	W25Q64_WriteDisable();//W25Q64禁止写使能
}
2.W25Q64 块擦除

W25Q64 芯片的块大小为 64KB


/******************************************************************************** 函数名:W25Q64_BlockErase* 描述  :块擦除函数* 输入  :Address		* 输出  :void* 调用  :内部调用* 备注  :在执行写入操作前要进行擦除*******************************************************************************/
void W25Q64_BlockErase(uint32_t Block_Address)
{W25Q64_WriteEnable();//W25Q64写使能	 SPI_CS_LOW();SPI_SendByte(W25Q64_Block_Erase_64KB);SPI_SendByte((Block_Address & 0xFF0000) >> 16);//24位扇区地址SPI_SendByte((Block_Address & 0xFF00) >> 8);SPI_SendByte(Block_Address & 0xFF);SPI_CS_HIGH();    W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	W25Q64_WriteDisable();//W25Q64禁止写使能
}
3.W25Q64 芯片擦除

W25Q64 芯片的芯片大小为 8MB

/******************************************************************************** 函数名:W25Q64_ChipErase* 描述  :芯片擦除函数* 输入  :void		* 输出  :void* 调用  :内部调用* 备注  :在执行写入操作前要进行擦除*******************************************************************************/
void W25Q64_ChipErase(void)
{W25Q64_WriteEnable();//W25Q64写使能	 SPI_CS_LOW();SPI_SendByte(W25Q64_Chip_Erase);SPI_CS_HIGH();W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	W25Q64_WriteDisable();//W25Q64禁止写使能
}

这些擦除函数之间的不同在于擦除的范围。扇区擦除函数擦除的是单个扇区(4KB)的数据;块擦除函数擦除的是单个块(64KB)的数据;而芯片擦除函数则会擦除整个芯片(8MB)的数据。根据实际需要,选择适当的擦除函数进行操作。

注意,如果是选用芯片擦除函数,W25Q64_WaitForBusyStatus();函数中的等待时间uint16_t Timeout = 0xFFFF;需更改为uint32_t Timeout = 0xFFFFFFFF;

8.W25Q64页写操作代码如下(示例):

当使用 W25Q64 芯片进行页写操作时,需要考虑到写入字节数大于 256 字节和不大于 256 字节的两种情况。

如果小于等于 256 字节,直接进行一次写操作;如果大于 256 字节,则先写入前 256 字节的数据,然后循环写入剩余数据,同时需要在每次写入之前等待上次写操作完成。


/******************************************************************************** 函数名:W25Q64_PageProgram* 描述  :W25Q64页写操作* 输入  :address	 要写入的起始地址*data	 要写入的数据缓冲区指针。dataSize	 要写入的数据大小,单位为字节。* 输出  :void* 调用  :内部调用* 备注  :*******************************************************************************/
void W25Q64_PageWrite(uint32_t address, uint8_t *data, uint16_t dataSize)
{W25Q64_WriteEnable();//W25Q64写使能    SPI_CS_LOW();SPI_SendByte(W25Q64_Page_Program);SPI_SendByte((address & 0xFF0000) >> 16);SPI_SendByte((address & 0xFF00) >> 8);SPI_SendByte(address & 0xFF);    if (dataSize <= 256){for (uint16_t i = 0; i < dataSize; i++){SPI_SendByte(data[i]);}}else{for (uint16_t i = 0; i < 256; i++){SPI_SendByte(data[i]);}dataSize -= 256;data += 256;        // 写入剩余数据W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	address += 256;        while (dataSize > 0){W25Q64_WriteEnable();//W25Q64写使能 SPI_CS_LOW();SPI_SendByte(W25Q64_Page_Program);SPI_SendByte((address & 0xFF0000) >> 16);SPI_SendByte((address & 0xFF00) >> 8);SPI_SendByte(address & 0xFF);       uint16_t chunkSize = (dataSize > 256) ? 256 : dataSize;for (uint16_t i = 0; i < chunkSize; i++){SPI_SendByte(data[i]);}       SPI_CS_HIGH();W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	         dataSize -= chunkSize;data += chunkSize;address += chunkSize;}}    SPI_CS_HIGH();W25Q64_WaitForBusyStatus();//等待 W25Q64 芯片的忙状态结束	W25Q64_WriteDisable();//W25Q64禁止写使能
}

9.W25Q64读数据代码如下(示例):

/******************************************************************************** 函数名:W25Q64_ReadData* 描述  :W25Q64读数据* 输入  :void* 输出  :void* 调用  :* 备注  :*******************************************************************************/
void W25Q64_ReadData(uint32_t address, uint8_t *data, uint16_t dataSize)
{uint16_t i;SPI_CS_LOW();SPI_SendByte(W25Q64_Read_Data);SPI_SendByte((address & 0xFF0000) >> 16);SPI_SendByte((address & 0xFF00) >> 8);SPI_SendByte(address & 0xFF);    for (i = 0; i < dataSize; i++){data[i] = SPI_SendByte(W25Q64_DUMMY_BYTE);}    SPI_CS_HIGH();
}

10.W25Q64读取设备ID代码如下(示例):

W25Q64的芯片ID为0xEF4017,用于标识该芯片型号的唯一性。

/******************************************************************************** 函数名:W25Q64_ReadID* 描述  :W25Q64读取设备ID* 输入  :*ID	存储ID的变量	* 输出  :void* 调用  :内部调用* 备注  :EF4017*******************************************************************************/
void W25Q64_ReadID(uint32_t *ID)
{SPI_CS_LOW();SPI_SendByte(W25Q64_JEDEC_ID);         // 读ID号指令*ID = SPI_SendByte(W25Q64_DUMMY_BYTE); // 厂商ID,默认为0xEF*ID <<= 8;*ID |= SPI_SendByte(W25Q64_DUMMY_BYTE); // 设备ID,表示存储类型,默认为0x40*ID <<= 8;*ID |= SPI_SendByte(W25Q64_DUMMY_BYTE); // 设备ID,表示容量,默认为0x17SPI_CS_HIGH();
}

11.W25Q64测试代码如下(示例):

/******************************************************************************** 函数名:W25Q64_Test* 描述  :W25Q64测试函数* 输入  :void* 输出  :void* 调用  :测试* 备注  :*******************************************************************************/
void W25Q64_Test(void)
{uint8_t i,j;	W25Q64_ReadID(&W25Q64_ID);	OLED_ShowString(1, 1, "ID:");OLED_ShowString(2, 1, "W:");OLED_ShowString(3, 1, "R:");	OLED_ShowHexNum(1, 5, W25Q64_ID, 6);	//printf("W25Q64_ID=%d\r\n",W25Q64_ID);	W25Q64_SectorErase(0x000000);// 擦除扇区的起始地址W25Q64_PageWrite(0x000000, TestWrite, 4);// 写入数据	W25Q64_ReadData(0x000000, TestRead, 4);	// 读取数据		for(i = 0;i < 4; i++){OLED_ShowHexNum(2, 3+i*3, TestWrite[i], 2);}for(j = 0;j < 4; j++){OLED_ShowHexNum(3, 3+j*3, TestRead[j], 2);}		
}

12.W25Q64测试结果:

我们可以在OLED显示屏看到W25Q64的ID为EF4017,测试写入和读出的数据是一样的。

在这里插入图片描述


三、总结

总的来说,使用 W25Q64 需要熟悉其相关的指令集、通信协议和时序要求,合理地设计读写操作流程,并注意处理特殊情况,比如数据跨页写入时的处理等。感谢你的观看,谢谢!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【IC前端虚拟项目】MVU模块方案与背景熟悉

【IC前端虚拟项目】数据搬运指令处理模块前端实现虚拟项目说明-CSDN博客 mvu这个模块是干嘛用的呢&#xff1f;从这个名字就可以看出来move_unit&#xff0c;应该是做数据搬运的。很多指令级中都会有数据搬运的指令&#xff0c;这类指令的作用一般是在片内片外缓存以及通用专用…

Java基础语法之抽象类和接口

抽象类 什么是抽象类 并不是所有的类都是用来描述对象的&#xff0c;这样的类就是抽象类 例如&#xff0c;矩形&#xff0c;三角形都是图形&#xff0c;但图形类无法去描述具体图形&#xff0c;所以它的draw方法无法具体实现&#xff0c;这个方法就可以没设计成抽象方法&…

常用模块之(time/datetime)

【 一 】时间模块&#xff08;time/datetime&#xff09; 【 二 】 表示时间的三种方式 *时间戳&#xff08;Timestamp&#xff09;是指1970年1月1日00:00:00开始计算的偏移量。可以使用time模块中的time()函数获取当前时间的时间戳&#xff0c;也可以使用datetime模块中的tim…

大创项目推荐 深度学习 python opencv 实现人脸年龄性别识别

文章目录 0 前言1 项目课题介绍2 关键技术2.1 卷积神经网络2.2 卷积层2.3 池化层2.4 激活函数&#xff1a;2.5 全连接层 3 使用tensorflow中keras模块实现卷积神经网络4 Keras介绍4.1 Keras深度学习模型4.2 Keras中重要的预定义对象4.3 Keras的网络层构造 5 数据集处理训练5.1 …

ElasticSearch学习篇8_Lucene之数据存储(Stored Field、DocValue、BKD Tree)

前言 Lucene全文检索主要分为索引、搜索两个过程&#xff0c;对于索引过程就是将文档磁盘存储然后按照指定格式构建索引文件&#xff0c;其中涉及数据存储一些压缩、数据结构设计还是很巧妙的&#xff0c;下面主要记录学习过程中的StoredField、DocValue以及磁盘BKD Tree的一些…

PyQt6 QScrollBar滚动条控件

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计48条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

录制第一个jmeter性能测试脚本2(http协议)_图书管理系统

我们手工编写了一个测试计划&#xff0c;现在我们通过录制的方式来实现那个测试计划。也就是说‘’测试计划目标和上一节类似&#xff1a;让5个用户在2s内登录图书管理系统&#xff0c;然后进入 页面进行查看。 目录 欢迎访问我的免费课程 PPT、安装包、视频应有尽有&#xff…

【微服务】Spring Aop原理深入解析

目录 一、前言 二、aop概述 2.1 什么是AOP 2.2 AOP中的一些概念 2.2.1 aop通知类型 2.3 AOP实现原理 2.3.1 aop中的代理实现 2.4 静态代理与动态代理 2.4.1 静态代理实现 三、 jdk动态代理与cglib代理 3.1 jdk动态代理 3.1.1 jdk代理示例 3.1.2 jdk动态代理模拟实现…

【OpenCV】 OpenCV 源码编译并实现 CUDA 加速 (Windows)

OpenCV 源码编译并实现 CUDA 加速 Windows 1. 环境准备1.1 软件环境1. 2 源码下载 2. CMake编译项目2.1 创建cmake项目2.2 设置编译配置2.3 解决异常2.3.1 文件下载异常2.3.2 解决CUDA版本异常 2.4 编译项目 3. Visual Studio 编译项目4. 项目测试5. 总结 OpenCV是一个基于Apac…

Ubuntu 常用命令之 ln 命令用法介绍

ln命令在Ubuntu系统中用于创建硬链接或符号链接。硬链接是指向文件的物理地址&#xff0c;而符号链接&#xff08;也称为软链接&#xff09;是指向文件路径的引用。 命令格式&#xff1a;ln [选项]... [-T] 目标&#xff08;源文件&#xff09; 链接&#xff08;目标文件&…

【FPGA】Verilog:编码器 | 实现 4 到 2 编码器

0x00 编码器&#xff08;Encoder&#xff09; 编码器与解码器相反。当多台设备向计算机提供输入时&#xff0c;编码器会为每一个输入生成一个与设备相对应的信号&#xff0c;因此有多少比特就有多少输出&#xff0c;以数字形式表示输入的数量。 例如&#xff0c;如果有四个输…

NAS搭建WebDAV服务同步Zotero科研文献

文章目录 一、Zotero安装教程二、群晖NAS WebDAV设置三、Zotero设置四、使用公网地址同步Zotero文献库五、使用永久固定公网地址同步Zotero文献库 Zotero 是一款全能型 文献管理器,可以 存储、管理和引用文献&#xff0c;不但免费&#xff0c;功能还很强大实用。 ​ Zotero 支…

重新认识Word——尾注

重新认识Word——尾注 参考文献格式文献自动生成器插入尾注将数字带上方括号将参考文献中的标号改为非上标 多处引用一篇文献多篇文献被一处引用插入尾注有横线怎么删除&#xff1f;删除尾注 前面我们学习了如何给图片&#xff0c;公式自动添加编号&#xff0c;今天我们来看看毕…

LSTM ——作业

习题6-4 推导LSTM网络中参数的梯度&#xff0c; 并分析其避免梯度消失的效果 习题6-3P 编程实现下图LSTM运行过程 1. 使用Numpy实现LSTM算子 import numpy as np # 创建一个numpy数组x&#xff0c;它是一个4x4的矩阵&#xff0c;包含9个元素 x np.array([[1, 0, 0, 1],[3, …

Unity中URP下的菲涅尔效果实现(URP下的法线和视线向量怎么获取)

文章目录 前言一、实现思路二、实现原理我们可以由下图直观的感受到 N 与 L夹角越小&#xff0c;点积越接近&#xff08;白色&#xff09;1。越趋近90&#xff0c;点积越接近0&#xff08;黑色&#xff09; 三、实现URP下的菲涅尔效果1、我们新建一个Shader&#xff0c;修改为最…

安全密码(字符串)

#include <stdio.h> #include <stdbool.h> #include <string.h> bool is_secure_password(const char* password); int main() {int M;char password[51];// 读取输入中的密码数量 Mscanf("%d", &M);// 处理每个密码for (int i 0; i < M; …

Pytorch:Tensorboard简要学习

目录 一、TensorBoard简介二、TensorBoard的安装与启动Tensorboard的安装Tensorboard的启动 三、TensorBoard的简单使用3.1 SummaryWriter()3.2 add_scalar()和add_scalars()3.3 add_histogram()3.4 模型指标监控 四、总结参考博客 一、TensorBoard简介 TensorBoard 是Google开…

17.Oracle中instr()函数查询字符位置

1、instr()函数的格式 &#xff08;俗称&#xff1a;字符查找函数&#xff09; 格式一&#xff1a;instr( string1, string2 ) // instr(源字符串, 目标字符串) 格式二&#xff1a;instr( string1, string2 [, start_position [, nth_appearance ] ] ) // instr(源字符…

typescript使用解构传参

看下面这个函数 interface Student {id: number;name: string;class: string;sex: string;}function matriculation(student: Student) {//...}我们要调用它,就需要传递一个实现了Student约束的对象进去 interface Student {id: number;name: string;class: string;sex: string…

C语言:将三个数从大到小输出

#include<stdio.h> int main() {int a 0;int b 0;int c 0;printf("请输入abc的值&#xff1a;");scanf_s("%d%d%d", &a, &b, &c);if (b > a){int tmp a;a b;b tmp;}if (c > a){int tmp a;a c;c tmp;}if (b < c){int t…