mirror of
https://github.com/DuRuofu/ESP32-Guide.git
synced 2026-02-05 22:52:22 +08:00
update: 添加代码
This commit is contained in:
26
README.md
26
README.md
@@ -18,9 +18,10 @@
|
||||
|
||||
### 目录:
|
||||
|
||||

|
||||

|
||||
|
||||
本教程共八个章节,三个阶段:基础(1-3),实践(4),进阶(5-10)
|
||||
|
||||
本教程共八个章节,三个阶段:基础(1-3),实践(4),进阶(5-8)
|
||||
其中基础章节一定要确保自己掌握,实践和进阶部分推荐按照个人需求进行选学。
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -520,25 +521,16 @@ MCPWM 外设是一个多功能 PWM 生成器,集成多个子模块,在电力
|
||||
- 图形界面优化技巧
|
||||
|
||||
---
|
||||
## 九、其他实用内容
|
||||
|
||||
## 九、项目实战
|
||||
> 补充一些综合性性案例,与实用功能,为前八章做补充。
|
||||
|
||||
|
||||
|
||||
## 十、项目实战
|
||||
|
||||
> 目标:通过综合项目实践,整合所学知识,独立开发基于ESP32的完整应用,提升实战能力。
|
||||
|
||||
### 9.1 实战项目:智能家庭控制中心
|
||||
|
||||
- 多外设联动
|
||||
- 无线通信与协议实现
|
||||
- 图形界面集成
|
||||
|
||||
|
||||
|
||||
## 十、补充内存
|
||||
|
||||
> 补充一些零碎的遗漏内容,总结一些开发经验
|
||||
|
||||
|
||||
|
||||
|
||||
## 参考链接
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 854 KiB |
BIN
attachments/目录.png
Normal file
BIN
attachments/目录.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 527 KiB |
5
code/.gitignore
vendored
Normal file
5
code/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
**/build/
|
||||
**managed_components/
|
||||
**sdkconfig
|
||||
**sdkconfig.old
|
||||
.vscode
|
||||
6
code/01.start/hello_world/CMakeLists.txt
Normal file
6
code/01.start/hello_world/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(hello_world)
|
||||
53
code/01.start/hello_world/README.md
Normal file
53
code/01.start/hello_world/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | Linux |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | ----- |
|
||||
|
||||
# Hello World Example
|
||||
|
||||
Starts a FreeRTOS task to print "Hello World".
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
## How to use example
|
||||
|
||||
Follow detailed instructions provided specifically for this example.
|
||||
|
||||
Select the instructions depending on Espressif chip installed on your development board:
|
||||
|
||||
- [ESP32 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html)
|
||||
- [ESP32-S2 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
|
||||
|
||||
|
||||
## Example folder contents
|
||||
|
||||
The project **hello_world** contains one source file in C language [hello_world_main.c](main/hello_world_main.c). The file is located in folder [main](main).
|
||||
|
||||
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` files that provide set of directives and instructions describing the project's source files and targets (executable, library, or both).
|
||||
|
||||
Below is short explanation of remaining files in the project folder.
|
||||
|
||||
```
|
||||
├── CMakeLists.txt
|
||||
├── pytest_hello_world.py Python script used for automated testing
|
||||
├── main
|
||||
│ ├── CMakeLists.txt
|
||||
│ └── hello_world_main.c
|
||||
└── README.md This is the file you are currently reading
|
||||
```
|
||||
|
||||
For more information on structure and contents of ESP-IDF projects, please refer to Section [Build System](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html) of the ESP-IDF Programming Guide.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* Program upload failure
|
||||
|
||||
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
|
||||
* The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again.
|
||||
|
||||
## Technical support and feedback
|
||||
|
||||
Please use the following feedback channels:
|
||||
|
||||
* For technical queries, go to the [esp32.com](https://esp32.com/) forum
|
||||
* For a feature request or bug report, create a [GitHub issue](https://github.com/espressif/esp-idf/issues)
|
||||
|
||||
We will get back to you as soon as possible.
|
||||
2
code/01.start/hello_world/main/CMakeLists.txt
Normal file
2
code/01.start/hello_world/main/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "hello_world_main.c"
|
||||
INCLUDE_DIRS "")
|
||||
52
code/01.start/hello_world/main/hello_world_main.c
Normal file
52
code/01.start/hello_world/main/hello_world_main.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_chip_info.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
printf("Hello world!\n");
|
||||
|
||||
/* Print chip information */
|
||||
esp_chip_info_t chip_info;
|
||||
uint32_t flash_size;
|
||||
esp_chip_info(&chip_info);
|
||||
printf("This is %s chip with %d CPU core(s), %s%s%s%s, ",
|
||||
CONFIG_IDF_TARGET,
|
||||
chip_info.cores,
|
||||
(chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "",
|
||||
(chip_info.features & CHIP_FEATURE_BT) ? "BT" : "",
|
||||
(chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "",
|
||||
(chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");
|
||||
|
||||
unsigned major_rev = chip_info.revision / 100;
|
||||
unsigned minor_rev = chip_info.revision % 100;
|
||||
printf("silicon revision v%d.%d, ", major_rev, minor_rev);
|
||||
if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
|
||||
printf("Get flash size failed");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024),
|
||||
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
|
||||
|
||||
printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());
|
||||
|
||||
for (int i = 10; i >= 0; i--) {
|
||||
printf("Restarting in %d seconds...\n", i);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
printf("Restarting now.\n");
|
||||
fflush(stdout);
|
||||
esp_restart();
|
||||
}
|
||||
53
code/01.start/hello_world/pytest_hello_world.py
Normal file
53
code/01.start/hello_world/pytest_hello_world.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
from typing import Callable
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
from pytest_embedded_qemu.app import QemuApp
|
||||
from pytest_embedded_qemu.dut import QemuDut
|
||||
|
||||
|
||||
@pytest.mark.supported_targets
|
||||
@pytest.mark.preview_targets
|
||||
@pytest.mark.generic
|
||||
def test_hello_world(
|
||||
dut: IdfDut, log_minimum_free_heap_size: Callable[..., None]
|
||||
) -> None:
|
||||
dut.expect('Hello world!')
|
||||
log_minimum_free_heap_size()
|
||||
|
||||
|
||||
@pytest.mark.linux
|
||||
@pytest.mark.host_test
|
||||
def test_hello_world_linux(dut: IdfDut) -> None:
|
||||
dut.expect('Hello world!')
|
||||
|
||||
|
||||
def verify_elf_sha256_embedding(app: QemuApp, sha256_reported: str) -> None:
|
||||
sha256 = hashlib.sha256()
|
||||
with open(app.elf_file, 'rb') as f:
|
||||
sha256.update(f.read())
|
||||
sha256_expected = sha256.hexdigest()
|
||||
|
||||
logging.info(f'ELF file SHA256: {sha256_expected}')
|
||||
logging.info(f'ELF file SHA256 (reported by the app): {sha256_reported}')
|
||||
|
||||
# the app reports only the first several hex characters of the SHA256, check that they match
|
||||
if not sha256_expected.startswith(sha256_reported):
|
||||
raise ValueError('ELF file SHA256 mismatch')
|
||||
|
||||
|
||||
@pytest.mark.esp32 # we only support qemu on esp32 for now
|
||||
@pytest.mark.host_test
|
||||
@pytest.mark.qemu
|
||||
def test_hello_world_host(app: QemuApp, dut: QemuDut) -> None:
|
||||
sha256_reported = (
|
||||
dut.expect(r'ELF file SHA256:\s+([a-f0-9]+)').group(1).decode('utf-8')
|
||||
)
|
||||
verify_elf_sha256_embedding(app, sha256_reported)
|
||||
|
||||
dut.expect('Hello world!')
|
||||
0
code/01.start/hello_world/sdkconfig.ci
Normal file
0
code/01.start/hello_world/sdkconfig.ci
Normal file
8
code/02.idf_basic/01/sample_project/CMakeLists.txt
Normal file
8
code/02.idf_basic/01/sample_project/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(main)
|
||||
35
code/02.idf_basic/01/sample_project/README.md
Normal file
35
code/02.idf_basic/01/sample_project/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# _Sample project_
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This is the simplest buildable example. The example is used by command `idf.py create-project`
|
||||
that copies the project to user specified path and set it's name. For more information follow the [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project)
|
||||
|
||||
|
||||
|
||||
## How to use example
|
||||
We encourage the users to use the example as a template for the new projects.
|
||||
A recommended way is to follow the instructions on a [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project).
|
||||
|
||||
## Example folder contents
|
||||
|
||||
The project **sample_project** contains one source file in C language [main.c](main/main.c). The file is located in folder [main](main).
|
||||
|
||||
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt`
|
||||
files that provide set of directives and instructions describing the project's source files and targets
|
||||
(executable, library, or both).
|
||||
|
||||
Below is short explanation of remaining files in the project folder.
|
||||
|
||||
```
|
||||
├── CMakeLists.txt
|
||||
├── main
|
||||
│ ├── CMakeLists.txt
|
||||
│ └── main.c
|
||||
└── README.md This is the file you are currently reading
|
||||
```
|
||||
Additionally, the sample project contains Makefile and component.mk files, used for the legacy Make based build system.
|
||||
They are not used or needed when building with CMake and idf.py.
|
||||
2
code/02.idf_basic/01/sample_project/main/CMakeLists.txt
Normal file
2
code/02.idf_basic/01/sample_project/main/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
6
code/02.idf_basic/01/sample_project/main/main.c
Normal file
6
code/02.idf_basic/01/sample_project/main/main.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
|
||||
}
|
||||
6
code/02.idf_basic/02/blink/CMakeLists.txt
Normal file
6
code/02.idf_basic/02/blink/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(blink)
|
||||
2
code/02.idf_basic/02/blink/main/CMakeLists.txt
Normal file
2
code/02.idf_basic/02/blink/main/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "blink_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
49
code/02.idf_basic/02/blink/main/Kconfig.projbuild
Normal file
49
code/02.idf_basic/02/blink/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,49 @@
|
||||
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
|
||||
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 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
|
||||
104
code/02.idf_basic/02/blink/main/blink_example_main.c
Normal file
104
code/02.idf_basic/02/blink/main/blink_example_main.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/* Blink 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 <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.
|
||||
*/
|
||||
#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);
|
||||
}
|
||||
}
|
||||
2
code/02.idf_basic/02/blink/main/idf_component.yml
Normal file
2
code/02.idf_basic/02/blink/main/idf_component.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
dependencies:
|
||||
espressif/led_strip: "^2.4.1"
|
||||
2
code/02.idf_basic/02/blink/sdkconfig.defaults
Normal file
2
code/02.idf_basic/02/blink/sdkconfig.defaults
Normal file
@@ -0,0 +1,2 @@
|
||||
CONFIG_BLINK_LED_GPIO=y
|
||||
CONFIG_BLINK_GPIO=8
|
||||
6
code/02.idf_basic/02/blink_menuconfig/CMakeLists.txt
Normal file
6
code/02.idf_basic/02/blink_menuconfig/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(blink)
|
||||
69
code/02.idf_basic/02/blink_menuconfig/README.md
Normal file
69
code/02.idf_basic/02/blink_menuconfig/README.md
Normal file
@@ -0,0 +1,69 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Blink Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to blink a LED by using the GPIO driver or using the [led_strip](https://components.espressif.com/component/espressif/led_strip) library if the LED is addressable e.g. [WS2812](https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf). The `led_strip` library is installed via [component manager](main/idf_component.yml).
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`.
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board with normal LED or addressable LED on-board (e.g., ESP32-S3-DevKitC, ESP32-C6-DevKitC etc.)
|
||||
* A USB cable for Power supply and programming
|
||||
|
||||
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
|
||||
|
||||
### Configure the Project
|
||||
|
||||
Open the project configuration menu (`idf.py menuconfig`).
|
||||
|
||||
In the `Example Configuration` menu:
|
||||
|
||||
* Select the LED type in the `Blink LED type` option.
|
||||
* Use `GPIO` for regular LED
|
||||
* Use `LED strip` for addressable LED
|
||||
* If the LED type is `LED strip`, select the backend peripheral
|
||||
* `RMT` is only available for ESP targets with RMT peripheral supported
|
||||
* `SPI` is available for all ESP targets
|
||||
* Set the GPIO number used for the signal in the `Blink GPIO number` option.
|
||||
* Set the blinking period in the `Blink period in ms` option.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
As you run the example, you will see the LED blinking, according to the previously defined period. For the addressable LED, you can also change the LED color by setting the `led_strip_set_pixel(led_strip, 0, 16, 16, 16);` (LED Strip, Pixel Number, Red, Green, Blue) with values from 0 to 255 in the [source file](main/blink_example_main.c).
|
||||
|
||||
```text
|
||||
I (315) example: Example configured to blink addressable LED!
|
||||
I (325) example: Turning the LED OFF!
|
||||
I (1325) example: Turning the LED ON!
|
||||
I (2325) example: Turning the LED OFF!
|
||||
I (3325) example: Turning the LED ON!
|
||||
I (4325) example: Turning the LED OFF!
|
||||
I (5325) example: Turning the LED ON!
|
||||
I (6325) example: Turning the LED OFF!
|
||||
I (7325) example: Turning the LED ON!
|
||||
I (8325) example: Turning the LED OFF!
|
||||
```
|
||||
|
||||
Note: The color order could be different according to the LED model.
|
||||
|
||||
The pixel number indicates the pixel position in the LED strip. For a single LED, use 0.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* If the LED isn't blinking, check the GPIO or the LED type selection in the `Example Configuration` menu.
|
||||
|
||||
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
||||
20
code/02.idf_basic/02/blink_menuconfig/dependencies.lock
Normal file
20
code/02.idf_basic/02/blink_menuconfig/dependencies.lock
Normal file
@@ -0,0 +1,20 @@
|
||||
dependencies:
|
||||
espressif/led_strip:
|
||||
component_hash: 28c6509a727ef74925b372ed404772aeedf11cce10b78c3f69b3c66799095e2d
|
||||
dependencies:
|
||||
- name: idf
|
||||
require: private
|
||||
version: '>=4.4'
|
||||
source:
|
||||
registry_url: https://components.espressif.com/
|
||||
type: service
|
||||
version: 2.5.5
|
||||
idf:
|
||||
source:
|
||||
type: idf
|
||||
version: 5.3.2
|
||||
direct_dependencies:
|
||||
- espressif/led_strip
|
||||
manifest_hash: a9af7824fb34850fbe175d5384052634b3c00880abb2d3a7937e666d07603998
|
||||
target: esp32
|
||||
version: 2.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "blink_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
49
code/02.idf_basic/02/blink_menuconfig/main/Kconfig.projbuild
Normal file
49
code/02.idf_basic/02/blink_menuconfig/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,49 @@
|
||||
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
|
||||
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 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
|
||||
104
code/02.idf_basic/02/blink_menuconfig/main/blink_example_main.c
Normal file
104
code/02.idf_basic/02/blink_menuconfig/main/blink_example_main.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/* Blink 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 <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.
|
||||
*/
|
||||
#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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
dependencies:
|
||||
espressif/led_strip: "^2.4.1"
|
||||
16
code/02.idf_basic/02/blink_menuconfig/pytest_blink.py
Normal file
16
code/02.idf_basic/02/blink_menuconfig/pytest_blink.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
|
||||
@pytest.mark.supported_targets
|
||||
@pytest.mark.generic
|
||||
def test_blink(dut: IdfDut) -> None:
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut.app.binary_path, 'blink.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
logging.info('blink_bin_size : {}KB'.format(bin_size // 1024))
|
||||
2
code/02.idf_basic/02/blink_menuconfig/sdkconfig.defaults
Normal file
2
code/02.idf_basic/02/blink_menuconfig/sdkconfig.defaults
Normal file
@@ -0,0 +1,2 @@
|
||||
CONFIG_BLINK_LED_GPIO=y
|
||||
CONFIG_BLINK_GPIO=8
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_BLINK_GPIO=5
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_BLINK_LED_STRIP=y
|
||||
@@ -0,0 +1,2 @@
|
||||
CONFIG_BLINK_GPIO=6
|
||||
CONFIG_BLINK_LED_STRIP=y
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_BLINK_LED_STRIP=y
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_BLINK_LED_STRIP=y
|
||||
@@ -0,0 +1,2 @@
|
||||
CONFIG_BLINK_LED_STRIP=y
|
||||
CONFIG_BLINK_GPIO=18
|
||||
@@ -0,0 +1,2 @@
|
||||
CONFIG_BLINK_LED_STRIP=y
|
||||
CONFIG_BLINK_GPIO=48
|
||||
BIN
docs/00.常见问题及解决方案/attachments/Pasted image 20250210094506.png
Normal file
BIN
docs/00.常见问题及解决方案/attachments/Pasted image 20250210094506.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
BIN
docs/00.常见问题及解决方案/attachments/Pasted image 20250210094818.png
Normal file
BIN
docs/00.常见问题及解决方案/attachments/Pasted image 20250210094818.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 367 KiB |
@@ -1,4 +1,8 @@
|
||||
# 常见问题与解决
|
||||
|
||||
## 索引
|
||||
|
||||
[[toc]]
|
||||
## 1. 头文件无法跳转,没有代码提示
|
||||
|
||||
**问题**:
|
||||
@@ -43,7 +47,7 @@
|
||||
|
||||

|
||||
|
||||
## 2.开发板在Windows下可以显示端口,但在Linux下找不到
|
||||
## 2. 开发板在Windows下可以显示端口,但在Linux下找不到
|
||||
|
||||
**问题**:
|
||||
|
||||
@@ -56,7 +60,7 @@
|
||||
安装对应型号的串口驱动程序,上网搜索安装教程一般都能找到。
|
||||
|
||||
|
||||
## 3.Linux下烧录代码报错(没有串口权限)
|
||||
## 3. Linux下烧录代码报错(没有串口权限)
|
||||
|
||||
**问题**:
|
||||
|
||||
@@ -78,4 +82,53 @@ sudo chmod a+rw /dev/ttyUSB0
|
||||
|
||||
但是注意`sudo chmod a+rw /dev/ttyUSB0` 的权限更改是暂时的,只会在当前设备被使用的会话期间生效。一旦系统重启或者设备断开并重新连接,设备节点(例如 /dev/ttyUSB0)可能会重新被创建,且权限会被重置为默认状态。
|
||||
|
||||
可以使用下面的命令,永久为用户添加串口权限:`sudo usermod -aG dialout username`,设置后重启方能生效。
|
||||
可以使用下面的命令,永久为用户添加串口权限:`sudo usermod -aG dialout username`,设置后重启方能生效。
|
||||
|
||||
## 4. 开发板烧录代码时出现MD5校验错误
|
||||
|
||||

|
||||
|
||||
解决办法如下:
|
||||
|
||||

|
||||
|
||||
需要在IDF环境下使用命令:]
|
||||
|
||||
```bash
|
||||
esptool.py --port PORT write_flash_status --non-volatile 0
|
||||
```
|
||||
|
||||
其中的PORT需要修改为实际连接的开发板端口。
|
||||
|
||||
|
||||
## 5. 烧录报错:无法验证闪存芯片连接(未收到串行数据。)
|
||||
|
||||
报错信息如下:
|
||||
|
||||
```bash
|
||||
Connecting....
|
||||
Chip is ESP32-D0WD-V3 (revision v3.1)
|
||||
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
|
||||
WARNING: Detected crystal freq 15.32MHz is quite different to normalized freq 26MHz. Unsupported crystal in use?
|
||||
Crystal is 26MHz
|
||||
MAC: fc:e8:c0:7c:b4:24
|
||||
Uploading stub...
|
||||
Running stub...
|
||||
Stub running...
|
||||
Changing baud rate to 460800
|
||||
Changed.
|
||||
|
||||
A fatal error occurred: Unable to verify flash chip connection (No serial data received.).
|
||||
CMake Error at run_serial_tool.cmake:66 (message):
|
||||
|
||||
/home/duruofu/.espressif/python_env/idf5.3_py3.10_env/bin/python;;/home/duruofu/esp32/esp-idf-v5.3/components/esptool_py/esptool/esptool.py;--chip;esp32
|
||||
failed.
|
||||
|
||||
|
||||
|
||||
FAILED: CMakeFiles/flash /home/duruofu/project/Mock-IoT-Device-ESP32/build/CMakeFiles/flash
|
||||
```
|
||||
|
||||
解决办法:
|
||||
|
||||
重新烧录引导程序:长按BOOT键,然后按复位键,再次烧录代码,即可成功烧录。
|
||||
File diff suppressed because it is too large
Load Diff
BIN
docs/05.FreeRTOS进阶/5.1-队列/attachments/20250110165359.png
Normal file
BIN
docs/05.FreeRTOS进阶/5.1-队列/attachments/20250110165359.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 190 KiB |
@@ -0,0 +1,142 @@
|
||||
# 信号量
|
||||
|
||||
FreeRTOS 提供了信号量和互斥锁,用于任务间的同步和资源共享管理。信号量更偏向于任务同步,而互斥锁用于保护共享资源。
|
||||
## 1. 二进制信号量
|
||||
|
||||
二进制信号量是最基本的信号量,仅有两个状态:可用和不可用(或 1 和 0)。
|
||||
通常用于任务之间或中断与任务之间的同步,当一个事件发生时,由中断或任务释放信号量,等待信号量的任务就会被唤醒。
|
||||
二进制信号量适用于简单的事件通知场景,比如通知某个任务处理外部输入或完成某项任务。
|
||||
|
||||
### 1.1 API说明:
|
||||
|
||||
### 1.2 示例代码:
|
||||
|
||||
```c
|
||||
// 二进制信号量
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
// 二进制信号量
|
||||
SemaphoreHandle_t semaphoreHandle;
|
||||
|
||||
// 公共变量
|
||||
int shareVariable = 0;
|
||||
|
||||
void task1(void *pvParameters)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
// 获取信号量,信号量变为0
|
||||
xSemaphoreTake(semaphoreHandle, portMAX_DELAY);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
shareVariable++;
|
||||
ESP_LOGI(TAG, "task1 shareVariable:%d", shareVariable);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
// 释放信号量,信号量变为1
|
||||
xSemaphoreGive(semaphoreHandle);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
void task2(void *pvParameters)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
// 获取信号量
|
||||
xSemaphoreTake(semaphoreHandle, portMAX_DELAY);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
shareVariable++;
|
||||
ESP_LOGI(TAG, "task2 shareVariable:%d", shareVariable);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
// 释放信号量,信号量变为1
|
||||
xSemaphoreGive(semaphoreHandle);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
semaphoreHandle = xSemaphoreCreateBinary();
|
||||
xSemaphoreGive(semaphoreHandle);
|
||||
|
||||
// 创建任务
|
||||
xTaskCreate(task1, "task1", 1024 * 2, NULL, 10, NULL);
|
||||
xTaskCreate(task2, "task2", 1024 * 2, NULL, 10, NULL);
|
||||
}
|
||||
```
|
||||
|
||||
## 2. 计数信号量
|
||||
|
||||
### 2.1 示例代码:
|
||||
|
||||
```c
|
||||
// 计数型信号量(占座)
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
// 信号量
|
||||
SemaphoreHandle_t semaphoreHandle;
|
||||
|
||||
|
||||
// 占座任务
|
||||
void task1(void *pvParameters)
|
||||
{
|
||||
// 定义空位
|
||||
int seat = 0;
|
||||
for (;;)
|
||||
{
|
||||
// 获取信号量
|
||||
seat = uxSemaphoreGetCount(semaphoreHandle);
|
||||
// 输出空位
|
||||
ESP_LOGI(TAG, "当前空位:%d", seat);
|
||||
|
||||
// 获取信号量(占座)
|
||||
if (xSemaphoreTake(semaphoreHandle, portMAX_DELAY) == pdPASS)
|
||||
{
|
||||
ESP_LOGI(TAG, "占座成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "占座失败");
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
// 离开座位任务
|
||||
void task2(void *pvParameters)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(6000));
|
||||
// 释放信号量
|
||||
xSemaphoreGive(semaphoreHandle);
|
||||
ESP_LOGI(TAG, "释放座位");
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
semaphoreHandle = xSemaphoreCreateCounting(5, 5);
|
||||
|
||||
// 创建占座任务
|
||||
xTaskCreate(task1, "task1", 1024 * 2, NULL, 10, NULL);
|
||||
// 创建离开座位任务
|
||||
xTaskCreate(task2, "task2", 1024 * 2, NULL, 10, NULL);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
# 互斥锁
|
||||
|
||||
## 1. 互斥量
|
||||
|
||||
互斥量(互斥锁Mutex):互斥锁和二进制信号量极为相似,但 有一些细微差异:互斥锁具有优先级继承机制, 但二进制信号量没有。
|
||||
### 1.1 示例代码:
|
||||
|
||||
```c
|
||||
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
SemaphoreHandle_t mutexHandle;
|
||||
|
||||
void task1(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "task1启动!");
|
||||
while (1)
|
||||
{
|
||||
if (xSemaphoreTake(mutexHandle, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
ESP_LOGI(TAG, "task1获取到互斥量!");
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
ESP_LOGI(TAG, "task1执行中...%d", i);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
xSemaphoreGive(mutexHandle);
|
||||
ESP_LOGI(TAG, "task1释放互斥量!");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "task1获取互斥量失败!");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void task2(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "task2启动!");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void task3(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "task3启动!");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
while (1)
|
||||
{
|
||||
if (xSemaphoreTake(mutexHandle, 1000) == pdPASS)
|
||||
{
|
||||
ESP_LOGI(TAG, "task3获取到互斥量!");
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
ESP_LOGI(TAG, "task3执行中...%d",i);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
xSemaphoreGive(mutexHandle);
|
||||
ESP_LOGI(TAG, "task3释放互斥量!");
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "task3未获取到互斥量!");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
mutexHandle = xSemaphoreCreateMutex();
|
||||
// mutexHandle = xSemaphoreCreateBinary();
|
||||
xTaskCreate(task1, "task1", 1024 * 2, NULL, 1, NULL);
|
||||
xTaskCreate(task2, "task2", 1024 * 2, NULL, 2, NULL);
|
||||
xTaskCreate(task3, "task3", 1024 * 2, NULL, 3, NULL);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 2. 递归互斥量
|
||||
|
||||
非递归互斥锁只能被一个任务 获取一次,如果同一个任务想再次获取则会失败, 因为当任务第一次释放互斥锁时,互斥锁就一直处于释放状态。与非递归互斥锁相反,递归互斥锁可以被同一个任务获取很多次, 获取多少次就需要释放多少次, 此时才会返回递归互斥锁。
|
||||
### 2.1 示例代码:
|
||||
|
||||
```c
|
||||
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
SemaphoreHandle_t mutexHandle;
|
||||
|
||||
void task1(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "-------------------------------");
|
||||
ESP_LOGI(TAG, "task1启动!");
|
||||
while (1)
|
||||
{
|
||||
xSemaphoreTakeRecursive(mutexHandle, portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "task1获取到互斥量-使用资源A");
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
ESP_LOGI(TAG, "task1执行中...%d -使用资源A", i);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
xSemaphoreTakeRecursive(mutexHandle, portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "task1获取到互斥量-使用资源B");
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
ESP_LOGI(TAG, "task1执行中...%d -使用资源B", i);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
xSemaphoreGiveRecursive(mutexHandle);
|
||||
ESP_LOGI(TAG, "task1释放互斥量-使用资源B");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
xSemaphoreGiveRecursive(mutexHandle);
|
||||
ESP_LOGI(TAG, "task1释放互斥量-使用资源A");
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void task2(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "task2启动!");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
while (1)
|
||||
{
|
||||
// 获取递归互斥锁
|
||||
if (xSemaphoreTakeRecursive(mutexHandle, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
ESP_LOGI(TAG, "task2获取到互斥量");
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
ESP_LOGI(TAG, "task2执行中...%d", i);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
xSemaphoreGiveRecursive(mutexHandle);
|
||||
ESP_LOGI(TAG, "task2释放互斥量");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "task2获取互斥量失败");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// 创建递归互斥量
|
||||
mutexHandle = xSemaphoreCreateRecursiveMutex();
|
||||
|
||||
xTaskCreate(task1, "task1", 1024 * 2, NULL, 1, NULL);
|
||||
xTaskCreate(task2, "task2", 1024 * 2, NULL, 2, NULL);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
|
||||
# 事件组
|
||||
|
||||
事件组是一种实现任务间通信和同步的机制,主要用于协调多个任务或中断之间的执行。
|
||||
|
||||
**事件位(事件标志)**:
|
||||
事件位用于指示事件 是否发生。事件位通常称为事件标志。例如, 应用程序可以:
|
||||
定义一个位(或标志), 设置为 1 时表示“已收到消息并准备好处理”, 设置为 0 时表示“没有消息等待处理”。
|
||||
定义一个位(或标志), 设置为 1 时表示“应用程序已将准备发送到网络的消息排队”, 设置为 0 时表示 “没有消息需要排队准备发送到网络”。
|
||||
定义一个位(或标志), 设置为 1 时表示“需要向网络发送心跳消息”, 设置为 0 时表示“不需要向网络发送心跳消息”。
|
||||
|
||||
**事件组**:
|
||||
事件组就是一组事件位。事件组中的事件位 通过位编号来引用。同样,以上面列出的三个例子为例:
|
||||
事件标志组位编号 为 0 表示“已收到消息并准备好处理”。
|
||||
事件标志组位编号 为 1 表示“应用程序已将准备发送到网络的消息排队”。
|
||||
事件标志组位编号 为 2 表示“需要向网络发送心跳消息”。
|
||||
|
||||
**事件组和事件位数据类型**:
|
||||
|
||||
事件组由 EventGroupHandle_t 类型的变量引用。
|
||||
|
||||
如果 configUSE_16_BIT_TICKS 设为 1,则事件组中存储的位(或标志)数为 8; 如果 configUSE_16_BIT_TICKS 设为 0,则为 24。 configUSE_16_BIT_TICKS 的值取决于 任务内部实现中用于线程本地存储的数据类型。
|
||||
|
||||
> (ESP-IDF中默认为24位)
|
||||
|
||||
事件组中的所有事件位都 存储在 EventBits_t 类型的单个无符号整数变量中。事件位 0 存储在位 0 中, 事件位 1 存储在位1 中,依此类推。
|
||||
|
||||
下图表示一个 24 位事件组, 使用 3 个位来保存前面描述的 3 个示例事件。在图片中,仅设置了 事件位 2。(包含 24 个事件位的事件组,其中只有三个在使用中)
|
||||
|
||||

|
||||
|
||||
|
||||
**事件组 RTOS API 函数**
|
||||
|
||||
提供的事件组 API 函数 允许任务在事件组中设置一个或多个事件位, 清除事件组中的一个或多个事件位, 并挂起(进入阻塞状态, 因此任务不会消耗任何处理时间)以等待 事件组中一个或多个事件位固定下来。
|
||||
|
||||
事件组也可用于同步任务, 创建通常称为“集合”的任务。任务同步点是 应用程序代码中的一个位置,在该位置任务将在 阻塞状态(不消耗任何 CPU 时间)下等待,直到参与同步的所有其他任务 也到达其同步点。
|
||||
|
||||
|
||||
### 1. API说明:
|
||||
|
||||
事件组操作主要涉及以下几个 API:
|
||||
|
||||
| 函数名 | 功能 | 备注 |
|
||||
| -------------------- | ---------------- | ------------------------- |
|
||||
| xEventGroupCreate | 创建一个事件组 | 返回一个事件组句柄,供后续操作使用 |
|
||||
| xEventGroupSetBits | 设置一个或多个事件标志 | 用于通知其他任务某些事件已发生 |
|
||||
| xEventGroupClearBits | 清除一个或多个事件标志 | 用于复位事件标志,防止重复触发 |
|
||||
| xEventGroupWaitBits | 等待一个或多个事件标志的设置状态 | 任务可以选择阻塞,直到指定事件发生 |
|
||||
| xEventGroupGetBits | 查询当前事件组的状态 | 返回事件组中所有事件标志的当前状态 |
|
||||
| xEventGroupSync | 同步多个任务 | 用于实现多个任务在同一时刻达到某一同步点后继续执行 |
|
||||
|
||||
#### xEventGroupCreate:创建事件组
|
||||
|
||||
**原型:**
|
||||
|
||||
```c
|
||||
EventGroupHandle_t xEventGroupCreate(void);
|
||||
```
|
||||
|
||||
**返回值**:成功时返回事件组句柄;失败时返回 NULL。
|
||||
|
||||
**示例:**
|
||||
|
||||
```c
|
||||
EventGroupHandle_t xEventGroup;
|
||||
xEventGroup = xEventGroupCreate();
|
||||
if (xEventGroup == NULL) {
|
||||
// 创建事件组失败,处理错误
|
||||
}
|
||||
```
|
||||
|
||||
#### xEventGroupSetBits:设置事件标志
|
||||
|
||||
**原型:**
|
||||
```c
|
||||
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet);
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
- xEventGroup:事件组句柄。
|
||||
- uxBitsToSet:需要设置的事件标志位(按位表示,例如 0x01 设置第 0 位)。
|
||||
**返回值**:返回事件组在调用前的状态。
|
||||
|
||||
#### xEventGroupWaitBits:等待事件标志
|
||||
|
||||
读取 RTOS 事件组中的位,选择性地进入“阻塞”状态(已设置 超时值)以等待设置单个位或一组位。无法从中断调用此函数。
|
||||
|
||||
**原型:**
|
||||
|
||||
```c
|
||||
EventBits_t xEventGroupWaitBits(
|
||||
EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
const BaseType_t xClearOnExit,
|
||||
const BaseType_t xWaitForAllBits,
|
||||
TickType_t xTicksToWait
|
||||
);
|
||||
```
|
||||
|
||||
**参数说明:**
|
||||
- xEventGroup:事件组句柄。
|
||||
- uxBitsToWaitFor:需要等待的事件标志位(按位表示)。
|
||||
- xClearOnExit:是否在退出等待时清除指定的事件标志。
|
||||
- xWaitForAllBits:是否等待所有指定事件标志都被设置,还是任意一个即可。
|
||||
- xTicksToWait:等待的最大时间(以 Tick 为单位,portMAX_DELAY 表示无限等待)。
|
||||
|
||||
**返回值**:返回当前满足条件的事件标志状态。
|
||||
|
||||
**示例**:
|
||||
|
||||
```c
|
||||
EventBits_t uxBits;
|
||||
uxBits = xEventGroupWaitBits(
|
||||
xEventGroup, // 事件组句柄
|
||||
0x03, // 等待第 0 位和第 1 位
|
||||
pdTRUE, // 退出等待时清除事件标志
|
||||
pdFALSE, // 等待任意一个事件
|
||||
portMAX_DELAY // 无限等待
|
||||
);
|
||||
|
||||
if (uxBits & 0x01) {
|
||||
// 第 0 位事件发生
|
||||
}
|
||||
|
||||
if (uxBits & 0x02) {
|
||||
// 第 1 位事件发生
|
||||
}
|
||||
```
|
||||
|
||||
#### xEventGroupSync:同步任务
|
||||
|
||||
以原子方式设置 RTOS 事件组中的位(标志),然后等待在同一事件组中设置位的组合。此功能通常用于同步多个任务(通常称为任务集合),其中每个任务必须等待其他任务到达同步点后才能继续。
|
||||
|
||||
**原型**:
|
||||
```c
|
||||
EventBits_t xEventGroupSync(
|
||||
EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
TickType_t xTicksToWait
|
||||
);
|
||||
```
|
||||
**参数说明**:
|
||||
- xEventGroup:事件组句柄。
|
||||
- uxBitsToSet:当前任务设置的事件标志位。
|
||||
- uxBitsToWaitFor:需要等待的其他任务设置的事件标志位。
|
||||
- xTicksToWait:最大等待时间。
|
||||
**返回值**:
|
||||
返回事件组的当前状态。
|
||||
|
||||
**示例**:
|
||||
```c
|
||||
xEventGroupSync(
|
||||
xEventGroup, // 事件组句柄
|
||||
0x01, // 当前任务设置第 0 位
|
||||
0x03, // 等待第 0 位和第 1 位都被设置
|
||||
portMAX_DELAY // 无限等待
|
||||
);
|
||||
```
|
||||
|
||||
### 2 示例程序:
|
||||
|
||||
#### 1. 事件组等待
|
||||
|
||||
task1等待task2设置事件位,然后执行程序:
|
||||
|
||||
```c
|
||||
// 事件组
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
EventGroupHandle_t xCreatedEventGroup;
|
||||
|
||||
#define BIT_0 (1 << 0)
|
||||
#define BIT_4 (1 << 4)
|
||||
|
||||
void task1(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "-------------------------------");
|
||||
ESP_LOGI(TAG, "task1启动!");
|
||||
|
||||
while (1)
|
||||
{
|
||||
EventBits_t uxBits;
|
||||
uxBits = xEventGroupWaitBits(
|
||||
xCreatedEventGroup, /* The event group being tested. */
|
||||
BIT_0 | BIT_4, /* The bits within the event group to wait for. */
|
||||
pdTRUE, /* BIT_0 & BIT_4 should be cleared before returning. */
|
||||
pdFALSE, /* Don't wait for both bits, either bit will do. */
|
||||
portMAX_DELAY); /* Wait a maximum of 100ms for either bit to be set. */
|
||||
|
||||
if ((uxBits & (BIT_0 | BIT_4)) == (BIT_0 | BIT_4))
|
||||
{
|
||||
ESP_LOGI(TAG, "BIT_0 和 BIT_4 都被设置了");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "BIT_0 和 BIT_4 有一个被设置了");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void task2(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "task2启动!");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
while (1)
|
||||
{
|
||||
xEventGroupSetBits(xCreatedEventGroup, BIT_0);
|
||||
ESP_LOGI(TAG, "BIT_0 被设置");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
xEventGroupSetBits(xCreatedEventGroup, BIT_4);
|
||||
ESP_LOGI(TAG, "BIT_4 被设置");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
|
||||
// 创建事件组
|
||||
xCreatedEventGroup = xEventGroupCreate();
|
||||
|
||||
if (xCreatedEventGroup == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "创建事件组失败");
|
||||
}
|
||||
else
|
||||
{
|
||||
xTaskCreate(task1, "task1", 1024 * 2, NULL, 1, NULL);
|
||||
xTaskCreate(task2, "task2", 1024 * 2, NULL, 1, NULL);
|
||||
}
|
||||
}
|
||||
```
|
||||
#### 2. 事件组同步
|
||||
|
||||
每个任务在启动后,等待一段时间,然后调用xEventGroupSync函数进行事件同步,等待所有任务的事件位都被设置。
|
||||
```c
|
||||
// 事件组
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
/* Bits used by the three tasks. */
|
||||
#define TASK_0_BIT (1 << 0)
|
||||
#define TASK_1_BIT (1 << 1)
|
||||
#define TASK_2_BIT (1 << 2)
|
||||
|
||||
#define ALL_SYNC_BITS (TASK_0_BIT | TASK_1_BIT | TASK_2_BIT)
|
||||
|
||||
static const char *TAG = "main";
|
||||
EventGroupHandle_t xEventBits;
|
||||
|
||||
|
||||
void task0(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "-------------------------------");
|
||||
ESP_LOGI(TAG, "task0启动!");
|
||||
|
||||
while (1)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
ESP_LOGI(TAG, "task0: 任务同步开始");
|
||||
// 事件同步
|
||||
xEventGroupSync(
|
||||
xEventBits, /* The event group being tested. */
|
||||
TASK_0_BIT, /* The bits within the event group to wait for. */
|
||||
ALL_SYNC_BITS, /* The bits within the event group to wait for. */
|
||||
portMAX_DELAY); /* Wait a maximum of 100ms for either bit to be set. */
|
||||
|
||||
ESP_LOGI(TAG, "task0: 任务同步完成");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
}
|
||||
}
|
||||
void task1(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "-------------------------------");
|
||||
ESP_LOGI(TAG, "task1启动!");
|
||||
|
||||
while (1)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(4000));
|
||||
ESP_LOGI(TAG, "task1: 任务同步开始");
|
||||
|
||||
// 事件同步
|
||||
xEventGroupSync(
|
||||
xEventBits, /* The event group being tested. */
|
||||
TASK_1_BIT, /* The bits within the event group to wait for. */
|
||||
ALL_SYNC_BITS, /* The bits within the event group to wait for. */
|
||||
portMAX_DELAY); /* Wait a maximum of 100ms for either bit to be set. */
|
||||
|
||||
ESP_LOGI(TAG, "task1: 任务同步完成");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
}
|
||||
}
|
||||
|
||||
void task2(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "-------------------------------");
|
||||
ESP_LOGI(TAG, "task2启动!");
|
||||
|
||||
while (1)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
ESP_LOGI(TAG, "task2: 任务同步开始");
|
||||
// 事件同步
|
||||
xEventGroupSync(
|
||||
xEventBits, /* The event group being tested. */
|
||||
TASK_2_BIT, /* The bits within the event group to wait for. */
|
||||
ALL_SYNC_BITS, /* The bits within the event group to wait for. */
|
||||
portMAX_DELAY); /* Wait a maximum of 100ms for either bit to be set. */
|
||||
|
||||
ESP_LOGI(TAG, "task2: 任务同步完成");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// 创建事件组
|
||||
xEventBits = xEventGroupCreate();
|
||||
|
||||
if (xEventBits == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "创建事件组失败");
|
||||
}
|
||||
else
|
||||
{
|
||||
xTaskCreate(task0, "task0", 1024 * 2, NULL, 1, NULL);
|
||||
xTaskCreate(task1, "task1", 1024 * 2, NULL, 1, NULL);
|
||||
xTaskCreate(task2, "task2", 1024 * 2, NULL, 1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
BIN
docs/05.FreeRTOS进阶/5.4-事件组/attachments/20250111145800.png
Normal file
BIN
docs/05.FreeRTOS进阶/5.4-事件组/attachments/20250111145800.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
@@ -0,0 +1,258 @@
|
||||
# 任务通知
|
||||
|
||||
任务通知(Task Notifications)是一种轻量级的任务间通信和同步机制,它比队列或事件组更加高效,因为它不需要动态分配内存。每个任务都内置了一个任务通知值,其他任务或中断服务例程(ISR)可以用它来通知该任务事件的发生。
|
||||
|
||||
**特点**:
|
||||
|
||||
- 每个任务都有一个任务通知值(32 位整数),可以用于存储信息。
|
||||
- 任务通知值默认初始化为 0。
|
||||
- 一个任务可以通过 通知函数 来操作另一个任务的通知值。
|
||||
- 可以将任务通知值用作二值信号量、计数信号量或简单的 32 位变量。
|
||||
- 当一个任务收到通知时,它可以选择阻塞(等待通知)或处理该通知。
|
||||
|
||||
## 1. API说明:
|
||||
|
||||
任务通知主要涉及以下几个 API:
|
||||
|
||||
| 函数名 | 功能 |
|
||||
| ------------------------------- | --------------------------------------------- |
|
||||
| xTaskNotify | 向指定任务发送通知,通知值可以被覆盖 |
|
||||
| xTaskNotifyGive | 简化版通知函数,用于发送信号量通知 |
|
||||
| xTaskNotifyWait | 等待通知值更新,并选择是否清除通知值 |
|
||||
| ulTaskNotifyTake | 等待任务通知并自动减少通知值(通常用于计数信号量) |
|
||||
| xTaskNotifyStateClear | 清除任务的通知状态 |
|
||||
### xTaskNotify
|
||||
|
||||
**功能**: 向指定任务发送通知,并修改该任务的通知值。
|
||||
|
||||
**原型**:
|
||||
|
||||
```c
|
||||
BaseType_t xTaskNotify(
|
||||
TaskHandle_t xTaskToNotify,
|
||||
uint32_t ulValue,
|
||||
eNotifyAction eAction
|
||||
);
|
||||
```
|
||||
**参数**:
|
||||
- xTaskToNotify:接收通知的任务句柄。
|
||||
- ulValue:要发送的通知值。
|
||||
- eAction:通知值的操作类型,可以是以下值:
|
||||
- eSetBits:设置通知值的指定位。
|
||||
- eIncrement:通知值递增。
|
||||
- eSetValueWithOverwrite:覆盖通知值。
|
||||
- eSetValueWithoutOverwrite:如果通知值未处理,则不覆盖当前值。
|
||||
**返回值**:
|
||||
- pdPASS:操作成功。
|
||||
- pdFAIL:操作失败(通常在 eSetValueWithoutOverwrite 时发生)。
|
||||
|
||||
**示例**:
|
||||
|
||||
```c
|
||||
xTaskNotify(xTaskHandle, 0x01, eSetBits); // 设置任务通知值的第 0 位
|
||||
```
|
||||
### xTaskNotifyGive
|
||||
|
||||
**功能**: 向任务发送一个 "信号量风格" 的通知,等效于 xTaskNotify() 的 eIncrement 模式。
|
||||
|
||||
**原型**:
|
||||
|
||||
```c
|
||||
|
||||
void xTaskNotifyGive(TaskHandle_t xTaskToNotify);
|
||||
```
|
||||
**参数**:
|
||||
- xTaskToNotify:接收通知的任务句柄。
|
||||
示例:
|
||||
```c
|
||||
xTaskNotifyGive(xTaskHandle); // 发送通知,通知值递增 1
|
||||
```
|
||||
### ulTaskNotifyTake
|
||||
|
||||
**功能**: 任务等待通知,并在接收到通知时自动减少通知值(通常用于实现计数信号量)。
|
||||
|
||||
**原型**:
|
||||
|
||||
```c
|
||||
uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit, TickType_t xTicksToWait);
|
||||
```
|
||||
**参数**:
|
||||
- xClearCountOnExit:
|
||||
pdTRUE:退出等待时将通知值清零。
|
||||
pdFALSE:退出等待时保留剩余通知值。
|
||||
- xTicksToWait:等待通知的时间(Tick 数,portMAX_DELAY 表示无限等待)。
|
||||
**返回值**:返回通知值(如果是计数信号量,表示剩余信号量计数)。
|
||||
|
||||
**示例**:
|
||||
|
||||
```c
|
||||
if (ulTaskNotifyTake(pdTRUE, portMAX_DELAY) > 0) {
|
||||
// 收到通知,处理任务
|
||||
}
|
||||
```
|
||||
### xTaskNotifyWait
|
||||
**功能**: 任务等待通知,可以选择获取通知值的内容,并决定是否清除通知值。
|
||||
**原型**:
|
||||
|
||||
```c
|
||||
|
||||
BaseType_t xTaskNotifyWait(
|
||||
uint32_t ulBitsToClearOnEntry,
|
||||
uint32_t ulBitsToClearOnExit,
|
||||
uint32_t *pulNotificationValue,
|
||||
TickType_t xTicksToWait
|
||||
);
|
||||
```
|
||||
**参数**:
|
||||
|
||||
- ulBitsToClearOnEntry:进入等待时清除的通知值位。
|
||||
- ulBitsToClearOnExit:退出等待时清除的通知值位。
|
||||
- pulNotificationValue:保存通知值的指针。
|
||||
- xTicksToWait:等待时间(Tick 数)。
|
||||
**返回值**:
|
||||
- pdTRUE:收到通知。
|
||||
- pdFALSE:超时未收到通知。
|
||||
**示例**:
|
||||
```c
|
||||
uint32_t ulNotificationValue;
|
||||
if (xTaskNotifyWait(0x00, 0xFFFFFFFF, &ulNotificationValue, portMAX_DELAY) == pdTRUE) {
|
||||
// 收到通知,ulNotificationValue 保存通知值
|
||||
}
|
||||
```
|
||||
### xTaskNotifyStateClear
|
||||
**功能**: 清除任务的通知状态(即标记任务为“未通知”)。
|
||||
|
||||
**原型**:
|
||||
```c
|
||||
void vTaskNotifyStateClear(TaskHandle_t xTask);
|
||||
```
|
||||
**参数**:xTask:需要清除通知状态的任务句柄。
|
||||
**示例**:
|
||||
|
||||
```c
|
||||
vTaskNotifyStateClear(xTaskHandle); // 清除通知状态
|
||||
```
|
||||
|
||||
## 2. 示例代码:
|
||||
|
||||
### 1.直接任务通知
|
||||
|
||||
由task2控制task1的运行:
|
||||
```c
|
||||
// 事件组
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
static TaskHandle_t xTask1 = NULL, xTask2 = NULL;
|
||||
|
||||
void task1(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "-------------------------------");
|
||||
ESP_LOGI(TAG, "task1启动!");
|
||||
|
||||
while (1)
|
||||
{
|
||||
ESP_LOGI(TAG, "task1: 等待task通知");
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
ESP_LOGI(TAG, "task1: 收到task通知");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
}
|
||||
}
|
||||
|
||||
void task2(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "-------------------------------");
|
||||
ESP_LOGI(TAG, "task2启动!");
|
||||
|
||||
while (1)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
ESP_LOGI(TAG, "task2: 发送task通知");
|
||||
xTaskNotifyGive(xTask1);
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
|
||||
xTaskCreate(task1, "task1", 1024 * 2, NULL, 1, &xTask1);
|
||||
xTaskCreate(task2, "task2", 1024 * 2, NULL, 1, &xTask2);
|
||||
}
|
||||
```
|
||||
|
||||
### 2.任务通知值
|
||||
|
||||
任务通知值按位判断-代替队列邮箱或者事件组
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
static TaskHandle_t xTask1 = NULL, xTask2 = NULL;
|
||||
|
||||
void task1(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "-------------------------------");
|
||||
ESP_LOGI(TAG, "task1启动!");
|
||||
|
||||
uint32_t ulNotifiedValue;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ESP_LOGI(TAG, "task1: 等待task通知");
|
||||
xTaskNotifyWait(0x00, ULONG_MAX, &ulNotifiedValue, portMAX_DELAY);
|
||||
// 通过不同的bit位来判断通知的来源
|
||||
if ((ulNotifiedValue & 0x01) != 0)
|
||||
{
|
||||
ESP_LOGI(TAG, "task1: 收到task通知-bit0");
|
||||
}
|
||||
if ((ulNotifiedValue & 0x02) != 0)
|
||||
{
|
||||
ESP_LOGI(TAG, "task1: 收到task通知-bit1");
|
||||
}
|
||||
if ((ulNotifiedValue & 0x04) != 0)
|
||||
{
|
||||
ESP_LOGI(TAG, "task1: 收到task通知-bit2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void task2(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(TAG, "-------------------------------");
|
||||
ESP_LOGI(TAG, "task2启动!");
|
||||
|
||||
while (1)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
ESP_LOGI(TAG, "task2: 发送task通知-bit0");
|
||||
xTaskNotify(xTask1, 0x01, eSetValueWithOverwrite);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
ESP_LOGI(TAG, "task2: 发送task通知-bit1");
|
||||
xTaskNotify(xTask1, 0x02, eSetValueWithOverwrite);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
ESP_LOGI(TAG, "task2: 发送task通知-bit2");
|
||||
xTaskNotify(xTask1, 0x04, eSetValueWithOverwrite);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
|
||||
xTaskCreate(task1, "task1", 1024 * 4, NULL, 1, &xTask1);
|
||||
xTaskCreate(task2, "task2", 1024 * 4, NULL, 1, &xTask2);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user