當(dāng)前位置:首頁 > 公眾號(hào)精選 > 嵌入式云IOT技術(shù)圈
[導(dǎo)讀]在實(shí)際產(chǎn)品開發(fā)過程中,我們常常會(huì)對(duì)一些產(chǎn)品的內(nèi)置參數(shù)進(jìn)行存儲(chǔ),比如: 1、當(dāng)前屬于哪種語言 2、機(jī)器開機(jī)密碼 3、機(jī)器出廠序列號(hào) 等等其它關(guān)鍵的參數(shù),最常用的存儲(chǔ)方法是基于xxx.ini的文件形式來進(jìn)行存儲(chǔ),ini文件是什么在以往的文章中也有相應(yīng)的介紹。 1

serif;font-size: 15px;text-align: start;">在實(shí)際產(chǎn)品開發(fā)過程中,我們常常會(huì)對(duì)一些產(chǎn)品的內(nèi)置參數(shù)進(jìn)行存儲(chǔ),比如:

  • 1、當(dāng)前屬于哪種語言
  • 2、機(jī)器開機(jī)密碼
  • 3、機(jī)器出廠序列號(hào)

等等其它關(guān)鍵的參數(shù),最常用的存儲(chǔ)方法是基于xxx.ini的文件形式來進(jìn)行存儲(chǔ),ini文件是什么在以往的文章中也有相應(yīng)的介紹。

1、了解什么是INI文件?

ini 文件是Initialization File的縮寫,即初始化文件,這是用來配置應(yīng)用軟件以實(shí)現(xiàn)不同用戶的要求。

2、INI文件的格式

INI文件由節(jié)、鍵、值組成。一個(gè)簡單的的INI文件例子如下:

[Setting]
INIT_FLAG=0;
VOLUME=1;
LANGUAGE=1;

如上例子,[Setting]就是節(jié),=號(hào)左邊的值是鍵,=號(hào)右邊的是值。

3、關(guān)于ini_parse開源C庫

在github上,關(guān)于ini文件的解析已經(jīng)有相應(yīng)的開源軟件了,網(wǎng)址如下:

https://github.com/ndevilla/iniparser

上面會(huì)非常詳細(xì)介紹這個(gè)開源程序是如何來編譯以及使用的,并且也開源了相應(yīng)的源代碼,具體原理本節(jié)不會(huì)多講,因?yàn)殚_源的文檔已經(jīng)講解得非常詳細(xì)了,本節(jié),我將基于小熊派,配置一個(gè)SD卡+Fatfs的工程,在確保文件系統(tǒng)在SD卡構(gòu)建的情況下,來移植ini_parse庫,以便于我們?nèi)粘i_發(fā)的使用。

4、stm32cubeMX SD卡+Fatfs文件系統(tǒng)工程配置

4.1 時(shí)鐘配置

這里我選擇是外部時(shí)鐘。


4.2 串行調(diào)試接口配置

4.3 SD卡接口參數(shù)配置

以下是SD卡接口在小熊派上的電路原理圖。

對(duì)應(yīng)主控MCU管腳的連接

由于這里只有一條輸出D0輸出線,所以在CubeMX上選擇SD 1bit模式,其余參數(shù)默認(rèn)。

4.4 配置調(diào)試串口

4.5 配置SD卡支持Fatfs

4.6 配置一路調(diào)試燈+2個(gè)按鍵

我們通過兩個(gè)按鍵來實(shí)現(xiàn)更改參數(shù)和讀取參數(shù),并且用LED來提示。

最后生成代碼即可 。

5、下載ini_parse庫到生成的代碼中并進(jìn)行移植以支持fatfs

將對(duì)應(yīng)的庫文件包含到工程源碼中:

由于ini_parse基于標(biāo)準(zhǔn)庫所寫,所以文件操作都是基于標(biāo)準(zhǔn)文件操作進(jìn)行編寫的,在這里我們需要把這些接口全部轉(zhuǎn)變成fatfs的接口。

iniparse.h

在iniparse.h中包含fatfs的頭文件
#include "fatfs.h"

原來標(biāo)準(zhǔn)文件操作的接口
//void iniparser_dump_ini(dictionary * d, FILE * f);
替換為現(xiàn)在支持Fatfs文件的操作接口
void iniparser_dump_ini(dictionary * d, /*FILE *f*/FIL * f);

原來標(biāo)準(zhǔn)文件操作的接口
//void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f);
替換為現(xiàn)在支持Fatfs文件的操作接口
void iniparser_dumpsection_ini(dictionary * d, char * s, /*FILE * f*/ FIL *f);

