ESP32用NVS存储wifi信息

通俗来说,NVS 就是在 flash 上分配的一块内存空间 ,提供给用户保存掉电不丢失的数据。 

  • 非易失性存储 (NVS) 库主要用于在 flash 中存储键值格式的数据。
  • NVS适合存储一些小数据,如果对象占用空间比较大,使用负载均衡的FAT文件系统。
  • 如果NVS分区被截断,比如更改分区表布局的时候,应该擦除分区内容。可以使用 idf.py erase_flash 命令擦除flash上全部的内容。

参考文章:http://t.csdn.cn/JkIFk

对照着官方的例程和API进行编写程序。

官方例程如下:

/* Non-Volatile Storage (NVS) Read and Write a Blob - Example

   For other examples please check:
   https://github.com/espressif/esp-idf/tree/master/examples

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "driver/gpio.h"

#define STORAGE_NAMESPACE "storage"

#if CONFIG_IDF_TARGET_ESP32C3
#define BOOT_MODE_PIN GPIO_NUM_9
#else
#define BOOT_MODE_PIN GPIO_NUM_0
#endif //CONFIG_IDF_TARGET_ESP32C3

/* Save the number of module restarts in NVS
   by first reading and then incrementing
   the number that has been saved previously.
   Return an error if anything goes wrong
   during this process.
 */
esp_err_t save_restart_counter(void)
{
    nvs_handle_t my_handle;
    esp_err_t err;

    // Open
    err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle);
    if (err != ESP_OK) return err;

    // Read
    int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS
    err = nvs_get_i32(my_handle, "restart_conter", &restart_counter);
    if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;

    // Write
    restart_counter++;
    err = nvs_set_i32(my_handle, "restart_conter", restart_counter);
    if (err != ESP_OK) return err;

    // Commit written value.
    // After setting any values, nvs_commit() must be called to ensure changes are written
    // to flash storage. Implementations may write to storage at other times,
    // but this is not guaranteed.
    err = nvs_commit(my_handle);
    if (err != ESP_OK) return err;

    // Close
    nvs_close(my_handle);
    return ESP_OK;
}

/* Save new run time value in NVS
   by first reading a table of previously saved values
   and then adding the new value at the end of the table.
   Return an error if anything goes wrong
   during this process.
 */
esp_err_t save_run_time(void)
{
    nvs_handle_t my_handle;
    esp_err_t err;

    // Open
    err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle);
    if (err != ESP_OK) return err;

    // Read the size of memory space required for blob
    size_t required_size = 0;  // value will default to 0, if not set yet in NVS
    err = nvs_get_blob(my_handle, "run_time", NULL, &required_size);
    if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;

    // Read previously saved blob if available
    uint32_t* run_time = malloc(required_size + sizeof(uint32_t));
    if (required_size > 0) {
        err = nvs_get_blob(my_handle, "run_time", run_time, &required_size);
        if (err != ESP_OK) {
            free(run_time);
            return err;
        }
    }

    // Write value including previously saved blob if available
    required_size += sizeof(uint32_t);
    run_time[required_size / sizeof(uint32_t) - 1] = xTaskGetTickCount() * portTICK_PERIOD_MS;
    err = nvs_set_blob(my_handle, "run_time", run_time, required_size);
    free(run_time);

    if (err != ESP_OK) return err;

    // Commit
    err = nvs_commit(my_handle);
    if (err != ESP_OK) return err;

    // Close
    nvs_close(my_handle);
    return ESP_OK;
}

/* Read from NVS and print restart counter
   and the table with run times.
   Return an error if anything goes wrong
   during this process.
 */
