STM32CubeMX学习笔记20——SD卡FATFS文件系统

1. FATFS文件系统简介

文件系统是操作系统用于明确存储设备或分区上的文件的方法和数据结构(即在存储设备上组织文件的方法)。操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统;不带文件系统的SD卡仅能实现简单的读写扇区操作,要真正应用SD卡必须要使用文件系统

FATFS文件存储原理(以FAT32为例),下图为FAT32文件系统布局:

簇是文件存储的最小单元,FAT32分区大小与对应簇空间大小关系如下表示:

分区空间大小簇空间大小每个簇包含的扇区数
< 8GB4KB8
[ 8GB, 16GB )8KB16
[ 16GB, 32GB )16KB32
>= 32GB32KB64

例如:创建一个50字节的test.txt文件,文件大小是50字节,但是占用磁盘空间为4096字节(一个簇)

FATFS是一个完全免费开源,专为小型嵌入式系统设计的FAT(File Allocation Table)文件系统模块。FATFS的编写遵循ANSI C,并且完全与磁盘I/O层分开。支持FAT12/FAT16/FAT32,支持多个存储媒介,有独立的缓冲区,可对多个文件进行读写。兼容Windows文件系统。

FatFs 文件系统的源码可以从 fatfs 官网下载:
FatFs - Generic FAT Filesystem Module

FATFS模块的层次结构如下图示:

- 最顶层是应用层:使用者只需要调用FATFS模块提供给用户的一系列应用接口函数(如f_open, f_read, f_write和f_close等),就可以像在PC上读写文件那样简单
- 中间层FATFS模块:实现了FAT文件读写协议;它提供了 ff.cff.h文件,一般情况下不用修改,使用时将头文件包含进去即可
- 最底层是FATFS模块的底层接口:包括存储媒介读写接口和供给文件创建修改时间的实时时钟,需要在移植时编写对应的代码

