Learn Esp32 with ESP-IDF - 3. A First Look

3. A First Look

3.1 Logging

介绍了 ESP_LOG 头文件 include "esp_log.h"

我们来看看 ESP_LOGE 的定义,这个命令意味着 log error:

Definition:  
#define ESP_LOGE(tag, format, ...) ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR,   tag, format, ##__VA_ARGS__)

烧写这个代码:

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"

void app_main(void)
{
    ESP_LOGE("LOG", "This is an error");
}

输出为:

剩下类似的还有:

ESP_LOGW - warning
ESP_LOGI - info
ESP_LOGD - debug
ESP_LOGV - verbose

注意ESP_LOGD 和 ESP_LOGV 默认是关闭的,要想开启,运行 idf.py menuconfig ,选择 component config - log output - default log verbosity (Info),然后选择 log 的最低输出级别,选择完毕之后 exit 即可。

例如,如果直接烧录这段程序:

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"

void app_main(void)
{
    ESP_LOGE("LOG", "This is an error");
    ESP_LOGW("LOG", "This is an warning");
    ESP_LOGI("LOG", "This is an info");
    ESP_LOGD("LOG", "This is an debug");
    ESP_LOGV("LOG", "This is an verbose");
}

只会输出 INFO 及以上级别的 LOG:

image

修改 LOG 级别为 verbose 之后:

image

注:括号中的数字表示输出时候的时间。

我们也可以用 esp_log_level_set(tag, level); 这个函数来为特定的 tag 指定 LOG 级别。

当 default log verbosity 为 Info

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"

void app_main(void)
{
    esp_log_level_set("LOG", ESP_LOG_INFO);
    ESP_LOGE("LOG", "This is an error");
    ESP_LOGW("LOG", "This is an warning");
    ESP_LOGI("LOG", "This is an info");
    ESP_LOGD("LOG", "This is an debug");
    ESP_LOGV("LOG", "This is an verbose");

    esp_log_level_set("TAG 2", ESP_LOG_DEBUG);
    ESP_LOGE("TAG 2", "This is an error");
    ESP_LOGW("TAG 2", "This is an warning");
    ESP_LOGI("TAG 2", "This is an info");
    ESP_LOGD("TAG 2", "This is an debug");
    ESP_LOGV("TAG 2", "This is an verbose");
}

输出的是:

image

而在 idf.py menuconfig 中将default log verbosity 改成 debug 之后,输出的是:

image

由此可分析得知,menuconfig 中设置的是最低级别的log,而 esp_log_level_set 是在 default log verbosity 上控制的特定 tag 的 log 级别,如果没有特定设置,则以 default log verbosity 为标准。

另外需要注意,其实 ESP_LOG 系列函数和 printf 一样支持 format print,例如:

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"

void app_main(void)
{
    esp_log_level_set("LOG", ESP_LOG_INFO);
    ESP_LOGE("LOG", "This is an error");
    ESP_LOGW("LOG", "This is an warning");
    ESP_LOGI("LOG", "This is an info");
    ESP_LOGD("LOG", "This is an debug");
    ESP_LOGV("LOG", "This is an verbose");

    esp_log_level_set("TAG 2", ESP_LOG_DEBUG);
    int number = 0;
    ESP_LOGE("TAG 2", "This is an error %d", number++);
    ESP_LOGW("TAG 2", "This is an warning %d", number++);
    ESP_LOGI("TAG 2", "This is an info %d", number++);
    ESP_LOGD("TAG 2", "This is an debug %d", number++);
    ESP_LOGV("TAG 2", "This is an verbose %d", number++);
}

会输出:

image

3.2 Delays

我们需要用到这两个头文件:

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

以及这个函数 vTaskDelay (v means void)

这个函数返回的值单位是 tick,所以如果我们要换成 1000 ms,需要这样使用: 1000 / portTICK_PERIOD_MS

我们编写以下程序:

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"

#define TAG "DELAY"

void app_main(void)
{
    int i = 0;
    while (1) {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        ESP_LOGI(TAG, "in loop %d", i++);
    }
}

输出为:

image

3.3 Random Number

需要用到头文件 esp_random.h

编写程序如下:

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

#define TAG "DICE"

void app_main(void)
{
    while (1) {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        ESP_LOGI(TAG, "random number %d", esp_random());
    }
}

输出为:

image

所以如果我们想编写一个骰子程序,可以这样:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_random.h"
#include "math.h"

#define TAG "DICE"

int dice_role() {
    int random = esp_random();
    int positiveNumber = abs(random);
    int diceNumber = (positiveNumber % 6) + 1;
    return diceNumber;
}

void app_main(void)
{
    while (1) {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        ESP_LOGI(TAG, "random number %d", dice_role());
    }
}

输出如下:

image

3.4 Blinky

我们需要用到板子上自带的 led(一般是 pin 2)

我们需要用到这个库: driver/gpio.h

gpio means general purpose input output

我们这样编写程序:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/gpio.h"

#define PIN 2

void app_main(void)
{
    esp_rom_gpio_pad_select_gpio(PIN);
    gpio_set_direction(PIN, GPIO_MODE_OUTPUT);
    int isOn = 0;
    while (true) {
        isOn = !isOn;
        gpio_set_level(PIN, isOn);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

这样就可以实现 esp32 的 built-in led

其中有三个关键函数:

# 告诉 espidf 什么引脚作为 GPIO
esp_rom_gpio_pad_select_gpio(PIN);
# 告诉 espidf GPIO 的引脚作为输入还是输出
gpio_set_direction(PIN, GPIO_MODE_OUTPUT);
# 设定高低电平
gpio_set_level(PIN, isOn);

3.5 KeyBoard Input

需要用到的头文件:string.h

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

void app_main(void)
{
    char c = 0;
    char str[100];
    memset(str, 0, sizeof str);
    while (c != '\n') {
        c = getchar();
        if (c != 0xff) {
            str[strlen(str)] = c;
            printf("%c", c);
        }
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }

    printf("you typed: %s\n", str);
}

输入 asdf 后回车,结果:

image