为了更好地理解如何在STM32微控制器上进行SD卡读写操作,以下是一个详细的代码案例,涵盖了初始化SD卡、写入数据和读取数据。该代码案例使用STM32Cube库和HAL驱动库。
代码案例概述:
- 初始化SD卡。
- 创建一个用于写入的缓冲区,并将其填充为示例数据。
- 在SD卡上创建一个新的文件。
- 将缓冲区的数据写入SD卡的文件中。
- 关闭写入文件。
- 打开同一个文件进行读取。
- 创建一个用于读取的缓冲区。
- 从SD卡文件中读取数据到缓冲区。
- 关闭读取文件。
- 验证读取到的数据是否与写入的数据一致。
代码实现: 首先,需要在STM32CubeMX中配置SD卡接口和相关GPIO引脚。确保已经添加了FATFS库。
#include "stm32f4xx_hal.h"
#include "fatfs.h"
#define BUFFER_SIZE 512
#define FILENAME "test.txt"
FATFS fs;
FIL file;
uint8_t write_buffer[BUFFER_SIZE] = "This is a test message for SD card read/write operation!";
uint8_t read_buffer[BUFFER_SIZE];
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SDIO_SD_Init(void);
void Error_Handler(void);
接下来,需要定义一些辅助函数,用于控制SD卡接口和处理错误。
void SD_IO_Init(void);
void SD_IO_WriteCmd(uint8_t cmd, uint32_t arg, uint8_t crc);
uint8_t SD_IO_WaitResponse(uint8_t response);
uint8_t SD_IO_ReadByte(void);
void SD_IO_WriteByte(uint8_t value);
void SD_IO_WriteDummy(void);
void SD_IO_WriteBytes(const uint8_t *data, uint32_t num_bytes);
void SD_IO_ReadBytes(uint8_t *data, uint32_t num_bytes);
void SD_Init(void);
void SD_OpenFile(FIL* file, const TCHAR* path);
void SD_CloseFile(FIL* file);
现在,我们可以开始编写主函数,用于初始化系统和SD卡,并执行读写操作。
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SDIO_SD_Init();
SD_Init();
if(f_mount(&fs, "", 1) != FR_OK)
{
Error_Handler();
}
SD_OpenFile(&file, FILENAME);
FRESULT res = f_write(&file, write_buffer, sizeof(write_buffer), NULL);
if(res != FR_OK)
{
Error_Handler();
}
SD_CloseFile(&file);
SD_OpenFile(&file, FILENAME);
res = f_read(&file, read_buffer, sizeof(read_buffer), NULL);
if(res != FR_OK)
{
Error_Handler();
}
SD_CloseFile(&file);
if(memcmp(write_buffer, read_buffer, sizeof(write_buffer)) != 0)
{
Error_Handler();
}
while (1);
}
下面是辅助函数的实现:
void SD_IO_Init(void)
{
HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SD_CLK_GPIO_Port, SD_CLK_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(SD_CMD_GPIO_Port, SD_CMD_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SD_D0_GPIO_Port, SD_D0_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SD_D1_GPIO_Port, SD_D1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SD_D2_GPIO_Port, SD_D2_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SD_D3_GPIO_Port, SD_D3_Pin, GPIO_PIN_SET);
}
void SD_IO_WriteCmd(uint8_t cmd, uint32_t arg, uint8_t crc)
{
SD_IO_WriteByte(0x40 | cmd);
SD_IO_WriteByte((uint8_t)(arg >> 24));
SD_IO_WriteByte((uint8_t)(arg >> 16));
SD_IO_WriteByte((uint8_t)(arg >> 8));
SD_IO_WriteByte((uint8_t)arg);
SD_IO_WriteByte(crc);
}
uint8_t SD_IO_WaitResponse(uint8_t response)
{
uint32_t timeout = 100000;
uint8_t r;
do
{
r = SD_IO_ReadByte();
if(--timeout == 0)
{
return 0xFF;
}
} while(r != response);
return r;
}
uint8_t SD_IO_ReadByte(void)
{
uint8_t value;
HAL_SD_ReadBlocks(&hsd, &value, 1, 0, 1);
return value;
}
void SD_IO_WriteByte(uint8_t value)
{
HAL_SD_WriteBlocks(&hsd, &value, 1, 0, 1);
}
void SD_IO_WriteDummy(void)
{
SD_IO_WriteByte(0xFF);
}
void SD_IO_WriteBytes(const uint8_t *data, uint32_t num_bytes)
{
HAL_SD_WriteBlocks(&hsd, (uint32_t*)data, 0, num_bytes/4, 1);
}
void SD_IO_ReadBytes(uint8_t *data, uint32_t num_bytes)
{
HAL_SD_ReadBlocks(&hsd, (uint32_t*)data, 0, num_bytes/4, 1);
}
void SD_Init(void)
{
SD_IO_Init();
SD_IO_WriteDummy();
SD_IO_WriteCmd(0x08, 0x00, 0x87);
SD_IO_WriteCmd(0x37, 0x00, 0x95);
uint8_t response = SD_IO_WaitResponse(0x01);
while(response == 0xFF)
{
response = SD_IO_WaitResponse(0x01);
}
if(response != 0x00)
{
Error_Handler();
}
SD_IO_WriteDummy();
SD_IO_WriteCmd(0x16, 0x00000200, 0x01);
response = SD_IO_WaitResponse(0x00);
while(response == 0xFF)
{
response = SD_IO_WaitResponse(0x00);
}
response = SD_IO_WaitResponse(0x00);
while(response != 0x00)
{
response = SD_IO_WaitResponse(0x00);
}
SD_IO_WriteDummy();
}
void SD_OpenFile(FIL* file, const TCHAR* path)
{
if(f_open(file, path, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
{
Error_Handler();
}
}
void SD_CloseFile(FIL* file)
{
if(f_close(file) != FR_OK)
{
Error_Handler();
}
}
在以上代码中,还使用了一些由HAL库提供的函数,例如SystemClock_Config和MX_GPIO_Init。这些函数的具体实现可以在相应的HAL库文件中找到。
这个代码案例提供了一个基本的框架,帮助您开始在STM32上使用SD卡进行读写操作。根据您的需求,您可以进一步扩展和优化代码。