esp: blink project

目录结构

blink示例的目录结构:

1
2
3
4
5
6
7
8
9
10
--blink
|--main(必有的main目录)
|--blink_example.c
|--CMakeLists.txt(底层编译配置文件)
|--idf_componect.yml
|--Kconfig.projbuild(Kconfig配置文件)
|--CMakeLists.txt(顶层编译配置文件)
|--pytest_blink.py
|--README.md
|--sdkconfig.ci.led_strip_spi

源文件代码

该项目就只有一个源文件:blink_example_main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "led_strip.h"
#include "sdkconfig.h"

static const char *TAG = "example";

/* Use project configuration menu (idf.py menuconfig) to choose the GPIO to blink,
or you can edit the following line and set a number here.
*/
// CONFIG_BLINK_GPIO的默认值是8
#define BLINK_GPIO CONFIG_BLINK_GPIO

static uint8_t s_led_state = 0;

#ifdef CONFIG_BLINK_LED_STRIP

static led_strip_handle_t led_strip;

static void blink_led(void)
{
/* If the addressable LED is enabled */
if (s_led_state) {
/* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */
led_strip_set_pixel(led_strip, 0, 16, 16, 16);
/* Refresh the strip to send data */
led_strip_refresh(led_strip);
} else {
/* Set all LED off to clear all pixels */
led_strip_clear(led_strip);
}
}

