news 2026/6/13 1:15:50

用STM32F103C8T6(正点原子Mini板)和SPI接口,实现一个简易的SD卡数据记录器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用STM32F103C8T6(正点原子Mini板)和SPI接口,实现一个简易的SD卡数据记录器

基于STM32F103的SD卡数据记录器实战开发指南

在物联网和嵌入式系统开发中,数据记录功能是许多项目的核心需求。无论是环境监测、设备运行日志还是实验数据采集,都需要可靠地将传感器数据存储到非易失性存储器中。本文将详细介绍如何使用STM32F103C8T6开发板(正点原子Mini板)和SPI接口,构建一个完整的SD卡数据记录系统。

1. 项目规划与硬件准备

1.1 系统架构设计

一个完整的SD卡数据记录器通常包含以下几个关键组件:

  • 微控制器单元:STM32F103C8T6作为主控芯片
  • 存储模块:通过SPI接口连接的SD卡
  • 数据采集模块:模拟或数字传感器
  • 文件系统:FATFS实现文件管理
  • 辅助调试:串口输出调试信息

硬件连接示意图

STM32引脚SD卡引脚功能描述
PA4CS片选信号
PA5SCK时钟信号
PA6MISO主机输入
PA7MOSI主机输出
3.3VVCC电源正极
GNDGND电源地

1.2 开发环境搭建

确保已安装以下软件工具:

  • STM32CubeMX V6.6.1(或更新版本)
  • Keil MDK-ARM V5.29(或兼容IDE)
  • 串口调试工具(如Putty、Tera Term)
  • 文本编辑器(推荐VS Code或Notepad++)

提示:建议使用最新版本的STM32CubeMX,以获得更好的兼容性和更多功能支持。

2. STM32CubeMX工程配置

2.1 基础外设配置

首先在STM32CubeMX中创建新工程,选择STM32F103C8T6芯片,然后进行以下配置:

  1. RCC配置

    • 高速外部时钟(HSE):Crystal/Ceramic Resonator
    • 低速外部时钟(LSE):Disable
  2. SYS配置

    • Debug:Serial Wire
    • Timebase Source:SysTick
  3. 时钟树配置

    • HCLK设置为72MHz(最大工作频率)
    • APB1 Prescaler设置为2(36MHz)
    • APB2 Prescaler设置为1(72MHz)

2.2 SPI接口配置

SD卡通过SPI1接口通信,配置如下:

hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; // 初始化低速 hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 10;

2.3 FATFS文件系统配置

在Middleware中启用FATFS,配置如下参数:

  • FATFS Mode:Enabled
  • Use DMA:Disabled
  • Volume:0
  • Max Sector Size:512
  • File System:FAT32
  • Use long file names:Disabled

3. 数据记录器核心代码实现

3.1 SD卡底层驱动

SD卡通信需要实现以下基本功能:

// SPI速度设置函数 void SPI1_SetSpeed(u8 prescaler) { assert_param(IS_SPI_BAUDRATE_PRESCALER(prescaler)); __HAL_SPI_DISABLE(&hspi1); hspi1.Instance->CR1 &= 0XFFC7; hspi1.Instance->CR1 |= prescaler; __HAL_SPI_ENABLE(&hspi1); } // SPI读写单字节函数 u8 SPI1_ReadWriteByte(u8 TxData) { u8 Rxdata; HAL_SPI_TransmitReceive(&hspi1, &TxData, &Rxdata, 1, 1000); return Rxdata; }

3.2 文件系统操作封装

为简化上层应用,我们封装几个常用文件操作函数:

// 初始化文件系统 FRESULT init_filesystem(void) { static FATFS fs; return f_mount(&fs, "", 1); } // 创建新数据文件 FRESULT create_data_file(const char* filename) { FIL file; FRESULT res = f_open(&file, filename, FA_CREATE_NEW | FA_WRITE); if(res == FR_OK) f_close(&file); return res; } // 追加数据到文件 FRESULT append_to_file(const char* filename, const char* data) { FIL file; FRESULT res = f_open(&file, filename, FA_OPEN_APPEND | FA_WRITE); if(res == FR_OK) { UINT bw; f_printf(&file, "%s\r\n", data); f_close(&file); } return res; }

3.3 数据记录任务实现

创建一个周期性记录任务,每秒采集并存储一次数据:

