采用FATFS读写SD卡中CSV格式的二维浮点数组

Posted on 2022-11-23 21:56  昨夜三更雨  阅读(1443)  评论(0)    收藏  举报

1. CSV文件的格式

CSV表格的基本格式为:

字符串,字符串,...,字符串\r\n
字符串,字符串,...,字符串\r\n
...
字符串,字符串,...,字符串\r\n

例如,对于如下表格:

1	2	3
1	2	3
1	2	3

当采用%5.3f格式存储为CSV文件时,存储的数据为:

'1'	'.'	'0'	'0'	'0'	','	'2'	'.'	'0'	'0'	'0'	'3'	'.'	'0'	'0'	'0'	'\r'	'\n'
'1'	'.'	'0'	'0'	'0'	','	'2'	'.'	'0'	'0'	'0'	'3'	'.'	'0'	'0'	'0'	'\r'	'\n'
'1'	'.'	'0'	'0'	'0'	','	'2'	'.'	'0'	'0'	'0'	'3'	'.'	'0'	'0'	'0'	'\r'	'\n'

本文所述读写CSV文件方法所采用的CSV文件将严格按照上述方式存储。特别地,对于读取CSV文件的情况,数据接受以科学计数法形式的字符串存储。

2. 基于FATFS文件系统读写CSV文件

STM32移植FATFS文件系统见SPI驱动SD卡及FATFS移植。以下给出关键文件代码:

  • ucsv.h
/**
 *******************************************************************************
 * @file    ucsv.h
 * @author  xixizhk
 *******************************************************************************
 * @version V2022 @ Nov 11, 2022 \n
 * Initial version.
 *******************************************************************************
 */


/* Define to prevent recursive inclusion **************************************/
#ifndef _UCSV_H
#define _UCSV_H