原來標(biāo)準(zhǔn)文件操作的接口
//void iniparser_dump(dictionary * d,*FILE * f);
替換為現(xiàn)在支持Fatfs文件的操作接口
void iniparser_dump(dictionary * d, /*FILE * f*/ FIL *f);

iniparse.c

調(diào)整支持fatfs的接口

iniparser_dump函數(shù)修改

void iniparser_dump(dictionary * d, /*FILE * f*/FIL *f)
{
int i ;
if (d == NULL || f == NULL) return ;

for (i = 0 ; i < d->size ; i++)
{
if (d->key[i] == NULL)
continue ;

if (d->val[i] != NULL)
{
f_printf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
//注釋這里為標(biāo)準(zhǔn)庫操作接口
//fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
}
else
{
f_printf(f, "[%s]=UNDEF\n", d->key[i]);
//注釋這里為標(biāo)準(zhǔn)庫操作接口
//fprintf(f, "[%s]=UNDEF\n", d->key[i]);
}
}
return ;
}

iniparser_dumpsection_ini修改

void iniparser_dumpsection_ini(dictionary * d, char * s, /*FILE * f*/ FIL *f)
{
int j ;
char *keym;
int secsize ;

if (d == NULL || f == NULL) return ;

if (! iniparser_find_entry(d, s)) return ;
//注釋這里為標(biāo)準(zhǔn)庫操作接口
//fprintf(f, "\n[%s]\n", s);
f_printf(f, "\n[%s]\n", s);
secsize = (int)strlen(s) + 2;
keym = (char *)malloc(secsize);
snprintf(keym, secsize, "%s:", s);

for (j = 0 ; j < d->size ; j++)
{
if (d->key[j] == NULL)
continue ;

if (!strncmp(d->key[j], keym, secsize - 1))
{
//注釋這里為標(biāo)準(zhǔn)庫操作接口
/*
fprintf(f,
"%-30s = %s\n",
d->key[j]+secsize-1,
d->val[j] ? d->val[j] : "");
*/
f_printf(f,
"%-30s = %s\n",
d->key[j] + secsize - 1,
d->val[j] ? d->val[j] : "");
}
}
//注釋這里為標(biāo)準(zhǔn)庫操作接口
//fprintf(f, "\n");
f_printf(f, "\n");
free(keym);
return ;
}

iniparser_load函數(shù)由于太長,限于篇幅,這里我們只具體截出更改的函數(shù):

注釋原始的文件描述符
//FILE * in = NULL ;

//修改fopen為f_open
//if ((in=fopen(ininame, "r"))==NULL)
//{
// fprintf(stderr, "iniparser: cannot open %s\n", ininame);
// goto out;
//}

retSD = f_open(&SDFile, ininame, FA_OPEN_EXISTING | FA_READ);
if(FR_OK != retSD)
{
fprintf(stderr, "iniparser: cannot open %s\n", ininame);
goto out ;
}

//修改fgets為f_gets
//while (fgets(line, ASCIILINESZ, in)!=NULL) {
while(f_gets(line, ASCIILINESZ, &SDFile) != NULL)

//修改feof為f_eof
// if (line[len]!='\n' && !feof(in)) {
if (line[len] != '\n' && !f_eof(&SDFile))

修改fclose為f_close
// if (in) {
// fclose(in);
f_close(&SDFile);

到這里移植就結(jié)束了,非常簡單,只需要把對(duì)應(yīng)的接口做替換就可以了。

6、編寫測試代碼

對(duì)應(yīng)頭文件包含

/* USER CODE BEGIN Includes */
#include "iniparser.h"
#include "multi_button.h"
/* USER CODE END Includes */

定義串口重定向

int fputc(int ch, FILE *stream)
{
/* 堵塞判斷串口是否發(fā)送完成 */
while((USART1->ISR & 0X40) == 0);

/* 串口發(fā)送完成,將該字符發(fā)送 */
USART1->TDR = (uint8_t) ch;

return ch;
}

定義例程對(duì)應(yīng)的全局參數(shù)

multi_button相關(guān),用于按鍵操作
/* USER CODE BEGIN PV */
Button button1, button2;
/* USER CODE END PV */

/*文件名*/
#define SETTING_PARA "0:Para.ini"

