STM32单片机入门学习——第40节: [11-5] 硬件SPI读写W25Q64
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做!
本文写于:2025.04.18
STM32开发板学习——第一节: [1-1]课程简介第40节: [11-5] 硬件SPI读写W25Q64
- 前言
- 开发板说明
- 引用
- 解答和科普
- 一、硬件接线
- 二、W25Q64
- 问题
- 总结
前言
本次笔记是用来记录我的学习过程,同时把我需要的困难和思考记下来,有助于我的学习,同时也作为一种习惯,可以督促我学习,是一个激励自己的过程,让我们开始32单片机的学习之路。
欢迎大家给我提意见,能给我的嵌入式之旅提供方向和路线,现在作为小白,我就先学习32单片机了,就跟着B站上的江协科技开始学习了.
在这里会记录下江协科技32单片机开发板的配套视频教程所作的实验和学习笔记内容,因为我之前有一个开发板,我大概率会用我的板子模仿着来做.让我们一起加油!
另外为了增强我的学习效果:每次笔记把我不知道或者问题在后面提出来,再下一篇开头作为解答!
开发板说明
本人采用的是慧净的开发板,因为这个板子是我N年前就买的板子,索性就拿来用了。另外我也购买了江科大的学习套间。
原理图如下
1、开发板原理图

2、STM32F103C6和51对比

3、STM32F103C6核心板

视频中的都用这个开发板来实现,如果有资源就利用起来。另外也计划实现江协科技的套件。
下图是实物图

引用
【STM32入门教程-2023版 细致讲解 中文字幕】
还参考了下图中的书籍:
STM32库开发实战指南:基于STM32F103(第2版)

数据手册

解答和科普
一、硬件接线




默认情况下,是作为JATG调试端口使用的,都需要先接触调试端口的复用。
SCK(PA5),MISO(PA6),MOSI(PA7),NSS(PA4或其他)。
我们的任务就是修改底层的这个MySPI.c文件,把这些初始化,和时序的执行步骤,由软件实现变成硬件实现。所以,我们把底层的实现,由软件改成硬件,不会影响到上层代码的。
这个就不移出了。

