STM32H750VBT6使用SDMMC和FatFS读写SD卡
2025年5月27日大约 4 分钟
STM32H750VBT6使用SDMMC和FatFS读写SD卡
/* USER CODE BEGIN 0 */
// 在全局变量中定义:
FRESULT f_res; /* 操作结果 */
FATFS fs; /* FAT句柄 */
FIL file; /* 文件句柄 */
UINT BW; /* 全称叫byte_write: 写入字节长度,这个变量一般用于接收 f_write() 函数执行后,实际写入了多少字节。 */
UINT BR; /* 全称叫byte_read: 读取字节长度,这个变量一般用于接收 f_read() 函数执行后,实际读取了多少字节。 */
char buffer[2048]; /* 存储文件内容的缓冲区 */
// 定义最大行长度和缓冲区大小
#define MAX_LINE_LEN 256
/**
* @brief 读取文件中指定行的内容
* @param path 文件路径
* @param target_line 要读取的目标行号(从0开始)
* @param buffer 存放结果的缓冲区
* @param bufsize 缓冲区大小
* @return 成功返回0,失败返回-1
*/
int read_specific_line_by_byte(const char *path, int target_line, char *buffer, size_t bufsize)
{
FIL file; // 局部文件对象
FRESULT res;
UINT br;
char c;
int current_line = 0;
int offset = 0;
memset(buffer, 0, bufsize); // 清空缓冲区
// 打开文件
res = f_open(&file, path, FA_READ);
if (res != FR_OK)
return -1;
// 初始化缓冲区
buffer[0] = '\0';
// 逐字节读取文件
while (f_read(&file, &c, 1, &br) == FR_OK && br == 1)
{
if (c == '\n')
{
if (current_line == target_line)
{
buffer[offset] = '\0';
f_close(&file);
return 0;
}
current_line++;
offset = 0;
}
else if (c != '\r')
{
if (offset < bufsize - 1)
{
buffer[offset++] = c;
}
else
{
buffer[offset] = '\0';
f_close(&file);
return -1;
}
}
}
// 如果最后一行没有换行符但仍为目标行
if (current_line == target_line)
{
buffer[offset] = '\0';
f_close(&file);
return 0;
}
f_close(&file);
return -1;
}
int pin = 0, state = 0;
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
/* 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_DMA_Init();
MX_SDMMC1_SD_Init();
MX_USART1_UART_Init();
MX_FATFS_Init();
/* USER CODE BEGIN 2 */
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, 0);
char senddata[40] = "";
sprintf(senddata, "\nStartTimeStamp: %u\n", HAL_GetTick());
HAL_UART_Transmit(&huart1, (uint8_t *)senddata, sizeof(senddata), 0xFFFF);
// ===== 1.首先要挂载设备 =====
f_res = f_mount(&fs, "0:", 1); // 0:不挂载 1:挂载
// ===== 2.按照需要的编辑方式打开文件 =====
f_res = f_open(&file, "0:test.txt", FA_OPEN_ALWAYS | FA_WRITE); // 如果文件存在则打开,如果文件不存在则创建并打开
// ===== 3.写入数据 =====
f_res = f_write(&file, "STM32H750VBT6打开了文件", strlen("STM32H750VBT6打开了文件"), &BW); // 在FA_OPEN_ALWAYS|FA_WRITE模式下这样写内容的话指针会在第一行
// ===== 4.卸载设备前关闭文件,5.卸载设备(看后面) =====
f_res = f_close(&file);
// ===== 现在开始测试读文件 =====
f_res = f_open(&file, "0:test.txt", FA_READ); // 用只读方式打开文件
if (f_res == FR_NO_FILE)
HAL_UART_Transmit(&huart1, (uint8_t *)"文件不存在\n", sizeof("文件不存在\n"), 0xFFFF);
else if (f_res == FR_INVALID_NAME)
HAL_UART_Transmit(&huart1, (uint8_t *)"路径错误了?\n", sizeof("路径错误了?\n"), 0xFFFF);
// 读取文件内容
f_read(&file, buffer, sizeof(buffer) - 1, &BR); // 留1字节给终止符
buffer[BR] = '\0';
/*在 C 语言中,字符串是以 \0 结尾的字符数组。如果不手动加上 \0,buffer 中虽然有数据,
但不能被当作字符串使用(例如不能用 printf("%s", buffer) 正确输出)。因为前面只读了 sizeof(buffer) - 1 字节,
所以最后一个位置 buffer[br] 一定存在,可以安全赋值。*/
HAL_UART_Transmit(&huart1, (uint8_t *)"\n读到了: \n", strlen("\n读到了: \n"), 0xFFFF);
HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), 0xFFFF);
HAL_UART_Transmit(&huart1, (uint8_t *)"\n", strlen("\n"), 0xFFFF);
f_close(&file);
if (read_specific_line_by_byte("0:test.txt", 4-1, buffer, sizeof(buffer)) == 0)
{
HAL_UART_Transmit(&huart1, (uint8_t *)"\n第i行内容为:", strlen("\n第i行内容为:"), 0xFFFF);
HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), 0xFFFF);
}
else
HAL_UART_Transmit(&huart1, (uint8_t *)"\n无法读取该行\n", strlen("\n无法读取该行\n"), 0xFFFF);
sscanf(buffer, "<AT>AT+GPIO=%d,%d", &pin, &state);
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, state);
// ===== 5.卸载设备
f_res = f_mount(&fs, "0:", 0); // 0:不挂载 1:挂载
if (f_res != FR_OK)
HAL_UART_Transmit(&huart1, (uint8_t *)"\n卸载失败", strlen("\n卸载失败"), 0xFFFF);
else
HAL_UART_Transmit(&huart1, (uint8_t *)"\n卸载成功", strlen("\n卸载成功"), 0xFFFF);
sprintf(senddata, "\nEndTimeStamp: %u\n", HAL_GetTick());
HAL_UART_Transmit(&huart1, (uint8_t *)senddata, sizeof(senddata), 0xFFFF);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
状态机与事件驱动框架
要不先自己上网查查?框架基本是一样的