FATFS源码相关文件介绍如下表示;移植FATFS模块时,一般只需要修改2个文件(即ffconf.hdiskio.c

与平台无关文件描述
ffconf.hFATFS模块配置文件
ff.hFATFS和应用模块公用的包含文件
ff.cFATFS模块
diskio.hFATFS和disk I/O模块公用的包含文件
interger.h数据类型定义
option可选的外部功能(比如支持中文)
与平台相关文件描述
diskio.cFATFS和disk I/O模块接口层文件

FATFS的移植主要分为三步:

  1. 数据类型:在integer.h里面去定义好数据的类型
  2. 配置:通过ffconf.h配置FATFS相关功能
  3. 函数编写:在diskio.c文件中进行底层驱动编写(6个接口函数disk_initialize、disk_status、disk_read、disk_write、disk_ioctl、get_fattime)

本例程使用的是STM32CubeMX图形化软件配置FATFS,只需要简单设置即可以完成以上三步的工作。下图是STM32CubeMX的FATFS底层实现框图:

STM32CubeMX生成的代码工程里,涉及底层驱动实现的文件主要有以下三个:

1、ff_gen_drv.c文件:FATFS提供的通用驱动文件的实现
//ff_gen_drv.h文件内容
/*Disk IO Driver structure definition */
typedef struct
{DSTATUS (*disk_initialize) (BYTE);    //通过指针指向diskio.c中的disk_initialize()DSTATUS (*disk_status)     (BYTE);    //通过指针指向diskio.c中的disk_status()DRESULT (*disk_read)       (BYTE, BYTE*, DWORD, UINT);    //指向disk_read()
#if _USE_WRITE == 1 DRESULT (*disk_write)      (BYTE, const BYTE*, DWORD, UINT);  //指向disk_write()
#endif 
#if _USE_IOCTL == 1  DRESULT (*disk_ioctl)      (BYTE, BYTE, void*);   //指向disk_ioctl() 
#endif
}Diskio_drvTypeDef;/*brief  Global Disk IO Drivers structure definition*/ 
typedef struct{ uint8_t                 is_initialized[_VOLUMES]; //磁盘是否初始化Diskio_drvTypeDef       *drv[_VOLUMES];   //磁盘的驱动uint8_t                 lun[_VOLUMES];    //磁盘的编号__IO uint8_t            nbr;
}Disk_drvTypeDef;
/* Exported functions ------------------------------------------------------- */
uint8_t FATFS_LinkDriverEx(Diskio_drvTypeDef *drv, char *path, uint8_t lun);
uint8_t FATFS_LinkDriver(Diskio_drvTypeDef *drv, char *path);
uint8_t FATFS_UnLinkDriver(char *path);
uint8_t FATFS_LinkDriverEx(Diskio_drvTypeDef *drv, char *path, BYTE lun);
uint8_t FATFS_UnLinkDriverEx(char *path, BYTE lun);
uint8_t FATFS_GetAttachedDriversNbr(void);
2、sd_diskio.c:针对SD底层驱动实现,封装成为通用的底层驱动API
//sd_diskio.c文件内容
const Diskio_drvTypeDef  SD_Driver = {SD_initialize,    //指向diskio.c中的disk_initialize()SD_status,    //指向diskio.c中的disk_status()SD_read,  //指向diskio.c中的disk_read()
#if  _USE_WRITE == 1SD_write, //指向diskio.c中的disk_write()
#endif /* _USE_WRITE == 1 */  
#if  _USE_IOCTL == 1SD_ioctl, //指向diskio.c中的disk_ioctl()
#endif /* _USE_IOCTL == 1 */
};  //定义Diskio_drvTypeDef类型的SD_Driver/* -------------------以上各函数的实现---------------------------*/
DSTATUS SD_initialize(BYTE lun){Stat = STA_NOINIT;  if(BSP_SD_Init() == MSD_OK){Stat &= ~STA_NOINIT;}return Stat;
}DSTATUS SD_status(BYTE lun){Stat = STA_NOINIT;if(BSP_SD_GetCardState() == MSD_OK){Stat &= ~STA_NOINIT;}return Stat;
}DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count){DRESULT res = RES_ERROR;uint32_t timeout = 100000;if(BSP_SD_ReadBlocks((uint32_t*)buff,(uint32_t) (sector), count, SD_DATATIMEOUT) == MSD_OK){while(BSP_SD_GetCardState()!= MSD_OK){if (timeout-- == 0)return RES_ERROR;}res = RES_OK;} return res;
}#if _USE_WRITE == 1
DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count){DRESULT res = RES_ERROR;uint32_t timeout = 100000;if(BSP_SD_WriteBlocks((uint32_t*)buff,(uint32_t)(sector),count, SD_DATATIMEOUT) == MSD_OK){while(BSP_SD_GetCardState()!= MSD_OK){if (timeout-- == 0)return RES_ERROR;}    res = RES_OK;}return res;
}
#endif /* _USE_WRITE == 1 */#if _USE_IOCTL == 1
DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff){DRESULT res = RES_ERROR;BSP_SD_CardInfo CardInfo;  if (Stat & STA_NOINIT) return RES_NOTRDY;  switch (cmd){/* Make sure that no pending write process */case CTRL_SYNC :res = RES_OK;break;/* Get number of sectors on the disk (DWORD) */case GET_SECTOR_COUNT :BSP_SD_GetCardInfo(&CardInfo);*(DWORD*)buff = CardInfo.LogBlockNbr;res = RES_OK;break;/* Get R/W sector size (WORD) */case GET_SECTOR_SIZE :BSP_SD_GetCardInfo(&CardInfo);*(WORD*)buff = CardInfo.LogBlockSize;res = RES_OK;break;/* Get erase block size in unit of sector (DWORD) */case GET_BLOCK_SIZE :BSP_SD_GetCardInfo(&CardInfo);*(DWORD*)buff = CardInfo.LogBlockSize;res = RES_OK;break;default:res = RES_PARERR;} return res;
}
#endif /* _USE_IOCTL == 1 */
3、bsp_driver_sd.c:HAL库的二次封装,将基于SD卡的操作都在该文件下实现
//bsp_driver_sd.h文件内容
uint8_t BSP_SD_Init(void);
uint8_t BSP_SD_ITConfig(void);
void    BSP_SD_DetectIT(void);
void    BSP_SD_DetectCallback(void);
uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout);
uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout);
uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks);
uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks);
uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr);
void BSP_SD_IRQHandler(void);
void BSP_SD_DMA_Tx_IRQHandler(void);
void BSP_SD_DMA_Rx_IRQHandler(void);
uint8_t BSP_SD_GetCardState(void);
void    BSP_SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo);
uint8_t BSP_SD_IsDetected(void);
void    BSP_SD_AbortCallback(void);
void    BSP_SD_WriteCpltCallback(void);
void    BSP_SD_ReadCpltCallback(void);