esp_err_t print_what_saved(void)
{
    nvs_handle_t my_handle;
    esp_err_t err;

    // Open
    err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle);
    if (err != ESP_OK) return err;

    // Read restart counter
    int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS
    err = nvs_get_i32(my_handle, "restart_conter", &restart_counter);
    if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
    printf("Restart counter = %d\n", restart_counter);

    // Read run time blob
    size_t required_size = 0;  // value will default to 0, if not set yet in NVS
    // obtain required memory space to store blob being read from NVS
    err = nvs_get_blob(my_handle, "run_time", NULL, &required_size);
    if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
    printf("Run time:\n");
    if (required_size == 0) {
        printf("Nothing saved yet!\n");
    } else {
        uint32_t* run_time = malloc(required_size);
        err = nvs_get_blob(my_handle, "run_time", run_time, &required_size);
        if (err != ESP_OK) {
            free(run_time);
            return err;
        }
        for (int i = 0; i < required_size / sizeof(uint32_t); i++) {
            printf("%d: %d\n", i + 1, run_time[i]);
        }
        free(run_time);
    }

    // Close
    nvs_close(my_handle);
    return ESP_OK;
}


void app_main(void)
{
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK( err );

    err = print_what_saved();
    if (err != ESP_OK) printf("Error (%s) reading data from NVS!\n", esp_err_to_name(err));

    err = save_restart_counter();
    if (err != ESP_OK) printf("Error (%s) saving restart counter to NVS!\n", esp_err_to_name(err));

    gpio_reset_pin(BOOT_MODE_PIN);
    gpio_set_direction(BOOT_MODE_PIN, GPIO_MODE_INPUT);

    /* Read the status of GPIO0. If GPIO0 is LOW for longer than 1000 ms,
       then save module's run time and restart it
     */
    while (1) {
        if (gpio_get_level(BOOT_MODE_PIN) == 0) {
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            if(gpio_get_level(BOOT_MODE_PIN) == 0) {
                err = save_run_time();
                if (err != ESP_OK) printf("Error (%s) saving run time blob to NVS!\n", esp_err_to_name(err));
                printf("Restarting...\n");
                fflush(stdout);
                esp_restart();
            }
        }
        vTaskDelay(200 / portTICK_PERIOD_MS);
    }
}

大概就分为几个步骤,初始化,打开,写入,读取,关闭

我们接下来也按照这个步骤进行编写就可以。

首先,我们在头文件里定义一个结构体,用来设置要保存的wifi信息。

#define MAX_SETTING_SSID_LEN 32//最大限制
#define MAX_SETTING_PSW_LEN  64//同上


typedef struct 
{
    char setting_ssid[MAX_SETTING_SSID_LEN];//WiFi名
    uint8_t setting_ssid_len;
    char setting_psw[MAX_SETTING_PSW_LEN];//密码
    uint8_t setting_psw_len;
    
}SYSSTERM_DATA_T;

然后就可以写相关程序了,基本上都是参照例程进行删改,不难的。

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "esp_log.h"

#include "ds_nvs_da.h"
#include "ds_system_data_da.h"


static const char *TAG = "ds_nvs";

NVS_WIFI_INFO_E wifi_config_flag = NVS_WIFI_INFO_NULL;

//保存信息
void ds_nvs_save_wifi_info(void){
    esp_err_t err;
    nvs_handle_t nvs_handle;
    //打开
    err = nvs_open("wificonfig", NVS_READWRITE, &nvs_handle);
    if (err != ESP_OK) {
        ESP_LOGI(TAG,"Error (%s) opening NVS handle!\n", esp_err_to_name(err));
        return ;
    }
    wifi_config_flag = NVS_WIFI_INFO_SAVE;

    ESP_ERROR_CHECK(nvs_set_u8(nvs_handle, "wifi_flag", wifi_config_flag));
    ESP_ERROR_CHECK(nvs_set_str(nvs_handle, "ssid", get_systerm_data().setting_ssid));
    ESP_ERROR_CHECK(nvs_set_str(nvs_handle, "psw",  get_systerm_data().setting_psw));
    ESP_ERROR_CHECK(nvs_commit(nvs_handle));
    nvs_close(nvs_handle);
}

