ESP8266低功耗解决方案之轻度睡眠Light-sleep

ESP8266 系列芯片提供三种可配置的睡眠模式,针对这些睡眠模式,我们提供了多种低功耗解决方案,用户可以结合具体需求选择睡眠模式并进行配置。三种睡眠模式如下:

ESP8266低功耗解决方案之轻度睡眠Light-sleep:

Light-sleep 的工作模式与 Modem-sleep 相似,不同的是,除了关闭 Wi-Fi 模块电路以外,在 Light-sleep 模式下,还会关闭时钟并暂停内部 CPU,比 Modem-sleep 功耗更低。在 Light-sleep 之前把处于输出状态的管脚改为输入状态,比如:MTDO、U0TXD、GPIO0,消除管脚上的漏电,可使 Light-sleep 的功耗更低。

应用场合:

Light-sleep 模式可用于需要保持与路由器的连接,可以实时响应路由器发来的数据的场合。并且在未接收到命令时,CPU 可以处于空闲状态。比如 Wi-Fi 开关的应用,大部分时间 CPU 都是空闲的,直到收到控制命令,CPU 才需要进行 GPIO 的操作。

自动休眠和强制休眠:

自动休眠:系统通过以下接口进入 Light-sleep 模式

/**
  * @brief     Set sleep type for force sleep function.
  *
  * @attention This API can only be called before wifi_fpm_open.
  *
  * @param     type  sleep type
  *
  * @return    null
  */
void esp_wifi_fpm_set_sleep_type(wifi_sleep_type_t type);

强制休眠: 用户可以使系统强制进入 Light-sleep 模式,即调用强制休眠接口,强制关闭射频。强制休眠接口调⽤用后,并不会立即休眠,而是等到系统空闲任务执行时才进入休眠。

外部唤醒:(能不用就不用,唤醒时间比较久,注意:GPIO16不能用于唤醒)

在 Light-sleep 模式下,CPU 在暂停状态下不会响应来自外围硬件接口的信号与中断,因此需要通过外部 GPIO 信号将 ESP8266 唤醒,硬件唤醒过程大约为 3 ms。由于 Wi-Fi 初始化过程需要大约 1 ms,所以建议用户 5 ms 之后再对芯片进行操作。

/**
  * @brief  Set a GPIO to wake the ESP8266 up from light-sleep mode 
  *         ESP8266 will be wakened from Light-sleep, when the GPIO is in low-level.
  * 
  * If the ESP8266 enters light-sleep automatically(esp_wifi_set_sleep_type(LIGHT_SLEEP_T);), 
  * after being waken up by GPIO, when the chip attempts to sleep again, it will check the status of the GPIO:
  * Note:
  * • If the GPIO is still in the wakeup status, the EP8266 will enter modem-sleep mode instead;
  * • If the GPIO is NOT in the wakeup status, the ESP8266 will enter light-sleep mode
  * 
  * @param gpio_num     GPIO number, range: [0, 15].
  *                     gpio_int_type_t intr_status: status of GPIO interrupt to trigger the wakeup process.
  *                     - if esp_wifi_fpm_set_sleep_type is set to be LIGHT_SLEEP_T, ESP8266 can wake up by GPIO.
  *                     - if esp_wifi_fpm_set_sleep_type is set to be MODEM_SLEEP_T, ESP8266 can wake up by esp_wifi_fpm_do_wakeup.
  * @param intr_status  GPIO interrupt type
  *
  * @return   null
  */
void esp_wifi_enable_gpio_wakeup(uint32_t gpio_num, gpio_int_type_t intr_status);

示例代码:

/* Simple WiFi Example

   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 
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "rom/ets_sys.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "esp_sleep.h"

/* The examples use simple WiFi configuration that you can set via
   'make menuconfig'.

   If you'd rather not, just change the below entries to strings with
   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_MODE_AP   CONFIG_ESP_WIFI_MODE_AP //TRUE:AP FALSE:STA
#define EXAMPLE_ESP_WIFI_SSID      CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS      CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_MAX_STA_CONN       CONFIG_MAX_STA_CONN

/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t wifi_event_group;

/* The event group allows multiple bits for each event,
   but we only care about one event - are we connected
   to the AP with an IP? */
const int WIFI_CONNECTED_BIT = BIT0;

static const char *TAG = "simple wifi";

static esp_err_t event_handler(void *ctx, system_event_t *event)
{
    /* For accessing reason codes in case of disconnection */
    system_event_info_t *info = &event->event_info;
    
    switch(event->event_id) {
    case SYSTEM_EVENT_STA_START:
        esp_wifi_connect();
        break;
    case SYSTEM_EVENT_STA_GOT_IP:
        ESP_LOGI(TAG, "got ip:%s",
                 ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
        xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
        break;
    case SYSTEM_EVENT_AP_STACONNECTED:
        ESP_LOGI(TAG, "station:"MACSTR" join, AID=%d",
                 MAC2STR(event->event_info.sta_connected.mac),
                 event->event_info.sta_connected.aid);
        break;
    case SYSTEM_EVENT_AP_STADISCONNECTED:
        ESP_LOGI(TAG, "station:"MACSTR"leave, AID=%d",
                 MAC2STR(event->event_info.sta_disconnected.mac),
                 event->event_info.sta_disconnected.aid);
        break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
        ESP_LOGE(TAG, "Disconnect reason : %d", info->disconnected.reason);
        if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
            /*Switch to 802.11 bgn mode */
            esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCAL_11B | WIFI_PROTOCAL_11G | WIFI_PROTOCAL_11N);
        }
        esp_wifi_connect();
        xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT);
        break;
    default:
        break;
    }
    return ESP_OK;
}

void wifi_init_softap()
{
    wifi_event_group = xEventGroupCreate();

    tcpip_adapter_init();
    ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    wifi_config_t wifi_config = {
        .ap = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
            .password = EXAMPLE_ESP_WIFI_PASS,
            .max_connection = EXAMPLE_MAX_STA_CONN,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK
        },
    };
    if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "wifi_init_softap finished.SSID:%s password:%s",
             EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
}

void wifi_init_sta()
{
    wifi_event_group = xEventGroupCreate();

    tcpip_adapter_init();
    ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL) );

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS
        },
    };

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");
    ESP_LOGI(TAG, "connect to ap SSID:%s password:%s",
             EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
}

void fpm_wakup_cb_func1(void) {
	esp_wifi_fpm_close();

	vTaskDelay(5000 / portTICK_RATE_MS);

	esp_wifi_set_mode(WIFI_MODE_STA);
	esp_wifi_connect();
}

void app_main()
{
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
    
#if EXAMPLE_ESP_WIFI_MODE_AP
    ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
    wifi_init_softap();
#else
    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    wifi_init_sta();
#endif /*EXAMPLE_ESP_WIFI_MODE_AP*/

    xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, true, false, portMAX_DELAY);

    esp_err_t error;

	esp_wifi_disconnect();
	esp_wifi_set_mode(WIFI_MODE_NULL);

	ESP_LOGI(TAG, "START WIFI_LIGHT_SLEEP_T\n");

	esp_wifi_fpm_set_sleep_type(WIFI_LIGHT_SLEEP_T);
	esp_wifi_fpm_open();

	esp_wifi_fpm_set_wakeup_cb(fpm_wakup_cb_func1);
	error = esp_wifi_fpm_do_sleep((1000 * 1000) * 10);

	ESP_LOGI(TAG, "RETURN DO_SLEEP:%d\n", error);

}

 

你可能感兴趣的:(FreeRTOS)