/*默認(rèn)系統(tǒng)配置信息*/
char *System_Config_Info =
"[Setting]\n"
"led_flag=1;\n" /*LED標(biāo)志*/
"plot_flag=0;\n" /*曲線開關(guān)*/
"WIFI_NAME=BearPi_ESP8266;\n" /*WIFI熱點(diǎn)*/
"WIFI_PASSWORD=12345678;\n" /*WIFI密碼*/
;

typedef struct
{
int led_flag ;
int plot_flag ;
char wifi_name[32] ;
char wifi_password[32];
} info ;

info ini_info ;
dictionary *Config_ini = NULL;

/*系統(tǒng)配置文件全局變量*/
uint8_t retUSER_SYS_CONFIG ;
FATFS USERFatFS_SYS_CONFIG ;
FIL USER_SYS_CONFIG_File ;

/*掛載SD卡*/
int Mount_SD(void)
{
/*掛載SD卡*/
retSD = f_mount(&SDFatFS, SDPath, 1);

if(FR_OK != retSD)
return -1 ;

return 0 ;
}

/*創(chuàng)建一個(gè)默認(rèn)的配置文件*/
void Create_Default_InI_File(void)
{
retUSER_SYS_CONFIG = f_open(&USER_SYS_CONFIG_File, SETTING_PARA, FA_OPEN_ALWAYS | FA_WRITE);

if(FR_OK != retUSER_SYS_CONFIG)
{
fprintf(stderr, "iniparser: cannot open %s\n", SETTING_PARA);
return ;
}

f_printf(&USER_SYS_CONFIG_File, System_Config_Info);
f_close(&USER_SYS_CONFIG_File);
}

/*加載INI文件*/
int Load_Confg_INI_Process(void)
{
/*加載INI文件*/
Config_ini = iniparser_load(SETTING_PARA);

if(NULL == Config_ini)
{
printf("加載出錯(cuò)\n");
Create_Default_InI_File();
Config_ini = iniparser_load(SETTING_PARA);

if(NULL == Config_ini)
{
printf("創(chuàng)建默認(rèn)INI文件后繼續(xù)加載出錯(cuò)\n");
return -1;
}
}

printf("加載INI文件成功\n");
return 0 ;
}

/*保存參數(shù)*/
int INI_Para_Save_Process(void)
{
/*write config.ini parse*/
retUSER_SYS_CONFIG = f_open(&USER_SYS_CONFIG_File, SETTING_PARA, FA_OPEN_EXISTING | FA_WRITE);

if(FR_OK != retUSER_SYS_CONFIG)
{
printf("iniparser: cannot open %s\n", SETTING_PARA);
return -1;
}

printf("參數(shù)設(shè)置保存成功\n");
iniparser_dump_ini(Config_ini, &USER_SYS_CONFIG_File);
f_close(&USER_SYS_CONFIG_File);
iniparser_freedict(Config_ini);
return 0 ;
}
//讀取按鍵1
uint8_t read_button1()
{
return HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) ;
}
//讀取按鍵2
uint8_t read_button2()
{
return HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) ;
}

//按鍵1回調(diào)
void button1_callback(void *ptr)
{
static uint8_t index = 0 ;
char *wifi_name_para[] = {"Yangyuanxin", "Bruce_Yang", "BearPi", "mculover666"};

if(index == 4)
index = 0 ;

printf("\r\n按下KEY1,改變并保存WIFI_NAME參數(shù)!\n");
Load_Confg_INI_Process();
iniparser_set(Config_ini, "Setting:WIFI_NAME", wifi_name_para[index]);
INI_Para_Save_Process();
printf("設(shè)置wifi_name:%s成功\n",wifi_name_para[index]);
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
++index ;
}
//按鍵2回調(diào)
void button2_callback(void *ptr)
{
char *wifi_name = NULL ;
printf("\r\n按下KEY2,讀取WIFI_NAME參數(shù)!\n");
Load_Confg_INI_Process();
wifi_name = iniparser_getstring(Config_ini, "Setting:WIFI_NAME", "not found");
INI_Para_Save_Process();
memset(ini_info.wifi_name, 0, strlen(ini_info.wifi_name));
memcpy(ini_info.wifi_name, wifi_name, strlen(wifi_name));
printf("wifi_name:%s\n", ini_info.wifi_name);
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
}

主函數(shù)實(shí)現(xiàn):