FATFS提供的应用接口如下图示:

下面简单介绍几个常用操作函数:

f_mount:在FATFS模块上注册/注销一个工作区(文件系统对象)
FRESULT f_mount(FATFS* fs, const TCHAR* path, BYTE opt);
参数--> fs:fs工作区(文件系统对象)指针,如果赋值为 NULL 可以取消物理设备挂载path:注册/注销工作区的逻辑设备编号,使用设备根路径表示opt:注册或注销选项(可选0或1),0表示不立即挂载,1表示立即挂载
f_mkfs:格式化物理设备
FRESULT f_mkfs(const TCHAR* path, BYTE sfd, UINT au);
参数--> path:逻辑设备编号,使用设备根路径表示sfd:0或1,0表示为硬盘设备;1表示为软盘设备au:指定扇区大小,若为0表示通过disk_ioctl函数获取
f_open:创建/打开一个文件对象
FRESULT f_open(FIL* fp, const TCHAR* path, BYTE mode);
参数--> fp:将创建或打开的文件对象指针path:文件名指针,指定将创建或打开的文件名(包含文件类型后缀名)mode:访问类型和打开方法
mode可选值:
FA_READ     指定读访问对象。可以从文件中读取数据。 与FA_WRITE结合可以进行读写访问。   
FA_WRITE    指定写访问对象。可以向文件中写入数据。与FA_READ结合可以进行读写访问。   
FA_OPEN_EXISTING    打开文件。如果文件不存在,则打开失败。(默认)  
FA_OPEN_ALWAYS      如果文件存在,则打开;否则,创建一个新文件。  
FA_CREATE_NEW       创建一个新文件。如果文件已存在,则创建失败。   
FA_CREATE_ALWAYS    创建一个新文件。如果文件已存在,则它将被截断并覆盖。
f_close:关闭一个打开的文件
FRESULT f_close (FIL *fp)
参数--> fp:将被关闭的已打开的文件对象结构的指针
f_write:写入数据到一个已打开的文件
FRESULT f_write (FIL* fp, const void *buff, UINT btw, UINT* bw)
参数--> fp:指向将被写入的已打开的文件对象结构的指针buff:指向存储写入数据的缓冲区的指针btw:要写入的字节数bw:指向返回已写入字节数的UINT变量的指针,返回为实际写入的字节数
f_read:从一个打开的文件中读取数据
FRESULT f_read (FIL* fp, const void *buff, UINT btr, UINT* br)
参数--> fp:指向将被读取的已打开的文件对象结构的指针buff:指向存储读取数据的缓冲区的指针btr:要读取的字节数br:指向返回已读取字节数的UINT变量的指针,返回为实际读取的字节数

2. 硬件设计

LED2指示灯用来提示系统运行状态,串口1用来打印调试信息,使用FATFS文件系统对SD卡进行相关操作

  • LED2指示灯
  • USART1
  • TF卡

3 、 STM32CubeMX设置

  • RCC设置外接HSE,时钟设置为72M
  • PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
  • 激活SDIO,详细请参考SD卡例程
  • 打开FATFS文件系统,选择SD卡模式,配置为中文编码,选择内存空间为HEAP,其余默认值
  • Function Parameters 跳过

  • Locale and Namespace Parameters:

        CODE_PAGE(Code page on target): Simplified Chinese GBK(DBCS,OEM,Windows) 支持简体中文编码
        USE_LFN(Use Long Filename): Enabled with dynamic working buffer on the STACK 支持长文件名,并指定使用栈空间为缓冲区