void data_logger_task(void) { // 初始化文件系统 if(init_filesystem() != FR_OK) { printf("File system init failed!\r\n"); return; } // 创建数据文件 char filename[32]; sprintf(filename, "DATA_%04d%02d%02d.csv", get_year(), get_month(), get_day()); if(create_data_file(filename) != FR_OK) { printf("Create file failed!\r\n"); return; } // 写入CSV表头 append_to_file(filename, "Timestamp,Temperature,Humidity,Pressure"); // 主循环 while(1) { // 获取传感器数据 float temp = read_temperature(); float humi = read_humidity(); float press = read_pressure(); // 格式化数据 char data_line[128]; sprintf(data_line, "%02d:%02d:%02d,%.2f,%.2f,%.2f", get_hour(), get_minute(), get_second(), temp, humi, press); // 写入文件 if(append_to_file(filename, data_line) != FR_OK) { printf("Write data failed!\r\n"); } // 每秒记录一次 HAL_Delay(1000); } }

4. 系统优化与问题排查

4.1 SPI通信速度优化

SD卡在不同工作阶段需要不同的通信速度:

  1. 初始化阶段:低速模式(SPI_BAUDRATEPRESCALER_256)
  2. 数据传输阶段:高速模式(SPI_BAUDRATEPRESCALER_4或更高)
// SD卡初始化时设置为低速 void SD_SPI_SpeedLow(void) { SPI1_SetSpeed(SPI_BAUDRATEPRESCALER_256); } // 正常工作时设置为高速 void SD_SPI_SpeedHigh(void) { SPI1_SetSpeed(SPI_BAUDRATEPRESCALER_4); }

4.2 文件系统稳定性处理

长时间数据记录需要考虑以下问题:

  • 文件大小管理:定期创建新文件避免单个文件过大
  • 异常处理:SD卡拔出检测和重新挂载
  • 数据完整性:确保每次写入操作完成
// 检查SD卡状态 uint8_t check_sd_card(void) { if(SD_Init() != 0) return 0; // 初始化失败 if(f_mount(NULL, "", 0) != FR_OK) return 0; // 卸载失败 return 1; // 状态正常 } // 定期检查文件大小并创建新文件 void manage_file_size(void) { static uint32_t file_counter = 0; FILINFO fno; if(f_stat(current_filename, &fno) == FR_OK) { if(fno.fsize > MAX_FILE_SIZE) { file_counter++; sprintf(current_filename, "DATA_%04d.csv", file_counter); create_data_file(current_filename); } } }

4.3 常见问题排查指南

问题现象可能原因解决方案
SD卡初始化失败接线错误/供电不足检查接线,确保3.3V供电稳定
文件创建失败卡未格式化/文件系统损坏使用电脑格式化SD卡为FAT32
数据写入不完整SPI速度过高/缓冲区不足降低SPI速度,增加写入缓冲区
频繁写入失败文件未正常关闭确保每次f_open后都有对应的f_close

5. 高级功能扩展

5.1 多文件并行记录

对于需要分类记录的数据,可以实现多文件同时记录:

typedef struct { FIL file; char filename[32]; uint32_t max_size; } data_logger_t; // 初始化多个记录器 data_logger_t temp_logger, humi_logger, press_logger; void init_multi_loggers(void) { strcpy(temp_logger.filename, "TEMP_LOG.CSV"); temp_logger.max_size = 1024*1024; // 1MB strcpy(humi_logger.filename, "HUMI_LOG.CSV"); humi_logger.max_size = 1024*1024; strcpy(press_logger.filename, "PRESS_LOG.CSV"); press_logger.max_size = 1024*1024; }

5.2 数据压缩存储

对于需要长期记录的应用,可以实现简单的数据压缩:

// 简易数据压缩函数 void compress_data(float *data, uint8_t *output) { uint16_t temp = (uint16_t)(data[0] * 100); uint16_t humi = (uint16_t)(data[1] * 100); uint16_t press = (uint16_t)(data[2] * 10); output[0] = temp >> 8; output[1] = temp & 0xFF; output[2] = humi >> 8; output[3] = humi & 0xFF; output[4] = press >> 8; output[5] = press & 0xFF; }

5.3 断电保护机制

实现基本的数据保护功能:

  1. 定期同步:使用f_sync强制写入物理设备
  2. 状态保存:记录最后写入位置
  3. 恢复机制:系统启动时检查未完成写入
// 安全写入函数 FRESULT safe_write(FIL* fp, const void* buff, UINT btw) { FRESULT res = f_write(fp, buff, btw, &bw); if(res == FR_OK) res = f_sync(fp); return res; }

在实际项目中,SD卡数据记录器的稳定性至关重要。经过多次测试发现,合理设置SPI时序参数和文件系统缓存大小能显著提高系统可靠性。当需要长时间连续记录时,建议定期检查文件系统状态并做必要的维护操作。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/13 1:07:58

i.MX21架构解析:异构计算与低功耗设计如何重塑嵌入式多媒体

1. 项目概述:为什么i.MX21是移动多媒体时代的“硬通货”在智能手机和各类移动娱乐设备尚未像今天这般普及的2000年代初期,嵌入式系统设计者面临的核心矛盾异常尖锐:用户渴望在巴掌大的设备上获得流畅的视频播放、清晰的视频通话和绚丽的3D游戏…

作者头像 李华
网站建设 2026/6/13 1:05:49

北睿科技填补ATR金刚石晶体国内空白

核心定义 北睿科技成功研发出ATR(衰减全反射)金刚石晶体,填补了国内在该高端光学材料领域的空白,打破了国外长期技术垄断,为红外光谱分析、激光窗口等关键应用提供了自主可控的核心元件。详细知识 1. **技术背景与突破…

作者头像 李华
网站建设 2026/6/13 0:56:57

Keystone认证授权流程详解:Token鉴权+RBAC权限控制通俗教程

Keystone是OpenStack的核心身份认证服务,承担整个云平台的用户登录、身份校验、权限管控核心职责,是学习OpenStack架构的基础。其整套工作机制可以高度概括为两大核心:Token负责用户身份认证、充当访问令牌,RBAC角色权限模型负责资…

作者头像 李华