嵌入式开发中, 经常会有主控板识别TF卡+读取数据+写入数据的 需求, 下面尽量用简介的描述详细说明一下, 相关驱动的实现细节,
实现TF-card的驱动需要配置的东西比较多, 基本流程就是:
①配置芯片的相关引脚 ②引用FatFS文件系统的三方库 ③根据具体需求配置相关引脚的参数 ④在main函数中调用相关功能的初始化函数初始化对应的硬件⑤实际跑通并测试相关功能(识别+读取+写入)⑥实际应用TF-card驱动功能
①配置相关引脚
这一步相对简单, 如图所示配置 数据线SDIO_D0~SDIO_D3,时钟线SDIO_CLK以及SDIO_CMD
这里我们配置了 四位的数据通讯(除非是引脚不够, 或者数据较少, 才会用一位的)
②引用FatFS文件系统的三方库
这个是必要的文件系统配置, 想要和 TF-card交互数据, 卡必须有文件系统, 通常情况下使用FatFS
配置较多, 扇区大小, 编码方式等, 相关配置如图所示
③+④基本参数配置好之看一下初始化代码, SDIO的相关参数配置需要在使用前初始化, 代码比较清晰, 不多加赘述
void HAL_SD_MspInit(SD_HandleTypeDef* sdHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(sdHandle->Instance==SDIO)
{
/* USER CODE BEGIN SDIO_MspInit 0 */
/* USER CODE END SDIO_MspInit 0 */
/* SDIO clock enable */
__HAL_RCC_SDIO_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/**SDIO GPIO Configuration
PC8 ------> SDIO_D0
PC9 ------> SDIO_D1
PC10 ------> SDIO_D2
PC11 ------> SDIO_D3
PC12 ------> SDIO_CK
PD2 ------> SDIO_CMD
*/
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* USER CODE BEGIN SDIO_MspInit 1 */
/* USER CODE END SDIO_MspInit 1 */
}
}
void HAL_SD_MspDeInit(SD_HandleTypeDef* sdHandle)
{
if(sdHandle->Instance==SDIO)
{
/* USER CODE BEGIN SDIO_MspDeInit 0 */
/* USER CODE END SDIO_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_SDIO_CLK_DISABLE();
/**SDIO GPIO Configuration
PC8 ------> SDIO_D0
PC9 ------> SDIO_D1
PC10 ------> SDIO_D2
PC11 ------> SDIO_D3
PC12 ------> SDIO_CK
PD2 ------> SDIO_CMD
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12);
HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2);
/* USER CODE BEGIN SDIO_MspDeInit 1 */
/* USER CODE END SDIO_MspDeInit 1 */
}
}
⑤这里基本就配置完了, 验证一下功能, (验证功能仅适用一位数据的交互方式)基本逻辑就是通过串口打印一下函数执行的结果
void SD_Test(void)
{
FRESULT res; /* FatFs function common result code */
uint32_t byteswritten, bytesread; /* File write/read counts */
uint8_t wtext[] = "This is STM32 working with FatFs.\n"; /* File write buffer */
uint8_t rtext[100]; /* File read buffer */
/* Register the file system object to the FatFs module */
if (f_mount(&SDFatFS, (TCHAR const*)PATH, 0) != FR_OK)
{
printf("Failed to mount SD card\r\n");
return;
}
/* Create/open a file, name is specified by Path with FileName */
res = f_open(&SDFile, "STM32.TXT", FA_CREATE_ALWAYS | FA_WRITE);
if (res != FR_OK)
{
printf("Failed to open/create file (error code: %d)\r\n", res);
return;
}
/* Write data to the file */
res = f_write(&SDFile, wtext, sizeof(wtext), (void *)&byteswritten);
if ((byteswritten < sizeof(wtext)) || (res != FR_OK))
{
printf("Failed to write file (error code: %d)\r\n", res);
return;
}
/* Close the file */
res = f_close(&SDFile);
if (res != FR_OK)
{
printf("Failed to close file (error code: %d)\r\n", res);
return;
}
printf("File written successfully: %s\r\n", wtext);
/* Open the file, name is specified by Path with FileName */
res = f_open(&SDFile, "STM32.TXT", FA_READ);
if (res != FR_OK)
{
printf("Failed to open file (error code: %d)\r\n", res);
return;
}
/* Read string from the file */
res = f_read(&SDFile, rtext, sizeof(rtext), (void *)&bytesread);
if ((bytesread == 0) || (res != FR_OK))
{
printf("Failed to read file (error code: %d)\r\n", res);
return;
}
/* Close the file */
res = f_close(&SDFile);
if (res != FR_OK)
{
printf("Failed to close file (error code: %d)\r\n", res);
return;
}
printf("Read from file: %s\r\n", rtext);
}
最终执行结果是, 407通过串口打印了相关测试函数的执行结果信息,显示识别并写入成功, 将SD接到电脑上, 可以看到一个 名为STM32.TXT的文件, 说明SD卡驱动已经成功跑通.
当然这里仅作为说明驱动使能, 简化了很多细节没有说明.
比如说 正常情况下, SD卡是有第九个引脚需要通过电位高低来识别SD-card存在, 以此来实现SD卡热插拔的功能,或者软件方式通过定时器定时轮询检测也可以实现,
又比如说,FatFS只是比较常见的文件系统, 如果 设备作为某个体系中的一部分, 需要用和整体一样的系统, 可能就无法通过cubeMX直接引用 FatFS的文件系统 的三方库, 那么相关的文件系统的配置 就需要一系列繁琐的配置.
MCU驱动TF-card具体实现
嵌入式开发中, 经常会有主控板识别TF卡+读取数据+写入数据的 需求, 下面尽量用简介的描述详细说明一下, 相 […]
关于WPF如何连接SQLite或MySQL数据库进行简单增删改查
以下是使用 Visual Studio WPF 项目来连接数据库操作人物角色数据的完整教程,使用 SQLite […]
Python爬虫的运行效率过低该怎么处理
一、网络请求优化 根据网络和目标网站响应速度设置合理超时时间,避免过长等待或因过短而频繁超时。 二、数据解析优 […]
Python识别空气断路器开状态
先说背景:在一个控制室里面有很多空气断路器,在不通过外接其它设备去监听这个开关的状态,可以通过高清摄像头去做图 […]
scada数据采集与监视控制系统定制开发
SCADA系统,即监控与数据采集系统,是一种在工业自动化领域中扮演着至关重要角色的自动化系统。它能够实时采集工 […]
关于C#上位机程序与PLC通讯的几种实现方式
在工业自动化中,上位机程序与 PLC(可编程逻辑控制器)之间的通信是至关重要的。正确的通讯方式可以提高系统的稳 […]
开源鸿蒙适配器KHP-系列硬件设备产测功能开发
案例背景 开源鸿蒙适配器KHP-系列的硬件设备的产测功能开发。实现了KHP-IC500设备在出厂前测试硬件功能 […]
产品缺陷智能拍照检测分析控制系统管理软件定制开发
案例背景 系统在接受到传感器信号后,根据相机配置信息,调用相应机位的相机进行拍照。系统获取照片后调用,单图判定 […]
实验室智能分析检测仪控制管理系统上位机软件开发
案例背景 智能连续流动分析仪是将比色分析自动化的一种分析测试系统。样品溶液泵入分析模块后可以自动进行样品前处理 […]
智能饲喂控制管理系统软件定制开发
案例背景 液态智能饲喂控制系统是一种现代化的饲喂方式,它使用液体饲料代替传统的固体饲料,为动物提供更营养、更健 […]
工业自动化机械臂多自由度智能操作系统嵌入式定制开发
案例背景 为了评估多自由度机械臂的性能和稳定性,以便在实际生产中更好地应用。在使用机械臂之前,需要对机械臂的性 […]
工厂MES生产线SCADA数据采集监控管理系统软件开发
案例背景 客户是一家以锂电智能装备研发生产的企业,现场产线设备自动化程度较高,现有大部分设备未能实现实时联动, […]
联系电话:
电子邮箱:unczzb@unicrom.cn
深圳研发中心(总部): 深圳市龙华区港深国际中心十楼E区
太原研发中心: 山西省太原市万迎泽西大街120号时代天峰1918室
上海办事处: 上海市浦东新区牡丹路60号,东辰大厦7楼702室
扫一扫,关注由你创科技