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

STM32单片机,通过Flash模拟U盘运用FATFS管理文件

这是最近项目上多次需要这个功能,于是倒腾了有些时候,其中参考了很多网上的资料,其次还咨询了我的一个王师兄,帮助了我很多,在此表示感谢。好了下面开始正儿八经的东西了。

1.他们的关系是什么?

完成这个任务需要先理清楚Flash、FATFS、虚拟U盘、STM32单片(单片机)机这几者之间的关系,Flash是一个存贮介质单片机会对其进行数据管理。而FATFS是一个操作系统,相当于自动的帮助我们管理数据,从数据结构的角度上来说就是管理入栈出栈以及数据的表头表尾中间位置数据的删除添加等等一系列的操作,这个都已经帮助我们完成了。这三个已经可以实现了一个完整的功能,就是单片机通过某种协议比如下面会使用的SPI通讯协议对Flash进行读写数据,而为了便于操作我们在单片机上面移植了FATFS文件管理系统,对于数据的管理更加的便携。现在你已经实现了单片机上的数据管理,但是现在你想把数据在电脑上显示,于是有一个叫虚拟U盘这个东西出现,它通过数据线将电脑与单片机连接起来,希望单片机可以像U盘一样把数据显示在电脑端,所以这个便叫虚拟U盘(自己瞎比喻的)。而实现这个功能就是通过CubeMx配置单片机上面的USB端口而实现这一功能。ok,下面开始实操。

2.对Flash进行操作

本项目使用的存储芯片是W25Q128,所以下述内容都基于此内容完成。还有更多的存储介质以及芯片需要不同的驱动代码。下面是本项目的驱动代码。

W25Qxx.c(代码出自:从 0 搭建 SPI Flash 文件系统:驱动、FatFS、读写与坑点 | 时光的轨迹)

#include "W25Qxx.h" static void W25Qxx_Reset(void); W25Qxx_Info_t W25Qxx_Info = {0}; __weak void W25Qxx_CS_Enable(void) { } __weak void W25Qxx_CS_Disable(void) { } // 返回1是正常 __weak uint8_t W25Qxx_ReadByte(uint8_t* RxData, uint16_t Size) { (void)RxData; (void)Size; return 0; } // 返回1是正常 __weak uint8_t W25Qxx_WriteByte(uint8_t* TxData, uint16_t Size) { (void)TxData; (void)Size; return 0; } __weak uint32_t W25Qxx_GetTick(void) { return 0; } /** * @brief Initializes the W25Q128FV interface. * @retval None */ uint8_t W25Qxx_Init(void) { /* Reset W25Qxx */ W25Qxx_Reset(); return W25Qxx_GetStatus(); } /** * @brief This function reset the W25Qx. * @retval None */ static void W25Qxx_Reset(void) { uint8_t cmd[2] = {RESET_ENABLE_CMD, RESET_MEMORY_CMD}; W25Qxx_CS_Enable(); /* Send the reset command */ W25Qxx_WriteByte(cmd, 2); W25Qxx_CS_Disable(); } /** * @brief Reads current status of the W25Q128FV. * @retval W25Q128FV memory status */ uint8_t W25Qxx_GetStatus(void) { uint8_t cmd[] = {READ_STATUS_REG1_CMD}; uint8_t status; W25Qxx_CS_Enable(); /* Send the read status command */ W25Qxx_WriteByte(cmd, 1); /* Reception of the data */ W25Qxx_ReadByte(&status, 1); W25Qxx_CS_Disable(); /* Check the value of the register */ if((status & W25QXX_FSR_BUSY) != 0) { return W25QXX_BUSY; } else { return W25QXX_OK; } } /** * @brief This function send a Write Enable and wait it is effective. * @retval None */ uint8_t W25Qxx_WriteEnable(void) { uint8_t cmd[] = {WRITE_ENABLE_CMD}; uint32_t tickstart = W25Qxx_GetTick(); /*Select the FLASH: Chip Select low */ W25Qxx_CS_Enable(); /* Send the read ID command */ W25Qxx_WriteByte(cmd, 1); /*Deselect the FLASH: Chip Select high */ W25Qxx_CS_Disable(); /* Wait the end of Flash writing */ while(W25Qxx_GetStatus() == W25QXX_BUSY) { /* Check for the Timeout */ if((W25Qxx_GetTick() - tickstart) > W25QXX_TIMEOUT_VALUE) { return W25QXX_TIMEOUT; } } return W25QXX_OK; } /** * @brief Read Manufacture/Device ID. * @param return value address * @retval None */ void W25Qxx_Read_ID(uint8_t* ID) { uint8_t cmd[4] = {READ_JEDEC_ID_CMD, 0x00, 0x00, 0x00}; W25Qxx_CS_Enable(); /* Send the read ID command */ W25Qxx_WriteByte(cmd, 1); /* Reception of the data */ W25Qxx_ReadByte(ID, 3); W25Qxx_CS_Disable(); } void W25Qxx_IC_Check(void) { uint32_t count; uint8_t temp_id[3]; /* Read FLASH ID */ W25Qxx_Read_ID(temp_id); W25Qxx_Info.Flash_ID = ((uint32_t)temp_id[0] << 16) | ((uint32_t)temp_id[1] << 8) | ((uint32_t)temp_id[2]); W25Qxx_Info.Flash_Sector_Count = 0x00; W25Qxx_Info.Flash_Sector_Size = 0x00; switch(W25Qxx_Info.Flash_ID) { /* W25XXX */ case W25X10_FLASH_ID: /* 0xEF3011-----1M bit */ count = 1; break; case W25X20_FLASH_ID: /* 0xEF3012-----2M bit */ count = 2; break; case W25X40_FLASH_ID: /* 0xEF3013-----4M bit */ count = 4; break; case W25X80_FLASH_ID: /* 0xEF4014-----8M bit */ count = 8; break; case W25Q16_FLASH_ID1: /* 0xEF3015-----16M bit */ case W25Q16_FLASH_ID2: /* 0xEF4015-----16M bit */ count = 16; break; case W25Q32_FLASH_ID1: /* 0xEF4016-----32M bit */ case W25Q32_FLASH_ID2: /* 0xEF6016-----32M bit */ count = 32; break; case W25Q64_FLASH_ID1: /* 0xEF4017-----64M bit */ case W25Q64_FLASH_ID2: /* 0xEF6017-----64M bit */ count = 64; break; case W25Q128_FLASH_ID1: /* 0xEF4018-----128M bit */ case W25Q128_FLASH_ID2: /* 0xEF6018-----128M bit */ count = 128; break; case W25Q256_FLASH_ID1: /* 0xEF4019-----256M bit */ case W25Q256_FLASH_ID2: /* 0xEF6019-----256M bit */ count = 256; break; default: if((W25Qxx_Info.Flash_ID != 0xFFFFFFFF) && (W25Qxx_Info.Flash_ID != 0x00000000)) { count = 16; } else { count = 0x00; } break; } count = ((uint32_t)count * 1024) * ((uint32_t)1024 / 8); if(count) { // 如果是内部,那么DEF_UDISK_SECTOR_SIZE是512,如果是外部,则DEF_SECTOR_SIZE是4096 W25Qxx_Info.Flash_Sector_Count = count / DEF_SECTOR_SIZE; // DEF_SECTOR_SIZE; W25Qxx_Info.Flash_Sector_Size = DEF_SECTOR_SIZE; // DEF_SECTOR_SIZE; W25Qxx_Info.Flash_Page_Size = 256; // 全系列固定的 } else { // printf ("External Flash not connected\r\n"); // while(1); } } /** * @brief Reads an amount of data from the QSPI memory. * @param pData: Pointer to data to be read * @param ReadAddr: Read start address * @param Size: Size of data to read * @retval QSPI memory status */ // TODO uint8_t W25Qxx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) { uint8_t cmd[4]; /* Configure the command */ cmd[0] = READ_CMD; cmd[1] = (uint8_t)(ReadAddr >> 16); cmd[2] = (uint8_t)(ReadAddr >> 8); cmd[3] = (uint8_t)(ReadAddr); W25Qxx_CS_Enable(); /* Send the read ID command */ W25Qxx_WriteByte(cmd, 4); /* Reception of the data */ if(W
http://www.cnnetsun.cn/news/2738387.html