static void configure_led(void)
{
ESP_LOGI(TAG, "Example configured to blink addressable LED!");
/* LED strip initialization with the GPIO and pixels number*/
led_strip_config_t strip_config = {
.strip_gpio_num = BLINK_GPIO,
.max_leds = 1, // at least one LED on board
};
#if CONFIG_BLINK_LED_STRIP_BACKEND_RMT
led_strip_rmt_config_t rmt_config = {
.resolution_hz = 10 * 1000 * 1000, // 10MHz
.flags.with_dma = false,
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
#elif CONFIG_BLINK_LED_STRIP_BACKEND_SPI
led_strip_spi_config_t spi_config = {
.spi_bus = SPI2_HOST,
.flags.with_dma = true,
};
ESP_ERROR_CHECK(led_strip_new_spi_device(&strip_config, &spi_config, &led_strip));
#else
#error "unsupported LED strip backend"
#endif
/* Set all LED off to clear all pixels */
led_strip_clear(led_strip);
}

#elif CONFIG_BLINK_LED_GPIO

static void blink_led(void)
{
/* Set the GPIO level according to the state (LOW or HIGH)*/
gpio_set_level(BLINK_GPIO, s_led_state);
}

static void configure_led(void)
{
ESP_LOGI(TAG, "Example configured to blink GPIO LED!");
gpio_reset_pin(BLINK_GPIO);
/* Set the GPIO as a push/pull output */
gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
}

#else
#error "unsupported LED type"
#endif

void app_main(void)
{

/* Configure the peripheral according to the LED type */
configure_led();

while (1) {
ESP_LOGI(TAG, "Turning the LED %s!", s_led_state == true ? "ON" : "OFF");
blink_led();
/* Toggle the LED state */
s_led_state = !s_led_state;
vTaskDelay(CONFIG_BLINK_PERIOD / portTICK_PERIOD_MS);
}
}

从源文件中需要主要的几个点:

  • CONFIG_BLINK_GPIO:这个宏是在哪里定义的,定义的值是什么?
  • CONFIG_BLINK_LED_STRIPCONFIG_BLINK_LED_GPIO:这两个宏在哪里定义的,作用又是什么?
  • CONFIG_BLINK_LED_STRIP_BACKEND_RMTCONFIG_BLINK_LED_STRIP_BACKEND_SPI:这两个宏是在哪里定义的,作用是什么?
  • CONFIG_BLINK_PERIOD:这个宏在哪里定义,作用是什么?
  • portTICK_PERIOD_MS:这个宏在哪里定义?

blink工程目录下有这么一个文件:Kconfig.projbuild

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
menu "Example Configuration"

orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"

choice BLINK_LED
prompt "Blink LED type"
default BLINK_LED_GPIO if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C2
default BLINK_LED_STRIP
help
Select the LED type. A normal level controlled LED or an addressable LED strip.
The default selection is based on the Espressif DevKit boards.
You can change the default selection according to your board.

config BLINK_LED_GPIO
bool "GPIO"
config BLINK_LED_STRIP
bool "LED strip"
endchoice

choice BLINK_LED_STRIP_BACKEND
depends on BLINK_LED_STRIP
prompt "LED strip backend peripheral"
default BLINK_LED_STRIP_BACKEND_RMT if SOC_RMT_SUPPORTED
default BLINK_LED_STRIP_BACKEND_SPI
help
Select the backend peripheral to drive the LED strip.

config BLINK_LED_STRIP_BACKEND_RMT
depends on SOC_RMT_SUPPORTED
bool "RMT"
config BLINK_LED_STRIP_BACKEND_SPI
bool "SPI"
endchoice

config BLINK_GPIO
int "Blink GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 5 if IDF_TARGET_ESP32
default 18 if IDF_TARGET_ESP32S2
default 48 if IDF_TARGET_ESP32S3
default 8
help
GPIO number (IOxx) to blink on and off the LED.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink.

config BLINK_PERIOD
int "Blink period in ms"
range 10 3600000
default 1000
help
Define the blinking period in milliseconds.

endmenu

这个文件定义了CONFIG_BLINK_GPIO ,在配置菜单中提供一个范围供用户选择,不同的目标芯片给定了一个默认值。由于测试的开发板的芯片的ESP32-C3,所以给了默认值8。

这个文件定义了CONFIG_BLINK_LED_STRIPCONFIG_BLINK_LED_GPIO,在配置菜单中提供支持的LED类型让用户选择,可选项:LED GPIO(普通的LED) or LED STRIP(可寻址的LED)。由于测试的开发板的芯片的ESP32-C3,所以给了默认值:CONFIG_BLINK_LED_STRIP

若选择LED类型是LED STRIP,还要为其选择驱动类型,可选项:SPI 和 RMT,即CONFIG_BLINK_LED_STRIP_BACKEND_RMTCONFIG_BLINK_LED_STRIP_BACKEND_SPI,由于测试的开发板的芯片的ESP32-C3,所以给了默认值:SPI。

这个文件还定义了CONFIG_BLINK_PERIOD ,提供一个范围给用户选择,此处的默认值是1000ms,用于闪烁周期。

最后一个宏portTICK_PERIOD_MS ,这个是真的难找,还不能按图索骥。还是通过浏览器搜索找到了一遍文章才找到:细说基于IDF-IDE的ESP32 入门例程blink工程。按照分享的文章,如何找到这个字段的定义:

  • 搜索这个文件:portmacro.h,在这个文件中找到了定义

    1
    #define portTICK_PERIOD_MS          ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
  • 接下来找这个:configTICK_RATE_HZ,可以在这个文件中找到:FreeRTOSConfig.h

    1
    #define configTICK_RATE_HZ                           CONFIG_FREERTOS_HZ
  • 最后查找:CONFIG_FREERTOS_HZ 就容易了,直接在sdkconfig文件中找就好了

就这种搞法,想让初学者入门真的难度太大了,都不用去看代码逻辑,光找这些宏和变量的定义就可以劝退很多人了。

简化代码

ESP32-C3-DevKit-M-1开发板GPIO8外接LED_STRIP类型ws2812设备,所以代码可以这样简化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "led_strip.h"
#include "sdkconfig.h"

static const char *TAG = "example";

#define BLINK_GPIO 8
#define BLINK_PERIOD 1000

// 支持定义两种STRIP模式:SPI 和 RMT
#define BLINK_LED_STRIP_BACKEND_TYPE "SPI"

static uint8_t s_led_state = 0;
static led_strip_handle_t led_strip;

static void blink_led(void)
{
/* If the addressable LED is enabled */
if (s_led_state)
{
/* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */
led_strip_set_pixel(led_strip, 0, 16, 16, 16);
/* Refresh the strip to send data */
led_strip_refresh(led_strip);
}
else
{
/* Set all LED off to clear all pixels */
led_strip_clear(led_strip);
}
}

static void configure_led(void)
{
ESP_LOGI(TAG, "Example configured to blink addressable LED!");
/* LED strip initialization with the GPIO and pixels number*/
led_strip_config_t strip_config = {
.strip_gpio_num = BLINK_GPIO,
.max_leds = 1, // at least one LED on board
};

if (!strcmp(BLINK_LED_STRIP_BACKEND_TYPE, "RMT"))
{
led_strip_rmt_config_t rmt_config = {
.resolution_hz = 10 * 1000 * 1000, // 10MHz
.flags.with_dma = false,
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
}
else if (!strcmp(BLINK_LED_STRIP_BACKEND_TYPE, "SPI"))
{
led_strip_spi_config_t spi_config = {
.spi_bus = SPI2_HOST,
.flags.with_dma = true,
};
ESP_ERROR_CHECK(led_strip_new_spi_device(&strip_config, &spi_config, &led_strip));
}

/* Set all LED off to clear all pixels */
led_strip_clear(led_strip);
}

void app_main(void)
{

/* Configure the peripheral according to the LED type */
configure_led();

while (1)
{
ESP_LOGI(TAG, "Turning the LED %s!", s_led_state == true ? "ON" : "OFF");
blink_led();

/* Toggle the LED state */
s_led_state = !s_led_state;
vTaskDelay(BLINK_PERIOD / 10);
}
}

用户通过BLINK_LED_STRIP_BACKEND_TYPE 宏来定义控制类型。