#ifdef __cplusplus
extern "C" {
#endif

/**
 *******************************************************************************
 * @addtogroup Includes
 * @{
 */

#include "stdint.h"

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Definitions
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Types
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Constants
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Variables
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Macros
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Functions
 * @{
 */

int ucsv_read(char* _path, float* _tab, unsigned int _row, unsigned int _col);
int ucsv_write(char* _path, float* _tab, unsigned int _row, unsigned int _col);

/**
 * @}
 */


#ifdef __cplusplus
}
#endif


#endif /* _UCSV_H */

/**************************** ALL RIGHTS RESERVED *****************************/
  • ucsv.c
/**
 *******************************************************************************
 * @file    ucsv.c
 * @author  xixizhk
 *******************************************************************************
 * @version V2022 @ Nov 11, 2022 \n
 * Initial version.
 *******************************************************************************
 */


/**
 *******************************************************************************
 * @addtogroup Includes
 * @{
 */

#include "ucsv.h"
#include "ff.h"
#include "stdio.h"

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Definitions
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Types
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Constants
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Variables
 * @{
 */

static FATFS csvfs;
static FIL csvfile;
static FRESULT csvfres;
static UINT csvbn;
static char csvbuffer[4096];

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Macros
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Functions
 * @{
 */

/**
 * @brief   Read specified .csv file into specified table.
 * @param   _path [In]: path of the file.
 * @param   _tab [Out]: point to the 2-D table for read data.
 * @param   _row [In]: number of row of the table.
 * @param   _col [In]: number of column of the table.
 * @return  0 if successful.
 */
int ucsv_read(char* _path, float* _tab, unsigned int _row, unsigned int _col)
{
    unsigned int  i, j, k;
    char str_data[64];
    char *pbuffer;

    char diskletter[2];
    diskletter[0] = _path[0];
    diskletter[1] = '\0';

    csvfres = f_mount(&csvfs, diskletter, 1);
    if (csvfres != FR_OK)
    {
        f_mount(0, "", 1);
        return 1;
    }
    csvfres = f_open(&csvfile, _path, FA_READ);
    if (csvfres != FR_OK)
    {
        f_close(&csvfile);
        f_mount(0, "", 1);
        return 2;
    }
    csvbn = f_size(&csvfile);
    if (csvbn > sizeof(csvbuffer))
    {
        f_close(&csvfile);
        f_mount(0, "", 1);
        return 3;
    }
    
    csvfres = f_read(&csvfile, csvbuffer, csvbn, &csvbn);
    pbuffer = csvbuffer;
    for (i = 0; i < _row; i++)
    {
        for (j = 0; j < _col; j++)
        {
            for (k = 0; k < sizeof(str_data); k++)
            {
                if ((*pbuffer == ',') || (*pbuffer == '\r'))
                {
                    str_data[k] = '\r';
                    str_data[k + 1] = '\n';
                    pbuffer = pbuffer + 1;
                    break;
                }
                else
                {
                    str_data[k] = *pbuffer;
                    pbuffer = pbuffer + 1;
                }
            }
            sscanf(str_data, "%f", _tab);
            _tab = _tab + 1;
        }
        pbuffer = pbuffer + 1;
    }
    
    f_close(&csvfile);
    f_mount(0, "", 1);
    return 0;
}

/**
 * @brief   Write specified table to specified .csv file.
 * @param   _path [In]: path of the file.
 * @param   _tab [Out]: point to the 2-D table for read data.
 * @param   _row [In]: number of row of the table.
 * @param   _col [In]: number of column of the table.
 * @return  0 if successful.
 */
int ucsv_write(char* _path, float* _tab, unsigned int _row, unsigned int _col)
{
    unsigned int i, j, n;

    char diskletter[2];
    diskletter[0] = _path[0];
    diskletter[1] = '\0';

    csvfres = f_mount(&csvfs, diskletter, 1);
    if (csvfres != FR_OK)
    {
        f_mount(0, "", 1);
        return 1;
    }
    csvfres = f_open(&csvfile, _path, FA_CREATE_ALWAYS | FA_WRITE |FA_READ);
    if (csvfres != FR_OK)
    {
        f_close(&csvfile);
        f_mount(0, "", 1);
        return 2;
    }
    
    for (i = 0; i < _row; i++)
    {
        for (j = 0; j < _col; j++)
        {
            n = snprintf(csvbuffer, sizeof(csvbuffer), "%8.4f", *_tab);
            if (j < _col - 1)
            {
                csvbuffer[n] = ',';
                n = n + 1;
            }
            else
            {
                csvbuffer[n] = '\r';
                csvbuffer[n + 1] = '\n';
                n = n + 2;
            }
            f_write(&csvfile, csvbuffer, n, &n);
            _tab = _tab + 1;
        }
    }
    
    f_close(&csvfile);
    f_mount(0, "", 1);
    return 0;
}

/**
 * @}
 */


/**************************** ALL RIGHTS RESERVED *****************************/

3. 函数使用说明

3.1 读取CSV文件至二维数浮点数组

  • Step 1: 定义数组,例如:
#define _ROW_NBR	(10U)
#define _COL_NBR	(10U)
float table[_ROW_NBR][_COL_NBR];
  • Step 2: 调用int ucsv_read(char* _path, float* _tab, unsigned int _row, unsigned int _col)函数将指定的CSV文件读取至二维浮点数组中(盘符号是必须的),例如:
ucsv_read("0:table.csv", &(table[0][0]), _ROW_NBR, _COL_NBR);

3.2 将二维浮点数组写入CSV文件

  • Step 1: 定义数组,例如:
#define _ROW_NBR	(10U)
#define _COL_NBR	(10U)
float table[_ROW_NBR][_COL_NBR];
  • Step 2: 调用int ucsv_write(char* _path, float* _tab, unsigned int _row, unsigned int _col)函数将二维数浮点数组写入指定的CSV文件中(盘符号是必须的),例如:
ucsv_write("0:table.csv", &(table[0][0]), _ROW_NBR, _COL_NBR);