【江协STM32】11-2/3 W25Q64简介、软件SPI读写W25Q64
1. W25Q64简介
- W25Qxx系列是一种低成本、小型化、使用简单的非易失性存储器,常应用于数据存储、字库存储、固件程序存储等场景
- 存储介质:Nor Flash(闪存)
- 时钟频率:80MHz / 160MHz (Dual SPI) / 320MHz (Quad SPI)
- 存储容量(24位地址):
W25Q40: 4Mbit / 512KByte
W25Q80: 8Mbit / 1MByte
W25Q16: 16Mbit / 2MByte
W25Q32: 32Mbit / 4MByte
W25Q64: 64Mbit / 8MByte
W25Q128: 128Mbit / 16MByte
W25Q256: 256Mbit / 32MByte
1.1 硬件电路
CS上面画条横线,或者左边画"/",表示低电平有效。
1.2 W25Q64框图
W25Q64的容量是8MB,如果不进行划分,只按照一整块来使用, 则容量太大,不利于管理,所以需要进行划分。常见划分方式为,一整块存储空间,先划分为若干的块Block,其中每一块再划分为若干的扇区Sector,对于每个扇区,内部又可以分成很多页Page。
1.3 Flash操作注意事项
写入操作时:
- 写入操作前,必须先进行写使能
- 每个数据位只能由1改写为0,不能由0改写为1
比如,在某一个字节的存储单元内,存储了0xAA(1010 1010)这个数据,如果直接再次在这个存储单元写入新的数据0x55(0101 0101),则这个存储单元最终的数据为0x00 - 写入数据前必须先擦除,擦除后,所有数据位变为1
比如,擦除后所有位变成1,也就是0xFF(1111 1111),此时写入0x55(0101 0101),这样根据第二条规则,存储单元最终的数据为0x55 - 擦除必须按最小擦除单元进行
在W25Q64中,可以选择整个芯片擦除、按块擦除、按扇区擦除,所以最小的擦除单元就是一个扇区(4KB,就是4096个字节),所以擦除,最少就需要4096个字节一起擦 - 连续写入多字节时,最多写入一页的数据,超过页尾位置的数据,会回到页首覆盖写入
因为页缓存区只有256Byte - 写入操作结束后,芯片进入忙状态,不响应新的读写操作
读取操作时:
- 直接调用读取时序,无需使能,无需额外操作,没有页的限制,读取操作结束后不会进入忙状态,但不能在忙状态时读取
2. 软件SPI读写W25Q64
2.1 接线图
SPI的四根通信线CS、DO、CLK和DI,因为这里使用软件模拟SPI,所以这4根线可以接到STM32的任意GPIO口。
CS(片选)接到PA4、DO(从机输出)接到PA6、CLK(时钟)接到PA5、DI(从机输入)接到PA7
2.2 代码
先建立一个MySPI模块,这个模块中主要包含通信引脚封装、初始化,以及SPI通信的3个拼图(起始、终止和交换一个字节)。
然后基于SPI层,再建立一个W25Q64的模块,在此模块中,调用底层SPI的拼图,来拼接各种指令和功能的完整时序,比如写使能、擦除、页编程、读数据等。这一层可以称为W25Q64的硬件驱动层。
最后,在主函数中调用驱动层的函数,实现想要的功能。
MySPI.c
#include "stm32f10x.h" // Device header// 写SS/CS引脚
void MySPI_W_SS(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}// 写SCK/CLK引脚
void MySPI_W_SCK(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue);
}// 写MOSI/DI引脚
void MySPI_W_MOSI(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue);
}// 读MISO/DO引脚
uint8_t MySPI_R_MISO(void)
{return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}void MySPI_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;// 输出引脚配置为推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;// CS/SS(PA4),CLK/SCK(PA5),DI/MOSI(PA7)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;// 输入引脚配置为上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;// DO/MISO(PA6)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);MySPI_W_SS(1);// 默认高电平,不选中从机MySPI_W_SCK(0);// 使用SPI模式0,所以默认是低电平
}// 时序基本单元:起始条件
void MySPI_Start(void)
{MySPI_W_SS(0);
}// 时序基本单元:终止条件
void MySPI_Stop(void)
{MySPI_W_SS(1);
}// 时序基本单元:交换一个字节(模式0)
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{uint8_t i,ByteReceive = 0x00;for(i = 0; i < 8; i++){MySPI_W_MOSI(ByteSend & (0x80 >> i));// 发送ByteSend最高位、次高位...MySPI_W_SCK(1);// 产生上升沿。上升沿时,从机会自动把MOSI的数据读走if(MySPI_R_MISO() == 1){ByteReceive |= (0x80 >> i);}// 如果读到MISO的数据位是1,则把最高位、次高位...存到ByteReceive中MySPI_W_SCK(0);// 产生下降沿。}return ByteReceive;
}
MySPI.h
#ifndef __MYSPI_H
#define __MYSPI_Hvoid MySPI_Init(void);
void MySPI_Start(void);
void MySPI_Stop(void);
uint8_t MySPI_SwapByte(uint8_t ByteSend);#endif
W25Q64.c
#include "stm32f10x.h" // Device header
#include "MySPI.h"
#include "W25Q64_Ins.h"void W25Q64_Init(void)
{MySPI_Init();
}// 读取ID。因为函数有2个返回值,所以使用指针实现
// MID为厂商ID,DID为设备ID
void W25Q64_ReadID(uint8_t *MID, uint16_t *DID)
{MySPI_Start();// SS引脚置低,开始传输MySPI_SwapByte(W25Q64_JEDEC_ID);// 发送0x9F(宏定义W25Q64_JEDEC_ID),返回值不使用。0x9F根据手册,代表读ID号指令*MID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);// 0xFF无意义(宏定义W25Q64_DUMMY_BYTE),这句的作用是把从机有意义的数据置换过来*DID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);// 0xFF无意义,置换出设备ID的高8位*DID <<= 8;// 把第一次读到的数据运到DID的高8位*DID |= MySPI_SwapByte(W25Q64_DUMMY_BYTE);// 0xFF无意义,置换出设备ID的低8位MySPI_Stop();
}// 写使能
void W25Q64_WriteEnable(void)
{MySPI_Start();MySPI_SwapByte(W25Q64_WRITE_ENABLE);MySPI_Stop();
}// 等待忙
void W25Q64_WaitBusy(void)
{uint32_t Timeout;MySPI_Start();MySPI_SwapByte(W25Q64_READ_STATUS_REGISTER_1);Timeout = 100000;// 给定超时计数时间while((MySPI_SwapByte(W25Q64_DUMMY_BYTE) & 0x01) == 0x01)// 返回值是状态寄存器1,取出最低位{Timeout --;// 等待时,计数值自减if (Timeout == 0)// 自减到0后,等待超时{/*超时的错误处理代码,可以添加到此处*/break;// 跳出等待,不等了}}MySPI_Stop();
}/*** 函 数:W25Q64页编程* 参 数:Address 页编程的起始地址,范围:0x000000~0x7FFFFF* 参 数:DataArray 用于写入数据的数组* 参 数:Count 要写入数据的数量,范围:0~256* 返 回 值:无* 注意事项:写入的地址范围不能跨页*/
void W25Q64_PageProgram(uint32_t Address, uint8_t *DataArray, uint16_t Count)
{uint16_t i;W25Q64_WriteEnable(); //写使能MySPI_Start(); //SPI起始MySPI_SwapByte(W25Q64_PAGE_PROGRAM); //交换发送页编程的指令MySPI_SwapByte(Address >> 16); //交换发送地址23~16位。例如0x123456,这里交换0x12MySPI_SwapByte(Address >> 8); //交换发送地址15~8位。右移8位为0x1234,由于交换字节函数只能接收8位数据,所以高位舍弃,实际发送0x34MySPI_SwapByte(Address); //交换发送地址7~0位。由于交换字节函数只能接收8位数据,所以高位舍弃,实际发送0x56for (i = 0; i < Count; i ++) //循环Count次{MySPI_SwapByte(DataArray[i]); //依次在起始地址后写入数据}MySPI_Stop(); //SPI终止W25Q64_WaitBusy(); //等待忙
}/*** 函 数:W25Q64扇区擦除(4KB)* 参 数:Address 指定扇区的地址,范围:0x000000~0x7FFFFF* 返 回 值:无*/
void W25Q64_SectorErase(uint32_t Address)
{W25Q64_WriteEnable(); //写使能MySPI_Start(); //SPI起始MySPI_SwapByte(W25Q64_SECTOR_ERASE_4KB); //交换发送扇区擦除的指令MySPI_SwapByte(Address >> 16); //交换发送地址23~16位。例如0x123456,这里交换0x12MySPI_SwapByte(Address >> 8); //交换发送地址15~8位。右移8位为0x1234,由于交换字节函数只能接收8位数据,所以高位舍弃,实际发送0x34MySPI_SwapByte(Address); //交换发送地址7~0位。由于交换字节函数只能接收8位数据,所以高位舍弃,实际发送0x56MySPI_Stop(); //SPI终止W25Q64_WaitBusy(); //等待忙
}/*** 函 数:W25Q64读取数据* 参 数:Address 读取数据的起始地址,范围:0x000000~0x7FFFFF* 参 数:DataArray 用于接收读取数据的数组,通过输出参数返回* 参 数:Count 要读取数据的数量,范围:0~0x800000* 返 回 值:无*/
void W25Q64_ReadData(uint32_t Address, uint8_t *DataArray, uint32_t Count)
{uint32_t i;MySPI_Start(); //SPI起始MySPI_SwapByte(W25Q64_READ_DATA); //交换发送读取数据的指令MySPI_SwapByte(Address >> 16); //交换发送地址23~16位MySPI_SwapByte(Address >> 8); //交换发送地址15~8位MySPI_SwapByte(Address); //交换发送地址7~0位for (i = 0; i < Count; i ++) //循环Count次{DataArray[i] = MySPI_SwapByte(W25Q64_DUMMY_BYTE); //依次在起始地址后读取数据}MySPI_Stop(); //SPI终止
}
W25Q64.h
#ifndef __W25Q64_H
#define __W25Q64_Hvoid W25Q64_Init(void);
void W25Q64_ReadID(uint8_t *MID, uint16_t *DID);
void W25Q64_PageProgram(uint32_t Address, uint8_t *DataArray, uint16_t Count);
void W25Q64_SectorErase(uint32_t Address);
void W25Q64_ReadData(uint32_t Address, uint8_t *DataArray, uint32_t Count);#endif
W25Q64_Ins.h
#ifndef __W25Q64_INS_H
#define __W25Q64_INS_H#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_UNIQUE_ID 0x4B
#define W25Q64_JEDEC_ID 0x9F
#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#define W25Q64_DUMMY_BYTE 0xFF#endif
main.c
#include "stm32f10x.h" // Device
#include "OLED.h"
#include "W25Q64.h"uint8_t MID; //定义用于存放MID号的变量
uint16_t DID; //定义用于存放DID号的变量
uint8_t ArrayWrite[] = {0xAA, 0xBB, 0xCC, 0xDD}; //定义要写入数据的测试数组
uint8_t ArrayRead[4]; //定义要读取数据的测试数组int main(void)
{OLED_Init();W25Q64_Init();/*显示静态字符串*/OLED_ShowString(1, 1, "MID: DID:");OLED_ShowString(2, 1, "W:");OLED_ShowString(3, 1, "R:");/*显示ID号*/W25Q64_ReadID(&MID, &DID); //获取W25Q64的ID号OLED_ShowHexNum(1, 5, MID, 2); //显示MIDOLED_ShowHexNum(1, 12, DID, 4); //显示DID/*W25Q64功能函数测试*/W25Q64_SectorErase(0x000000); //扇区擦除W25Q64_PageProgram(0x000000, ArrayWrite, 4); //将写入数据的测试数组写入到W25Q64中W25Q64_ReadData(0x000000, ArrayRead, 4); //读取刚写入的测试数据到读取数据的测试数组中/*显示数据*/OLED_ShowHexNum(2, 3, ArrayWrite[0], 2); //显示写入数据的测试数组OLED_ShowHexNum(2, 6, ArrayWrite[1], 2);OLED_ShowHexNum(2, 9, ArrayWrite[2], 2);OLED_ShowHexNum(2, 12, ArrayWrite[3], 2);OLED_ShowHexNum(3, 3, ArrayRead[0], 2); //显示读取数据的测试数组OLED_ShowHexNum(3, 6, ArrayRead[1], 2);OLED_ShowHexNum(3, 9, ArrayRead[2], 2);OLED_ShowHexNum(3, 12, ArrayRead[3], 2);while(1){}
}
其他引用的头文件和c代码可在此处查阅:OLED.h(【江协STM32】4 OLED调试工具)
相关文章:

【江协STM32】11-2/3 W25Q64简介、软件SPI读写W25Q64
1. W25Q64简介 W25Qxx系列是一种低成本、小型化、使用简单的非易失性存储器,常应用于数据存储、字库存储、固件程序存储等场景存储介质:Nor Flash(闪存)时钟频率:80MHz / 160MHz (Dual SPI) / 320MHz (Quad SPI)存储容…...

《自动驾驶与机器人中的SLAM技术》ch2:基础数学知识
目录 2.1 几何学 向量的内积和外积 旋转矩阵 旋转向量 四元数 李群和李代数 SO(3)上的 BCH 线性近似式 2.2 运动学 李群视角下的运动学 SO(3) t 上的运动学 线速度和加速度 扰动模型和雅可比矩阵 典型算例:对向量进行旋转 典型算例:旋转的复合 2.3 …...

算法日记2:洛谷p3853路标设置(二分答案)
一、题目: 二、解题思路: 2.1:首先,我们二分空旷指数 1、因为题目中要求我们求解最大值最小应该是属于第二类模型2.也就是说,当check()函数为true时候,说明这个空旷指数是成立的,对应的路标数…...

浅谈云计算06 | 云管理系统架构
云管理系统架构 一、云管理系统架构(一)远程管理系统(二)资源管理系统(三)SLA 管理系统(四)计费管理系统 二、安全与可靠性保障(一)数据安全防线(…...

Blender常规设置
移动:Shift鼠标中键 旋转:鼠标中键 缩放:Ctrl鼠标中键...
c++ 中的容器 vector、deque 和 list 的区别
表格汇总: 容器存储结构随机访问性能中间插入/删除性能两端插入/删除性能内存管理特点迭代器类型适用场景vector连续存储的动态数组 O ( 1 ) O(1) O(1) O ( n ) O(n) O(n)(需要移动元素)末尾: O ( 1 ) O(1) O(1),头部…...

【物流管理系统 - IDEAJavaSwingMySQL】基于Java实现的物流管理系统导入IDEA教程
有问题请留言或私信 步骤 下载项目源码:项目源码 解压项目源码到本地 打开IDEA 左上角:文件 → 新建 → 来自现有源代码的项目 找到解压在本地的项目源代码文件,点击确定,根据图示步骤继续导入项目 查看项目目录ÿ…...

数据集-目标检测系列- 电话 测数据集 call_phone >> DataBall
数据集-目标检测系列- 电话 测数据集 call DataBall 助力快速掌握数据集的信息和使用方式,会员享有 百种数据集,持续增加中。 需要更多数据资源和技术解决方案,知识星球: “DataBall - X 数据球(free)” 贵在坚持! …...
VUE3 自定义指令的介绍
自定义指令的概述 在 Vue 中,自定义指令是一种机制,允许开发者在模板中直接操作 DOM 元素,执行一些低级别的操作。Vue 提供了几个内置指令(如 v-if、v-for、v-model 等),但当我们需要一些特定功能时&#…...
HTML学习笔记记录---速预CSS(2) 复合属性、盒子模型、边框线、浮动、定位
复合属性写法: {font: font-style font-weitght font-size/line-height font-family} {font: 样式 粗细 字号 字体} (书写瞬间为固定的不可更改) block 块级元素 div inline 行内元素 span inline-block 行内块元素 …...
二 RK3568 固件中打开 ADB 调试
一 usb adb Android 系统,设置->开发者选项->已连接到计算机 打开,usb调试开关打开 通过 usb otg 口连接 开发上位机 (windows/linux) 上位机安装 adb 服务之后 , 通过 cmd/shell: #1 枚举设备 adb devices #2 进入 android shell adb shell # 3 验证上传下载…...

centos9设置静态ip
CentOS 9 默认使用 NetworkManager 管理网络,而nmcli是 NetworkManager 命令行接口的缩写,是一个用来进行网络配置、管理网络连接的命令工具,可以简化网络设置,尤其是在无头(没有图形界面)环境下。 1、 cd…...

【Python】Python之Selenium基础教程+实战demo:提升你的测试+测试数据构造的效率!
这里写目录标题 什么是Selenium?Selenium基础用法详解环境搭建编写第一个Selenium脚本解析脚本脚本执行结果常用的元素定位方法常用的WebDriver方法等待机制 Selenium高级技巧详解页面元素操作处理弹窗和警告框截图和日志记录多窗口和多标签页操作 一个实战的小demo…...
内网服务器添加共享文件夹功能并设置端口映射
参考网址 https://blog.csdn.net/Think88666/article/details/118438465 1.服务器安装smb服务,由于网路安全不允许使用默认端口(445,446),于是修改端口为62445、62446。 2.每台需要共享的电脑都要修改端口映射&#x…...

第三十六章 Spring之假如让你来写MVC——拦截器篇
Spring源码阅读目录 第一部分——IOC篇 第一章 Spring之最熟悉的陌生人——IOC 第二章 Spring之假如让你来写IOC容器——加载资源篇 第三章 Spring之假如让你来写IOC容器——解析配置文件篇 第四章 Spring之假如让你来写IOC容器——XML配置文件篇 第五章 Spring之假如让你来写…...
TypeScript语言的学习路线
TypeScript语言的学习路线 TypeScript(TS)是由Microsoft开发的一种开源编程语言,是JavaScript的超集,提供了严格的类型检查和基于类的面向对象编程特性。随着前端开发的不断进步,TypeScript逐渐成为了现代前端开发的主…...

Python爬虫-汽车之家各车系周销量榜数据
前言 本文是该专栏的第43篇,后面会持续分享python爬虫干货知识,记得关注。 在本专栏之前,笔者在文章《Python爬虫-汽车之家各车系月销量榜数据》中,有详细介绍,如何爬取“各车系车型的月销量榜单数据”的方法以及完整代码教学教程。 而本文,笔者同样以汽车之家平台为例,…...
C#格式化输出
上一期: C#格式化输出-CSDN博客 字符串插值 字符串插入功能,使得我们可以更直观地嵌入表达式到字符串中,只需要在字符串前加上$符号即可实现这一点。着中国方法不仅提高了代码的可读性,而且简化了字符串构造的过程。 使用Inse…...

Open FPV VTX开源之默认MAVLink设置
Open FPV VTX开源之默认MAVLink设置 1. 源由2. 准备3. 连接4. 安装5. 配置6. 测试6.1 启动wfb-ng服务6.2 启动wfb-ng监测6.3 启动QGroundControl6.4 观察测试结果 7. 总结8. 参考资料9. 补充9.1 telemetry_tx异常9.2 DEBUG串口部分乱码9.3 PixelPilot软件问题 1. 源由 飞控图传…...
【初识扫盲】逆概率加权
我们正在处理一个存在缺失数据的回归模型,并且希望采用一种非参数的逆概率加权方法来调整估计,以应对这种缺失数据的情况。 首先,我们需要明确问题的背景。我们有样本 { ( Y i , X i , r i ) : i 1 , … , n } \left\{\left(Y_i, \boldsym…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
命令行关闭Windows防火墙
命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)方法二:CMD命令…...
js 设置3秒后执行
如何在JavaScript中延迟3秒执行操作 在JavaScript中,要设置一个操作在指定延迟后(例如3秒)执行,可以使用 setTimeout 函数。setTimeout 是JavaScript的核心计时器方法,它接受两个参数: 要执行的函数&…...