第一步,开启时钟,开启SPI和GPIO的时钟;
第二步,初始化GPIO口,其中SCK、和MOSI,是由硬件外设控制的输出信号,所以配置为复用推挽输出,MISO是硬件外设的输入信号,我们可以配置为上拉输入;因为输入设备可以有多个,不存在复用输入这个东西,直接上拉输入就可,普通GPIO口可以输入,外设也可以输入;SS引脚,是软件控制的输出信号,所以配置为通用推挽输出;
第三步,配置SPI外设,这一块,使用一个结构体选参数即可,调用一下SPI_Init,这里的各种参数就都配置好了;
第四步,开关控制,SPI_Cmd,给SPI使能。
写DR、读DR、获取标志位。
库文件
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
写DR寄存器,写数据到发送数据寄存器TDR.
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);
读DR寄存器,接收数据寄存器RDR.
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
获取TXE和RXNE标志位的状态;
这样就可以控制时序产生。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_7;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;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);
void MySPI_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_7;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;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);SPI_InitTypeDef SPI_InitStructure;SPI_InitStructure.SPI_Mode=SPI_Mode_Master; //模式:主机SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex; //单双向模式SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b; //数据帧长度SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB; //高位先行SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_128; //外设时钟128分频SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low; //模式0SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge;SPI_InitStructure.SPI_NSS=SPI_NSS_Soft; //软件SPI_InitStructure.SPI_CRCPolynomial=7; //CRC校验7SPI_Init(SPI1,&SPI_InitStructure);SPI_Cmd(SPI1,ENABLE);MySPI_W_SS(1); //默认不选中从机
}
SS
void MySPI_W_SS(uint8_t BitValue)
{GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)BitValue);
}
void MySPI_Start(void)
{MySPI_W_SS(0);
}void MySPI_Stop(void)
{MySPI_W_SS(1);
}
第一步,等待TXE为1,第二步,写入发送的数据至TDR,第三步,等待RXNE为1,第四步,读取RDR接收的数据,之后交换第二个字节,重复这4步。
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);SPI_I2S_SendData(SPI1,ByteSend);while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);return SPI_I2S_ReceiveData(SPI1);}
硬件SPI初始化
void MySPI_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_7;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;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);SPI_InitTypeDef SPI_InitStructure;SPI_InitStructure.SPI_Mode=SPI_Mode_Master; //模式:主机SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex; //单双向模式SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b; //数据帧长度SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB; //高位先行SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_128; //外设时钟128分频SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low; //模式0SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge;SPI_InitStructure.SPI_NSS=SPI_NSS_Soft; //软件SPI_InitStructure.SPI_CRCPolynomial=7; //CRC校验7SPI_Init(SPI1,&SPI_InitStructure);SPI_Cmd(SPI1,ENABLE);MySPI_W_SS(1); //默认不选中从机
}
#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
应用层不变
#include "stm32f10x.h" // Device header
#include "MySPI.h"
#include "W25Q64_Ins.h"
void W25Q64_Init(void)
{MySPI_Init();
}void W25Q64_ReadID(uint8_t *MID ,uint16_t *DID)
{MySPI_Start();MySPI_SwapByte(W25Q64_JEDEC_ID); //读ID号的指令,抛玉引砖,返回值没有意义没用*MID = MySPI_SwapByte(W25Q64_DUMMY_BYTE); //0XFF没有意义,抛砖引玉,就是为了把对面有意义的数据置换过来*DID = MySPI_SwapByte(W25Q64_DUMMY_BYTE); // 读取设备ID高8位*DID <<=8;*DID |= MySPI_SwapByte(W25Q64_DUMMY_BYTE); //获得16位的DIDMySPI_Stop();
}void W25Q64_WriteEnable(void)
{MySPI_Start();MySPI_SwapByte(W25Q64_WRITE_ENABLE);MySPI_Stop();
}void W25Q64_WaiteBusy(void)
{uint32_t TimeOut;MySPI_Start();MySPI_SwapByte(W25Q64_READ_STATUS_REGISTER_1);TimeOut=10000;while ((MySPI_SwapByte(W25Q64_DUMMY_BYTE)& 0x01)==0x01) //用掩码取出低位{TimeOut--;if(TimeOut==0){break;}}MySPI_Stop();
}void W25Q64_PageProgram(uint32_t Address,uint8_t *DataArray,uint16_t Count)
{uint16_t i;W25Q64_WriteEnable();MySPI_Start();MySPI_SwapByte(W25Q64_PAGE_PROGRAM);MySPI_SwapByte(Address>>16); //0x123456 变为 0x12MySPI_SwapByte(Address>>8); //0x123456 变为 0x1234 高位自动舍去就是0x34 MySPI_SwapByte(Address); //0x123456 高位自动舍去就是0x56 for(i=0;i<Count;i++){MySPI_SwapByte(DataArray[i]);}MySPI_Stop();W25Q64_WaiteBusy(); //事后等待
}void W25Q64_SectorErase(uint32_t Address)
{W25Q64_WriteEnable(); //写使能MySPI_Start();MySPI_SwapByte(W25Q64_SECTOR_ERASE_4KB);MySPI_SwapByte(Address>>16); //0x123456 变为 0x12MySPI_SwapByte(Address>>8); //0x123456 变为 0x1234 高位自动舍去就是0x34 MySPI_SwapByte(Address);MySPI_Stop();W25Q64_WaiteBusy(); //事后等待
}
void W25Q64_ReadData(uint32_t Address,uint8_t *DataArray,uint32_t Count)
{uint32_t i;MySPI_Start();MySPI_SwapByte(W25Q64_READ_DATA);MySPI_SwapByte(Address>>16); //0x123456 变为 0x12MySPI_SwapByte(Address>>8); //0x123456 变为 0x1234 高位自动舍去就是0x34 MySPI_SwapByte(Address); for(i=0;i<Count;i++){DataArray[i]=MySPI_SwapByte(W25Q64_DUMMY_BYTE);}MySPI_Stop();}
#ifndef __W25Q64_H
#define __W25Q64_Hvoid W25Q64_Init(void);
void W25Q64_ReadID(uint8_t *MID ,uint16_t *DID);
void W25Q64_ReadData(uint32_t Address,uint8_t *DataArray,uint32_t Count);
void W25Q64_SectorErase(uint32_t Address);
void W25Q64_PageProgram(uint32_t Address,uint8_t *DataArray,uint16_t Count);#endif
#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
问题
总结
本节课主要是了解硬件SPI读写W25Q64,在硬件层面对整个SPI进行写,主要是各种时序,标志位和事件来进行,硬件会自动开启时序,需要进行配置。
相关文章:
STM32单片机入门学习——第40节: [11-5] 硬件SPI读写W25Q64
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.18 STM32开发板学习——第一节: [1-1]课程简介第40节: [11-5] 硬件SPI读…...
【Java学习笔记】关键字汇总
Java 关键字汇总 用于定义数据类型的关键字: classinterfaceenumbyteshortintlongfloatdoublecharbooleanvoid 用于定义数据值的关键字: truefalsenull 用于定义流程控制的关键字: ifelseswitchcasedefaultwhiledoforbreakcontinueretu…...
langgraph框架之初识
1.什么是langgraph? LangGraph 是一个用于构建可控代理的底层编排框架。在AI中,代理也就是执行动作的智能体,也就是agent。使用这个框架可以构建一个可以自由控制的智能执行体,它可以帮我们做许多事情,如下࿱…...
如何将 .txt 文件转换成 .md 文件
一、因为有些软件上传文件的时候需要 .md 文件,首先在文件所在的目录中,点击“查看”,然后勾选上“文件扩展名”,这个时候该目录下的所有文件都会显示其文件类型了。 二、这时直接对目标的 .txt 文件进行重命名,把后缀…...
pdfjs库使用记录1
import React, { useEffect, useState, useRef } from react; import * as pdfjsLib from pdfjs-dist; // 设置 worker 路径 pdfjsLib.GlobalWorkerOptions.workerSrc /pdf.worker.min.js; const PDFViewer ({ url }) > { const [pdf, setPdf] useState(null); const […...
Qt 创建QWidget的界面库(DLL)
【1】新建一个qt库项目 【2】在项目目录图标上右击,选择Add New... 【3】选择模版:Qt->Qt设计师界面类,选择Widget,填写界面类的名称、.h .cpp .ui名称 【4】创建C调用接口(默认是创建C调用接口) #ifnd…...
Django REST framework 并结合 `mixin` 的示例
下面为你提供一个使用 Django REST framework 并结合 mixin 的示例,该示例将实现一个简单的图书管理 API。 项目需求 我们要创建一个图书管理系统的 API,支持对图书信息的创建、读取、更新和删除操作。 实现步骤 1. 项目初始化 首先,确保你已经安装了 Django 和 Django…...
linux查看及修改用户过期时间
修改用户有效期 密码到期时间 sudo chage -E 2025-12-31 username sudo chage -M 180 username sudo chage -d $(date %F) username 查询用户密码到期时间 for user in $(cat /etc/passwd |cut -d: -f1); do echo $user; chage -l $user | grep "Password expires"; …...
Vue.directive自定义v-指令
翻阅文章有感,记录学习 vue前端菜单权限控制_vue权限管理菜单思路-CSDN博客 一、定义:Vue.directive是Vue框架中给开发者用于注册自定义指令和返回已注册指令的API 二、基本语法: // 注册 Vue.directive(my-directive, {bind: function () …...
AI Agent 元年,于 2025 开启
私人博客传送门 AI Agent 元年,于 2025 开启 | 魔筝炼药师...
Django 自带开发服务器
$ python manage.py runserver $ python manage.py runserver 666 # 用 666 端口 $ python manage.py runserver 0.0.0.0:8000 # 让局域网内其他客户端也可访问 $ python manage.py runserver --skip-checks # 跳过检查自动检查 $ python manage.py runserver --…...
Spring 数据库编程
Spring JDBC 传统的JDBC在操作数据库时,需要先打开数据库连接,执行SQL语句,然后封装结果,最后关闭数据库连接等资源。频繁的数据库操作会产生大量的重复代码,造成代码冗余,Spring的JDBC模块负责数据库资源…...
进阶篇|CAN FD 与性能优化
引言 1. CAN vs. CAN FD 对比 2. CAN FD 帧结构详解...
CTF--各种绕过哟
一、原网页: 二、步骤: 1.源代码: <?php highlight_file(flag.php); $_GET[id] urldecode($_GET[id]); $flag flag{xxxxxxxxxxxxxxxxxx}; if (isset($_GET[uname]) and isset($_POST[passwd])) {if ($_GET[uname] $_POST[passwd])pr…...
【Pandas】pandas DataFrame where
Pandas2.2 DataFrame Indexing, iteration 方法描述DataFrame.head([n])用于返回 DataFrame 的前几行DataFrame.at快速访问和修改 DataFrame 中单个值的方法DataFrame.iat快速访问和修改 DataFrame 中单个值的方法DataFrame.loc用于基于标签(行标签和列标签&#…...
嵌入式ARM RISCV toolchain工具 梳理arm-none-eabi-gcc
嵌入式TOOLchain工具 梳理 简介 本文总结和梳理一下一些toolchain的规则和原理,方便后续跨平台的时候,给大家使用toolchain做一个参考。 解释如何理解arm-none-eabi-gcc等含义,以及如何一看就知道该用什么编译器。 当然如果有哪里写的不是…...
OpenBMC:BmcWeb log输出
BmcWeb的log函数定义于:http\logging.hpp 说实话,个人觉得这一版的log函数有点炫技,使用起来也没有之前的版本方便,不过也还是值的参考一下。 1.如何输出log BMCWEB_LOG_ERROR("GetAll on path {} iface {} service {} failed with code {}",objectPath, inte…...
复现SCI图像增强(Toward fast, flexible, and robust low-light image enhancement.)
运行train.py报错 > File "/home/uriky/桌面/SCI-main/SCI-main/train.py", line 105, in main > train_queue torch.utils.data.DataLoader( File "/home/uriky/anaconda3/envs/AA/lib/python3.8/site-packages/torch/utils/data/dataloader.py&q…...
深入理解C++中string的深浅拷贝
目录 一、引言 二、浅拷贝与深拷贝的基本概念 2.1 浅拷贝 2.2 深拷贝 在C 中, string 类的深浅拷贝有着重要的区别。 浅拷贝 深拷贝 string 类中的其他构造函数及操作 resize 构造 构造(赋值构造) 构造(拼接构造…...
性能测试面试题的详细解答
以下是性能测试面试题的详细解答: 1. 性能测试的流程是怎样的? 性能测试流程通常包括以下几个步骤: - **需求分析**:明确测试目标、性能指标(如响应时间、吞吐量等)。 - **环境搭建**:搭建测试环…...
第八篇:系统分析师第三遍——3、4章
目录 一、目标二、计划三、完成情况四、意外之喜(最少2点)1.计划内的明确认知和思想的提升标志2.计划外的具体事情提升内容和标志 五、总结 一、目标 通过参加考试,训练学习能力,而非单纯以拿证为目的。 1.在复习过程中,训练快速阅读能力、掌…...
Unity粒子特效打包后不显示
1.粒子发mesh,如果打包后不显示,尝试勾选r/w 2.如果还不行,mesh重做,目前发现ab包打出的,有的mesh会出问题,暂时原因不详。...
PFC 是什么?
现在进行液晶电视机和等离子电视机电路分析时、故障维修时,都经常的提到“PFC 电路”一词,这 在早期的电视机中是没有的,早期维修电视机的师傅从来没有接触过的,但是 PFC 电路是目前液晶电视机 和等离子电视机中不可缺少的电路。那…...
6.5 GitHub监控系统实战:双通道采集+动态调度打造高效运维体系
GitHub Sentinel Agent 定期更新功能设计与实现 关键词:GitHub API 集成、定时任务调度、Python 爬虫开发、SMTP 邮件通知、系统稳定性保障 1. GitHub 项目数据获取功能 1.1 双通道数据采集架构设计 #mermaid-svg-ZHJIMXcMAyDHVhmV {font-family:"trebuchet ms",v…...
楼梯上下检测数据集VOC+YOLO格式5462张2类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):5462 标注数量(xml文件个数):5462 标注数量(txt文件个数):5462 …...
消防营区管控:从智能仓储、装备管理、应急物资调用等多维度出发
近期,一系列消防安全热点事件引发了社会各界的广泛关注。某老旧城区的一场火灾,由于消防通道被杂物堵塞,消防车辆无法及时靠近火源,加之周边消防设施老化,灭火物资储备不足,导致火势迅速蔓延,造…...
Flutter 自定义插件基础
1、Flutter插件是什么?官方插件库 在开发Flutter应用过程中会涉及到平台相关接口调用,例如数据库操作、相机调用、外部浏览器跳转等业务场景。其实Flutter自身并不支持直接在平台上实现这些功能,而是通过插件包接口去调用指定平台API从而实现…...
解锁古籍中的气候密码,探索GPT/BERT在历史灾害研究中的前沿应用;气候史 文本挖掘 防灾减灾;台风案例、干旱案例、暴雨案例
历史灾害文献分析方法论的研究,是连接过去与未来的关键桥梁。通过对古籍、方志、档案等非结构化文本的系统性挖掘与量化分析,不仅能够重建千年尺度的灾害事件序列(如台风、洪旱等),弥补仪器观测数据的时空局限性&#…...
【java 13天进阶Day12】XML和Dom4j,装饰模式,工厂模式,commons-io工具包,Base64
XML XML 指可扩展标记语言(EXtensible Markup Language),由各种标记(元素标签)组成。 可扩展:所有的标签都是自定义的,可以随意扩展的,如 。 XML 是一种标记语言,很类似 HTML,HTML…...
vue3 Element-plus修改内置样式复现代码
笔者在修改Element-plus的内置样式时,遇到一点挫折,现提供需求场景与解决方案。 一、实现(1)透明弹窗可拖拽,且不影响点击弹窗外内容;(2)弹窗内置表格,表格需修改样式颜色…...
