当前位置: 首页 > news >正文

STM32CUBUMX配置FLASH(W25Q128)--保姆级教程

————————————————————————————————————
⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大三学生。
⏩最近在开发一个STM32H723ZGT6的板子,使用STM32CUBEMX做了很多驱动,包括ADC、UART、RS485、EEPROM(IIC)、FLASH(SPI)等等。
⏩本篇文章对STM32CUBEMX配置RS485做一个详细的使用教程。
⏩感谢你的阅读,不对的地方欢迎指正。
————————————————————————————————————

FLASH

  • W25Q128简介
  • 实验环境
  • MX配置
  • 驱动代码
  • 测试结果

W25Q128简介

W25Q128是华邦公司推出的一款SPI接口的NOR Flash芯片,其存储空间为128Mbit,相当于16M字节。W25Q128V芯片是串行闪存,可以通过标准/两线/四线SPI控制。
W25Q128JV阵列被组织成65536个可编程页面,每个页面256字节。一次最多可编程256个字节。页面可以按16组(4KB扇区擦除)、128组(32KB块擦除)、256组(64KB块擦除或整个芯片(芯片擦除)擦除。W25Q128JV分别具有4096个可擦除扇区和256个可擦除块。小4KB扇区允许在需要数据和参数存储的应用中具有更大的灵活性。
在这里插入图片描述
在这里插入图片描述
具体可以看这个:通过数据手册带你全面解析闪存芯片W25Q128

实验环境

  • STM32H723ZGT6开发板
  • USB转串口
  • W25Q128

硬件连接:
在这里插入图片描述

MX配置

板子、时钟、调试之类的配置就不说了,具体可以看看这篇:
STM32CUBEMX配置ADC(多通道轮询)(STM32H7)–保姆级教程
下面是SPI的具体配置
在这里插入图片描述
CS引脚配置
在这里插入图片描述
在这里插入图片描述

驱动代码

w25qxx.h

#ifndef W25Q128_W25QXX_H_
#define W25Q128_W25QXX_H_#include "stm32H7xx_hal.h" //HAL库文件声明//FLASH_CS 片选引脚定义
#define W25Q128_CS_GPIO_Port GPIOB
#define W25Q128_CS_Pin GPIO_PIN_12//25系列FLASH芯片厂商与容量代号(厂商代号EF)
#define W25Q80    0XEF13
#define W25Q16    0XEF14
#define W25Q32    0XEF15
#define W25Q64    0XEF16
#define W25Q128   0XEF17
#define W25Q256 0XEF18
#define EX_FLASH_ADD 0x000000 //W25Q128的地址是24位宽
extern uint16_t W25QXX_TYPE;//定义W25QXX芯片型号
extern SPI_HandleTypeDef hspi2;
//
//指令表
#define W25X_WriteEnable             0x06
#define W25X_WriteDisable            0x04
#define W25X_ReadStatusReg1      0x05
#define W25X_ReadStatusReg2      0x35
#define W25X_ReadStatusReg3      0x15
#define W25X_WriteStatusReg1         0x01
#define W25X_WriteStatusReg2         0x31
#define W25X_WriteStatusReg3     0x11
#define W25X_ReadData             0x03
#define W25X_FastReadData         0x0B
#define W25X_FastReadDual         0x3B
#define W25X_PageProgram          0x02
#define W25X_BlockErase              0xD8
#define W25X_SectorErase          0x20
#define W25X_ChipErase            0xC7
#define W25X_PowerDown            0xB9
#define W25X_ReleasePowerDown    0xAB
#define W25X_DeviceID             0xAB
#define W25X_ManufactDeviceID    0x90
#define W25X_JedecDeviceID           0x9F
#define W25X_Enable4ByteAddr         0xB7
#define W25X_Exit4ByteAddr        0xE9
uint8_t SPI2_ReadWriteByte(uint8_t  TxData);//SPI2总线底层读写
void W25QXX_CS(uint8_t a);//W25QXX片选引脚控制
uint8_t W25QXX_Init(void);//初始化W25QXX函数
uint16_t  W25QXX_ReadID(void);//读取FLASH ID
uint8_t W25QXX_ReadSR(uint8_t regno);//读取状态寄存器
void W25QXX_4ByteAddr_Enable(void);//使能4字节地址模式
void W25QXX_Write_SR(uint8_t regno,uint8_t  sr);//写状态寄存器
void W25QXX_Write_Enable(void);//写使能
void W25QXX_Write_Disable(void);//写保护
void W25QXX_Write_NoCheck(uint8_t*  pBuffer,uint32_t WriteAddr,uint16_t  NumByteToWrite);//无检验写SPI FLASH
void W25QXX_Read(uint8_t* pBuffer,uint32_t  ReadAddr,uint16_t NumByteToRead);//读取flash
void W25QXX_Write(uint8_t* pBuffer,uint32_t  WriteAddr,uint16_t NumByteToWrite);//写入flash
void W25QXX_Erase_Chip(void);//整片擦除
void W25QXX_Erase_Sector(uint32_t  Dst_Addr);//扇区擦除
void W25QXX_Wait_Busy(void);//等待空闲
void W25QXX_PowerDown(void);//进入掉电模式
void W25QXX_WAKEUP(void);//唤醒
void W25QXX_Write_Page(uint8_t*  pBuffer,uint32_t WriteAddr,uint16_t  NumByteToWrite);
void delay_us(uint32_t us); //C文件中的函数声明#endif /* W25Q128_W25QXX_H_ */

w25qxx.c

#include "w25qxx.h"
#include "main.h"
uint16_t W25QXX_TYPE=W25Q128;//默认是W25Q128
//4Kbytes为一个Sector
//16个扇区为1个Block
//W25Q128
//容量为16M字节,共有128个Block,4096个Sector
//SPI2总线读写一个字节
//参数是写入的字节,返回值是读出的字节
uint8_t SPI2_ReadWriteByte(uint8_t TxData)
{uint8_t Rxdata;//定义一个变量RxdataHAL_SPI_TransmitReceive(&hspi2,&TxData,&Rxdata,1,1000);//调用固件库函数收发数据return Rxdata;//返回收到的数据
}
void W25QXX_CS(uint8_t a)//软件控制函数(0为低电平,其他值为高电平)
{if(a==0)HAL_GPIO_WritePin(W25Q128_CS_GPIO_Port, W25Q128_CS_Pin, GPIO_PIN_RESET);else  HAL_GPIO_WritePin(W25Q128_CS_GPIO_Port,  W25Q128_CS_Pin, GPIO_PIN_SET);
}
//初始化SPI FLASH的IO口
uint8_t W25QXX_Init(void)
{uint8_t temp;//定义一个变量tempW25QXX_CS(1);//0片选开启,1片选关闭W25QXX_TYPE = W25QXX_ReadID();//读取FLASH  ID.if(W25QXX_TYPE == W25Q256)//SPI FLASH为W25Q256时才用设置为4字节地址模式{temp = W25QXX_ReadSR(3);//读取状态寄存器3,判断地址模式if((temp&0x01)==0)//如果不是4字节地址模式,则进入4字节地址模式{W25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(W25X_Enable4ByteAddr);//发送进入4字节地址模式指令W25QXX_CS(1);//0片选开启,1片选关闭}}if(W25QXX_TYPE==W25Q256||W25QXX_TYPE==W25Q128||W25QXX_TYPE==W25Q64||W25QXX_TYPE==W25Q32||W25QXX_TYPE==W25Q16||W25QXX_TYPE==W25Q80)return 0; else return 1;//如果读出ID是现有型号列表中的一个,则识别芯片成功!
}
//读取W25QXX的状态寄存器,W25QXX一共有3个状态寄存器
//状态寄存器1:
//BIT7  6   5   4   3   2   1   0
//SPR   RV  TB BP2 BP1 BP0 WEL BUSY
//SPR:默认0,状态寄存器保护位,配合WP使用
//TB,BP2,BP1,BP0:FLASH区域写保护设置
//WEL:写使能锁定
//BUSY:忙标记位(1,忙;0,空闲)
//默认:0x00
//状态寄存器2:
//BIT7  6   5   4   3   2   1   0
//SUS   CMP LB3 LB2 LB1 (R) QE  SRP1
//状态寄存器3:
//BIT7      6    5    4   3   2   1   0
//HOLD/RST  DRV1 DRV0 (R) (R) WPS (R) (R)
//regno:状态寄存器号,范:1~3
//返回值:状态寄存器值
uint8_t W25QXX_ReadSR(uint8_t regno)
{uint8_t byte=0,command=0;switch(regno){case 1:command=W25X_ReadStatusReg1;//读状态寄存器1指令break;case 2:command=W25X_ReadStatusReg2;//读状态寄存器2指令break;case 3:command=W25X_ReadStatusReg3;//读状态寄存器3指令break;default:command=W25X_ReadStatusReg1;//读状态寄存器1指令break;}W25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(command);//发送读取状态寄存器命令byte=SPI2_ReadWriteByte(0Xff);//读取一个字节W25QXX_CS(1);//0片选开启,1片选关闭return byte;//返回变量byte
}
//写W25QXX状态寄存器
void W25QXX_Write_SR(uint8_t regno,uint8_t  sr)
{uint8_t command=0;switch(regno){case 1:command=W25X_WriteStatusReg1;//写状态寄存器1指令break;case 2:command=W25X_WriteStatusReg2;//写状态寄存器2指令break;case 3:command=W25X_WriteStatusReg3;//写状态寄存器3指令break;default:command=W25X_WriteStatusReg1;break;}W25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(command);//发送写取状态寄存器命令SPI2_ReadWriteByte(sr);//写入一个字节W25QXX_CS(1);//0片选开启,1片选关闭
}
//W25QXX写使能
//将WEL置位
void W25QXX_Write_Enable(void)
{W25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(W25X_WriteEnable);//发送写使能W25QXX_CS(1);//0片选开启,1片选关闭
}
//W25QXX写禁止
//将WEL清零
void W25QXX_Write_Disable(void)
{W25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(W25X_WriteDisable);//发送写禁止指令W25QXX_CS(1);//0片选开启,1片选关闭
}
//读取芯片ID
//高8位是厂商代号(本程序不判断厂商代号)
//低8位是容量大小
//0XEF13型号为W25Q80
//0XEF14型号为W25Q16
//0XEF15型号为W25Q32
//0XEF16型号为W25Q64
//0XEF17型号为W25Q128(目前洋桃2号开发板使用128容量芯片)
//0XEF18型号为W25Q256
uint16_t W25QXX_ReadID(void)
{uint16_t Temp = 0;W25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(0x90);//发送读取ID命令SPI2_ReadWriteByte(0x00);SPI2_ReadWriteByte(0x00);SPI2_ReadWriteByte(0x00);Temp|=SPI2_ReadWriteByte(0xFF)<<8;Temp|=SPI2_ReadWriteByte(0xFF);W25QXX_CS(1);//0片选开启,1片选关闭return Temp;
}
//读取SPI FLASH
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void W25QXX_Read(uint8_t* pBuffer,uint32_t  ReadAddr,uint16_t NumByteToRead)
{uint16_t i;W25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(W25X_ReadData);//发送读取命令if(W25QXX_TYPE==W25Q256)//如果是W25Q256的话地址为4字节的,要发送最高8位{SPI2_ReadWriteByte((uint8_t)((ReadAddr)>>24));}SPI2_ReadWriteByte((uint8_t)((ReadAddr)>>16));//发送24bit地址SPI2_ReadWriteByte((uint8_t)((ReadAddr)>>8));SPI2_ReadWriteByte((uint8_t)ReadAddr);for(i=0;i<NumByteToRead;i++){pBuffer[i]=SPI2_ReadWriteByte(0XFF);//循环读数}W25QXX_CS(1);//0片选开启,1片选关闭
}
//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
void W25QXX_Write_Page(uint8_t*  pBuffer,uint32_t WriteAddr,uint16_t  NumByteToWrite)
{uint16_t i;W25QXX_Write_Enable();//SET WELW25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(W25X_PageProgram);//发送写页命令if(W25QXX_TYPE==W25Q256)//如果是W25Q256的话地址为4字节的,要发送最高8位{SPI2_ReadWriteByte((uint8_t)((WriteAddr)>>24));}SPI2_ReadWriteByte((uint8_t)((WriteAddr)>>16));//发送24bit地址SPI2_ReadWriteByte((uint8_t)((WriteAddr)>>8));SPI2_ReadWriteByte((uint8_t)WriteAddr);for(i=0;i<NumByteToWrite;i++)SPI2_ReadWriteByte(pBuffer[i]);//循环写数W25QXX_CS(1);//0片选开启,1片选关闭W25QXX_Wait_Busy();//等待写入结束
}
//无检验写SPI FLASH
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck(uint8_t*  pBuffer,uint32_t WriteAddr,uint16_t  NumByteToWrite)
{uint16_t pageremain;pageremain=256-WriteAddr%256; //单页剩余的字节数if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节while(1){W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);if(NumByteToWrite==pageremain)break;//写入结束了else //NumByteToWrite>pageremain{pBuffer+=pageremain;WriteAddr+=pageremain;NumByteToWrite-=pageremain;            //减去已经写入了的字节数if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节else pageremain=NumByteToWrite;     //不够256个字节了}};
}
//写SPI FLASH
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
uint8_t W25QXX_BUFFER[4096];
void W25QXX_Write(uint8_t* pBuffer,uint32_t  WriteAddr,uint16_t NumByteToWrite)
{uint32_t secpos;uint16_t secoff;uint16_t secremain;uint16_t i;uint8_t* W25QXX_BUF;W25QXX_BUF=W25QXX_BUFFER;secpos=WriteAddr/4096;//扇区地址secoff=WriteAddr%4096;//在扇区内的偏移secremain=4096-secoff;//扇区剩余空间大小//printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节while(1){W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容for(i=0;i<secremain;i++)//校验数据{if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除}if(i<secremain)//需要擦除{W25QXX_Erase_Sector(secpos);//擦除这个扇区for(i=0;i<secremain;i++)//复制{W25QXX_BUF[i+secoff]=pBuffer[i];}W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区}else  W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.if(NumByteToWrite==secremain)break;//写入结束了else//写入未结束{secpos++;//扇区地址增1secoff=0;//偏移位置为0pBuffer+=secremain;  //指针偏移WriteAddr+=secremain;//写地址偏移NumByteToWrite-=secremain;//字节数递减if(NumByteToWrite>4096)secremain=4096;//下一个扇区还是写不完else  secremain=NumByteToWrite;//下一个扇区可以写完了}};
}
//擦除整个芯片
//等待时间超长...
void W25QXX_Erase_Chip(void)
{W25QXX_Write_Enable();//SET WELW25QXX_Wait_Busy();//等待忙状态W25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(W25X_ChipErase);//发送片擦除命令W25QXX_CS(1);//0片选开启,1片选关闭W25QXX_Wait_Busy();//等待芯片擦除结束
}
//擦除一个扇区
//Dst_Addr:扇区地址 根据实际容量设置
//擦除一个扇区的最少时间:150ms
void W25QXX_Erase_Sector(uint32_t Dst_Addr)
{Dst_Addr*=4096;W25QXX_Write_Enable();//SET WELW25QXX_Wait_Busy();W25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(W25X_SectorErase);//发送扇区擦除指令if(W25QXX_TYPE==W25Q256)//如果是W25Q256的话地址为4字节的,要发送最高8位{SPI2_ReadWriteByte((uint8_t)((Dst_Addr)>>24));}SPI2_ReadWriteByte((uint8_t)((Dst_Addr)>>16));//发送24bit地址SPI2_ReadWriteByte((uint8_t)((Dst_Addr)>>8));SPI2_ReadWriteByte((uint8_t)Dst_Addr);W25QXX_CS(1);//0片选开启,1片选关闭W25QXX_Wait_Busy();//等待擦除完成
}
//等待空闲
void W25QXX_Wait_Busy(void)
{while((W25QXX_ReadSR(1)&0x01)==0x01);//等待BUSY位清空
}
//进入掉电模式
void W25QXX_PowerDown(void)
{W25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(W25X_PowerDown);//发送掉电命令 0xB9W25QXX_CS(1);//0片选开启,1片选关闭delay_us(3);//等待TPD
}
//唤醒
void W25QXX_WAKEUP(void)
{W25QXX_CS(0);//0片选开启,1片选关闭SPI2_ReadWriteByte(W25X_ReleasePowerDown);//发送电源唤醒指令 0xABW25QXX_CS(1);//0片选开启,1片选关闭delay_us(3);//等待TRES1
}
//延时
void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
{uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数while (delay--); //循环delay次,达到1微秒延时
}

main.c

		//W25Q128测试程序device_id = W25QXX_ReadID();printf("\r\nW25Q64 Device ID is 0x%04x\r\n", device_id);/* 为了验证,首先读取要写入地址处的数据 */printf("-------- read data before write -----------\r\n");W25QXX_Read(read_buf, 0, 10);for(i = 0; i < 10; i++) {printf("[0x%08x]:0x%02x\r\n", i, *(read_buf+i));}/* 擦除该扇区 */printf("-------- erase sector 0 -----------\r\n");W25QXX_Erase_Sector(0);HAL_Delay(50);/* 再次读数据 */printf("-------- read data after erase -----------\r\n");W25QXX_Read(read_buf, 0, 10);for(i = 0; i < 10; i++) {printf("[0x%08x]:0x%02x\r\n", i, *(read_buf+i));}/* 写数据 */printf("-------- write data -----------\r\n");for(i = 0; i < 10; i++) {write_buf[i] = i;}W25QXX_Write(write_buf, 0, 10);HAL_Delay(50);/* 再次读数据 */printf("-------- read data after write -----------\r\n");W25QXX_Read(read_buf, 0, 10);for(i = 0; i < 10; i++) {printf("[0x%08x]:0x%02x\r\n", i, *(read_buf+i));}

测试结果

在这里插入图片描述
注意:在FLASH写数据之前一定要进行擦除。

相关文章:

STM32CUBUMX配置FLASH(W25Q128)--保姆级教程

———————————————————————————————————— ⏩ 大家好哇&#xff01;我是小光&#xff0c;嵌入式爱好者&#xff0c;一个想要成为系统架构师的大三学生。 ⏩最近在开发一个STM32H723ZGT6的板子&#xff0c;使用STM32CUBEMX做了很多驱动&#x…...

【Golang 接口自动化04】 解析接口返回JSON串

目录 前言 解析到结构体 json数据与struct字段是如何相匹配的呢&#xff1f; 解析到interface Go类型和JSON类型 实例代码 simpleJson 总结 资料获取方法 前言 上一次我们一起学习了如何解析接口返回的XML数据&#xff0c;这一次我们一起来学习JSON的解析方法。 JSO…...

EPPlus与Microsoft.Office.Interop.Excel的使用区别

文章目录 代码的使用区别EPPlus的工作原理Microsoft.Office.Interop.Excel的使用原理代码的使用区别 static void ExportToExcel(List<(string, double, double)> list, string outputFilePath){//Microsoft.Office.Interop.Excel的使用 /* Excel.Application excelAp…...

ncrack工具使用说明

介绍 网络认证破解工具。 Ncrack是用于网络身份验证破解的开源工具。 它设计为使用可适应不同网络情况的动态引擎进行高速并行破解。 Ncrack还可以针对特殊情况进行广泛的微调,尽管默认参数的通用性足以覆盖几乎所有情况。 它建立在模块化架构上,可以轻松扩展以支持其他协议…...

第二章:进程管理(处理机/CPU管理)

文章目录 2.1 进程与线程1.进程(1)进程的概念、进程的组成、进程的组织(2)进程控制块PCB(3)进程的状态与转换:五状态模型(4)进程控制(5)进程间的通信①共享存储②消息传递③管道通信(6)父进程与子进程(7)进程的内存空间2.线程 Thread(1)线程的概念(2)线程的实现方式:用户级线…...

MySQL中锁的简介——表级锁-元数据锁、意向锁

1.元数据锁 查看元数据锁 select object_type,object_scheme,object_name,lock_type,lock_duration from perfomance_scheme.metadata_locks;2.意向锁 线程A开启事务后在执行update更新语句时候&#xff0c;会给数据加上行锁&#xff0c;加上行锁以后&#xff0c;会对整张表加…...

React几种避免子组件无效刷新的方案

您好&#xff0c;如果喜欢我的文章&#xff0c;可以关注我的公众号「量子前端」&#xff0c;将不定期关注推送前端好文~ 前言 一个很常见的场景&#xff0c;React中父组件和子组件在一起&#xff0c;子组件不依赖于父组件任何数据&#xff0c;但是会一起发生变化。 在探究原…...

分享亿款好用的PDF编辑工具

所周知&#xff0c;PDF文件是不能够像word/excel/ppt等文件一样&#xff0c;可以被随意编辑的&#xff0c;PDF文件往往只能够被查看&#xff0c;我们无法对它进行编辑&#xff0c;或者对上面的文字进行复制&#xff0c;也不能任意删除上面的页面。但是很多时候&#xff0c;我们…...

AI生成式视频技术来临:Runway Gen-2文本生成视频

Runway Gen-2的官方网站提供了一种文本生成视频的工具。以下是对该工具的介绍&#xff1a; 文本生成视频&#xff1a;Runway Gen-2是一个创新的在线工具&#xff0c;可以将文本转化为视频。用户只需输入文本描述或句子&#xff0c;Runway Gen-2就能自动生成相应的视频内容。这…...

react钩子函数

React组件的生命周期包括多个阶段和方法&#xff0c;用于在组件不同的生命周期时执行特定的操作。以下是React类组件中常见的生命周期方法&#xff1a; 挂载阶段&#xff08;Mounting Phase&#xff09;&#xff1a; constructor&#xff1a;组件实例化时调用&#xff0c;用于初…...

RISC-V公测平台发布 · 如何在SG2042上玩转k3s

前言 Kubernetes是一个开源的容器管理平台&#xff0c;通过Kubernetes的跨集群管理功能&#xff0c;用户可以方便地进行应用程序的复制、迁移和跨云平台的部署。 而k3s作为Kubernetes的轻量级发行版&#xff0c;相比传统的Kubernetes具有更小的二进制文件大小和更低的资源消耗…...

Linux系统常见小问题

1、新系统在输入命令时&#xff0c;不会自动提示&#xff0c;按上箭头&#xff08;↑&#xff09;和下向下箭头&#xff08;↓&#xff09;不会匹配之前的输入 以CentOS 为例&#xff0c;可以通过配置 ~/.bashrc 文件来实现按向上箭头显示最相近的命令。以下是具体的实现步骤 …...

WEB:mfw

背景知识 Git泄露 Githack使用 命令执行漏洞 题目 这里页面里有Git&#xff0c;猜测是Git泄露 先用dirsearch扫一下 确实存在.git目录&#xff0c;可以尝试访问一下 使用Githack来下载并恢复.git文件 这里记得使用的时候关闭杀毒软件 结果会自动保存 点进去先看一下flag这个…...

2.4 传统经验光照模型详解

一、光照模型 光照模型&#xff08;illumination model&#xff09;&#xff0c;也称为明暗模型&#xff0c;用于计算物体某点处的光强&#xff08;颜色值&#xff09;。从算法理论基础而言&#xff0c;光照模型分为两类&#xff1a;一种是基于物理理论的&#xff0c;另一种是…...

基于高通QCC5171的对讲机音频数据传输系统设计

一 研发资料准备 二 设计方法 蓝牙连接与配对&#xff1a;使用QCC5171的蓝牙功能&#xff0c;实现设备之间的蓝牙连接和配对。确保设备能够相互识别并建立起稳定的蓝牙连接。 音频采集与处理&#xff1a;将麦克风采集到的音频数据通过QCC5171的ADC&#xff08;模数转换器&…...

【题解】判断链表中是否有环、链表中环的入口结点

文章目录 判断链表中是否有环链表中环的入口结点 判断链表中是否有环 题目链接&#xff1a;判断链表中是否有环 解题思路1&#xff1a;快慢指针 代码如下&#xff1a; bool hasCycle(ListNode *head) {if(head nullptr) return false;ListNode* fast head;ListNode* slow …...

Pytorch 最全入门介绍,Pytorch入门看这一篇就够了

本文通过详细且实践性的方式介绍了 PyTorch 的使用&#xff0c;包括环境安装、基础知识、张量操作、自动求导机制、神经网络创建、数据处理、模型训练、测试以及模型的保存和加载。 1. Pytorch简介 在这一部分&#xff0c;我们将会对Pytorch做一个简单的介绍&#xff0c;包括它…...

Lambda 表达式的作用域

在Lambda表达式中访问外层作用域和旧版本的匿名对象中的方式类似。你可以直接访问标记了final的外层局部变量&#xff0c;或者实例的字段以及静态变量。 Lambda表达式不会从超类&#xff08;supertype&#xff09;中继承任何变量名&#xff0c;也不会引入一个新的作用域。Lambd…...

【portswigger】第二专题-XSS(二)

portswigger 靶场&#xff08;第二章节&#xff09;XSS 视频同步更新至bilibili bibi地址 【【portswigger】第二专题-XSS&#xff08;一前置知识&#xff09;】 https://www.bilibili.com/video/BV1mp4y157xA/?share_sourcecopy_web 【【portswigger】第二专题-XSS&#xff…...

【计算机视觉|人脸建模】3D人脸重建基础知识(入门)

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 一、三维重建基础 三维重建&#xff08;3D Reconstruction&#xff09;是指根据单视图或者多视图的图像重建三维信息的过程。 1. 常见三维重建技术 人工几何模型仪器采集基于图像的建模描述基于几何建模…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

未授权访问事件频发,我们应当如何应对?

在当下&#xff0c;数据已成为企业和组织的核心资产&#xff0c;是推动业务发展、决策制定以及创新的关键驱动力。然而&#xff0c;未授权访问这一隐匿的安全威胁&#xff0c;正如同高悬的达摩克利斯之剑&#xff0c;时刻威胁着数据的安全&#xff0c;一旦触发&#xff0c;便可…...

Selenium 查找页面元素的方式

Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素&#xff0c;以下是主要的定位方式&#xff1a; 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...