基于STM32-RTX-FATFS-U盘操作实现.ini文件读写操作

INI文件以良好的可阅读与修改特性,在程序运行初期,能够提供一些初始变量。使用C++进行程序编写过程中,微软官方提供了良好的文件操作API,便于直接使用。但是在嵌入式操作系统中,缺乏一套良好的方法。现参考https://github.com/wernsey/rengine/blob/master/src/ini.c提供的方式,结合STM32进行实现。另附工程源码。

本文基于RTX嵌入式操作系统和FatFs文件操作系统,实现对INI文件的读写操作。

1. 采用STM32CubeMX生成相关的底层库,需要配置U盘、SD卡以及FatFs。

2. 打开配置好的工程文件,并添加RTX操作系统。

3. 添加Thread.c、ini.c以及utils.c文件

4. 修改ini.c以及utils.c文件,以适应FatFs操作系统

首先需要添加#include "fatfs.h"头文件,另外由于ini.c中运用了大量的断言语句,所以需要结合Keil自身的断言编写__aeabi_assert这个函数。

void __aeabi_assert(const char *s1, const char *s2, int len)

{

    printf(">> error: (%s). function: %s, line %d\r\n", s1, s2, len);

}

其次,将源文件中关于文件API接口统一修改为FatFs操作系统的API接口,主要有以下几类函数

a. 变量 FILE *f -> FIL *f = &SDFile

b. 文件打开操作 f = fopen(fname, "w"); -> f_open(f, fname, FA_WRITE)

c. 文件关闭操作 fclose(f) -> f_close(f)

d. 字符串写入操作 fputs("]\n", f) -> f_puts("]\n", f)

e. 读文件函数


char *my_readfile(const char *fname)
{
	FILE *f;
	long len, r;
	char *str;

	if (!(f = fopen(fname, "rb")))
		return NULL;

	fseek(f, 0, SEEK_END);
	len = ftell(f);
	rewind(f);

	if (!(str = malloc(len + 2)))
		return NULL;
	r = fread(str, 1, len, f);

	if (r != len)
	{
		free(str);
		return NULL;
	}

	fclose(f);
	str[len] = '\0';
	return str;
}

修改为


char *my_readfile(const char *fname)
{
	FIL *f = &SDFile;
	unsigned int len, r;
	char *str;

	if (f_open(f, fname, FA_READ) != FR_OK)
	{
		return NULL;
	}

	len = f_size(f);

	str = malloc(len + 2);
	if (str == NULL)
	{
		return NULL;
	}
	f_read(f, str, len, &r);
	if(r!=len)
	{
		free(str);
		return NULL;
	}
	f_close(f);
	str[len] = '\0';
	return str;
}

这样就完成了对ini.c以及utils.c文件的移植

5. 修改usbd_storage_if.c文件,以适配电脑读取操作

6. 在Thread.c文件中,编写相关读写函数入下

#include "cmsis_os2.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "usart.h"

#include "ini.h"
#include "fatfs.h"

/*----------------------------------------------------------------------------
 *      Thread 1 'Thread_Name': Sample thread
 *---------------------------------------------------------------------------*/

int fputc(int ch, FILE *file)
{
	HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 1000);
	return ch;
}

typedef enum
{
    TSK_RECORD,
    TSK_MAX,
} TSK_ID_e;

#define T(x) \
    case x:  \
        return #x
char *Fil_RetInfo(FRESULT ret)
{
    switch (ret)
    {
        T(FR_OK);
        T(FR_DISK_ERR);
        T(FR_INT_ERR);
        T(FR_NOT_READY);
        T(FR_NO_FILE);
        T(FR_NO_PATH);
        T(FR_INVALID_NAME);
        T(FR_DENIED);
        T(FR_EXIST);
        T(FR_INVALID_OBJECT);
        T(FR_WRITE_PROTECTED);
        T(FR_INVALID_DRIVE);
        T(FR_NOT_ENABLED);
        T(FR_NO_FILESYSTEM);
        T(FR_MKFS_ABORTED);
        T(FR_TIMEOUT);
        T(FR_LOCKED);
        T(FR_NOT_ENOUGH_CORE);
        T(FR_TOO_MANY_OPEN_FILES);
        T(FR_INVALID_PARAMETER);
    default:
        return "Erro Status";
    }
}
#undef T

#define FF_INFO(x) printf(">> Fatfs Status(%s).\r\n", Fil_RetInfo(sta));

#define IF_RET_BOOL(x, sta)                                                                                      \
    retSD = x;                                                                                                   \
    if ((retSD != sta))                                                                                          \
    {                                                                                                            \
        printf(">> Fatfs Error(%s). Fun %s, Line %d.\r\n", Fil_RetInfo((FRESULT)retSD), __FUNCTION__, __LINE__); \
        return false;                                                                                            \
    }

osThreadId_t tskId[TSK_MAX];