缓存工作区为什么放在栈?其实fatfs提供了三个选项:BSS,STACK , HEAP,根据个人情况选一个。
在BSS上启用带有静态工作缓冲区的LFN,不能动态分配。
如果选择了HEAP(堆)且自己有属于自己的malloc就去重写ff_memalloc  ff_memfree函数。如果是库的malloc就不需要。
一般都选择使用STACK(栈),能动态分配。
当使用堆栈作为工作缓冲区时,请注意堆栈溢出。

Physical Drive Parameters:
        VOLUMES(Logical drivers): 2 指定物理设备数量,这里设置为 2,包括预留 SD 卡和 SPI Flash 芯片
        MAX_SS(Maximum Sector Size): 512 指定扇区大小的最大值。SD 卡扇区大小一般都为 512 字节,SPI Flash 芯片扇区大小一般设置为 4096 字节,所以需要把 _MAX_SS 改为 512
        MIN_SS(Minimum Sector Size): 512 指定扇区大小的最小值

配置SD卡检测引脚

        SD卡插入检测引脚,如果不配置一个引脚生成文件时会报错,所以这里即使没有硬件连接,也可以任意设置一引脚使用,生成工程后注释代码。

增大栈空间

将最小栈空间改到 0x1000

注意:由于刚才设置长文件名动态缓存存储在堆中,故需要增大堆大小,如果不修改则程序运行时堆会生成溢出,程序进入硬件错误中断(HardFault),死循环。

 输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

4、程序编程

int main(void){HAL_Init();SystemClock_Config();/* Initialize all configured peripherals */MX_GPIO_Init();MX_CRC_Init();MX_FSMC_Init();MX_SDIO_SD_Init();MX_USART1_UART_Init();MX_FATFS_Init();/* USER CODE BEGIN 2 */uint32_t byteswritten;                /* File write counts */uint32_t bytesread;                   /* File read counts */uint8_t wtext[] = "This is STM32 working with FatFs"; /* File write buffer */uint8_t rtext[100];                   /* File read buffers */char filename[] = "STM32cube.txt";char SensorBuff[100];printf("********* STM32CubeMX FatFs Example *********\r\n\r\n");    if(f_mount(&SDFatFS,SDPath,1) == FR_OK){printf("f_mount sucess!!! \r\n");if(f_open(&SDFile,filename,FA_CREATE_ALWAYS|FA_WRITE) == FR_OK){printf("f_open file sucess!!! \r\n");if(f_write(&SDFile,wtext,sizeof(wtext),&byteswritten) == FR_OK){printf("f_write file sucess!!! \r\n");printf("f_write Data : %s\r\n",wtext);if(f_close(&SDFile) == FR_OK)printf("f_close sucess!!! \r\n");elseprintf("f_close error : %d\r\n",retSD);}elseprintf("f_write file error\r\n");    }elseprintf("f_open file error\r\n");  }elseprintf("f_mount error : %d \r\n",retSD);retSD = f_open(&SDFile, filename, FA_READ);if(retSD)printf("f_open file error : %d\r\n",retSD);elseprintf("f_open file sucess!!! \r\n");retSD = f_read(&SDFile, rtext, sizeof(rtext), (UINT*)&bytesread);if(retSD)printf("f_read error!!! %d\r\n",retSD);else{printf("f_read sucess!!! \r\n");printf("f_read Data : %s\r\n",rtext);}retSD = f_close(&SDFile);if(retSD)printf("f_close error!!! %d\r\n",retSD);elseprintf("f_close sucess!!! \r\n");if(bytesread == byteswritten)printf("FatFs is working well!!!\r\n");if(f_open(&SDFile,(const char*)"Sensor.csv",FA_CREATE_ALWAYS|FA_WRITE) == FR_OK){printf("Sensor.csv was opened/created!!!\r\n");sprintf(SensorBuff, "Item,Temp,Humi,Light\r\n");f_write(&SDFile,SensorBuff,strlen(SensorBuff),&byteswritten);for(int i = 0; i < 10; i++){sprintf(SensorBuff, "%d,%d,%d,%d\r\n",i + 1, i + 20, i + 30, i + 40);f_write(&SDFile,SensorBuff,strlen(SensorBuff),&byteswritten);f_sync(&SDFile);}f_close(&SDFile);}while (1){HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);HAL_Delay(500);}
}

