ESP32 固件开发入门
ESP32 是一款小型且廉价的 SoC,具有原生 WiFi 和蓝牙(带 LE)功能。它们有各种口味和尺寸,但通常看起来像这样(在我手中作为尺寸参考):

我拥有的这个特定版本是我在全球速卖通上找到的 this model 的中文仿制品。我买了一包 10 个,价格约为 70 美元。它使用 ESP32-WROOM-32D 芯片,并具有 USB-C 连接器以及固定到 GPIO-2(板上标记为 D2)的集成 LED。这对于测试非常有用。
无论如何,在为 ESP32 编写代码时,您可以选择 4 条不同的路径。
1.使用esp-idf编写C代码
2.编写micropython代码
3. 使用 C 外部函数和回调编写 C++ 代码(也使用 esp-idf)
4.编写Arduino代码
本文的目的是回顾每种方法的优点和缺点,以决定哪种方法最适合您。
标准 C
用 C 语言编写是在该芯片上进行固件开发的绝佳选择。 SDK esp-idf 文档齐全且功能强大。然而,用 C 语言编写意味着手动内存管理、难以阅读的代码以及非客观的编程范例。使用 C 语言做 得到的是高效的代码和对硬件的直接访问。下面是一个使用 C 代码的简单 hello-world 类型的闪烁示例:
#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";
#define BLINK_GPIO 2
static uint8_t s_led_state = 0;
static void blink_led(void) {
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);
gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
}
void app_main(void) {
configure_led();
while (1) {
ESP_LOGI(TAG, "Turning the LED %s!", s_led_state == true ? "ON" : "OFF");
blink_led();
s_led_state = !s_led_state;
vTaskDelay(CONFIG_BLINK_PERIOD / portTICK_PERIOD_MS);
}
}
微型蟒蛇
Micropython 是 CPython 的一个端口,旨在在 ESP32 等 SoC 上运行。可以将其视为传统 Python 3 的子集。要使其正常工作,您需要将提供的 Micropython 固件刷新到芯片上,然后芯片通过 UART 连接为您提供交互式 REPL。还可以使用名为 adafruit-ampy 的工具将文件复制到文件系统上,以使它们在芯片启动时运行,而不是简单地生成 REPL,但如果您愿意,您可以对此进行自己的研究。
我对 Micropython 的感情很复杂。一方面,(对我而言)这是迄今为止对 ESP32 进行编程以执行简单任务(例如发出 http 请求)的最简单方法。然而,它在硬件访问方面受到限制,高度依赖于预构建的软件包,并且由于它需要解释器(Micropython 固件),因此它可用的程序和内存的大小也非常有限。
这是用 Micropython 编写的相同的眨眼示例:
import machine
import time
led = machine.Pin(2, machine.Pin.OUT)
while True:
led.value(1)
time.sleep(1)
led.value(0)
time.sleep(1)
正如您所看到的,它非常易于阅读和理解,这使得它对新用户非常有吸引力。
C++
这是一个奇怪的现象。由于 C++ 在设计上是 C 的超集,因此可以在 C++ 中编写代码并让它以与普通 C 相同的方式使用 esp-idf。不幸的是,有一些事情应该注意。
- 由于板上资源有限,C++动态内存管理可能是一个缺点
- 您需要使用 extern 语句来与
esp-idf集成 - 混合两种语言时事情会变得棘手
这是用 C++ 编写的相同的闪烁示例:
#ifdef __cplusplus
extern "C" {
#endif
#include <esp_log.h>
#include <string>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#ifdef __cplusplus
}
#endif
static char tag[] = "cpp_helloworld";
extern "C"
{
void app_main(void);
}
class Blink
{
public:
Blink(gpio_num_t blinkPin)
{
this->blinkPin = blinkPin;
gpio_pad_select_gpio(blinkPin);
gpio_set_direction(blinkPin, GPIO_MODE_OUTPUT);
}
void blinkTimes(int x)
{
ESP_LOGD(tag, "Blink Times %d", x);
int delayMs = 50;
int level = gpio_get_level(blinkPin);
gpio_set_level(blinkPin, 0);
vTaskDelay(1000 / delayMs);
for (int i = 0; i < x; i++)
{
gpio_set_level(blinkPin, 1);
vTaskDelay(1000 / delayMs);
gpio_set_level(blinkPin, 0);
vTaskDelay(1000 / delayMs);
}
gpio_set_level(blinkPin, level);
}
private:
gpio_num_t blinkPin = GPIO_NUM_2;
};
void app_main(void)
{
vTaskDelay(1);
Blink blink(GPIO_NUM_2);
blink.blinkTimes(5);
}
Arduino
Arduino很奇怪,我还没有完全理解它。 Arduino 作为一种语言是 C 语言的包装器和抽象层。arduino 的伟大之处在于它拥有广泛的库和支持,而且非常简单。 arduino 核心提供了 esp-idf 的几乎所有功能,以及 arduino 漂亮且易于阅读的语法。这样做的缺点是相当抽象并且有点争议。我看到的反对使用 arduino 编写 ESP32 代码的主要论点是,在编写大量代码时,它最终会成为一种负担,通常围绕着反对 setup() 和 loop() 函数的论点。
这是相同的示例,但在 arduino 中:
const int ledPin = 2;
void setup() {
pinMode (ledPin, OUTPUT);
}
void loop() {
digitalWrite (ledPin, HIGH);
delay(1000);
digitalWrite (ledPin, LOW);
delay(1000);
}
太长了;博士
- 用 C 编写是 男子气概 和 凉爽的 做事的方式”,但是很痛苦。
- 用 C++ 编写与 C 语言相同,但适合那些“对普通 C 来说太酷了”的人。
- 使用 micropython 编写非常适合 小而简单 项目,例如发出快速 HTTP 请求。
- 用 Arduino 编写主要与 C 相同,但没有 男子气概 和 凉爽的 方面,并且使用起来非常容易,而且拥有更大的社区。