//读取
NVS_WIFI_INFO_E ds_nvs_read_wifi_info(void){
    esp_err_t err;
    nvs_handle_t nvs_handle;
    err = nvs_open("wificonfig",NVS_READWRITE,&nvs_handle);
    if (err != ESP_OK) {
        ESP_LOGI(TAG,"Error (%s) opening NVS handle!\n", esp_err_to_name(err));
        return NVS_WIFI_INFO_ERROR;
    }
    uint8_t wifi_config = 0;
    ESP_ERROR_CHECK(nvs_get_u8(nvs_handle,"wifi_flag",&wifi_config));
    wifi_config_flag = wifi_config;
    if(wifi_config_flag == NVS_WIFI_INFO_SAVE){
        ESP_LOGI(TAG,"has wifi config info");
        char ssid[32];
        char psw[64];
        size_t ssid_len = sizeof(ssid);
        size_t psw_len = sizeof(psw);
        ESP_ERROR_CHECK(nvs_get_str(nvs_handle,"ssid",ssid,&ssid_len));
        ESP_ERROR_CHECK(nvs_get_str(nvs_handle,"psw",psw,&psw_len));
        set_systerm_data_wifi_info(ssid,ssid_len,psw,psw_len);
        print_systerm_data_wifi_info();

    }else{
        ESP_LOGI(TAG,"wifi config info null");

    }
    nvs_close(nvs_handle);
    return wifi_config_flag;
}
void ds_nvs_init(void){
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK( err );

}

特别注意的是这里还有一个ds_systerm_data_da.h头文件,这里 是为了处理数据方便写的,可以不写,但还是最好写一下。

#include "sdkconfig.h"
#include "esp_system.h"
#include "esp_log.h"

#include "ds_system_data_da.h"


static const char *TAG = "ds_system_data";

SYSSTERM_DATA_T g_system_data; //定义要数据结构

//初始化数据
void ds_systerm_data_init(void){

    memset(&g_system_data,0,sizeof(SYSSTERM_DATA_T));//将所有的内容替换为0
}

//获取数据,返回量为SYSTERM_DATA_T结构体
SYSSTERM_DATA_T get_systerm_data(void){

    return g_system_data;
}

//设置数据
void set_systerm_data_wifi_info(char *p_ssid,uint8_t p_ssidlen,char * p_psw,uint8_t p_pswlen){
    if(p_pswlen >= MAX_SETTING_PSW_LEN || p_ssidlen >=MAX_SETTING_SSID_LEN)//判断长度是否在范围内
    {
        ESP_LOGE(TAG,"MAX_SETTING_SSID_PSW_LEN ERROR!");
    }
    g_system_data.setting_psw_len = p_pswlen;
    g_system_data.setting_ssid_len = p_ssidlen;
    memcpy(g_system_data.setting_ssid,p_ssid,p_ssidlen);
    memcpy(g_system_data.setting_psw,p_psw,p_pswlen);
    g_system_data.setting_ssid[p_ssidlen] = '\0';
    g_system_data.setting_psw[p_pswlen] = '\0';

}

//打印获取到的数据
void print_systerm_data_wifi_info(void){

    printf("\r\nwifi_ssid:");
    for(int i = 0;i<g_system_data.setting_ssid_len;i++){
        printf("%c",g_system_data.setting_ssid[i]);
    }
     printf("\r\nwifi_password:");
    for(int i = 0;i<g_system_data.setting_psw_len;i++){
        printf("%c",g_system_data.setting_psw[i]);
    }
    printf("\r\n");

}

//检查是否已经有wifi的信息传进来
SETTING_DATA_E check_systerm_data_wifi_info(void){
    if(g_system_data.setting_ssid_len != 0){
        return SETTING_DATA_HAS_WIFI_INFO;
    }
    return SETTING_DATA_INIT;
}

然后在主程序里面测试,这里是基于上次文件系统改的。

在上次的基础上,增加了这些,主要就是设置wifi的信息进行测试。

然后上开发板进行测试。

 可以看到,已经成功打印出我们所设置的wifi信息。

成功!

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值