unsigned char USB_IsConected(void);
DIR dataDir;
const char dirData[] = "Data";
const char dirTask[] = "Task";
const char dirInit[] = "Init";
const char filData[] = "Data.txt";
const char filTask[] = "Task.auv";
const char filInit[] = "Init.ini";
const char *dirContent[] = {dirData, dirTask, dirInit};
const char *filName[] = {filData, filTask, filInit};
char *filContent[3];
bool isSDLoadOK = false;
bool isDirExist[3] = {false};

/* 加载 SD 卡 
 *
 */
bool SD_Load(void)
{
    IF_RET_BOOL(f_mount(&SDFatFS, SDPath, FM_FAT32), FR_OK);
    return true;
}

/* 创建子目录
 *
 */
bool Dir_CreateOpen(const char *name)
{
    if (!isSDLoadOK)
    {
        return false;
    }
    retSD = f_stat(name, NULL);
    if (retSD == FR_OK)
    {
        IF_RET_BOOL(f_opendir(&dataDir, name), FR_OK);
        IF_RET_BOOL(f_closedir(&dataDir), FR_OK);
    }
    else
    {
        IF_RET_BOOL(f_mkdir(name), FR_OK);
        IF_RET_BOOL(f_opendir(&dataDir, name), FR_OK);
        IF_RET_BOOL(f_closedir(&dataDir), FR_OK);
    }
    return true;
}

/* 创建文件目录名称
 *
 */
bool Fil_CreateName(const char *s1, const char *s2, char **ret)
{
    if (ret[0] != NULL)
        return false;
    const char spliter[] = "/";
    ret[0] = calloc(strlen(s1) + strlen(s2) + 2 + 1, sizeof(char));
    if (ret[0] == NULL)
        return false;

    strcpy(ret[0], spliter);
    strcat(ret[0], s1);
    strcat(ret[0], spliter);
    strcat(ret[0], s2);
    return true;
}

bool Fil_Create(bool isDirOK, char *path)
{
    if (isDirOK)
    {
        if (f_stat(path, NULL) != FR_OK)
        {
            IF_RET_BOOL(f_open(&SDFile, path, FA_CREATE_NEW), FR_OK);
            IF_RET_BOOL(f_close(&SDFile), FR_OK);
        }
        return true;
    }
    else
    {
        return false;
    }
}

void Thread_Record(void *arg)
{
    uint32_t ulTim = 0;
    while (1)
    {
        ulTim = osKernelGetTickCount();
        osDelayUntil(ulTim + 100);
    }
}

bool test(void);
int Thread_Init(void)
{
    printf("=== %s %s === Init Test ===\r\n", __TIME__, __DATE__);
    isSDLoadOK = SD_Load();
    for (unsigned char i = 0; i < 3; i++)
    {
        isDirExist[i] = Dir_CreateOpen(dirContent[i]);
        Fil_CreateName(dirContent[i], filName[i], &filContent[i]);
        Fil_Create(isDirExist[i], filContent[i]);
    }
    test();
    tskId[TSK_RECORD] = osThreadNew(Thread_Record, NULL, NULL);
    if (tskId[TSK_RECORD] == 0)
        return -1;
    return 0;
}
static struct ini_file *iniTst = NULL;
double p1;
char numToStrBuf[15];
bool test()
{
    int err, line;
    p1 = 1234.56789111;
    sprintf(numToStrBuf,"%lf", p1);
    iniTst = ini_read(filContent[2], &err, &line);
    ini_put(iniTst, "Tst1", "a", "0");
    ini_put(iniTst, "Tst2", "b", "0.0");
    ini_put(iniTst, "Tst2", "c", "0.0");
    ini_put(iniTst, "Tst2", "d", "0.0");

    ini_put(iniTst, "Tst3", "b", "0.0");
    ini_put(iniTst, "Tst3", "c", "0.0");
    ini_put(iniTst, "Tst3", "d", numToStrBuf);

    int result = ini_write(iniTst, filContent[2]);
    if (result != SUCCESS)
    {
        printf(">> function %s, line %d\r\n", __FUNCTION__, __LINE__);
    }
    else
    {
        printf(">> ok\r\n");
    }
    ini_free(iniTst);

    iniTst = ini_read(filContent[2], &err, &line);
    p1 = atof(ini_get(iniTst,"Tst3", "d", NULL));
    printf(">> p1 = %lf, numToStrBuf = %s\r\n", p1, numToStrBuf);
    ini_free(iniTst);

    iniTst = NULL;
    return true;
}

7. 程序运行结果如下

a. 串口打印图示

b. U盘插入电脑中图示

