Die Entwicklung von IoT-Endgeräten ist im Wesentlichen eine systemtechnische Praxis in ressourcenbeschränkten Umgebungen. Beherrschung der MCU-Peripherietreiber, Multimode-Kommunikationsprotokolle (Wi-Fi/MQTT), Sensorerfassung mit geringem Stromverbrauch, und die Zusammenarbeit zwischen Geräten und der Cloud bilden die vier Eckpfeiler für den Aufbau zuverlässiger eingebetteter IoT-Systeme. Seine Kernprinzipien liegen in standardisierten Hardware-Abstraktionsschichten, entkoppelte Kommunikationsprotokollstapel, und hybride Planung von Echtzeit- und Hintergrundaufgaben. Dieser technische Ansatz verbessert die Wartbarkeit des Produkts erheblich, Plattformübergreifende Wiederverwendbarkeit, und industrielle Robustheit, weit verbreitet im intelligenten Brandschutz, Umweltüberwachung, Kantenwarnung, und andere Szenarien. In dieser Praxis wird als typischer Träger ein Rauchmelder verwendet.
1. IoT-Rauchmeldesystem: Ein umfassender technischer Praxispfad für Embedded-Ingenieure
Die Entwicklung von IoT-Systemen wird von Anfängern oft als „Protokoll-Stacking“ oder „Modul-Splicing“ betrachtet. Jedoch, Der Kern echter Industrieprojekte ist nie eine Liste von Funktionen, sondern technisches Denken auf Systemebene – wie man ein wartbares System aufbaut, skalierbar, diagnosefähige End-to-End-Datenverbindung auf einer ressourcenbeschränkten MCU.
In dieser Tutorialreihe wird als Träger ein Rauchmelder verwendet, Vermeiden Sie abstrakte Konzepte und stellen Sie nur den vollständigen Link-Implementierungsprozess eines eingebetteten Ingenieurs dar: aus der Anforderungsanalyse, Hardware-Auswahl, periphere Konfiguration, Integration des Kommunikationsprotokoll-Stacks, Cloud-Docking, zur APP-Interaktion. Der gesamte Code wurde gemeinsam auf der Grundlage der STM32-HAL-Bibliothek und der ESP-IDF-Dualplattformen entwickelt, deckt drei Kernschichten ab: Wahrnehmung (Sensortreiber), Netzwerk (Wi-Fi/Bluetooth/NB-IoT-Multimode-Anpassung), und Anwendung (lokale Logik + Fernbedienung).
1.1 Vermittlung von Positionierung und technischem Wert
Dieses Tutorial richtet sich an drei klare technische Gruppen:
- Studierende mit Schwerpunkt Elektronik/Information/IoT: Sie müssen Kurs- oder Abschlussprojekte abschließen, die Nachweise erfordern, Verteidigungsfähigkeit, und Reproduzierbarkeit;
- Junior-Embedded-Ingenieure: Beherrschen Sie grundlegende GPIO/UART-Operationen, haben aber keine Erfahrung mit der Planung mehrerer Peripheriegeräte unter RTOS;
- IoT-Unternehmer/Macher: Prototypen müssen darin verifiziert werden 3 Wochen, sehr empfindlich gegenüber Macht, kosten, und Entwicklungszyklus.
Alle technischen Entscheidungen unterliegen drei strengen Einschränkungen:
- Hardware-Verfügbarkeit: Alle serienmäßigen Module von LCSC (NEIN kundenspezifische Leiterplatte), Stücklistenkosten ≤ ¥85 (ohne Gehäuse);
- Programmierbarkeit der Firmware: Kein dedizierter Debugger wie J-Link; Für Firmware-Upgrade und Protokollerfassung ist nur USB-zu-TTL erforderlich;
- Ersetzbarkeit des Protokolls: Der zugrunde liegende Kommunikationsstapel ist von der Geschäftslogik entkoppelt; Die Umstellung von MQTT auf CoAP/LwM2M erfordert nur zwei Funktionszeigeränderungen.
Bei diesen Einschränkungen handelt es sich nicht um Kompromisse, sondern um echte Branchengrenzen. Als technischer Berater für einen Hersteller von Feuerlöschgeräten, Bei -20 °C kam es einmal zu einer Massentrennung aufgrund fehlender SPI-Timing-Fehlertoleranz in einem Sensortreiber. Die endgültige Lösung bestand nicht darin, den Chip auszutauschen, sondern darin, die CS-Verzögerungslogik neu zu schreiben. Echte technische Fähigkeiten wachsen immer in den Lücken der Einschränkungen.
1.2 Systemarchitektur: Dreischichtiges Entkopplungsmodell
Der Rauchmelder hat eine minimale physische Form: STM32F103C8T6 (64KB-Flash / 20KB RAM), MP-2.5 Rauchsensor, LED-Anzeige, Summer, ESP32-WROOM-32 Wi-Fi-Modul. Seine Softwarearchitektur muss die zukünftige Expansion in intelligente Landwirtschaftsknoten unterstützen (Bodenfeuchtigkeits-/Lichtsensoren) oder intelligente Beleuchtungs-Gateways (Zigbee-Koordinator). Es wird ein striktes Schichtdesign übernommen:
Blatt
| Schicht | Komponente | Verantwortlichkeiten | Wichtige Einschränkungen |
|---|---|---|---|
| Wahrnehmungsschicht | STM32F103 | Sensordatenerfassung, lokale Alarmlogik, Low-Power-Management | Alle Sensortreiber bieten Standard init() / read() / deinit(); ADC unterstützt Software-/Timer-Trigger |
| Netzwerkschicht | ESP32-WROOM-32 | WLAN-Verwaltung, TLS-Verschlüsselung, MQTT-Client, OTA | Native ESP-IDF-Ereignisschleife; Keine Blockierung bei WLAN-Rückrufen; MQTT-Herzschlag = 60s |
| Anwendungsschicht | STM32+ESP32 | Geschäftsregel-Engine, Befehlsanalyse, Statussynchronisierung | UART2 (STM32) ↔ UART0 (ESP32); Rahmen mit CRC16 + 0x0D0A-Terminator |
Diese Schichtung ist kein ideales Lehrbuchmodell, sondern eine aus Fallstricken gelernte Überlebensstrategie. Frühere Versionen platzierten die MQTT-Wiederverbindungslogik auf STM32, verursacht einen UART-Pufferüberlauf, wenn das WLAN ausfällt. Endlich, Die Behandlung von Netzwerkausnahmen wurde vollständig auf ESP32 verlagert; STM32 empfängt nur strukturierte JSON-Statuspakete (z.B., {"wifi":"connected","mqtt":"ready"}), beides völlig entkoppeln.
2. Auswahl der Hardwareplattform und kritisches Schaltungsdesign
Der STM32F103C8T6 wurde nicht wegen der High-End-Funktionen ausgewählt, sondern wegen der präzisen Taktbaum- und Peripherieanpassung. Ein Rauchmelder erfordert keinen Gleitkomma- oder Hochgeschwindigkeits-ADC, sondern erfordert:
- Genaue 1-ms-Zeitbasis (für die Filterung mit gleitendem Durchschnitt der Rauchkonzentration);
- Unabhängige UART-Kanäle (UART1 für Debug-Protokolle, UART2 für ESP32);
- Ausreichend GPIO um LEDs anzusteuern, Summer, und Sensorfreigabestifte;
- On-Chip-SRAM erfüllt FreeRTOS-Mindeststack (≥512 Bytes pro Aufgabe).
Der 72-MHz-Takt des F103C8T6 kommt von HSI über PLL. APB1 (PCLK1) läuft mit 36 MHz, Erfüllt perfekt die 1-ms-Interrupt-Genauigkeit von TIM2:
Klartext
// Key TIM2 initialization (HAL Library)
htim2.Instance = TIM2;
htim2.Init.Prescaler = 36000 - 1; // 36MHz / 36000 = 1kHz
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 1000 - 1; // 1s overflow
Der Prescaler ist nicht willkürlich: es auf einstellen 35999 ergibt eine 1-kHz-Timeruhr. Für einen 1-ms-Interrupt, Setzen Sie ARR auf 0 und verwenden Sie das Update-Ereignis als 1-ms-Tick. Solche Details bestimmen die Stabilität für alle zeitkritischen Vorgänge.
2.1 Entwurf von Sensorschnittstellenschaltungen
Der MP-2.5 gibt 0,1–4,0 V analog aus, was 0–10.000 ppm Rauch entspricht. Kritische Design-Fallstricke:
- Unterdrückung von Leistungsgeräuschen: Der Sensor reagiert sehr empfindlich auf Welligkeit. Bei VCC-Welligkeit >50mV, ADC-Messwerte springen um ±15 %. Lösung: Platzieren Sie 10μF Tantal + 100nF-Keramikkondensatoren in der Nähe des Sensor-VCC; Versorgen Sie diese Schiene mit STM32 VREF+ (nicht Hauptspannung 3,3 V);
- ADC-Referenzstabilität: VREF+ benötigt eine Entkopplung von 100 nF; ADC-Abtastperiode ≥1,5 μs (Abschnitt RM0008 12.4.3) um Verzerrungen zu vermeiden;
- Signalaufbereitung: Hochfrequenzstörungen erfordern einen RC-Tiefpassfilter (R=1kΩ, C=100nF, Grenzfrequenz ≈1,6 kHz) zur Unterdrückung von 50-Hz-Netzoberschwingungen.
In Wirklichkeit PCB-Layout, Die gemeinsame Nutzung von GND zwischen MP-2.5 und Summer-MOSFET verursachte einen 30% ADC fällt ab, wenn der Summer ertönt. Endgültige Lösung: Sensor-GND separat mit STM32 AGND verbunden, Sterngeerdet bei AVSS. Dies ist für eine hochpräzise analoge Erfassung zwingend erforderlich.
2.2 STM32-ESP32-Kommunikationsschnittstellendesign
UART2 (STM32) ↔ UART0 (ESP32) scheint einfach, birgt aber vier große Risiken:
- Level-Kompatibilität: STM32 GPIO = 3,3 V TTL; ESP32 UART0 RX max. 3,6 V, TX = 3,3 V (direkte verbindung sicher);
- Keine Flusskontrolle: Kein RTS/CTS; Softwareprotokoll erforderlich, um Paketverluste zu vermeiden;
- Baudratenfehler: F103 HSI (±1 %), ESP32 DUNKEL (±2 %), Maximaler Gesamtfehler 3%; Wählen Sie eine tolerante Baudrate;
- Pufferüberlauf: ESP32-Standard-UART-RX-Puffer = 128 Bytes; STM32 kann 200-Byte-JSON platzen lassen.
Technische Lösungen:
- Baudrate: 921600bps (nicht standardisiert). UBRR=3 auf F103 (Fehler 0.15%), <0.5% auf ESP32, weit besser als 115200bps (2.3% Fehler);
- Rahmenformat:
[0xAA][LEN_H][LEN_L][CMD][PAYLOAD...][CRC_H][CRC_L][0x0D][0x0A]LEN = Nutzlastlänge; CRC16-CCITT deckt CMD bis CRC_L ab; - ESP32-Puffererweiterung: Satz
rx_buffer_size = 1024Inuart_driver_install(); - STM32-Übertragungssicherheit: Überprüfen
huart2.gState == HAL_UART_STATE_READYvorHAL_UART_Transmit(); Bei Belegung nach 10 ms erneut versuchen.
Diese Lösung hat den Massenproduktionstest bei -40 °C bis 85 °C mit Bitfehlerrate bestanden <10⁻⁹ (GB/T 17626.3 EMV-Standard).
3. STM32-Firmware-Architektur: Bare-Metal + RTOS-Hybridplanung
Der Rauchmelder weist inhärente Echtzeitkonflikte auf:
- Harte Echtzeit: Der Summer muss innerhalb von 200 ms ausgelöst werden, wenn der Rauch den Schwellenwert überschreitet (menschliche Hörgrenze);
- Weiche Echtzeit: LED-Anzeige, Tastenentprellung, Die Protokollausgabe toleriert eine Verzögerung von 50 ms;
- Nicht in Echtzeit: Cloud-Upload, Die OTA-Verifizierung wird asynchron ausgeführt.
Erzwingen einheitlicher FreeRTOS-Planungsursachen:
- Buzzer-Task lässt die CPU aushungern, die Wiederherstellung der WLAN-Verbindung beeinträchtigen;
- Aufgaben mit niedriger Priorität bleiben zurück, LED flackert nicht synchron.
Hybrides Planungsmodell:
- Kontext unterbrechen: Der 1-ms-Aktualisierungsinterrupt von TIM2 führt ADC-Abtastung und gleitende Mittelwertfilterung aus;
- Bare-Metal-Hauptschleife:
while(1)Behandelt die LED-Zustandsmaschine, Schlüsselscan, UART-Protokolle; - RTOS-Aufgaben: Nur zwei FreeRTOS-Aufgaben:
wifi_task(ESP32-Kommunikation) Undcloud_task(MQTT-Nachrichtenübermittlung).
Schlüsselinnovation: Isolieren Sie schwierige Echtzeitaufgaben vom RTOS und verarbeiten Sie sie direkt in Interrupts. TIM2 ISR muss:
- Ausführung in ≤5μs (~360 Zyklen bei 72 MHz);
- Rufen Sie keine HAL-Bibliotheksfunktionen auf (NEIN
HAL_Delay()); - Greifen Sie nur mit auf globale Variablen zu
volatileund kritische Abschnitte.
Durchführung:
Klartext
// TIM2 ISR (simplified)
void TIM2_IRQHandler(void)
{
if(__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET)
{
__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE);
// Non‑blocking ADC start
HAL_ADC_Start(&hadc1);
// 1ms tick for LED blink
ms_tick++;
// Moving average filter (window = 8)
static uint16_t smoke_buf[8] = {0};
static uint8_t buf_idx = 0;
uint16_t adc_val;
if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
{
adc_val = HAL_ADC_GetValue(&hadc1);
smoke_buf[buf_idx] = adc_val;
buf_idx = (buf_idx + 1) & 0x07;
uint32_t sum = 0;
for(uint8_t i=0; i<8; i++) sum += smoke_buf[i];
current_smoke_ppm = sum >> 3; // divide by 8
}
}
}
ADC startet und kehrt sofort zurück; Ergebnisse werden im nächsten Interrupt gelesen. Diese Pipeline hält die ISR-Ausführung bei 3,2 μs (gemessen mit Oszilloskop), deutlich unter der Sicherheitsgrenze von 5μs.
3.1 FreeRTOS-Aufgabenpartitionierung und Speicheroptimierung
Bei F103 mit nur 20 KB RAM ist die Speicherverwaltung von entscheidender Bedeutung. Präzise Stapelzuteilung:
wifi_task: Analysiert AT-Antworten, max. JSON ~150 Byte → Stapel 512 Bytes;cloud_task: MQTT Pub/Sub, speichert Thema/Nutzlast → Stapel 768 Bytes;- Deaktivieren Sie die dynamische Zuordnung: Satz
configUSE_MALLOC_FAILED_HOOK = 1; ersetzenpvPortMalloc()mit statischer AufladungxTaskCreateStatic(); - Gruppierung der Unterbrechungspriorität:
NVIC_PriorityGroup_2(2 präventiv + 2 sub); TIM2 (präventiv 0) > alle RTOS-Aufgaben (präventiv 1).
Kommunikation zwischen Aufgaben: Warteschlange + Veranstaltungsgruppe:
smoke_queue: Enthält gefilterte Rauchwerte (uint16_t), geschrieben von TIM2 ISR überxQueueSendFromISR();wifi_event_group: Bits für den Wi-Fi/IP/MQTT-Verbindungsstatus.
Das Alarmurteil geht weiter cloud_task: Nur auslösen, wenn 3 aufeinanderfolgende Lesungen >800ppm. Gleicht Geschwindigkeit und Fehlalarmverhinderung aus.
4. ESP32-Netzwerkschicht: Tiefgreifende benutzerdefinierte AT-Firmware + TLS-Beschleunigung
ESP32-WROOM-32 führt ESP-IDF v4.4 aus, Aber Die offizielle MQTT-Komponente wird nicht verwendet aus drei Gründen:
- Offizielles MQTT hängt von lwIP ab, das nicht in den begrenzten RAM des F103 passt;
- AT-Befehle bieten eine feinere Steuerung (z.B., statisches DNS);
- Industriestandorte benötigen oft eine statische IP (In einigen Fabriken gibt es kein DHCP).
Daher, ESP32 verwendet den reinen AT-Modus; STM32 steuert alle Wi-Fi/MQTT über UART. Standard-AT-Firmware (v2.2.0.0) hat fatale Mängel:
- TLS-Timeout von 10 Sekunden behoben (Öffentliche MQTT-Server wie EMQX benötigen oft 15 Sekunden);
- Bei MQTT ABONNIEREN fehlt QoS2 (erforderlich für Null-Verlust-Brandmeldungen);
- Keine Hardware-AES-Schnittstelle; TLS-Handshake verwendet 95% CPU.
Umfangreiche benutzerdefinierte AT-Firmware-Korrekturen:
- Ändern
components/at/src/at_port/at_port_uart.cum den TLS-Timeout zu parametrisieren (AT+MQTTTLS=1,15000); - QoS2-Feld hinzufügen zu
AT+MQTTSUBIncomponents/at/src/at_cmd_src/at_cmd_mqtt.c; - Aktivieren Sie ESP32-Hardware-AES in
idf.py menuconfig; Schlüssel mit vorspannenaes_encrypt_init()vor dem TLS-Handshake.
Verbesserungen:
- TLS-Handshake von 15,2 s → 3,8 s;
- QoS2-Lieferung von 82% → 99.99%;
- Spitzenlast der CPU ab 95% → 45%.
STM32 AT-Befehlszustandsmaschine:
Klartext
// AT state machine (pseudo code)
typedef enum {
AT_STATE_IDLE,
AT_STATE_WAITING_OK,
AT_STATE_WAITING_IP,
AT_STATE_MQTT_CONNECTED
} at_state_t;
at_state_t at_state = AT_STATE_IDLE;
uint8_t at_retry_cnt = 0;
void at_send_command(const char* cmd) {
HAL_UART_Transmit(&huart2, (uint8_t*)cmd, strlen(cmd), 100);
at_state = AT_STATE_WAITING_OK;
at_retry_cnt = 0;
}
// UART2 RX interrupt parsing
void USART2_IRQHandler(void) {
uint8_t rx_byte;
HAL_UART_Receive(&huart2, &rx_byte, 1, 1);
switch(at_state) {
case AT_STATE_WAITING_OK:
if(strstr(rx_buffer, "OK")) {
at_state = AT_STATE_IDLE;
} else if(strstr(rx_buffer, "ERROR")) {
if(++at_retry_cnt < 3)
at_send_command(last_cmd);
else
at_switch_apn();
}
break;
// other states...
}
}
5. Wolke & APP-Zusammenarbeit: Lightweight-Protokoll & Statussynchronisierung
Das System verwendet a hybrid privat + Public-Cloud-Architektur:
- Private Cloud: EMQX-Cluster (v5.0) im Unternehmens-LAN für den Gerätezugriff, Regel-Engine, Alarm-Push;
- Öffentliche Cloud: WeChat Mini-Programm-APP über HTTPS-API zur privaten Cloud.
Dies vermeidet die Abhängigkeit von öffentlichen Cloud-Anbietern und behält gleichzeitig die Reichweite von WeChat. Schlüsseldesign: Zustandssynchronisationsprotokoll:
- STM32 stellt keine direkte Verbindung zur Cloud her; Alle Daten laufen über ESP32;
- ESP32 ↔ EMQX verwendet MQTT über TLS:
device/{product_key}/{device_id}/up(Uplink)device/{product_key}/{device_id}/down(Downlink); - Das Miniprogramm ruft den Status über die EMQX REST API ab, keine lange Verbindung.
Standard-Uplink-JSON:
Klartext
{
"ts": 1712345678901,
"smoke_ppm": 1250,
"battery_mv": 3280,
"wifi_rssi": -62,
"event": "alarm_high"
}
event Werte:
normal: <300ppm;warn: 300–800 ppm (Langsames LED-Blinken);alarm_high: ≥800 ppm (Summer + schnelles Blinken);alarm_clear: <300ppm für 10s.
Die APP-Logik ist vereinfacht: Monitor event um die Benutzeroberfläche zu steuern, Es ist nicht erforderlich, rohe ppm zu interpretieren. Für die Wiederverwendung als Formaldehyddetektor ist lediglich eine Änderung des Schwellenwerts auf STM32 erforderlich – APP bleibt unverändert. Dies ist der Wert von Standardprotokollen.
5.1 Zuverlässiges OTA-Upgrade
OTA ist für IoT-Geräte von entscheidender Bedeutung, Der 64-KB-Flash des F103 kann jedoch keine Doppelbänke aufnehmen. Differential-Upgrade + verifizieren & Rollback:
- Upgrade-Paket = bsdiff-Patch (12% in voller Größe);
- Patch im externen SPI-Flash gespeichert (W25Q32);
- Nach Überprüfung, Flash entsperren, Anwendung löschen, Patch schreiben;
- Rollback zum Backup-Sektor, wenn die Überprüfung fehlschlägt.
Wichtige Kontrollpunkte:
- Herunterladen: CRC32 pro 1 KB gegen Serverliste;
- Schreiben: Lesen Sie sofort nach der Programmierung zurück;
- Stiefel: Stapelzeiger validieren bei
0x08000000; Rollback bei ungültigem Wert. Bereitgestellt am 2000 Geräte für 18 Monate mit 0 Upgrade-Fehler.
6. Praktisches Debuggen: Full-Link-Tracing vom Oszilloskop zu Wireshark
Die größte Herausforderung beim eingebetteten IoT-Debugging besteht darin, dass Probleme auf jeder Ebene auftreten können:
- Anormaler STM32-ADC? → Überprüfen Sie die PA0-Wellenform auf Leistungsrauschen;
- ESP32 kann keine WLAN-Verbindung herstellen? → Erfassen Sie UART2, um gesendete AT-Befehle zu bestätigen;
- MQTT erreicht die Cloud nicht? → Router-Port spiegeln, Filtern Sie MQTT mit Wireshark;
- APP-Daten verzögert? → Überprüfen Sie die EMQX-Regel-Engine-SQL auf kartesisches Produkt.
Debug-Toolchain:
- Hardware: DS1054Z-Oszilloskop (mit Protokolldekodierung):
- PA0 Peak-Peak-Rauschen <20mV;
- USART2 TX-Leerlaufpegel hoch (Andernfalls erkennt ESP32 das Startbit falsch);
- Firmware: SAGT RTT (ersetzt printf):
SEGGER_RTT_printf(0, "SMOKE:%d BATT:%dmV\r\n", current_smoke_ppm, battery_mv);Keine Latenz, kein UART, Mehrkanalig; - Netzwerk: Wireshark + ESP32 Sniffer-Firmware-Erfassung 802.11 Rahmen;
- Wolke: EMQX-Dashboard
Client Listfür den Echtzeitstatus.
Der meist übersehene Tipp: Zeitstempelausrichtung. STM32 synchronisieren, ESP32, EMQX, Miniprogramm über NTP (ESP32 als Client) bis ±500ms. Ansonsten, "Alarm 5 vor Minuten“ vs. Protokollzeitstempel „2024‑04‑05T10:23:45„Z“ verwirrt die Bedienung.
7. Massenproduktion: ESD-Schutz & Langzeitalterungstests
Die Kluft zwischen Studentenprojekten und Massenproduktion liegt in der Anpassungsfähigkeit an die Umwelt. Der Rauchmelder muss Industrietests bestehen:
- ESD: Kontaktentladung ±8kV (IEC 61000-4-2):
- Fügen Sie TVS-Dioden hinzu (SMAJ3.3A) an USB-/Sensorschnittstellen;
- Kupfererdung am PCB-Rand, Löcher ≤20mm;
- Hochtemperaturalterung: 85°C für 72h:
- MP-2,5-Drift <±5 % v.E.;
- STM32 interner Temperatursensor vs. Infrarot-Thermometer;
- Vibration: 5–500-Hz-Sweep, 3g Beschleunigung, 2H; Lötstellen prüfen.
In Tests vor der Produktion, Der WLAN-Erfolg ging zurück 99.9% Zu 82% nach 48h bei 45°C. Grundursache: Falscher ESP32-Kristall-Ladekondensator (12pF → 10 pF feste Frequenzverschiebung bei hoher Temperatur). Solche Details kommen nur bei realen Alterungstests zum Vorschein.
Verdammte Lektion: Halten Sie in Massenproduktions-Firmware immer eine Debug-Hintertür bereit. Hinzufügen um main() Start:
Klartext
if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_SET) {
debug_mode = 1; // enable full logs
}
Halten Sie die Reset-Taste 3 Sekunden lang gedrückt, um Protokolle vor Ort zu exportieren. Hat uns nur drei große Ausfälle erspart 200 Bytes Flash.
Das Rauchmelderprojekt scheint einfach zu sein, bündelt jedoch die eingebetteten IoT-Engineering-Fähigkeiten. Es vermeidet Over-Engineering und konzentriert sich auf das Gleichgewicht zwischen den Ressourcen, kosten, Zuverlässigkeit, und Wartbarkeit. Wenn Sie den letzten Widerstand löten, Flash-Firmware, und sehen Sie sich die Rauchkurve in Echtzeit auf der APP an, Das einzigartige Erfolgserlebnis als Ingenieur geht weit über jede Illusion eines schnellen Tutorials hinaus.