/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
int ret = -1 ;
char *wifi_name = NULL ;
char *wifi_password = NULL ;
/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SDMMC1_SD_Init();
MX_USART1_UART_Init();
MX_FATFS_Init();
/* USER CODE BEGIN 2 */
//初始化并注冊按鍵
button_init(&button1, read_button1, 0);
button_init(&button2, read_button2, 0);
button_attach(&button1, SINGLE_CLICK, button1_callback);
button_attach(&button2, SINGLE_CLICK, button2_callback);
button_start(&button1);
button_start(&button2);
//掛載SD卡
ret = Mount_SD();
if(ret != 0)
{
printf("SD Card mount ERROR\r\n");
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
return -1 ;
}
printf("SD卡掛載成功!\n");
//加載INI文件
ret = Load_Confg_INI_Process();

if(ret != 0)
{
printf("讀取INI文件失敗!\r\n");
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
return -2 ;
}

/*加載系統(tǒng)參數(shù)*/
ini_info.led_flag = iniparser_getint(Config_ini, "Setting:led_flag", -1);
ini_info.plot_flag = iniparser_getint(Config_ini, "Setting:plot_flag", -1);
wifi_name = iniparser_getstring(Config_ini, "Setting:WIFI_NAME", "not found");
wifi_password = iniparser_getstring(Config_ini, "Setting:WIFI_PASSWORD", "not found");
memcpy(ini_info.wifi_name, wifi_name, strlen(wifi_name));
memcpy(ini_info.wifi_password, wifi_password, strlen(wifi_password));
/*改變參數(shù)led_flag*/
ret = iniparser_set(Config_ini, "Setting:led_flag", "0");
if(ret != 0)
{
printf("改變參數(shù)失敗!\n");
return -3 ;
}
printf("改變參數(shù)成功\n");
/*參數(shù)保存,并釋放內(nèi)存*/
ret = INI_Para_Save_Process();
if(ret != 0)
{
printf("寫入保存INI文件失敗!\r\n");
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
return -4 ;
}

printf("寫入保存INI文件成功!\r\n");
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
//以5ms周期調(diào)用按鍵tick
button_ticks();
HAL_Delay(5);
}

/* USER CODE END 3 */
}

注意,在Keil中,把堆棧盡量設(shè)大一些,以支持fatfs和iniparse的使用,可以通過CubeMX工程設(shè)置:

也可以直接在Keil中設(shè)置,但是下次用CubeMX生成的時(shí)候參數(shù)又會(huì)復(fù)原噢,建議采用CubeMX工程設(shè)置:

7、運(yùn)行效果

還記得在上上節(jié)WIFI配網(wǎng)的粗暴方式,就可以以這種粗暴的方式直接改SSID和PASSWORD,然后產(chǎn)品開機(jī)直接就加載SD卡ini文件中的SSID和PASSWORD。

基于小熊派WIFI-ESP8266實(shí)踐(上)

例程下載

鏈接:https://pan.baidu.com/s/13AJ6Pds4UzNSdkk1PcCGDQ
提取碼:7y54
復(fù)制這段內(nèi)容后打開百度網(wǎng)盤手機(jī)App,操作更方便哦

公眾號(hào)粉絲福利時(shí)刻

這里我給大家申請到了福利,本公眾號(hào)讀者購買小熊派開發(fā)板可享受9折優(yōu)惠,有需要購買小熊派的朋友,淘寶搜索即可,跟客戶說你是公眾號(hào):嵌入式云IOT技術(shù)圈 的粉絲,立享9折優(yōu)惠!

往期精彩

網(wǎng)紅物聯(lián)網(wǎng)開發(fā)板小熊派使用評(píng)測

基于小熊派WIFI-ESP8266實(shí)踐(上)

超輕量級(jí)網(wǎng)紅軟件定時(shí)器multi_timer(51+stm32雙平臺(tái)實(shí)戰(zhàn))

基于小熊派WIFI-ESP8266實(shí)踐(中)-多功能處理顯示等大雜燴

基于小熊派光強(qiáng)傳感器BH1750實(shí)踐(multi_timer+狀態(tài)機(jī)工程應(yīng)用)

基于小熊派光強(qiáng)傳感器BH1750狀態(tài)機(jī)驅(qū)動(dòng)項(xiàng)目升級(jí)(帶LCD屏顯示)

基于小熊派光強(qiáng)傳感器BH1750狀態(tài)機(jī)驅(qū)動(dòng)項(xiàng)目再度升級(jí)(帶上位機(jī)曲線顯示)

若覺得本次分享的文章對(duì)您有幫助,隨手點(diǎn)[在看]并轉(zhuǎn)發(fā)分享,也是對(duì)我的支持。

serif;font-size: 15px;text-align: start;box-sizing: border-box !important;overflow-wrap: break-word !important;">

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