至此,基于C语言加载ini文件方式介绍完毕。

 

 

 

 

 

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: STM32F103是STMicroelectronics(意法半导体)推出的一款32位ARM Cortex-M3内核的微控制器系列产品。而RTX则是Keil MDK(Microcontroller Development Kit)中提供的一种实时操作系统,用于在嵌入式系统中管理任务和资源。 要配置STM32F103的RTX,首先需要安装MDK-ARM开发环境和ST-Link驱动程序。接下来,可以使用Keil MDK提供的"CubeMX"工具生成工程代码,其中包括了RTX的配置。 在CubeMX中,可以选择需要的外设和引脚功能,然后配置RTOS(RTX)选项。在RTOS选项中,可以选择启用RTX,并设置时钟频率以及堆栈和线程的大小。还可以设置RTOS的优先级和任务调度方式等相关参数。 配置完毕后,CubeMX会自动生成代码,并生成工程的HAL(Hardware Abstract Layer)驱动文件。接下来,可以使用Keil MDK打开该工程,并将生成的代码添加到工程中。然后,编写应用程序代码,利用RTX提供的API函数来创建任务、互斥信号量、消息队列、定时器等,实现所需的多任务管理和资源共享。 最后,通过编译、烧录和调试,可以将配置好的RTX程序部署到STM32F103微控制器上运行。在运行过程中,RTX会按照设定的优先级和任务调度方式来管理系统中的任务和资源,确保多任务的协调和实时性。 总之,配置STM32F103的RTX需要安装MDK-ARM开发环境、ST-Link驱动程序和CubeMX工具,通过CubeMX生成RTX的配置代码,然后结合Keil MDK编写应用程序代码,并最终将程序烧录到STM32F103上运行。这样,就可以实现STM32F103的多任务管理和实时操作系统的使用。 ### 回答2: STM32F103是STMicroelectronics推出的一款基于ARM Cortex-M3内核的32位微控制器。RTX(Real-Time eXecutive)是Keil MDK软件套件中的一个实时操作系统(RTOS),用于编写实时响应和多任务应用程序。 要对STM32F103进行RTX配置,可以按照以下步骤进行操作: 1. 下载安装Keil MDK软件套件,并打开Keil uVision5集成开发环境。 2. 在工程目录下创建一个新的工程,并选择正确的STM32F103系列芯片作为目标设备。 3. 在源文件夹中创建一个名为"cmsis_os.c"的新文件,并在文件中包含"CMSIS/RTOS2/Include/cmsis_os2.h"头文件。 4. 在"cmsis_os.c"文件中定义一个全局变量作为操作系统对象: ```c osKernelState_t osKernelRunning; // 操作系统状态 ``` 5. 在"main.c"文件中,添加以下代码以初始化RTX: ```c #include "cmsis_os2.h" int main(void) { osKernelInitialize(); // 初始化操作系统 osKernelRunning = osKernelRunning; // 设置操作系统状态为运行中 osKernelStart(); // 启动操作系统 while(1) {} // 进入主循环,等待任务执行 } ``` 6. 在工程配置(Options for Target)中,选择RTX作为操作系统,并设置正确的操作系统堆栈大小和任务堆栈大小。 7. 在工程目录中创建一个新的任务文件,并在文件中定义一个任务函数。例如,创建一个名为"task1.c"的新文件,并添加以下代码: ```c #include "cmsis_os2.h" void task1(void *argument) { while(1) { // 任务执行的代码 } } ``` 8. 在"main.c"文件中添加以下代码以创建并启动任务: ```c #include "cmsis_os2.h" extern void task1(void *argument); // 声明任务函数 int main(void) { // ... osThreadNew(task1, NULL, NULL); // 创建并启动任务 // ... } ``` 9. 编译并下载程序到STM32F103芯片上,并通过调试器进行调试。 通过以上步骤,你可以在STM32F103上成功配置和使用RTX实时操作系统,并编写适用于该微控制器的实时响应和多任务应用程序。注意在编写任务代码时,需要遵循RTX的API规范和RTOS的原则,确保任务能够按照预期执行。 ### 回答3: stm32f103系列是意法半导体推出的一款高性能微控制器,它采用了高性能ARM Cortex-M3内核,拥有丰富的外设和强大的处理能力。 RTX是一种优秀的实时操作系统,可以帮助开发者更好地管理任务调度和资源分配,提高系统的稳定性和可靠性。在stm32f103中配置RTX需要以下步骤: 1. 首先,下载并安装Keil MDK开发环境,该软件包含了RTX实时操作系统。 2. 打开Keil MDK,创建一个新的项目。 3. 在创建项目时,可以选择指定所需的STM32F103系列设备。 4. 在项目创建完成后,需要添加RTX的库文件。可以在Keil MDK的安装目录中找到RTX的库文件,添加到项目中。 5. 配置RTX的相关参数。可以通过在项目中创建的配置文件中修改相关参数,例如任务的优先级、堆栈大小等。 6. 在主函数中,初始化RTX,并创建需要的任务。可以使用RTX的API函数来创建任务和设置任务的优先级。 7. 在任务中,可以编写需要实现的功能代码。可以使用RTX提供的API函数来实现任务间的通信和同步,提高系统的效率。 8. 最后,编译和下载代码到stm32f103系列设备,即可开始测试和运行。 需要注意的是,对于初学者来说,配置RTX可能会有一定的难度。建议参考官方的文档和示例代码,以便更好地理解和掌握配置RTX的方法。同时,也可以参考其他开发者的经验,通过网络上的论坛和社区进行交流和学习。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值