Dieser Artikel soll keine vollständige Anleitung sein, sondern eine Sammlung von Materialquellen und Empfehlungen. In diesem Artikel möchte ich auf die Probleme eingehen, mit denen ich bei der Auswahl von Softwaretools für die Projektentwicklung konfrontiert war, sowie auf einige Fälle der praktischen Anwendung von ESP32-Modulen. Im nächsten Artikel möchte ich ein anschauliches Beispiel für die Verwendung des ESP32 als Steuerungscontroller für eine kleine mobile Plattform mit zwei Rädern zeigen. Daher werden wir hier folgende Details betrachten:
- Auswahl einer Entwicklungsumgebung;
- Einrichten der Arbeitsumgebung, Kompilieren und Laden des ESP-IDF-Projekts;
- Verarbeitung von Eingangs- / Ausgangssignalen GPIO;
- Pulsweitenmodulation mit MCPWM-Modul;
- PCNT-Hardware-Zähler;
- Verbindung zu WI-Fi und MQTT.
ESP32-WROOM-32E Modulübersicht
Laut Datenblatt enthält das Modul:
MCU
- ESP32-D0WD-V3 eingebetteter Xtensa-Dual-Core-32-Bit-LX6-Mikroprozessor mit bis zu 240 MHz
- 448 KB ROM für Boot- und Kernfunktionen
- 520 KB SRAM für Daten und Anweisungen
- 16 KB SRAM in RTC
W-lan
- 802.11b / g / n
- Bitrate: 802.11n bis zu 150 Mbit / s
- A-MPDU- und A-MSDU-Aggregation
- Unterstützung des Schutzintervalls von 0,4 µs
- Mittenfrequenzbereich des Betriebskanals: 2412 ~ 2484 MHz
Bluetooth
- Bluetooth V4.2 BR / EDR- und Bluetooth LE-Spezifikation
- Sender der Klassen 1, 2 und 3
- AFH
- CVSD und SBC
Hardware
- Interfaces: SD card, UART, SPI, SDIO, I 2 C, LED PWM, Motor PWM, I 2 S, IR, pulse counter, GPIO, capacitive touch sensor, ADC, DAC
- 40 MHz crystal oscillator
- 4 MB SPI flash
- Operating voltage/Power supply: 3.0 ~ 3.6 V
- Operating temperature range: –40 ~ 85 °C
- Dimensions: See Table 1
Certification
- Bluetooth certification: BQB
- RF certification: FCC/CE-RED/SRRC
- Green certification: REACH/RoHS
Funktionsblockdiagramm
Weitere Details zu den Funktionen des Mikrocontrollers finden Sie auf Wikipedia .
Das Modul basiert auf der Mikroschaltung ESP32-D0WD-V3 *. Der eingebettete Chip wurde unter Berücksichtigung der Skalierbarkeit und Anpassungsfähigkeit entwickelt. Die Zentraleinheit enthält zwei Kerne, die einzeln gesteuert werden können, und die CPU-Taktrate ist von 80 MHz bis 240 MHz einstellbar. Der Chip verfügt außerdem über einen Coprozessor mit geringem Stromverbrauch, der anstelle der CPU verwendet werden kann, um Strom zu sparen, wenn Aufgaben ausgeführt werden, die nicht viel Rechenleistung erfordern, z. B. die Überwachung des Status von Pins. ESP32 integriert eine Vielzahl von Peripheriegeräten, die von kapazitiven Berührungssensoren, Hallsensoren, SD-Kartenschnittstelle, Ethernet, Hochgeschwindigkeits-SPI, UART, I²S und I²C reichen.
Die technische Dokumentation finden Sie in der offiziellen Ressource .
Informationen über die Belegung des ESP-Wroom-32 Modul kann einfach auf die offenen Räume des Netzwerks gefunden werden, da hier
Auswahl einer Entwicklungsumgebung
Arduino IDE
Mikrocontroller der AVR-Familie und dann der Arduino-Plattform erschienen lange vor dem ESP32. Eines der Hauptmerkmale des Arduino ist seine relativ niedrige Eintrittsbarriere, die es fast jedem ermöglicht, schnell und einfach etwas zu erstellen. Die Plattform hat einen wichtigen Beitrag zur Open-Source-Hardware-Community geleistet und einer großen Anzahl von Funkamateuren den Beitritt ermöglicht. Die Arduino IDE kann kostenlos von außerhalb heruntergeladen werden . Trotz der offensichtlichen Einschränkungen im Vergleich zu einer professionellen Entwicklungsumgebung deckt die Arduino IDE 90% der Anforderungen für Hobbyprojekte ab. Es gibt auch eine ausreichende Anzahl von Artikeln im Netzwerk zum Thema Installation und Konfiguration der Arduino IDE für die Programmierung von ESP32-Modulen, zum Beispiel: Arduino Core für das ESP32 , habr.com, voltiq.ru und randomnerdtutorials.com .
Bei der Programmierung des ESP32 in der Arduino-Umgebung müssen Sie die Pinbelegung berücksichtigen, die auf der Seite arduino-esp32 angegeben ist .
Pinbelegung
des ESP32-Moduls Der Hauptvorteil dieses Entwicklungsansatzes ist der schnelle Einstieg und die einfache Erstellung von Projekten nach denselben Prinzipien wie bei Arduino. Und auch die Verwendung vieler Bibliotheken, wie für Arduino. Ein weiteres nettes Feature ist die Möglichkeit, Arduino-Bibliotheken und Designprinzipien mit dem ursprünglichen ESP-IDF-Framework zu kombinieren.
PlatformIO
Wie in der offiziellen Ressource angegeben : „Plattformübergreifende PlatformIO-IDE und Unified Debugger · Static Code Analyzer und Remote Unit Testing. Build-System für mehrere Plattformen und mehrere Architekturen · Firmware-Datei-Explorer und Speicherinspektion »Mit anderen Worten, PlatformIO ist ein Ökosystem für die Entwicklung eingebetteter Geräte, das mehrere Plattformen unterstützt, einschließlich Arduino und ESP32. Die IDE ist Visual Studio Code oder Atom. Die Installation und Konfiguration ist recht einfach: Wählen Sie nach der Installation des Code-Editors PlatformIO aus der Liste der Plugins aus und installieren Sie es. Auch hier gibt es im Internet viele Materialien zu diesem Thema, angefangen von der offiziellen Quelle hier und hier bis hin zu Artikeln mit detaillierten Abbildungen hier und hier....
Im Vergleich zur Arduino IDE verfügt PlatformIO über alle Eigenschaften einer modernen Entwicklungsumgebung: Projektorganisation, Plug-In-Unterstützung, Code-Vervollständigung und vieles mehr.
Ein Merkmal der Entwicklung auf PlatformIO ist eine einheitliche Projektstruktur für alle Plattformen
project_dir
├── lib
│ └── README
├── platformio.ini
└── src
└── main.cpp
Jedes PlatformIO-Projekt enthält eine Konfigurationsdatei mit dem Namen platformio.ini im Stammverzeichnis des Projekts. platformio.ini enthält Abschnitte (jeweils mit einem [Titel] gekennzeichnet) und Schlüssel / Wert-Paare innerhalb von Abschnitten. Zeilen, die mit einem Punktsemikolon ";" beginnen werden ignoriert und können für Kommentare verwendet werden. Mehrere Wertparameter können auf zwei Arten angegeben werden:
- Trennen des Wertes durch "," (Komma + Leerzeichen);
- Mehrzeilenformat, bei dem jede neue Zeile mit mindestens zwei Leerzeichen beginnt.
Die nächste Entwicklungsfunktion für ESP32 ist die Möglichkeit, ein Framework auszuwählen: Arduino oder ESP-IDF. Durch die Wahl von Arduino als Framework erhalten wir die zuvor beschriebenen Entwicklungsvorteile.
PlatformIO enthält praktische Tools zum Erstellen, Herunterladen und Debuggen von Projekten
Espressif IoT Development Framework
Für ESP32 hat Espressif ein Framework namens IoT Development Framework entwickelt, das als „ESP-IDF“ bekannt ist. Es kann auf Github gefunden werden . Das Projekt enthält eine sehr gute Dokumentation und enthält Beispiele, die Sie als Grundlage verwenden können. Das Einrichten und Einrichten der Umgebung ist im Abschnitt Erste Schritte gut dokumentiert . Es gibt verschiedene Möglichkeiten, das Framework zu installieren und damit zu arbeiten.
Klonen eines Projekts aus dem Repository und manuelles Installieren der Dienstprogramme.
Klonen eines Projekts von Github
mkdir -p ~/esp
cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git
Unter Windows ist die Installation von Entwicklungsdienstprogrammen mithilfe des Installationsprogramms oder mithilfe von Skripten für die Befehlszeile möglich:
cd %userprofile%\esp\esp-idf
install.bat
Für PowerShell
cd ~/esp/esp-idf
./install.ps1
Für Linux und MacOS
cd ~/esp/esp-idf
./install.sh
Der nächste Schritt ist das Einrichten von Umgebungsvariablen . Wenn die Entwicklungstools unter Windows mit dem Installationsprogramm installiert wurden, wird dem Menü und dem Desktop eine Verknüpfung zur Befehlskonsole hinzugefügt. Anschließend können Sie die Befehlsshell öffnen und mit Projekten arbeiten. Alternativ können Sie eine Windows-Befehlsshell ausführen:
%userprofile%\esp\esp-idf\export.bat
oder Windows PowerShell:
.$HOME/esp/esp-idf/export.ps1
Linux und MacOS:
. $HOME/esp/esp-idf/export.sh
Beachten Sie den Abstand zwischen dem Punkt und dem Pfad zum Skript.
Im Handbuch wird außerdem empfohlen, dem Skript einen Alias zum Festlegen von Umgebungsvariablen im Benutzerprofil hinzuzufügen, wenn Sie unter Linux oder MacOS arbeiten. Kopieren Sie dazu den folgenden Befehl und fügen Sie ihn in Ihr Shell-Profil ein (.profile, .bashrc, .zprofile usw.):
alias get_idf='. $HOME/esp/esp-idf/export.sh'
Durch Aufrufen des Befehls get_idf in der Konsole werden die erforderlichen Umgebungsvariablen exportiert. In meinem Fall musste auch ein Alias registriert werden, um die virtuelle Python-Umgebung zu starten
alias esp_va=’source $HOME/.espressif/python_env/idf4.2_py2.7_env/bin/activate’
und fügen Sie es dem nächsten Alias hinzu
alias get_idf='esp_ve && . $HOME/esp/esp-idf/export.sh'
Um ein neues Projekt von Grund auf neu zu erstellen , können Sie die Quellen von github.com klonen oder mit Beispielen aus dem Verzeichnis kopieren. Esp-idf / examples / get-Started / hello_world /.
Informationen zur Projektstruktur, zum Kompilieren, Laden, Konfigurieren von Dienstprogrammen usw. finden Sie hier .
Das Projekt ist ein Verzeichnis mit folgender Struktur:
- myProject/
- CMakeLists.txt
- sdkconfig
- components/ - component1/ - CMakeLists.txt
- Kconfig
- src1.c
- component2/ - CMakeLists.txt
- Kconfig
- src1.c
- include/ - component2.h
- main/ - CMakeLists.txt
- src1.c
- src2.c
- build/
Die Projektkonfiguration ist in der Datei sdkconfig im Stammverzeichnis enthalten. Um die Einstellungen zu ändern, müssen Sie den Befehl idf.py menuconfig (oder möglicherweise idf.py.exe menuconfig unter Windows) aufrufen.
Normalerweise werden zwei Anwendungen in einem Projekt erstellt - "Projekt-App" (die ausführbare Hauptdatei, dh Ihre benutzerdefinierte Firmware) und "Bootloader-App" (Programm des Bootloaders des Projekts).
"Komponenten" sind modulare Teile von eigenständigem Code, die in statischen Bibliotheken (.a-Dateien) kompiliert und mit der Anwendung verknüpft werden. Einige davon werden von ESP-IDF selbst bereitgestellt, andere können aus anderen Quellen bezogen werden.
Das Befehlszeilenprogramm idf.py bietet eine Schnittstelle zum einfachen Verwalten von Projekterstellungen. Der Speicherort unter Windows ist% userprofile% \. Espressif \ tools \ idf-exe \ 1.0.1 \ idf.py.exe. Sie steuert folgende Instrumente:
- CMake - Konfiguriert das zu erstellende Projekt
- Builder für Konsolenprojekte: Ninja oder GNU Make)
- esptool.py - zum Flashen von Modulen.
Jedes Projekt verfügt über eine CMakeLists.txt-Datei der obersten Ebene, die Build-Einstellungen für das gesamte Projekt enthält. Die minimale Dateikonfiguration umfasst die folgenden erforderlichen Zeilen:
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(myProject)
Ein ESP-IDF-Projekt kann als eine Sammlung von Komponenten betrachtet werden, in denen das Hauptverzeichnis die Hauptkomponente ist, in der der Code ausgeführt wird. Daher enthält dieses Verzeichnis auch die Datei CMakeLists.txt. Meistens ist seine Struktur ähnlich:
idf_component_register(SRCS "main.c" INCLUDE_DIRS ".")
Wo angegeben wird, dass die Quelldatei main.c für die Komponente registriert sein muss und die Header-Dateien im aktuellen Verzeichnis enthalten sind. Bei Bedarf können Sie das Hauptverzeichnis umbenennen, indem Sie EXTRA_COMPONENT_DIRS im Projekt CMakeLists.txt festlegen. Weitere Details finden Sie hier .
Darüber hinaus enthält das Verzeichnis die ursprüngliche Datei main.c (der Name kann beliebig sein) mit einem Einstiegspunkt - der Funktion void app_main (void).
Benutzerdefinierte Komponenten werden im Komponentenverzeichnis erstellt. Der Prozess wird im Abschnitt Komponentenanforderungen ausführlicher beschrieben .
Das Anschließen des ESP32-Moduls an einen Computer erfolgt aufgrund des vorhandenen Bootloaders in den meisten Fällen über ein USB-Kabel wie Arduino-Karten. Der Vorgang wird hier näher beschrieben... Das einzige, was erforderlich ist, ist das Vorhandensein eines USB-zu-UART-Konvertertreibers im System, der von der bereitgestellten Quelle heruntergeladen werden kann. Nach der Installation des Treibers müssen Sie die COM-Port-Nummer im System ermitteln, um die kompilierte Firmware in das Modul zu laden.
Projekt konfigurieren.
Die Standardeinstellungen sind in den meisten Fällen in Ordnung. Um die Menüoberfläche der Konsole aufzurufen, müssen Sie in das Projektverzeichnis wechseln und die Befehlszeile eingeben:
idf.py menuconfig
Menü mit Konfigurationseinstellungen
Nach dem Aufrufen dieses Befehls wird die Datei sdkconfig erstellt, wenn sie zuvor nicht vorhanden war oder wenn sie neu konfiguriert wurde. In früheren Tutorials sehen Sie, dass make menuconfig-Befehle veraltet sind.
Das Hinzufügen benutzerdefinierter Einstellungen zur Datei sdkconfig ist manuell möglich, zum Beispiel:
#
# WiFi Settings
#
CONFIG_ESP_HOST_NAME=" "
CONFIG_ESP_WIFI_SSID=" "
CONFIG_ESP_WIFI_PASSWORD=""
Die bevorzugte Methode ist jedoch die Verwendung einer zusätzlichen Konfigurationsdatei Kconfig.projbuild, die sich im Verzeichnis mit der Komponente befinden muss. Der Inhalt der Datei kann wie folgt sein:
# put here your custom config value
menu "Example Configuration"
config ESP_WIFI_SSID
string "Keenetic"
default "myssid"
help
SSID (network name) for the example to connect to.
config ESP_WIFI_PASSWORD
string "password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
endmenu
Nach dem Aufruf des Befehls idf.py menuconfig wird der Datei sdkconfig automatisch ein zusätzlicher Abschnitt hinzugefügt. Das Aufrufen des Befehls idf.py menuconfig ist auch im PlatformIO-Projekt möglich. Sie müssen jedoch berücksichtigen, dass sich die Struktur des PlatformIO-Projekts von der klassischen ESP-IDF unterscheidet, wodurch die Datei sdkconfig neu generiert und benutzerdefinierte Einstellungen angepasst werden können. Hier sind die oben genannten Optionen möglich: Bearbeiten der Datei von Hand, vorübergehendes Umbenennen des src-Verzeichnisses in main oder Einrichten der Datei CMakeLists.txt
Kompilieren und Laden des Projekts.
Um ein Projekt zu erstellen, müssen Sie den Befehl eingeben
idf.py build
Dieser Befehl kompiliert die Anwendung und alle ESP-IDF-Komponenten und generiert dann den Loader, die Partitionstabelle und die Anwendungsbinärdateien.
$ idf.py build
Running cmake in directory /path/to/hello_world/build
Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"...
Warn about uninitialized values.
-- Found Git: /usr/bin/git (found version "2.17.0")
-- Building empty aws_iot component due to configuration
-- Component names: ...
-- Component paths: ...
... (more lines of build system output)
[527/527] Generating hello-world.bin
esptool.py v2.3.1
Project build complete. To flash, run this command:
../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin
or run 'idf.py -p PORT flash'
Es sollte berücksichtigt werden, dass der anfängliche Kompilierungsprozess selbst eines einfachen Projekts einige Zeit in Anspruch nimmt. Im Gegensatz zum Arduino-Framework werden daher viele zusätzliche ESP-IDF-Module kompiliert. Eine weitere Änderung der Quellen führt nur zur Kompilierung derselben Dateien. Eine Ausnahme ist die Konfigurationsänderung. Führen Sie den folgenden Befehl aus, um die
kompilierten Binärdateien (bootloader.bin, partition-table.bin und hello-world.bin) auf die ESP32-Karte herunterzuladen:
idf.py -p PORT [-b BAUD] flash
Hier ersetzen wir PORT durch das, was wir benötigen (COM1, / dev / ttyUSB1), und wir können optional die Download-Geschwindigkeit ändern, indem wir die erforderlichen Werte für BAUD angeben.
Um das geladene Programm zu verfolgen, können Sie jedes Dienstprogramm zur Überwachung des COM-Ports verwenden, z. B. HTerm , CoolTerm Geben Sie den folgenden Befehl ein , oder verwenden Sie das Überwachungsdienstprogramm IDF Monitor , um es zu starten:
idf.py -p PORT monitor
ESP-IDF Eclipse Plugin
Die Dokumentation zum Installieren und Konfigurieren des Plugins finden Sie hier.
Voreinstellungen zur Verwendung:
- Java 11 und höher; (obwohl es auf Java 8 funktioniert, möglicherweise aufgrund dieser Störungen);
- Python 3.5 und höher;
- Eclipse 2020-06 CDT;
- Git;
- ESP-IDF 4.0 und höher;
Das Plugin ist recht gut in die Entwicklungsumgebung integriert und automatisiert den Löwenanteil der Funktionalität. Aber leider nicht ohne eine Fliege in der Salbe. In Eclipse-Versionen nach 2019-09 weisen ESP-IDF-Projekte unter Windows immer noch einen Fehler bei der Indizierung von Quelldateien auf. Darüber
hinaus gibt es andere Probleme , wenn das Projekt aus einem unbekannten Grund einfach nicht erstellt wird. Nur das Schließen des Projekts und das Neustarten von Eclipse helfen.
ESP-IDF Visual Studio-Codeerweiterung
Und die letzte, meiner Meinung nach interessanteste Option ist das offizielle Plugin für Visual Studio Code.
Wie PlatformIO kann es einfach über den Erweiterungsbereich installiert werden. Das Installieren und Konfigurieren des ESP-IDF-Frameworks in dieser Erweiterung wird als Onboarding-Menü dargestellt, das auch in der Beschreibung beschrieben wird. Das Herunterladen und Installieren aller Komponenten erfolgt automatisch, während die Menüphasen durchlaufen werden. Alle Screenshots des Prozesses können zitiert werden, sind jedoch intuitiv und bedürfen keiner oder nur geringer Erklärung. Für PlatformIO kann ein praktischeres Toolkit zum Erstellen, Herunterladen und Überwachen eines Projekts bereitgestellt werden. Im Gegensatz dazu wird das ESP-IDF-Plugin über ein Befehlsmenü gesteuert, das mit der Taste F1 oder einer im Handbuch beschriebenen Tastenkombination aufgerufen werden kann.
Erstes Plugin-Setup
Der Vorteil der Verwendung des Plugins besteht darin, dass die klassische Projektstruktur eingehalten wird und es nicht erforderlich ist, die Einstellungen irgendwie zu schamanisieren (in PlatformIO tritt ein solcher Bedarf auf). Es gibt eine Nuance: Wenn wir ein zuvor erstelltes Projekt in Visual Studio-Code mit dem ESP-IDF-Plugin öffnen möchten, müssen wir nur das Verzeichnis .vscode in das Stammverzeichnis des Projekts kopieren, das durch mindestens einmaliges Generieren eines Vorlagenprojekts mit ESP- abgerufen werden kann. IDF Plugin.
Befehlsmenü
FreeRTOS
Laut Wikipedia ist FreeRTOS ein Echtzeit-Multitasking-Betriebssystem (RTOS) für eingebettete Systeme. FreeRTOS bietet Multitasking, indem die CPU-Zeit von allen Threads oder in der Betriebssystemterminologie von Aufgaben gemeinsam genutzt wird. Meiner Meinung nach ist die vollständigste und verständlich FreeRTOS Handbuch in Russisch ist hier . In der Originalsprache können die Handbücher aus der offiziellen Quelle gelesen werden . Ich werde nur ein Bild vom Status der Aufgaben geben.
FreeRTOS wurde auf eine Vielzahl von Hardwareplattformen portiert, einschließlich der im ESP32 verwendeten Xtensa-Prozessoren. Weitere Details finden Sie in der Dokumentation.
GPIOs
GPIO oder universeller Ein- / Ausgang ist die Fähigkeit, einen Pin mit einem "1" - oder "0" -Signal diskret zu steuern.
Wie der Name schon sagt, haben solche Pins zwei Betriebsarten - Eingang oder Ausgang. Im ersten Fall lesen wir den Wert, im zweiten schreiben wir ihn auf. Ein weiterer wichtiger Faktor beim Umgang mit GPIOs ist der Spannungspegel. Der ESP32 ist ein 3,3-V-Gerät. Daher sollten Sie vorsichtig sein, wenn Sie mit anderen Geräten arbeiten, die eine Spannung von 5 V oder mehr haben. Es ist auch wichtig zu verstehen, dass der maximale Strom, der an den GPIO-Pin angelegt werden kann, 12 mA beträgt. Um die von ESP-IDF bereitgestellten GPIO-Funktionen nutzen zu können, müssen Sie den Header driver / gpio.h verbinden. Sie können dann gpio_pad_select_gpio () aufrufen, um die Funktion dieses Pins anzugeben. Auf dem ESP32 stehen 34 verschiedene GPIOs zur Verfügung. Sie sind bezeichnet als:
- GPIO_NUM_0 - GPIO_NUM_19
- GPIO_NUM_21 - GPIO_NUM_23
- GPIO_NUM_25 - GPIO_NUM_27
- GPIO_NUM_32 - GPIO_NUM_39
Die folgende Nummerierung ist nicht in der Anzahl der Pins 20, 24, 28, 29, 30 und 31 enthalten. Die
Pinbelegungstabelle finden Sie hier .
Bitte beachten Sie, dass die Pins GPIO_NUM_34 - GPIO_NUM_39 - nur den Eingabemodus verwenden. Sie können nicht für die Signalausgabe verwendet werden. Darüber hinaus werden die Pins 6, 7, 8, 9, 10 und 11 für die Interaktion mit einer externen Flash-Karte über SPI verwendet. Es wird nicht empfohlen, sie für andere Zwecke zu verwenden. Wenn Sie dies jedoch wirklich möchten, können Sie dies tun. Der Datentyp gpio_num_t ist eine Aufzählung mit Werten, die den Pin-Nummern entsprechen. Es wird empfohlen, diese Werte anstelle von Zahlen zu verwenden. Die Pin-Richtung wird mit der Funktion gpio_set_direction () festgelegt. So setzen Sie beispielsweise einen Pin als Ausgang:
gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT);
So setzen Sie einen Pin als Eingang:
gpio_set_direction(GPIO_NUM_17, GPIO_MODE_INPUT);
Wenn wir GPIO als Ausgabe konfiguriert haben, können wir seinen Wert durch Aufrufen von gpio_set_level () auf 1 oder 0 setzen.
Im folgenden Beispiel werden GPIOs einmal pro Sekunde gewechselt:
gpio_pad_select_gpio(GPIO_NUM_17);
gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT);
while(1) {
printf("Off\n");
gpio_set_level(GPIO_NUM_17, 0);
vTaskDelay(1000 / portTICK_RATE_MS);
printf("On\n");
gpio_set_level(GPIO_NUM_17, 1);
vTaskDelay(1000 / portTICK_RATE_MS);
}
Alternativ zum Festlegen aller Attribute einzelner Pins können wir die Eigenschaften eines oder mehrerer Kontakte festlegen, indem wir die Funktion gpio_config () aufrufen. Es verwendet eine gpio_config_t-Struktur als Eingabe und legt die Einstellungen für Richtung, Hochziehen, Herunterziehen und Unterbrechen für alle in der Bitmaske dargestellten Pins fest.
Zum Beispiel:
gpio_config_t gpioConfig;
gpioConfig.pin_bit_mask = (1 << 16) | (1 << 17);
gpioConfig.mode = GPIO_MODE_OUTPUT;
gpioConfig.pull_up_en = GPIO_PULLUP_DISABLE;
gpioConfig.pull_down_en = GPIO_PULLDOWN_ENABLE;
gpioConfig.intr_type = GPIO_INTR_DISABLE;
gpio_config(&gpioConfig);
Pull-Up- und Pull-Down-Einstellungen
Es wird normalerweise gelesen, dass der GPIO-Eingangspin hoch oder niedrig ist. Dies bedeutet, dass es an eine Stromquelle oder an Masse angeschlossen ist. Wenn der Pin jedoch mit nichts verbunden ist, befindet er sich in einem "schwebenden" Zustand. Es ist häufig erforderlich, den Anfangspegel eines nicht verbundenen Pins auf hoch oder niedrig einzustellen. In diesem Fall wird ein Hardware- (Anschluss über Widerstände) oder Software-Pull-up des Ausgangs durchgeführt, um + V - hochzuziehen oder 0 - herunterzuziehen. Im ESP32-SDK können wir einen GPIO mithilfe der Funktion gpio_set_pull_mode () als Pull-up oder Pulldown definieren. Diese Funktion verwendet als Eingabe die Nummer des Pins, den wir einstellen möchten, und den diesem Pin zugeordneten Pull-up-Modus.
Zum Beispiel:
gpio_set_pull_mode (21, GPIO_PULLUP_ONLY);
GPIO-Interrupt-Behandlung
Um eine Änderung des Eingangssignals an einem Pin zu erkennen, können wir dessen Status regelmäßig abfragen. Dies ist jedoch aus mehreren Gründen nicht die beste Lösung. Zuerst müssen wir die Prüfung durchlaufen und CPU-Zeit verschwenden. Zweitens ist der Status des Pins zum Zeitpunkt des Abrufs aufgrund der Verzögerung möglicherweise nicht mehr relevant, und Sie können die Eingangssignale überspringen. Die Lösung für diese Probleme ist die Unterbrechung. Eine Unterbrechung ist wie eine Türklingel. Ohne zu klingeln, müssen wir regelmäßig überprüfen, ob jemand an der Tür ist. Im Quellcode können wir eine Interrupt-Rückruffunktion definieren, die aufgerufen wird, wenn der Pin den Wert seines Signals ändert. Wir können auch feststellen, was den Aufruf des Handlers verursacht, indem wir die folgenden Parameter einstellen:
- Deaktivieren - Löst keinen Interrupt aus, wenn sich das Signal ändert.
- PosEdge - Ruft den Interrupt-Handler auf, wenn Sie von niedrig nach hoch wechseln.
- NegEdge - Ruft einen Interrupt-Handler auf, wenn Sie von hoch nach niedrig wechseln.
- AnyEdge - Ruft den Interrupt-Handler entweder beim Wechsel von niedrig nach hoch oder beim Wechsel von hoch nach niedrig auf.
Ein Interrupt-Handler kann zum Laden in den RAM zur Kompilierungszeit markiert werden. Standardmäßig befindet sich der generierte Code im Flash-Speicher. Wenn Sie es zuvor als IRAM_ATTR markieren, kann es sofort aus dem RAM ausgeführt werden.
void IRAM_ATTR my_gpio_isr_handle(void *arg) {...}
Diejenigen, die mit Mikrocontrollern gearbeitet haben, wissen, dass die Verarbeitung von Eingangssignalen von Tasten mit einem Kontaktsprung einhergeht. Dies kann als eine Reihe von Übergängen und damit als eine Reihe von Interrupt-Handler-Ereignissen interpretiert werden. Dazu müssen wir dem Code die Behandlung von Kontakt-Bounce hinzufügen. Dazu müssen wir das ursprüngliche Ereignis lesen, warten, bis die Vibrationen nachlassen, und dann den Eingangszustand erneut abtasten.
Das folgende Beispiel zeigt die Interrupt-Behandlung von Eingangssignalen. Ich empfehle Ihnen dringend, sich mit der Warteschlangenverwaltung in FreeRTOS vertraut zu machen, um den Code besser zu verstehen, falls Sie noch nicht mit ihm vertraut sind. Das Beispiel zeigt zwei Aufgaben:
- test1_task, der entsperrt wird, wenn ein Interrupt-Ereignis auftritt, wenn das Signal an Pin 25 aktiviert wird und die Meldung "Registered a click" einmal auf der Konsole angezeigt wird;
- test2_task wird regelmäßig abgefragt, und wenn das Signal an Pin 26 aktiviert ist, wird alle 100 ms die Meldung „GPIO 26 ist hoch!“ an die Konsole ausgegeben.
In diesem Beispiel ist auch ein Software-Timer xTimer eingestellt. Dies ist in diesem Fall optional und kein Beispiel für eine asynchrone Verzögerung.
Anti-Bounce wird mit der Funktion timeval_durationBeforeNow ausgeführt , die prüft, ob die Druckmaschine länger als 100 ms dauert. Es gibt andere Anti-Bounce-Softwaremuster, aber die Bedeutung ist ungefähr gleich. ESP-IDF enthält auch ein Beispiel für die Funktionsweise von GPIO.
Eingangssignalverarbeitung
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "freertos/queue.h"
#include "c_timeutils.h"
#include "freertos/timers.h"
static char tag[] = "test_intr";
static QueueHandle_t q1;
TimerHandle_t xTimer;
#define TEST_GPIO (25)
static void handler(void *args) {
gpio_num_t gpio;
gpio = TEST_GPIO;
xQueueSendToBackFromISR(q1, &gpio, NULL);
}
void test1_task(void *ignore) {
struct timeval lastPress;
ESP_LOGD(tag, ">> test1_task");
gpio_num_t gpio;
q1 = xQueueCreate(10, sizeof(gpio_num_t));
gpio_config_t gpioConfig;
gpioConfig.pin_bit_mask = GPIO_SEL_25;
gpioConfig.mode = GPIO_MODE_INPUT;
gpioConfig.pull_up_en = GPIO_PULLUP_DISABLE;
gpioConfig.pull_down_en = GPIO_PULLDOWN_ENABLE;
gpioConfig.intr_type = GPIO_INTR_POSEDGE;
gpio_config(&gpioConfig);
gpio_install_isr_service(0);
gpio_isr_handler_add(TEST_GPIO, handler, NULL);
while(1) {
//ESP_LOGD(tag, "Waiting on queue");
BaseType_t rc = xQueueReceive(q1, &gpio, portMAX_DELAY);
//ESP_LOGD(tag, "Woke from queue wait: %d", rc);
struct timeval now;
gettimeofday(&now, NULL);
if (timeval_durationBeforeNow(&lastPress) > 100) {
if(gpio_get_level(GPIO_NUM_25)) {
ESP_LOGD(tag, "Registered a click");
if( xTimerStart( xTimer, 0 ) != pdPASS ) {
// The timer could not be set into the Active state.
}
}
}
lastPress = now;
}
vTaskDelete(NULL);
}
void test2_task(void *ignore) {
gpio_set_direction(GPIO_NUM_26, GPIO_MODE_INPUT);
gpio_set_pull_mode(GPIO_NUM_26, GPIO_PULLDOWN_ONLY);
while(true) {
if(gpio_get_level(GPIO_NUM_26)) {
ESP_LOGD(tag, "GPIO 26 is high!");
if( xTimerStart( xTimer, 0 ) != pdPASS ) {
// The timer could not be set into the Active state.
}
}
vTaskDelay(100/portTICK_PERIOD_MS);
}
}
void vTimerCallback( TimerHandle_t pxTimer ) {
ESP_LOGD(tag, "The timer has expired!");
}
void app_main(void)
{
xTaskCreate(test1_task, "test_task1", 5000, NULL, 8, NULL);
xTaskCreate(test2_task, "test_task2", 5000, NULL, 8, NULL);
xTimer = xTimerCreate("Timer", // Just a text name, not used by the kernel.
2000/portTICK_PERIOD_MS, // The timer period in ticks.
pdFALSE, // The timers will auto-reload themselves when they expire.
( void * ) 1, // Assign each timer a unique id equal to its array index.
vTimerCallback // Each timer calls the same callback when it expires.
);
}
PCNT (Impulszähler)
Das PCNT- Modul (Pulse Counter) dient zum Zählen der Anzahl ansteigender und / oder fallender Flanken des Eingangssignals. Jeder Block des Moduls verfügt über ein 16-Bit-Register mit Vorzeichen und zwei Kanäle, die so konfiguriert werden können, dass der Zählerwert erhöht oder verringert wird. Jeder Kanal verfügt über ein Eingangssignal, das die Änderung des Signals erfasst, sowie einen Steuereingang, über den das Zählen aktiviert oder deaktiviert werden kann. Die Eingänge verfügen über zusätzliche Filter, mit denen unerwünschte Signalspitzen vermieden werden können.
Der PCNT-Zähler verfügt über acht unabhängige Einheiten, die von 0 bis 7 nummeriert sind. In der API werden sie mit pcnt_unit_t angegeben. Jedes Modul verfügt über zwei unabhängige Kanäle mit den Nummern 0 und 1, die durch pcnt_channel_t gekennzeichnet sind.
Die Konfiguration wird für jeden Gerätekanal mit pcnt_config_t separat bereitgestellt und umfasst:
- Gerätenummer und Kanalnummer, zu der diese Konfiguration gehört;
- GPIO-Nummern des Impulseingangs und des Gate-Eingangs;
- Zwei Parameterpaare, pcnt_ctrl_mode_t und pcnt_count_mode_t, um zu definieren, wie der Zähler in Abhängigkeit vom Zustand des Steuersignals reagiert und wie die ansteigenden / abfallenden Flanken gezählt werden.
- Zwei Grenzwerte (min / max), mit denen Überwachungspunkte gesetzt und Interrupts ausgelöst werden, wenn der Impulszähler einen bestimmten Grenzwert erreicht.
Die Konfiguration eines bestimmten Kanals erfolgt dann durch Aufrufen der Funktion pcnt_unit_config () mit der obigen Konfigurationsstruktur pcnt_config_t als Eingabeparameter.
Um einen Impuls- oder Steuereingang in der Konfiguration zu deaktivieren, müssen Sie anstelle der GPIO-Nummer PCNT_PIN_NOT_USED angeben.
Nach der Konfiguration mit pcnt_unit_config () wird der Zähler sofort ausgeführt. Der akkumulierte Zählerwert kann durch Aufrufen von pcnt_get_counter_value () überprüft werden.
Mit den folgenden Funktionen können Sie die Zähleroperation steuern: pcnt_counter_pause (), pcnt_counter_resume () und pcnt_counter_clear ()
Sie können zuvor eingestellte Zählermodi auch mithilfe von pcnt_unit_config () dynamisch ändern, indem Sie pcnt_set_mode () aufrufen.
Falls gewünscht, können der Impulseingangspin und der Steuereingangspin im laufenden Betrieb mit pcnt_set_pin () geändert werden.
Das PCNT-Modul verfügt über Filter an jedem Impuls- und Steuereingang, sodass kurze Spitzen in den Signalen ignoriert werden können. Die Länge der ignorierten Impulse wird in APB_CLK-Taktzyklen durch Aufrufen von pcnt_set_filter_value () angegeben. Die aktuellen Filtereinstellungen können mit pcnt_get_filter_value () überprüft werden. Der APB_CLK-Zyklus arbeitet mit 80 MHz.
Der Filter wird durch Aufrufen von pcnt_filter_enable () / pcnt_filter_disable () gestartet / angehalten.
Die folgenden in pcnt_evt_type_t definierten Ereignisse können einen Interrupt auslösen. Das Ereignis tritt ein, wenn der Impulszähler bestimmte Werte erreicht:
- : counter_l_lim counter_h_lim, pcnt_config_t;
- 0 1, pcnt_set_event_value ().
- = 0
Um den Interrupt für die oben genannten Ereignisse zu registrieren, zu aktivieren oder zu deaktivieren, müssen Sie pcnt_isr_register (), pcnt_intr_enable () und pcnt_intr_disable () aufrufen. Um Ereignisse zu aktivieren oder zu deaktivieren, wenn Schwellenwerte erreicht sind, müssen Sie auch pcnt_event_enable () und pcnt_event_disable () aufrufen.
Verwenden Sie die Funktion pcnt_get_event_value (), um zu überprüfen, welche Schwellenwerte derzeit festgelegt sind.
Ein Beispiel von ESP-IDF wird hier vorgestellt .
Ich habe einen PCNT-Zähler verwendet, um die Radgeschwindigkeit zu berechnen. Dazu ist es notwendig, die Anzahl der Impulse pro Umdrehung zu zählen und dann den Zähler zurückzusetzen.
Beispielcode
typedef struct {
uint16_t delay; //delay im ms
int pin;
int ctrl_pin;
pcnt_channel_t channel;
pcnt_unit_t unit;
int16_t count;
} speed_sensor_params_t;
esp_err_t init_speed_sensor(speed_sensor_params_t* params) {
/* Prepare configuration for the PCNT unit */
pcnt_config_t pcnt_config;
// Set PCNT input signal and control GPIOs
pcnt_config.pulse_gpio_num = params->pin;
pcnt_config.ctrl_gpio_num = params->ctrl_pin;
pcnt_config.channel = params->channel;
pcnt_config.unit = params->unit;
// What to do on the positive / negative edge of pulse input?
pcnt_config.pos_mode = PCNT_COUNT_INC; // Count up on the positive edge
pcnt_config.neg_mode = PCNT_COUNT_DIS; // Keep the counter value on the negative edge
pcnt_config.lctrl_mode = PCNT_MODE_REVERSE; // Reverse counting direction if low
pcnt_config.hctrl_mode = PCNT_MODE_KEEP; // Keep the primary counter mode if high
pcnt_config.counter_h_lim = INT16_MAX;
pcnt_config.counter_l_lim = - INT16_MAX;
/* Initialize PCNT unit */
esp_err_t err = pcnt_unit_config(&pcnt_config);
/* Configure and enable the input filter */
pcnt_set_filter_value(params->unit, 100);
pcnt_filter_enable(params->unit);
/* Initialize PCNT's counter */
pcnt_counter_pause(params->unit);
pcnt_counter_clear(params->unit);
/* Everything is set up, now go to counting */
pcnt_counter_resume(params->unit);
return err;
}
int32_t calculateRpm(speed_sensor_params_t* params) {
pcnt_get_counter_value(params->unit, &(params->count));
int32_t rpm = 60*(1000/params->delay)*params->count/PULSE_PER_TURN;
pcnt_counter_clear(params->unit);
return rpm;
}
Pulsweitenmodulation (PWM) mit MCPWM-Modul
Informationen zum Modul finden Sie hier.
Es gibt viele Artikel im Internet zum Thema PWM , insbesondere wenn Sie in Bezug auf das Arduino suchen.
Wikipedia gibt eine kurze und prägnante Definition - Pulsweitenmodulation (PWM) - den Prozess der Leistungssteuerung durch Ein- und Ausschalten des Geräts. Das Prinzip der PWM-Steuerung besteht darin, die Impulsbreite bei konstanter Amplitude und Frequenz des Signals zu ändern.
Die PWM-Frequenz von Arduino beträgt 488,28 Hz. Die Auflösung beträgt 8 Bit (0 ... 255), und es können sechs Hardware-Pins 3, 5, 6, 9, 10, 11 verwendet werden. Mit den Registereinstellungen des AVR-Mikrocontrollers können Sie jedoch andere Werte erzielen PWM-Frequenz.
Der ESP32-Mikrocontroller hat in seinem Arsenal ein separates MCPWM-Modul oder vielmehr zwei Module, von denen jedes drei Paare von PWM-Pins aufweist.
Ferner sind in der Dokumentation die Ausgänge eines separaten Blocks als PWMxA / PWMxB gekennzeichnet.
Ein detaillierteres Blockdiagramm des MCPWM-Blocks ist unten dargestellt. Jedes A / B-Paar kann mit einem von drei Timern synchronisiert werden: Timer 0, 1 und 2. Mit demselben Timer können mehr als ein Paar PWM-Ausgänge synchronisiert werden. Jede Einheit kann auch Eingangsdaten wie Synchronisationssignale erfassen, Alarme wie Überstrom oder Motorüberspannung erkennen und Rückmeldungen mit Erfassungssignalen wie der Rotorposition empfangen.
Der Umfang der Konfiguration hängt vom Motortyp ab, insbesondere davon, wie viele Ausgänge und Eingänge erforderlich sind und wie die Signalfolge zur Steuerung des Motors aussehen wird.
In unserem Fall beschreiben wir eine einfache Konfiguration zum Antreiben eines bürstenbehafteten Gleichstrommotors, der nur einige der verfügbaren MCPWM-Ressourcen verwendet. Eine beispielhafte Schaltung ist unten gezeigt. Es enthält eine H-Brücke zum Umschalten der Polarisation der dem Motor (M) zugeführten Spannung und zum Bereitstellen eines ausreichenden Stroms, um ihn anzutreiben.
Die Konfiguration umfasst die folgenden Schritte:
- Auswahl des MPWn-Blocks, der zum Antrieb des Motors verwendet wird. Auf der ESP32-Karte stehen zwei Module zur Verfügung, die unter mcpwm_unit_t aufgeführt sind.
- Initialisiert zwei GPIOs als Ausgaben für das ausgewählte Modul durch Aufrufen von mcpwm_gpio_init (). Die beiden Ausgangssignale werden normalerweise verwendet, um den Motor nach rechts oder links zu treiben. Alle verfügbaren Signalparameter sind in mcpwm_io_signals_t aufgeführt. Verwenden Sie die Funktion mcpwm_set_pin () zusammen mit mcpwm_pin_config_t, um mehr als einen Pin gleichzeitig zu setzen.
- Timerauswahl. Auf dem Gerät stehen drei Timer zur Verfügung. Timer sind in mcpwm_timer_t aufgeführt.
- Festlegen der Timerfrequenz und des Bootstraps in der Struktur mcpwm_config_t.
- Aufruf von mcpwm_init () mit den oben genannten Parametern.
Die PWM-Steuermethoden sind wie folgt:
- mcpwm_set_signal_high () mcpwm_set_signal_low (). . A B .
- — , mcpwm_start () mcpwm_stop (). .
- , mcpwm_set_duty () . mcpwm_set_duty_in_us (), . mcpwm_get_duty (). , mcpwm_set_duty_type (). A B mcpwm_generator_t. . mcpwm_init (), , mcpwm_duty_type_t.
Ein Beispiel für einen Code für einen Bürstenmotor finden Sie hier.
In meinem Projekt habe ich den Code aus dem Beispiel praktisch verwendet, ihn leicht korrigiert und eine zweite Motorsteuerung hinzugefügt. Zur unabhängigen Steuerung der PWM-Kanäle muss jeder von ihnen mit einem separaten Timer konfiguriert werden, z. B. MCPWM_TIMER_0 und CPWM_TIMER_1:
Beispielcode
void mcpwm_example_gpio_initialize(void)
{
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, GPIO_PWM1A_OUT);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1B, GPIO_PWM1B_OUT);
//mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_SYNC_0, GPIO_SYNC0_IN);
mcpwm_config_t pwm_config;
pwm_config.frequency = 1000; //frequency = 500Hz,
pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 0
pwm_config.cmpr_b = 0; //duty cycle of PWMxb = 0
pwm_config.counter_mode = MCPWM_UP_COUNTER;
pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //Configure PWM0A & PWM0B with above settings
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_1, &pwm_config); //Configure PWM0A & PWM0B with above settings
// deadtime (see clock source changes in mcpwm.c file)
mcpwm_deadtime_enable(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_BYPASS_FED, 80, 80); // 1us deadtime
mcpwm_deadtime_enable(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_BYPASS_FED, 80, 80);
}
Herstellen einer Verbindung zu WI-Fi und Arbeiten mit MQTT
Das Thema des Wi-FI-Protokolls ist ziemlich umfangreich. Zur Beschreibung des Protokolls wird eine Reihe separater Artikel benötigt. Im offiziellen Handbuch finden Sie den Abschnitt Wi-Fi-Treiber . Eine Beschreibung der Software-API finden Sie hier . Codebeispiele finden Sie hier.
Wi-Fi-Bibliotheken bieten Unterstützung für die Konfiguration und Überwachung von ESP32-Wi-Fi-Netzwerkfunktionen. Folgende Konfigurationen stehen zur Verfügung:
- ( STA Wi-Fi). ESP32 .
- AP ( Soft-AP ). ESP32.
- AP-STA (ESP32 , ).
- (WPA, WPA2, WEP . .)
- ( ).
- Wi-Fi IEEE802.11.
MQTT
Hier oder hier können Sie sich mit dem Thema vertraut machen . Das ESP-IDF-Handbuch mit Beispielen finden Sie hier .
Um MQTT im Code einzurichten, müssen Sie zunächst eine Verbindung zu einem Wi-Fi-Netzwerk herstellen. Stellen Sie dann eine Verbindung zum Broker her. Die Nachricht wird in einem Rückruf verarbeitet, dessen Parameter das Ereignis esp_mqtt_event_handle_t ist. Wenn der Ereignistyp MQTT_EVENT_DATA ist, können das Thema und die Daten analysiert werden. Sie können aufgrund erfolgreicher Verbindung, Trennung und Themenabonnements unterschiedliche Verhaltensweisen anpassen.
Beispiel für eine Wi-Fi-Verbindung:
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
wifi_config_t sta_config = {
.sta = {
.ssid = CONFIG_ESP_WIFI_SSID,
.password = CONFIG_ESP_WIFI_PASSWORD,
.bssid_set = false
}
};
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config) );
ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_ESP_WIFI_SSID, "******");
ESP_ERROR_CHECK( esp_wifi_start() );
ESP_LOGI(TAG, "Waiting for wifi");
xEventGroupWaitBits(wifi_event_group, BIT0, false, true, portMAX_DELAY);
//MQTT init
mqtt_event_group = xEventGroupCreate();
mqtt_app_start(mqtt_event_group);
Verbindung zum MQTT-Broker herstellen
void mqtt_app_start(EventGroupHandle_t event_group)
{
mqtt_event_group = event_group;
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "mqtt://mqtt.eclipse.org:1883", //mqtt://mqtt.eclipse.org:1883
.event_handle = mqtt_event_handler,
.keepalive = 10,
.lwt_topic = "esp32/status/activ",
.lwt_msg = "0",
.lwt_retain = 1,
};
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_start(client);
MQTT-Handler
esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
int msg_id;
command_t command;
// your_context_t *context = event.context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
xEventGroupSetBits(mqtt_event_group, BIT1);
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, "esp32/car/#", 0);
msg_id = esp_mqtt_client_subscribe(client, "esp32/camera/#", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "esp32/status/activ", "1", 0, 0, 1);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
memset(topic, 0, strlen(topic));
memset(data, 0, strlen(data));
strncpy(topic, event->topic, event->topic_len);
strncpy(data, event->data, event->data_len);
command_t command = {
.topic = topic,
.message = data,
};
parseCommand(&command);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
default:
break;
}
return ESP_OK;
}
Damit ist meine Geschichte über die Verwendung des ESP32-Moduls abgeschlossen. In dem Artikel wurden Beispiele zu ESP-IDF als Framework betrachtet, das die Ressourcen des Moduls optimal nutzt. Die Programmierung mit anderen Plattformen wie JavaScript, MicroPython und Lua finden Sie in den zugehörigen Ressourcen. Wie bereits erwähnt, werde ich im nächsten Artikel ein praktisches Beispiel für die Verwendung eines Mikrocontrollers geben und auch den Softwareansatz von Arduino und ESP-IDF vergleichen.