相关文章:

  • PanTools (多网盘批量管理工具) v1.1.18 中文绿色版
  • 深度解析:douyin-downloader 抖音批量下载工具的技术架构与实战应用
  • Windows系统自动化配置工具架构解析:实现原理与性能优化指南
  • SpaceX拟750亿美元募资上市,1.75万亿美元估值能否撑起商业帝国扩张?
  • 量子计算在数据质量管理与异常检测中的应用
  • 别再只会用Postman了!用HttpClient在Java里玩转微信登录(附工具类封装)
  • Windows 11系统瘦身秘籍:3步告别臃肿,让你的电脑重获新生
  • 设计走查表与设计还原度优化:像素级精准的工程实践
  • 把开发环境装进U盘:用WTG打造一个即插即用的Python/数据分析移动工作站
  • Axure RP中文界面3步搞定:告别英文困扰,轻松实现专业原型设计
  • 从PBMC数据实战出发:手把手教你用Scanpy完成细胞类型注释全流程(含Marker基因字典与聚类验证)
  • 如何用零代码数据采集工具破解闲鱼市场情报困局?
  • 除了KMS激活失败,Windows Server 2016自动关机还有这个隐藏原因和临时救急脚本
  • 从RC滤波到双稳态:分立元件声控逻辑电路设计与实践
  • Win11 WSL2 + Ubuntu 18.04:不止装ROS,打造你的机器人开发一体化环境(含CUDA/PyTorch配置)
  • Android平台上的统一SDR驱动架构:rtl_tcp_andro的技术实现与应用生态
  • 深入探讨 Go 语言中 context上下文控制 的底层实现与并发安全
  • 一个RAG系统上线一周,召回率从85%掉到30%——问题出在没人告诉你的地方
  • TVA引发的工业视觉范式革命(8)
  • HBase与Hadoop:基于什么开发?深度剖析与架构图
  • RapidOCR深度解析:从毫秒级响应到微秒级突破的实时推理架构揭秘
  • 终极Windows程序兼容方案:Wine如何让Linux/macOS无缝运行Windows应用
  • 基于使用 AI 自动化生成前端单元测试构建高响应与流式人机交互的现代化 AI 前端界面
  • 如何在电脑上轻松编辑PDF | 最新指南
  • 如何快速激活Adobe CC:Adobe-GenP 3.0终极完整指南
  • AI Agent Harness并发控制优化
  • 【算法设计与分析】第40篇:空间数据结构:KD树与四叉树的查询分析
  • 基于555定时器与齐纳二极管的音乐驱动跳舞机器人电路设计与实现
  • 别再傻傻输验证码了!用BurpSuite Intruder模块,5分钟搞定那些“形同虚设”的登录防护
  • 天赐范式第62天:从128到256的非定常自适应验证——跨尺度记忆传承