Освой Arduino играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Мигаем светодиодом
RGB-светодиод
Измеряем температуру чипа
Датчик Холла для обнаружения магнита
Базовая информация о модуле: getSdkVersion(), esp_get_idf_version()
Программная перезагрузка платы: restart()
Случайное число: esp_random()
BASE64
Джойстик
Датчик температуры и влажности DHT11/DHT22
Задействуем разные ядра микроконтроллера
Если использовать стандартный скетч из File | Examples | 01.Basics | Blink, то получим ошибку. Причина в следующем - у ESP32 нет константы LED_BUILTIN, которая указывает на встроенный светодиод (что достаточно странно). Поэтому следует явно указать вывод платы, как это было в старых примерах. Кроме того, встроенный светодиод находится не на выводе 13, а на выводе 2. С учётом этих особенностей скетч для мигания встроенным светодиодом будет следующим.
// Мигаем встроенным светодиодом на ESP32
const int LED = 2;
void setup() {
pinMode(LED, OUTPUT);
}
void loop() {
delay(1000);
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
}
У ESP32 нет функции analogWrite(), поэтому стандартный способ не подходит. Взамен можно использовать другие функции, о которых в другой статье. А пока простой пример для включения основных цветов без промежуточных вариантов для модуля RGB-светодиода. Используем выводы 12, 13, 14 и GND.
void setup()
{
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
pinMode(14, OUTPUT);
}
void loop()
{
digitalWrite(12, HIGH);
digitalWrite(13, HIGH);
digitalWrite(14, HIGH);
delay(2000);
digitalWrite(12, LOW);
digitalWrite(13, LOW);
digitalWrite(14, LOW);
delay(2000);
digitalWrite(12, LOW);
digitalWrite(13, HIGH);
digitalWrite(14, LOW);
delay(2000);
digitalWrite(12, LOW);
digitalWrite(13, LOW);
digitalWrite(14, HIGH);
delay(2000);
}
Другой пример работы с RGB-модулем
У платы есть встроенный температурный датчик, измеряющий температуру чипа. Датчик не получится использовать для измерения окружающей температуры воздуха, поэтому в большинстве случаев он бесполезен. Скорее всего он пригодится при использовании очень ресурсоёмких задач, когда есть риск спалить процессор.
При тестировании у меня всегда выводилось 53.33 градуса. Даже не знаю, можно ли ему вообще доверять.
#ifdef __cplusplus
extern "C" {
#endif
uint8_t temprature_sens_read();
#ifdef __cplusplus
}
#endif
uint8_t temprature_sens_read();
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.print("Temperature: ");
// Convert raw temperature in F to Celsius degrees
Serial.print((temprature_sens_read() - 32) / 1.8);
Serial.println(" C");
delay(1000);
}
У платы есть встроенный датчик Холла, который умеет обнаруживать магниты. Напишем скетч, который при обнаружении магнита будет включать светодиод. Также в Serial Monitor выводятся текущие показания.
const int LED = 2;
void setup() {
Serial.begin(115200);
pinMode(LED, OUTPUT);
}
void loop() {
int sensor = hallRead(); // считываем показания датчика Холла
Serial.print("Sensor Reading:");
Serial.println(sensor);
digitalWrite(LED, (sensor < 0) ? HIGH : LOW); // включаем светодиод при обнаружении магнита
delay(500);
}
Смотри также пример для MicroPython.
У платы есть 2 аналоговых выхода с ЦАП (8 бит): вывод 25 (DAC1) и вывод 26 (DAC2). Аналоговый выход цифро-аналогового преобразователя позволяет формировать 8-битные уровни напряжения.
#define DAC1 25
void setup() {
Serial.begin(115200);
}
void loop() {
int value = 128; // 255= 3.3V, 128=1.65V
dacWrite(DAC1, value);
delay(1000);
}
Запустите скетч и проверьте мультиметром значение напряжения на выводе 25. Можете менять в скетче уровень напряжения.
Версия SDK, размер флеш-памяти, кучи (heap). У функции getSdkVersion() есть аналог в виде низкоуровневой функции esp_get_idf_version(), которая вернёт такой же ответ.
void setup() {
Serial.begin(115200);
Serial.println("SDK");
Serial.println(ESP.getSdkVersion());
Serial.println("SDK через низкоуровневую функцию:");
Serial.println(esp_get_idf_version());
}
void loop() {}
Ответ на момент написания примера.
SDK
v3.2.3-14-gd3e562907
SDK через низкоуровневую функцию:
v3.2.3-14-gd3e562907
У платы есть готовая функция restart() для программной перезагрузки. Смотри пример в API.
Перепишем пример, добавив счётчик. Он будет уменьшаться раз каждую секунду с 10 до 0.
int counter = 10;
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println(counter);
if (counter == 0) {
Serial.println("Reset..");
ESP.restart();
}
counter--;
delay(1000);
}
У Arduino есть стандартные функции для получения случайных чисел random(). У ESP32 есть своя дополнительная функция esp_random(), которая возвращает число от 0 до UINT32_MAX (наибольшее беззнаковое число INT). Чтобы число было действительно случайным, должен работать Wi-Fi или Bluetooth-модуль для взятия значений из сигналов беспроводной связи.
Напишем скетч, который будет использовать все доступные функции.
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println("-----------");
Serial.println(esp_random());
Serial.println(random(10)); // 0-9
Serial.println(random(10, 20)); // 10-19
delay(1000);
}
Переводим строку в схему кодирования BASE64. Для этого есть готовая библиотека base64.h.
#include <base64.h>
void setup() {
Serial.begin(115200);
String toEncode = "Hello Kitty";
String encoded = base64::encode(toEncode);
Serial.println(encoded);
}
void loop() {}
Раскодировать сообщение можно на онлайн-сервисах, например, https://www.base64decode.org/.
Рассмотрим пример использования джойстика.
Подключение (вместо 5В используем 3В). Скетч для джойстика остаётся без изменений, только поменяем номера выводов
KY-023 | ESP32
----------------
GND | GND
+5V | 3V3
VRx | 2
VRy | 4
SW | 23
const int xPin = 2;
const int yPin = 4;
const int buttonPin = 23;
Если для плат Arduino возвращаемые значения джойстика в спокойном состоянии находятся в районе 511-512, то у ESP32 в районе 1445 (x), 1870 (y). А общий диапазон значений: 0-4095.
Кроме стандартной библиотеки для Arduino, есть отдельная библиотека для ESP32, доступная через менеджер библиотек по ключевым словам "DHT sensor library for ESPx by beegee".
Общий пример.
#include "DHTesp.h"
DHTesp dht;
void setup()
{
Serial.begin(115200);
dht.setup(27);
}
void loop()
{
float humidity = dht.getHumidity();
Serial.print("Humidity: ");
Serial.println(humidity);
delay(10000);
}
Есть продвинутый вариант примера для датчика DHT22. Датчик требует задержки как минимум 2 секунды, мы можем узнать более точное значение задержки через функцию getMinimumSamplingPeriod()
#include "DHTesp.h"
DHTesp dht;
void setup()
{
Serial.begin(115200);
dht.setup(27);
Serial.print("Minimum Sampling Period: ");
Serial.println(dht.getMinimumSamplingPeriod());
}
void loop()
{
delay(dht.getMinimumSamplingPeriod());
float temperature = dht.getTemperature();
Serial.println("------------------");
Serial.print("Temperature: ");
Serial.println(temperature);
}
Обычно ESP32 работает на одном ядре из двух возможных. Проверить можно через функцию xPortGetCoreID().
void setup() {
Serial.begin(115200);
Serial.print("Функция setup() запущена на ядре: ");
Serial.println(xPortGetCoreID());
}
void loop() {
Serial.print("Функция loop() запущена на ядре: ");
Serial.println(xPortGetCoreID());
delay(3000);
}
// Результат
// Функция setup() запущена на ядре: 1
// Функция loop() запущена на ядре: 1
Arduino IDE поддерживает FreeRTOS и её API позволяет создавать задачи, которые могут запускаться независимо на обеих ядрах.
Создадим для примера задачу при помощи функции xTaskCreatePinnedToCore(), которая содержит семь (!) параметров.
// Пример
xTaskCreatePinnedToCore(Task1code, "Task1", 10000, NULL, 1, NULL, 0);
M5Stack. Датчик температуры и влажности DHT11 (ESP32)