5. 下载验证

如果使用的是新SD卡,需要在电脑上进行格式化,建立FAT文件系统,FATFS才能识别并操作SD卡

编译无误下载到开发板后,可以看到LED2指示灯不断闪烁,串口打印出如下信息:

将SD卡插入PC后,可以看到SD卡里建立了2个文件:Sensor.csv和STM32cube.txt,打开文件后可以看到写入的数据

 

6、参考文献

STM32CubeMX学习笔记(27)——FatFs文件系统使用(操作SD卡)_stm32cubemx fatfs-CSDN博客

STM32CubeMX系列 | FATFS文件系统 - 知乎 (zhihu.com) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/273727.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024牛客寒假算法基础集训营6

目录 A.宇宙的终结 B.爱恨的纠葛 C.心绪的解剖 D.友谊的套路 E.未来的预言 F.命运的抉择 G.人生的起落 I.时空的交织 J.绝妙的平衡 K.错综的统一 A.宇宙的终结 直接暴力 我们可以发现数据范围特别小题目特别简单&#xff0c;如果能够马上想到一个容易写的做法就可以…

若依框架的使用

文章目录 1,前端2,后端3,数据库4,测试 1,前端 2,后端 3,数据库 4,测试

MinGW-w64的下载与安装

文章目录 1 下载2 安装3 配置环境变量4 验证 1 下载 官网地址&#xff1a;https://www.mingw-w64.org/github地址&#xff1a;https://github.com/niXman/mingw-builds-binaries/releases windows下载 跳转github下载 版本号选择&#xff1a;13.2.0是GCC的版本号&#xff1b…

鸿蒙开发(四)-低代码开发

鸿蒙开发(四)-低代码开发 本文主要介绍下鸿蒙下的低代码开发。 鸿蒙低代码是指在鸿蒙操作系统进行应用开发时&#xff0c;采用简化开发流程和减少编码量的方式来提高开发效率。 1&#xff1a;开启低代码开发 首先我们打开DevEco Studio .然后创建工程。 如图所示&#xff…

如何在Linux部署FastDFS文件服务并实现无公网IP远程访问内网文件——“cpolar内网穿透”

文章目录 前言1. 本地搭建FastDFS文件系统1.1 环境安装1.2 安装libfastcommon1.3 安装FastDFS1.4 配置Tracker1.5 配置Storage1.6 测试上传下载1.7 与Nginx整合1.8 安装Nginx1.9 配置Nginx 2. 局域网测试访问FastDFS3. 安装cpolar内网穿透4. 配置公网访问地址5. 固定公网地址5.…

【C++】string类(介绍、常用接口)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;http://t.csdnimg.cn/eCa5z 目录 string类的常用接口说明 string类对象的常见构造 ​编辑 string字符串的遍历&#xff08;迭代器&#xf…

