STM32F103ZET6移植FATFS文件系统教程(W25Q32)
一、FATFS核心特性
跨平台支持
支持FAT12/FAT16/FAT32格式,兼容Windows文件系统;
采用标准C语言编写,代码量小且支持RTOS。
配置灵活性
通过宏定义实现功能裁剪,例如:
FF_FS_READONLY:设为1时禁用写操作相关函数(如f_write()、f_unlink());
FF_FS_MINIMIZE:设置不同精简级别(0-3),逐步移除非必要API(如目录操作、文件统计等)。
二、移植关键步骤
存储介质初始化
需初始化底层存储设备(如SD卡、SPI Flash),涉及存储地址映射与读写函数实现;
在user_diskio.c中实现底层接口:disk_initialize(初始化)、disk_read(读)、disk_write(写)。
文件系统挂载
调用f_mount()函数挂载存储设备(如f_mount(fs, "0:", 1)),分配逻辑驱动器号(如"0:")。
三、应用层操作
文件读写流程
创建文件:f_open(&file, "0:/file.txt", FA_CREATE_ALWAYS | FA_WRITE);
数据写入:使用f_write()时需将非字符类型数据(如int/float)转换为字符格式;
资源释放:操作完成后需调用f_close()关闭文件。
辅助功能配置
支持长文件名需启用FF_USE_LFN并选择编码方式(如UTF-8);
多卷管理需配置FF_VOLUMES参数。
四、注意事项
存储介质格式化:首次使用前需通过工具或代码格式化,以创建文件分配表和目录结构;
内存管理:合理分配缓冲区以避免内存溢出,尤其在动态内存模式下;
实时性优化:在RTOS中需确保文件系统操作与任务调度兼容。
开始移植
我们先使用STM32CubeMX创建一个纯净的工程
配置好SPI1
然后在初始化一个片选引脚(PC13)
之后在中间件里设置好FATFS(选择User-defind就好,其他的可以不用改)
最后选择MDK-ARM,生成工程
底层驱动兼容SFUD
一、通用驱动兼容性
广泛硬件支持:兼容市面主流SPI Flash芯片(如W25Q64、SST25VF等),支持SPI/QSPI接口的基础读写擦除操作,无需针对不同芯片重复开发驱动。
接口标准化:通过统一API(如sfud_read、sfud_erase)屏蔽底层硬件差异,降低代码与硬件的耦合度。
二、参数自动检测
动态识别能力:运行时自动读取Flash的厂商ID、容量、擦除粒度等参数,减少因芯片停产或型号变更导致的维护风险。
SFDP协议支持:基于JEDEC标准的SFDP(Serial Flash Discoverable Parameters)规范,自动解析设备特性表,避免手动配置。
三、轻量级设计
低资源占用:标准模式代码量约5.5KB ROM/0.2KB RAM,最小模式可压缩至3.6KB ROM/0.1KB RAM,适用于STM32等资源受限的MCU。
可裁剪性:通过宏定义关闭非必要功能(如QSPI支持),进一步优化存储和运行效率。
四、扩展性与易用性
多设备管理:支持通过注册机制同时驱动多个Flash设备,适用于多存储介质的复杂场景(如主控+备份存储)。
分层架构设计:与FAL(Flash抽象层)组件无缝集成,提供统一的Flash访问接口,简化文件系统(如FATFS)或OTA升级功能的实现。
五、开发效率提升
快速移植:仅需实现底层SPI接口函数(如spi_send、spi_recv),缩短从零开发驱动的时间。
动态适配优势:新增Flash型号时无需修改驱动代码,仅需更新设备参数表或依赖SFDP自动识别。
场景 | SFUD作用 |
外部存储扩展(如W25Q32) | 提供统一接口,简化文件系统(FATFS)或日志存储的实现流程 |
多Flash设备管理 | 通过注册机制区分不同存储介质,支持并行操作 |
特性 | 嵌入式开发价值 |
兼容性 | 覆盖90%以上主流SPI Flash型号,降低硬件选型限制 |
低资源消耗 | 适配低端MCU(如STM32F103),节省ROM/RAM资源 |
维护成本低 | 动态参数检测减少代码修改频率,提升长期项目可持续性 |
移植SFUD
SFUD会检测单片机上的Flash芯片,所以我们这里选择SFUD驱动做一个兼容,就算更换芯片后也不需要修改底层代码。
SFUD: https://github.com/armink/SFUD.git - Gitee.com
把代码克隆到本地,然后把sfud文件夹复制出来,放到工程目录下,里面共有3个目录(inc,port,src)
将port和src内的C文件加到Keil工程内
然后添加inc路径
我们只需要实现底层的函数接口
进入到sfud_port.c文件内,实现spi_write_read函数
#include <sfud.h>
#include <stdarg.h>
#include "main.h"static char log_buf[256];extern SPI_HandleTypeDef hspi1;#define SPI_Start() (HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET))
#define SPI_Stop() (HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET))void sfud_log_debug(const char* file, const long line, const char* format, ...);/*** SPI write data then read data*/
static sfud_err spi_write_read(const sfud_spi* spi, const uint8_t* write_buf, size_t write_size, uint8_t* read_buf, size_t read_size) {sfud_err result = SFUD_SUCCESS;uint8_t send_data, read_data;/*** add your spi write and read code*/SPI_Start();if (write_size > 0) {if (HAL_OK != HAL_SPI_Transmit(&hspi1, (uint8_t*)write_buf, write_size, 1000))result = SFUD_ERR_TIMEOUT;}if (read_size > 0) {if (HAL_OK != HAL_SPI_Receive(&hspi1, (uint8_t*)read_buf, read_size, 1000))result = SFUD_ERR_TIMEOUT;}SPI_Stop();return result;
}
实现sfud_spi_port_init函数,注释后面提示Required的都是需要配置的
关于delay的配置,就随便用软件的方式延时一下就好了
void delay(void) {uint16_t count = 10000;while (count--) {__NOP();}
}sfud_err sfud_spi_port_init(sfud_flash* flash) {sfud_err result = SFUD_SUCCESS;/*** add your port spi bus and device object initialize code like this:* 1. rcc initialize* 2. gpio initialize* 3. spi device initialize* 4. flash->spi and flash->retry item initialize* flash->spi.wr = spi_write_read; //Required* flash->spi.qspi_read = qspi_read; //Required when QSPI mode enable* flash->spi.lock = spi_lock;* flash->spi.unlock = spi_unlock;* flash->spi.user_data = &spix;* flash->retry.delay = null;* flash->retry.times = 10000; //Required*/flash->spi.wr = spi_write_read;flash->retry.delay = delay;flash->retry.times = 10000;return result;
}
测试SFUD和芯片是否移植成功
在main.c内引入 sfud.h文件
int fputc(int ch, FILE* f) {HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 1000);return ch;
}// sfud测试
void es(void) {printf("擦除数据\r\n");const sfud_flash* flash = sfud_get_device(0);sfud_erase(flash, 0, 100);
}void ws(void) {//获取到设备Flashconst sfud_flash* flash = sfud_get_device(0);uint8_t buff[300] = {0};for (uint16_t i = 0; i < 300; i++) {buff[i] = i;}//先擦除在写入sfud_erase_write(flash, 0, 300, buff);
}void rs(void) {const sfud_flash* flash = sfud_get_device(0);uint8_t buff[300] = {0};sfud_read(flash, 0, 300, buff);for (uint16_t i = 0; i < 300; i++) {printf("%d ", buff[i]);if (i % 10 == 0) {printf("\r\n");}}
}
// sfud测试int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_SPI1_Init();//MX_FATFS_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */sfud_init();rs();HAL_Delay(1000);ws();HAL_Delay(1000);rs();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1) {/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
先读取数据在写入数据,再读出来,看看数据是否一致,读取数据就是把1变0,擦除就是把0变1,所以默认都是1,所以读出来都是255
配置FATFS
打开user_diskio.c 文件,修改USER_initialize和USER_status函数
/*** @brief Initializes a Drive* @param pdrv: Physical drive number (0..)* @retval DSTATUS: Operation status*/
DSTATUS USER_initialize(BYTE pdrv /* Physical drive nmuber to identify the drive */
) {/* USER CODE BEGIN INIT */Stat &= ~STA_NOINIT;return Stat;/* USER CODE END INIT */
}/*** @brief Gets Disk Status* @param pdrv: Physical drive number (0..)* @retval DSTATUS: Operation status*/
DSTATUS USER_status(BYTE pdrv /* Physical drive number to identify the drive */
) {/* USER CODE BEGIN STATUS */Stat &= ~STA_NOINIT;return Stat;/* USER CODE END STATUS */
}
实现USER_read函数
DRESULT USER_read(BYTE pdrv, /* Physical drive nmuber to identify the drive */BYTE* buff, /* Data buffer to store read data */DWORD sector, /* Sector address in LBA */UINT count /* Number of sectors to read */
) {/* USER CODE BEGIN READ */const sfud_flash* flash = sfud_get_device(0);uint32_t read_addr = sector * 4096;sfud_read(flash, read_addr, count * 4096, buff);return RES_OK;/* USER CODE END READ */
}
实现USER_write函数
DRESULT USER_write(BYTE pdrv, /* Physical drive nmuber to identify the drive */const BYTE* buff, /* Data to be written */DWORD sector, /* Sector address in LBA */UINT count /* Number of sectors to write */
) {/* USER CODE BEGIN WRITE */const sfud_flash* flash = sfud_get_device(0);uint32_t write_addr = sector * 4096;sfud_erase_write(flash, write_addr, count * 4096, buff);/* USER CODE HERE */return RES_OK;/* USER CODE END WRITE */
}
实现USER_ioctl函数
DRESULT USER_ioctl(BYTE pdrv, /* Physical drive nmuber (0..) */BYTE cmd, /* Control code */void* buff /* Buffer to send/receive control data */
) {/* USER CODE BEGIN IOCTL */DRESULT res = RES_OK;switch (cmd) {case CTRL_SYNC:break;case GET_SECTOR_COUNT:*((DWORD*)buff) = 1024;break;case GET_SECTOR_SIZE:*((WORD*)buff) = 4096;break;case GET_BLOCK_SIZE:*((DWORD*)buff) = 1;break;default:res = RES_PARERR;}return res;/* USER CODE END IOCTL */
}
打开ffconf.h文件,修改__MAX_SS为4096
进去到fatfs.c文件,USERPath是文件的起始路径,这里使用 \,前面在转义一下
如果我们这里设置起始路径的话,在ff_gen_drv.c文件内需要注释掉path代码,如果不设置的话会给我们一个默认的起始路径,这里就不需要注释掉了
回到main.c文件内,取消注释FATFS初始化函数
测试FATFS文件系统
// fatfs测试
void mkfs(void) {uint8_t res = f_mkfs(USERPath, 1, _MAX_SS);printf("mkfs res: %d\r\n", res);
}FATFS fs;void mnt(void) {uint8_t res = f_mount(&fs, USERPath, 1);printf("mnt res: %d\r\n", res);
}FIL file;void create_file(char* file_name, char* content) {int res = 0;int bwritten = 0;printf("Create file :%s\r\n", file_name);// 创建一个a.txt文件res = f_open(&file, file_name, FA_WRITE | FA_CREATE_ALWAYS);printf("Create file res:%d\r\n", res);// 写入数据到文件中res = f_write(&file, content, strlen(content), (UINT*)&bwritten);printf("write file res:%d\r\n", res);// 关闭文件f_close(&file);
}void list_files(char* path) {printf("file list:\r\n");FILINFO fno;DIR dir;FRESULT res;res = f_opendir(&dir, path);if (res == FR_OK) {while (1) {res = f_readdir(&dir, &fno);if (res != FR_OK || fno.fname[0] == 0)break;printf("%s\r\n", fno.fname);}f_closedir(&dir);}
}void read_file(char* file_name, char* content) {int res = 0;int bread = 0;printf("Show File Content:%s\r\n", file_name);res = f_open(&file, file_name, FA_READ);printf("Open file res : %d\r\n", res);res = f_read(&file, content, 100, (UINT*)&bread);printf("Read file res : %d\r\n", res);f_close(&file);
}
// fatfs测试int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_SPI1_Init();MX_FATFS_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */sfud_init();mnt();mkfs();char content_a[100] = "hello world\r\nhello fatfs\r\nhello violet\r\n";create_file("a.txt", content_a);char content_b[100] = "37193719731831300\r\n";create_file("b.txt", content_b);char content_c[100] = "dadajdlajldjajajflajf\r\n";create_file("c.txt", content_c);list_files(USERPath);char read_content[100] = {0};read_file("a.txt", read_content);printf("%s\r\n", read_content);memset(read_content, 0, sizeof(read_content));read_file("b.txt", read_content);printf("%s\r\n", read_content);memset(read_content, 0, sizeof(read_content));read_file("c.txt", read_content);printf("%s\r\n", read_content);// rs();// HAL_Delay(1000);// ws();// HAL_Delay(1000);// rs();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1) {/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
结果
测试成功,完成了对FATFS的移植了,喜欢的话点个关注吧。
相关文章:
STM32F103ZET6移植FATFS文件系统教程(W25Q32)
一、FATFS核心特性 跨平台支持 支持FAT12/FAT16/FAT32格式,兼容Windows文件系统; 采用标准C语言编写,代码量小且支持RTOS。 配置灵活性 通过宏定义实现功能裁剪,例如: FF_FS_READONLY:设为1时禁…...
数据泄露防护系统:全面保护企业信息安全的功能解析
随着信息技术的快速发展,数据泄露事件频发,给企业带来了巨大的经济损失和声誉损害。为了有效应对这一挑战,越来越多的企业开始部署专业的数据泄露防护(DLP)系统。安固软件作为一款领先的数据防泄漏解决方案,…...
【野火模型】利用深度神经网络替代 ELMv1 野火参数化:机制、实现与性能评估
目录 一、ELMv1 野火过程表示法(BASE-Fire)关键机制野火模拟的核心过程 二、采用神经网络模拟野火过程三、总结参考 一、ELMv1 野火过程表示法(BASE-Fire) ELMv1 中的野火模型(称为 BASE-Fire)源自 Commun…...
【WPF】 在WebView2使用echart显示数据
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、NuGet安装WebView2二、代码部分1.xaml中引入webview22.编写html3.在WebView2中加载html4.调用js方法为Echarts赋值 总结 前言 为了实现数据的三维效果&…...
java实现二叉树的前序、中序、后序遍历(递归和非递归方式)以及层级遍历
java实现二叉树的前序、中序、后序遍历以及层级遍历 一、二叉树节点定义二、递归方式1.前序遍历2.中序遍历3.后序遍历 三、非递归方式1.前序遍历2.中序遍历3.后序遍历4.层级遍历5.分层打印 四、测试用例 一、二叉树节点定义 class TreeNode {int val;TreeNode left;TreeNode r…...
学习笔记十三—— 理解 Rust 闭包:从语法到 impl Fn vs Box<dyn Fn>
🧠 理解 Rust 闭包:从语法到 impl Fn vs Box 📚 目录 闭包是什么?和普通函数有什么不同?闭包的语法长什么样?闭包“捕获变量”是什么意思?闭包和所有权的关系Fn、FnMut、FnOnce 三种闭包类型的…...
Linux虚拟机filezilla总是连不上
刚好有两个虚拟机,测试了一下问题所在 从第一个到第二个需要设置什么 image PNG 68.59KB image PNG 134.39KB ChatGLM 从第一个到第二个需要设置开启ssh服务,具体步骤如下: 输入以下命令来启动SSH服务: bash 复制 sud…...
NO.94十六届蓝桥杯备战|图论基础-单源最短路|常规dijkstra|堆优化dijkstra|bellman-ford|spfa(C++)
在图G中,假设 v i v_{i} vi和 v j v_{j} vj为图中的两个顶点,那么 v i v_{i} vi到 v j v_{j} vj路径上所经过边的权值之和就称为带权路径⻓度。 由于 v i v_{i} vi到 v j v_{j} vj的路径可能有多条,将带权路径⻓度最短的那条路径…...
DISCO:利用大型语言模型提取反事实
DISCO: Distilling Counterfactuals with Large Language Models - ACL Anthologyhttps://aclanthology.org/2023.acl-long.302/ 1. 概述 尽管在自然语言处理(NLP)领域针对各种推理任务取得了巨大进展(Wang 等, 2018, 2019a;Xu 等, 2020),但数据集偏差仍然是构建鲁棒模型…...
若依微服务版启动小程序后端
目录标题 本地启动,dev对应 nacos里的 xxx-xxx-dev配置文件 本地启动,dev对应 nacos里的 xxx-xxx-dev配置文件...
C语言 - 深拷贝与浅拷贝详解
深拷贝与浅拷贝详解 在 C 语言编程中,处理指针和动态内存是常见任务。在涉及数据拷贝操作时,我们经常会听到“深拷贝”和“浅拷贝”这两个术语。理解它们之间的区别对于避免程序中的内存错误和数据覆盖问题至关重要。 本文将全面讲解 C 语言中的深拷贝与…...
Serverless集群搭建:Knative
文章目录 Knative搭建1.准备工作安装Kubernetes安装 Istio 2.部署Knative Knative搭建 搭建流程图: 1.准备工作 准备工作 ● 本安装操作中的步骤 bash 适用于 MacOS 或 Linux 环境。对于 Windows,某些命令可能需要调整。 ● 本安装操作假定您具有现有…...
今日行情明日机会——20250416
指数在区间震荡,还需要等突破下跌趋势企稳 2025年4月16日涨停的主要行业方向分析 1. 外贸(9家涨停) 细分领域:跨境物流、纺织出口、供应链服务。代表个股: 五板:泰慕士(纺织服装出口龙头&…...
STM32基础教程——DMA
目录 前言 编辑 技术实现 接线图 代码实现 技术要点 DMA时钟 DMA初始化 DMA数据传输设置 数据改变与显示 实验结果 问题记录 前言 DMA(Direct Memory Access)直接存储器存取,用来提供在外设和存储器 之间或者存储器和存储器之间的高速数据传输。无需…...
Node.js 中文件系统模块(`fs`)的详细总结,包括定义、作用、各种写入方式及使用场景
Node.js 中文件系统模块(fs)的详细总结,包括定义、作用、各种写入方式及使用场景: 🧩 一、fs 模块简介 ✅ 定义 fs(File System)是 Node.js 官方内置模块,用于实现对文件和目录的操…...
MyBatis与MyBatis-Plus:字段自动填充的两种实现方式
目录 1. 使用 MyBatis 拦截器实现字段自动填充 2. 使用 MyBatis-Plus 实现字段自动填充 1. 使用 MyBatis 拦截器实现字段自动填充 实现步骤 创建拦截器 实现 MyBatis 的 Interceptor 接口,通过拦截 MyBatis 执行的 SQL 操作来自动填充公共字段 Intercepts({Signa…...
比特率、码元速率(波特率)的定义、关系及相关计算公式
一、相关定义 (一)比特率 比特率(Bit Rate):单位时间内传输的二进制比特数,是信息传输速率的度量。单位:比特每秒(bit/s,bps)。公式:比特率 传…...
炫云平台全面支持Blender4.4云渲染
随着世界渲染大赛众多优秀作品被大家关注,Blender作为建模渲染一体化的软件,也是众多3D艺术家最常用的软件之一。云渲染自然是提升创作效率必不可少的工作。这篇文章说一下炫云云渲染平台近期对Blender云渲染支持的情况。 首先,炫云客户端已经…...
Python自学第1天:变量,打印,类型转化
突然想学Python了。经过Deepseek的推荐,下载了一个Python3.12安装。安装过程请自行搜索。 乖乖从最基础的学起来,废话不说了,上链接,呃,打错了,上知识点。 变量的定义 # 定义一个整数类型的变量 age 10#…...
Flutter 从零到一
iOS 调试与开发工具指南 真机调试 Xcode run 在控制台获取 Dart VM service URIVSCode 点击 Cmd Shift P 选择 Debug: Attach to Flutter on Device粘贴 the URI 后点击 Enter 对于iOS开发者来说,使用appuploader这样的iOS开发助手可以简化真机调试的准备工作。…...
ocr-身份证正反面识别
在阿里云官网,申请一个token [阿里官方]身份证OCR文字识别_API专区_云市场-阿里云 (aliyun.com) 观察一下post请求body部分json字符串,我们根据这个创建一个java对象 先默认是人像面 public class IdentityBody {public String image;class configure…...
深入解析Spring Boot核心组件及其关键功能
【版本:spring-boot-2.1.3.RELEASE】 深入Spring Boot核心组件 Spring Boot是一个流行的框架,简化了基于Spring的应用程序的开发和部署。它通过自动配置和“开箱即用”的特性,使得开发者可以快速启动和运行应用程序。在Spring Boot中&#x…...
JVM 调优不再难:AI 工具自动生成内存优化方案
在 Java 应用程序的开发与运行过程中,Java 虚拟机(JVM)的性能调优一直是一项极具挑战性的任务,尤其是内存优化方面。不合适的 JVM 内存配置可能会导致应用程序出现性能瓶颈,甚至频繁抛出内存溢出异常,影响业…...
分层式设备控制架构、分布式微服务架构及插件化架构
在现代高端装备制造(如半导体设备、精密自动化系统)中,分层式设备控制架构、分布式微服务架构和插件化架构是提升系统灵活性、实时性和可扩展性的核心技术。以下从设计原理、实现方式及行业应用三个维度展开说明:  1.…...
上门服务 APP 30 亿营收商业模式在乌干达的技术赋能与实践
不久前,非洲乌干达出现黑人女技师提供上门足疗服务的消息引发关注。据了解,当地一次40分钟的上门按摩服务仅需约40元人民币,价格仅为国内同类服务的十分之一。这一现象折射出全球健康服务行业正在经历的数字化转型浪潮。 国内领先的上门服务平…...
Chemical Review IF=51.4 综述 | 柔性机器人的当下与未来:材料、技术与应用的深度融合
2025.03.31. 新加坡南洋理工大学研究团队在《Chemical Reviews》期刊上发表 “Soft Materials and Devices Enabling Sensorimotor Functions in Soft Robots” 综述型文章。软机器人的传感器运动功能对其与环境交互至关重要,本文全面综述了相关软材料和设备。传感技…...
Python抽象基类
abstractmethod 详解 abstractmethod 是 Python 中 abc 模块(Abstract Base Classes,抽象基类)提供的一个装饰器,用于定义抽象方法。抽象方法是一种在基类中声明但不实现具体逻辑的方法,强制子类必须实现该方法。以下…...
计算机网络中各种物理量的单位总结
在计算机网络中,数据速率的单位容易混淆,以下是清晰总结: 一、基本单位区分 比特(bit)与字节(Byte) 小写 b 表示 比特(bit),是数据传输的基本单位。 大写 B…...
PCIE网卡驱动DMA初始化配置
1. DMA 启用的时机 e1000e 驱动在 设备初始化阶段 启用 DMA,具体步骤如下: (1) PCIe 设备初始化 调用路径: e1000_probe() → e1000_sw_init() → e1000_init_hw() → e1000_configure() 关键操作: 启用 PCIe 设备的 DMA 主控模…...
音视频小白系统入门笔记-1
本系列笔记为博主学习李超老师课程的课堂笔记,仅供参阅 课程传送门:音视频小白系统入门课 音视频基础ffmpeg原理 往期课程笔记传送门:音视频小白系统入门笔记-0 课程实践代码仓库:传送门 音频采集 命令行采集 Android端音频…...
技术速递|使用 BrowserStack App Automate 和 Appium UI 测试 .NET MAUI 应用
作者:Sweeky&Gerald 排版:Alan Wang 本文是 Gerald 的博客《开始使用 Appium 测试 .NET MAUI 应用的 UI 》中创建的 .NET MAUI – 使用 Appium 和 NUnit 进行 UI 测试的续篇。 在本篇博客中,我们将了解如何使用 BrowserStack App Automa…...
在多系统环境中实现授权闭环,Tetra Pak 借助CodeMeter打造食品工业的安全自动化体系
一、 行业背景与安全新挑战 在食品加工自动化不断深化的背景下,食品安全、功能安全与知识产权保护的需求日益迫切。Tetra Pak 作为全球领先的食品加工和包装解决方案提供商,业务遍布 160 多个国家,涵盖从配料混合、碳酸化处理到全线自动包装。…...
Nginx+SpringBoot跨域那些事儿(多域名跨域加强版——Nginx配置详解)
嘿,小伙伴们,咱们接着上回书说到,当你的应用需要支持多个域名跨域访问时,Nginx+SpringBoot这对黄金搭档绝对是你的不二之选!今天,咱们就深入聊聊如何在Nginx中配置多个域名跨域,让你的应用更加灵活、强大! 一、跨域问题再科普(多域名跨域场景) 在前后端分离开发中,…...
基于Python的App流量大数据分析与可视化方案
一、引言 App流量数据通常包括用户的访问时间、停留时间、点击行为、页面跳转路径等信息。这些数据分散在不同的服务器日志、数据库或第三方数据平台中,需要通过有效的技术手段进行整合和分析。Python在数据科学领域的广泛应用,得益于其简洁的语法、强大…...
windows下使用nginx + waitress 部署django
架构介绍 linux一般采用nginx uwsgi部署django,在Windows下,可以取代uwsgi的选项包括Waitressa、Daphnea、Hypercoma和Gunicorna(通过WSLa 运行)。windows服务器一般采用nginx waitress 部署django,,他们的关系如下 django是WEB应用…...
openssh离线一键升级脚本分享(含安装包)
查看当前的版本 [rootmyoracle ~]#ssh -V相关安装包下载地址 openssh下载地址:http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssl下载地址:https://www.openssl.org/source/zlib下载地址:http://www.zlib.net/今天演示从7.4升级…...
【专题刷题】双指针(二)
📝前言说明: 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分每题主要记录:(1)本人解法 本人屎山代码;(2)优质解法 优质代码;ÿ…...
Ubuntu服务器中了木马且处于局域网内无法直接通过公网正向连接
如果你的Ubuntu服务器中了木马且处于局域网内无法直接通过公网正向连接,可以尝试以下方法进行应急响应和恢复控制: 一、尝试通过局域网内部访问(优先方案) 如果攻击者未完全封锁你的权限,且你有局域网内其他机器的控制权: 通过跳板机连接: 使用同一局域网内的其他机器…...
Day09 【基于LSTM实现文本加标点的任务】
基于LSTM实现文本加标点的任务 目标数据准备参数配置数据处理模型构建定义模型结构前向传播方法优化器选择 主程序测试与评估类初始化模型评估统计记录显示统计结果 测试结果 目标 本文基于给定的词表,将输入的文本基于jieba分词分割为若干个词,然后基于…...
SQL刷题日志(day2)
1、timestampdiff:计算时间间隔 timestampdiff(unit,start_date,end_date) 参数说明: unit:返回的时间单位,如minute,hour等start_date:开始日期end_date:结束日期 2、dense_rank(ÿ…...
仿 ElementUI 搭建自己的 vue 组件库
仿 ElementUI 搭建自己的 vue 组件库 一、创建 my-ui-can 项目1. 新建项目2. 自定义组件3. 创建 MyButton 组件4. 导出组件5. package.json 二、发布到 npm 仓库1. npm 账号注册(忽略)2. 发布 my-ui-can 二、项目引用 my-ui-can 依赖包方式一:…...
CentOS 操作系统下搭建 tsung性能测试环境
写在前面 为何这么安装,实际就是这么做的,这是经过好几次实践得出的经验总结。 这为了让大家更清楚的知道怎么安装 tsung性能测试环境,按步照搬的安装即可。 步骤 1、 下载软件安装包 CentOS-6.0-x86_64-bin-DVD1.iso jdk-6u4-linux-x64-rpm.bin erlang: otp_src_1…...
基于YOLOv9的课堂行为检测系统
基于YOLOv9的课堂行为检测系统 项目概述 本项目是一个基于YOLOv9深度学习模型的课堂行为检测系统,旨在通过计算机视觉技术自动识别和监测课堂中学生的各种行为状态,帮助教师更好地了解课堂教学效果。 项目结构 课堂行为检测/ ├── data/ │ ├──…...
Linux常见工具的基本使用,同时介绍了编译过程和动/静态链接的原理
目录 一、工具的本质 二、一些常用的工具 1.yum 2.vim 1)vim的三种基本模式: 2)vim的基本操作 ①命令模式下的基本操作: ②插入模式: ③底行模式: 3)vim的配置:让他变得更好用 3.gcc…...
6.(vue3.x+vite)动态挂载组件并传递参数和方法
1:效果截图 2:父组件代码 <template><div id="cesiumID"></div><div>子组件使用方法传递给父组件的值:{...
大数据人工智能
在大数据人工智能领域,需要具备多种算法和深度学习知识,以下是一些常见的: 机器学习算法 - 线性回归:用于建立输入特征与连续型输出变量之间的线性关系,常用于预测数值型数据。 - 逻辑回归:主要用于二分类…...
Vue3 nextTick
nextTick 是 Vue 中非常重要的一个 API,它允许你在 DOM 更新周期后执行延迟回调。 核心源码位置 Vue3 的 nextTick 实现主要在 packages/runtime-core/src/scheduler.ts 文件中。 基本实现 const resolvedPromise Promise.resolve() as Promise<any> let …...
快速入手-基于python和opencv的人脸检测
1、安装库 pip install opencv-python 如果下载比较卡的话,指向国内下载地址: pip3 install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple 2、下载源码 https://opencv.org/ windows11对应的版本下载: https://pan.baidu…...
第七节:React HooksReact 18+新特性-并发模式(Concurrent Mode)解决了什么问题?
• 考点:可中断渲染、优先级调度、startTransition使用场景 • 示例:搜索框输入防抖优化 React Hooks 进阶:自定义 Hook 设计实战指南(以 useWindowSize 和 useFetch 为例) 一、自定义 Hook 设计规范 在实现 useWind…...
jwt的无感刷新
jwt无感刷新 如果没有引入额外的刷新机制,JWT 过期后后续请求就会因验证失败而拒绝,导致用户需要重新登录,从而被“强制下线”。为实现无感刷新,可以考虑以下几种方案: 引入 Refresh Token 双 token 机制:…...