前言:SD卡作为一个大容量的存储介质,用来做一些本地数据存储还是不错的,最近一个项目采用SD来存储设备的一些实时运行信息,最终敲定用.csv文件格式来做存储,方便管理和后续的数据分析处理~~主要是一个.csv文件可以装贼多条数据^ _ ^!
话不多说,接下来进入正题~~
这里我们用STM32CubeMx生成底层驱动,一些STM32的一些基础的时钟、GPIO等配置我就不赘述咯,直接上一些图吧
生成的驱动文件结构如下如图所示:
下面对生成的文件进行一个说明:
文件名 | 文件内容 |
---|---|
diskio.c | FATFS 和 disk I/O 模块接口层文件 |
ff.c | FATFS 模块 |
ff_gen_drv.c | FatFs通用底层驱动 |
syscall.c | 这里是对使用操作系统时的同步、内存管理操作的一些示例 |
bsp_driver_sd.c | SD卡的底层驱动,BSP_SD_ReadBlocks_DMA、BSP_SD_WriteBlocks_DMA等API的实现 |
sd_diskio.c | SD Disk I/O驱动,含SD_initialize、SD_read、SD_write、SD_ioctl等 |
sdio.c | 包含SDIO驱动的配置,SDIO的时钟、引脚、速率、DMA通道等配置 |
fatfs_platform.c | 这个文件里面是SD卡插入状态检测的代码 |
下面用代码来阐述一下SD卡文件读写的一个流程
uint8_t BSP_SdCheck(void)
{
SD_DiskStuTypeDef cardStu;
if(BSP_SD_IsDetected() == SD_PRESENT)
{
//连接底层驱动
FATFS_LinkDriver(&SD_Driver,SDPath );
if(f_mount(&SDFatFS, (TCHAR const*)SDPath, 0) == FR_OK){/* 注册文件系统对象,立即注册 */
cardStu = SD_STU_OK;
}else{
cardStu = SD_STU_INVAL;
}
g_SdDetectedFlag = DEF_SET;
}else{
if(g_SdDetectedFlag == DEF_SET ){
f_mount(NULL, (TCHAR const*)SDPath, 0);/* 注销文件系统对象 */
FATFS_UnLinkDriver(SDPath); /* 解除底层连接,否则不能实现热插拔 */
g_SdDetectedFlag = DEF_CLR;
}
}
return cardStu;
}
.csv文件其实就是数据之间加逗号分隔符就可以将各个数据分开了,一般先写好标题,后面换行一直填充数据就行了~~
void RunInfoRecord(void)
{
FIL fileobj; /* File objects */
FRESULT fr; /* FatFs function common result code */
UINT br; /* File read/write count */
CPU_SR_ALLOC();
uint32_t size=0; /* File size */
uint8_t buf[512]; /* File read/write data buffer */
uint8_t p[25]; /* File path */
if(SD_STU_OK == BSP_SdCheck())
{
sprintf((char *)buf,"FC%02d%02d%02d.csv",(RTC_GetTimeYear()%100),RTC_GetTimeMonth(),RTC_GetTimeDate());//按日期进行数据存储
sprintf((char *)p,"0:/%s",buf); //0:为SD卡盘符
fr = f_open (&fileobj,(const char *)buf, FA_OPEN_ALWAYS | FA_WRITE);
if(fr == FR_OK)
{
size = f_size(&fileobj);
if(size == 0) //第一次创建文件,添加标题栏
{
memset(buf,0,sizeof(buf));
sprintf((char *)buf,"%s,%s,%s\r\n","Time","SysStep","ErrCode");
fr= f_write(&fileobj, buf, sizeof(buf),(void *)&br);
if(fr != FR_OK){
printf("Title write process error code is %d...\r\n",fr);
}
}else{
OS_CRITICAL_ENTER(); //防止写数据过程被打断
fr= f_lseek(&fileobj,size); //指针移至文件尾部,追加数据,如果用追加方式打开文件则不需要
/* 分组追加运行数据 */
for(int i=0;i<FUN_LIST_SIZE;i++){
memset(buf,0,sizeof(buf));
sprintf((char *)buf,"%d:%d:%d,%d,%d,",
RTC_GetTimeHours(),
RTC_GetTimeMinutes(),
RTC_GetTimeSeconds(),
sys_step,
sys_errCode);
fr = f_write(&fileobj, buf, sizeof(buf),(void *)&br);
if(fr != FR_OK){
printf("Data write process error code is %d...\r\n",fr);
}
}
}
}else{
printf("File Open failed,error code is %d...\r\n",fr);
}
fr = f_close(&fileobj);
if(fr != FR_OK){
printf("f_close error code is %d...\r\n",fr);
}
OS_CRITICAL_EXIT();
}else{
printf("SD Card check err...\r\n");
}
SetSD_CardStau(SD_STU_IDLE);
}
当然啦,上面只是个范例,实际项目中我可不止这么点数据,上面简单写了个实现的方法,数据只要往buff里面加就好了~~不过需要注意的是我这里一次写的数据没有超过512byte,超过512byte可就需要再做做处理了。
########## 完结撒花 ##########
注意一点:SDIO的速率不要太快了,否则会容易出现 FR_DISK_ERR