LoadRunner学习:RuntimeSetting、参数化、关联、(unfinished

LoadRunner RuntimeSetting 运行时设置 在Vuser中设置Run-time Settings RunLogic&#xff1a;运行逻辑&#xff0c;决定了脚本真正执行逻辑&#xff0c; Init和End部分代码只能执行一次。决定脚本真正执行逻辑的意思是&#xff0c;在Run中的代码和Number of Iteration决定了…

[HackMyVM]Quick 2

kali:192.168.56.104 主机发现 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 0a:00:27:00:00:05 (Un…

如何把黑白照片变成彩色?分享3款神奇的技术!

在数字化时代&#xff0c;我们手中的老照片不仅仅是回忆的载体&#xff0c;更是时光的见证。那些年代久远的黑白照片&#xff0c;虽然承载着珍贵的记忆&#xff0c;但却少了些许生动的色彩。那么&#xff0c;你是否想过让这些黑白旧影焕发新生&#xff0c;重现昔日的斑斓色彩呢…

ChatGPT无法发送消息问题解决

如果您的 Chatgpt 网页版这几日一直无法发送消息&#xff0c;或者发送了消息&#xff0c;也没有相应的回复&#xff0c;如下图所示&#xff1a; 现在 OpenAI 已经修复了这个 BUG。 用户可以尝试清理 OpenAI 网站的缓存&#xff0c;之后再重新登录&#xff0c;即可正常发送消息。…

全网最全压力测试攻略大全,建议收藏备用!

压力测试 压力测试是一种软件测试&#xff0c;用于验证软件应用程序的稳定性和可靠性。压力测试的目标是在极其沉重的负载条件下测量软件的健壮性和错误处理能力&#xff0c;并确保软件在危急情况下不会崩溃。它甚至可以测试超出正常工作点的测试&#xff0c;并评估软件在极端…

Linux 学习(持续更新。。。)

wc命令 命令直接执行&#xff0c;输出包含四项&#xff0c;分别代表&#xff1a;行数、字数、字节数、文件。 例子:编译下列代码: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #inclu…

Facebook、亚马逊养号选择什么代理IP?

之前我们讨论过很多关于代理器的问题。它们的工作原理是什么?在不同的软件中要使用那些代理服务器?这些代理服务器之间的区别是什么?什么是反检测浏览器等等。 除了这些问题&#xff0c;相信很多人也会关心在使用不同平台的时代理器的选择问题。比如&#xff0c;为什么最好…

MATLAB 四点确定唯一球面参数(44)

MATLAB 四点确定唯一球面参数(44) 一、算法简介二、算法实现1.代码2.结果一、算法简介 根据给定的四个点,快速拟合获取球的中心和半径,具体代码如下: 二、算法实现 1.代码 代码如下(示例): point1 = [0.0, 0.0, 0.0]

一个系列很多样式的wordpress外贸建站模板

菌菇干货wordpress跨境电商模板 食用菌、羊肚菌、牛肝菌、香菇、干黄花菜、梅干菜、松茸wordpress跨境电商模板。 https://www.jianzhanpress.com/?p3946 餐饮调味wordpress跨境电商模板 豆制品、蛋黄糖、烘焙、咖啡、调料、调味酱、餐饮调味wordpress跨境电商模板。 http…

git 如何将多个提交点合并为一个提交点 commit

文章目录 核心命令详细使用模式总结示例 核心命令 git merge branch2 是将分支branch2的提交点合并到本地当前分支。 而在执行这条命令的时候&#xff0c;加一个选项--squash就表示在合并的时候将多个提交点合并为一个提交点。 git merge --squash branch2 先看squash单词的意…

基于单片机的视觉导航小车设计

目 录 摘 要 I Abstract II 引 言 1 1 总体方案设计 3 1.1 方案论证 3 1.2 项目总体设计 3 2 项目硬件设计 4 2.1 主控模块设计 4 2.1.1单片机选型 4 2.1.2 STM32F103RCT6芯片 4 2.2单片机最小系统电路 5 2.3电机驱动模块设计 7 2.4红外模块设计 8 2.5红外遥控模块设计 9 2.6超…

css相邻元素边框重合问题,解决方案

1、如下图所示&#xff0c;在给元素设置边框后&#xff0c;相邻元素会出现重合的问题 2、解决方案 给每个元素设置margin-top以及margin-left为负的边框 <div style"width: 300px;display: flex;flex-wrap: wrap;margin-top: 50px;"><div style"border…

MySQL-QA-异常问题及解决方案(持续更新)

MySQL-Q&A(持续更新) 1.1 PID文件找不到 问题描述 错误详情&#xff1a; ERROR&#xff01;The server quit without updating PID file (/usr/local/mysql/data/localhost.localdomain.pid) 解决方案 首先排查配置文件&#xff0c;一般路径为&#xff1a;/etc/my.cnf 检查…

蓝桥杯2023真题(4)

1.景区导游&#xff08;树上前缀和、最近公共祖先&#xff09; 思路 路线&#xff1a;2 -> 6 -> 5 -> 1 1.一个点都不去去掉的花费记作sum 2.去掉第一个点&#xff0c;sum - cost[2 -> 6] 3.去掉第二个点&#xff0c;sum - cost[2 -> 6] - cost[6 -> 5] co…