Wie implementiert man eine Status-LED in einem System? [geschlossen]

Diese Frage bezieht sich auf die allgemeine Software-Embedded-System-Praxis. Ich möchte eine blinkende LED als Status-LED für meine MCU haben.

Wie richtig ist es, es mit dem Timer-Interrupt zu implementieren? Wobei dem die niedrigste Priorität eingeräumt wird.

Wie wäre es mit einer PWM mit einer bestimmten Frequenz? Welche Methode kann Vorteile gegenüber der anderen haben?

Was ist die allgemeine Methode, die Ingenieure in der Industrie verwenden, um den Status des Systems/der MCU-Einheit mithilfe einer LED anzuzeigen?

Im Allgemeinen bauen Ingenieure eine Schaltung und schreiben die FW, die sie antreibt. Und sie beginnen das Design normalerweise nicht mit einer Status-LED.
Es hängt genau davon ab, welchen Status die LED anzeigen soll.
Ja ich verstehe. Aber was ist die beste Vorgehensweise, um eine Status-LED zu steuern, nachdem die Firmware mit der Zielfunktionalität geschrieben wurde? Wie in einem Interrupt oder PWM oder irgendwo in der Hauptschleife?
Sagen Sie einfach, eine LED mit einer gewissen Frequenz blinken zu lassen.
Es kommt auf den Aufbau deiner FW an. Wenn es eine Hauptschleife mit fester Zeit hat, verwenden Sie die Hauptschleife. Wenn es hauptsächlich Interrupt-gesteuert ist, verwenden Sie Interrupt. Wenn es Multithreading ist, verwenden Sie Thread.
Wie Finbarr sagte, hängt es davon ab, welchen Status die LED anzeigen soll. Möchten Sie eine Status-LED, die nur blinkt, um anzuzeigen, dass eine Status-LED blinkt, oder gibt es andere, vielleicht weniger skurrile Informationen, die die blinkende LED vermitteln soll? Verwandte Frage: Warum soll es blinken und nicht durchgehend leuchten?
Das Blinken würde mir sagen, dass die MCU Interrupts korrekt bedient, wenn ich sie in Interrupts verwende. Außerdem kam mir das Blinken ganz natürlich in den Sinn, denn so fangen wir mit jedem MCU an. Mir ist nicht sehr bewusst, wie die Industrie die LED-Anzeige für den Status verwendet, daher die Frage. Aber ich bin offen für Ideen!
„Industrie“ ist ein weit gefasster Begriff. Alles hängt von den Anforderungen ab. Man kann sich entscheiden, die LED zu verwenden, um den Status als Morsecode zu senden.
Im Allgemeinen haben Sie bereits einen Timer in Ihrem System für was auch immer die Anwendung bei zB 10kHz läuft, also erhöhen Sie einen Zähler in der Interrupt-Routine und wenn es einen Grenzwert erreicht, schalten Sie die LED um.

Antworten (2)

Generell treibe ich eine Status-LED mit verschiedenen Blinkmustern an, je nach Zustand des Systems. Jedes Blinkmuster dauert 1 Sekunde.

Um die Muster zu definieren, unterteile ich das 1-Sekunden-Intervall in Zeitscheiben. Eine Bitmaske definiert dann irgendwo, ob die LED für jede Zeitscheibe jedes Musters ein- oder ausgeschaltet sein soll.

Dies ist keine kritische Aufgabe, für die es sich lohnt, Interrupts zu verwenden. Mein Standard-Status-LED-Modul enthält eine Routine, die periodisch aufgerufen werden kann. Es betrachtet den aktuellen 1-ms-Tick-Zähler und handhabt das gesamte Timing entsprechend. Solange diese Routine relativ zu den Blink-Zeitscheiben oft aufgerufen wird, funktioniert alles reibungslos. Normalerweise rufe ich die Routine aus der Hauptereignisschleife auf, wenn keine anderen Ereignisse verarbeitet wurden. Mit anderen Worten, dies ist ungefähr die Sache mit der niedrigsten Priorität, die der Prozessor tut. Das ist das komplette Gegenteil von der Verwendung von Interrupts.

Ich mache das oft genug, dass ich dafür vorgefertigte Routinen habe. Auf Microchip dsPIC-Prozessoren verwende ich 48 Slices pro Blinkmuster. Das liegt daran, dass Programmspeicherworte 24 Bit breit sind, sodass 48 Bit aus der Verwendung von zwei Wörtern zur Definition jedes Blinkmusters stammen. Das bedeutet, dass jede Scheibe etwa 21 ms lang ist. Der vorgefertigte Code verwendet ganze ms-Ticks pro Zeitscheibe, variiert aber automatisch zwischen 20 und 21 ms, um das gesamte Muster langfristig bei 1 s zu halten.

Hier ist der Vorlagencode für das STAT-Modul auf dsPIC-Prozessoren. Sie kopieren dieses Modul in Ihr Projekt und benennen es um. Die QQn-Sequenzen werden durch projektspezifische Strings ersetzt.

; ****************************************************** *************
; * Copyright (C) 2005, Embed Inc (http://www.embedinc.com) *
; * *
; * Die Erlaubnis zum Kopieren dieser Datei wird erteilt, solange dies *
; * Copyright-Hinweis ist vollständig unter * enthalten
; * Beginn der Datei, ob die Datei als Ganzes kopiert wird *
; * oder teilweise und unabhängig davon, ob andere Informationen *
; * zur Kopie hinzugefügt. *
; * *
; * Der Inhalt dieser Datei darf beliebig verwendet werden, *
; * kommerziell oder anderweitig. Diese Datei wird "wie besehen" bereitgestellt, *
; * und Embed Inc erhebt keinen Anspruch auf Eignung für ein *
; * bestimmten Verwendungszweck und übernimmt keine Haftung, die sich daraus ergibt *
; * sein Nutzen. *
; ****************************************************** *************
;
; Dieses Modul verwaltet die Statusanzeige-LED.
;
; Die Statusanzeige-LED blinkt mit einem systemabhängigen Muster
; Status. Dieses Modul ermittelt das Blinkmuster aus dem Systemstatus,
; und führt die Mechanik des Blinkens der LED entsprechend durch.
;
; Exportierte Routinen:
;
; STAT_INIT
;
; Muss zuerst in dieses Modul aufgerufen werden.
;
; STAT_UPDATE
;
; Muss regelmäßig angerufen werden. Es ermittelt den Systemzustand, entscheidet
; welches Muster angezeigt werden soll, verfolgt Echtzeit und aktualisiert die LED
; entsprechend. Es soll von der Hauptereignisschleife als aufgerufen werden
; ein Ereignis mit niedriger Priorität.
;
; Konfigurationsparameter:
;
; NAME
;
; Name des /OUTBIT-Pins, der die LED steuert. Setzen Sie diese Zeile auf ON
; wird angenommen, um die LED zu aktivieren, und OFF, um sie zu deaktivieren. Die LED kann sein
; beliebig verdrahtet, solange die Polarität im /OUTBIT-Befehl gesetzt ist
; entsprechend. Der Standardwert ist "ledstat".
;
; NSTBITS
;
; Anzahl der Bits in einem Muster. Der Standardwert ist 48.
;
/include "qq2.ins.dspic"

;**************************************************** ******************************
;
; Konfigurationskonstanten.
;
/const name string = "ledstat" ;Name des Ausgangspins, der die LED steuert
/const nstbits integer = 48 ;Anzahl der Slices in einem einsekündigen Anzeigemuster

////////////////////////////////////////////////// //////////////////////////////
//
// Makro PATTNUM
//
// Bestimmen Sie die Nummer des anzuzeigenden Musters. Dieses Makro verlässt das 0-N
// Musternummer in W0. W1-W3 kann gelöscht werden.
//
/Makropattnum
         Bewegung #0, w0

havepatt: ;W0 enthält die 0-N Nummer des anzuzeigenden Musters
  /endmac
//
////////////////////////////////////////////////// //////////////////////////////

/include "(cog)src/dspic/stat.ins.dspic"

;**************************************************** ******************************
;
; Mustertabelle anzeigen.
;
; Jedes Anzeigemuster muss hier definiert werden. Muster werden definiert
; sequentiell beginnend mit 0 bei TBL_PATT.
;
; Jedes Muster wird mit dem PATTERN-Makro definiert. Der Parameter für dieses Makro
; ist eine Reihe von Sternen (*) oder Bindestrichen (-). Ein Stern steht für LED an und a
; Strich-LED aus. Es müssen genau NSTBITS Gesamtzeichen in der sein
; Muster. Muster werden von links nach rechts angezeigt, wie durch definiert
; PATTERN-Makroparameter.
;
tbl_patt:
         Muster ************************------------------------ ; 0 - Normalbetrieb

.Ende

Dies ist der einzige Code, der angepasst werden muss. Im Allgemeinen müssen Sie nur den Namen der Ausgangsleitung definieren, die die LED steuert, den Code eingeben, der entscheidet, welches Muster abhängig vom Systemstatus angezeigt werden soll, und die tatsächlichen Muster.

Beachten Sie die starke Nutzung meines PIC-Assembler-Präprozessors. Beispielsweise macht das unten verwendete PATTERN-Makro das Definieren von Mustern sehr einfach. Das Makro generiert die eigentlichen .PWORD-Anweisungen, um die Musterbits im Programmspeicher zu definieren. Sie könnten das direkt tun, aber das PATTERN-Makro bietet eine viel intuitivere Schnittstelle zum Definieren von Blinkmustern.

Der Vollständigkeit halber hier der Code in der Include-Datei. Dies wird als vorgefertigte Datei behandelt und nicht pro Anwendung geändert:

; ****************************************************** *************
; * Copyright (C) 2005, Embed Inc (http://www.embedinc.com) *
; * *
; * Die Erlaubnis zum Kopieren dieser Datei wird erteilt, solange dies *
; * Copyright-Hinweis ist vollständig unter * enthalten
; * Beginn der Datei, ob die Datei als Ganzes kopiert wird *
; * oder teilweise und unabhängig davon, ob andere Informationen *
; * zur Kopie hinzugefügt. *
; * *
; * Der Inhalt dieser Datei darf beliebig verwendet werden, *
; * kommerziell oder anderweitig. Diese Datei wird "wie besehen" bereitgestellt, *
; * und Embed Inc erhebt keinen Anspruch auf Eignung für ein *
; * bestimmten Verwendungszweck und übernimmt keine Haftung, die sich daraus ergibt *
; * sein Nutzen. *
; ****************************************************** *************
;
; Konservierter Code für das STAT-Modul. Siehe die Header-Kommentare in der
; Datei QQQ_STAT.DSPIC für eine Beschreibung der möglichen Konfiguration
; Parameter.
;

;**************************************************** ******************************
;
; Konfigurationskonstanten.
;
/if [nicht [existieren "Name"]] dann
  /const name string = "ledstat"
  /endif

/if [nicht [existieren "nstbits"]] dann
  /const nstbits Ganzzahl = 48
  /endif
;
; Abgeleitete Konstanten.
;
/Block
  /var lokale ii-Ganzzahl
  /var lokal r reell
  /var lokaler s-String

  /const npattw integer = [div [+ nstbits 23] 24] ;N Programmspeicherworte pro Muster
  /set r [/ 1000 nstbits] ;ms Ticks pro Anzeigemuster-Slice
  /const add1ms integer = [rnd [/ 65536 r]] ;Akkumulatorinkrement pro ms
  /endblock

;**************************************************** ******************************
;
; Variablen.
;
;*******************
;
; Globaler Zustand.
;
.Abschnitt .stat, bss


;*******************
;
; Lokaler Staat.
;
alloc lastclock ; letzter 1-ms-Taktwert aktualisiert auf
alloc accslice ;Überlauf bei Zeit für nächsten Display-Slice
alloc Slice ;0-N aktuelle Anzeige-Slice-Nummer
alloc pattn ;0-N Anzahl der angezeigten Muster

.section .stat_code, Code
;**************************************************** ******************************
;
; Unterprogramm STAT_INIT
;
; Initialisieren Sie den von diesem Modul verwalteten Hardware- und Softwarestatus.
;
         glbsub stat_init, regg0

         mov tick1ms, w0
         mov w0, lastclock ;initiert letzten aktuellen Wert der Uhr mit
         Bewegung #65535, w0
         mov w0, accslice ;Erzwinge Slice-Aktualisierung als nächstes STAT_UPDATE
         mov w0, pattn ;aktuelle Musternummer auf ungültig setzen
         mov #[- nstbits 1], w0
         mov w0, Slice; die erste Aktualisierung beginnt am Anfang des Musters

         Urlaub

;**************************************************** ******************************
;
; Unterprogramm STAT_UPDATE
;
; Diese Routine soll periodisch von der Hauptereignisschleife aufgerufen werden.
; Er ermittelt den aktuellen Systemzustand, sofern er sich innerhalb des Stroms befindet
; Anzeigemuster und aktualisiert die Anzeige entsprechend.
;
; Das Timing für die Anzeige wird hier von der globalen TICK1MS-Uhr abgeleitet
; Variable. Diese Routine muss nicht mit einem bestimmten Timing aufgerufen werden.
; Da die verstrichene Zeit in ganzen ms erkannt wird, wird sie schneller aufgerufen als das
; kein Vorteil, obwohl es keinen Schaden anrichtet, außer mehr Hinrichtung zu nehmen
; Fahrräder. Wenn Sie es seltener anrufen, wird keine Zeit verloren gehen, aber
; bewirkt, dass die Anzeige in Schüben aktualisiert wird, sodass sie „stotternd“ erscheint
; wenn zu langsam. Es wird empfohlen, diese Routine ungefähr alle 1 bis 5 ms aufzurufen.
;
         glbsub stat_update, regg0 | regf1 | regf2 | regf3

stupd_recheck: ;hier zurück, nachdem ein Uhr-Tick verarbeitet wurde
         mov lastclock, w0 ;den letzten Uhrwert aktualisieren auf
         mov tick1ms, w1 ;holt die aktuelle Uhr
         siehe w0, w1
         bra z, stupd_leave ;kein neuer Tick, nichts mehr zu tun ?
;
; Ein neuer Uhrtick ist aufgetreten.
;
         addiere #1, w0 ;aktualisiere den letzten Uhrenwert, mit dem wir jetzt aktuell sind
         mov w0, letzte Uhr

         mov accslice, w0 ; Slice-Zeitakkumulator auf diesen neuen Tick aktualisieren
         mov #[v add1ms], w1
         addiere w0, w1, w0
         mov w0, accslice
         bra nc, stupd_recheck ;kein neuer Display-Slice in diesem Tick ?
         ;
         ; Weiter zum nächsten Display-Slice.
         ;
         mov Slice, w0 ;erhält die aktuelle 0-N-Slice-Nummer
         addiere #1, w0 ;erhöhe es
         mov #[- nstbits 1], w1 ;erhalte die maximale Slice-Nummer
         siehe w0, w1
         skip_leu ;noch im gültigen Bereich ?
         mov #0, w0 ;nein, zurück zu 0
         mov w0, Scheibe
;
; Die Anzeige wird aktualisiert.
;
; Bestimmen Sie das anzuzeigende Muster.
;
         pattnum ;Setze W0 auf die 0-N Nummer des anzuzeigenden Musters
;
; W0 enthält die 0-N Nummer des anzuzeigenden Musters.
;
         mov pattn, w1 ; Nummer des aktuell angezeigten Musters abrufen
         mov w0, pattn ;Nummer des jetzt anzuzeigenden Musters aktualisieren
         cp w0, w1 ;neues Muster mit vorherigem vergleichen
         bra z, stupd_hpatsl ; gleiches Muster wie letztes Mal ?
         ;
         ; Das Anzeigemuster hat sich geändert. Zurücksetzen auf Anzeige des Beginns von
         ; das Muster.
         ;
         Bewegung #0, w0
         mov w0, Slice ;auf erstes Slice im Muster setzen
         mov w0, accslice ;auf Anfang dieses Slice setzen

stupd_hpatsl: ;PATTN und SLICE alle gesetzt
;
; Aktualisieren Sie die Anzeige. PATTN ist die Nummer des anzuzeigenden Musters und
; SLICE ist der 0-N-Slice, der innerhalb des Musters angezeigt werden soll.
;
         ;
         ; Init W3:W2, um auf den Anfang der Mustertabelle im Programm zu zeigen
         ; Speicher.
         ;
         mov #tbloffset(tbl_patt), w2 ;init W3:W2 zeigt auf Tabellenanfang
         mov #tblpage(tbl_patt), w3
         und #0xFF, w3
         ;
         ; Aktualisieren Sie W3:W2 so, dass es auf den Anfang des ausgewählten Musters zeigt.
         ;
         mov pattn, w0 ;erhalte 0-N Musternummer
         mov #[* npattw 2], w1 ;Programmspeicheradressen pro Muster erhalten
         mul.uu w0, w1, w0 ;Adress-Offset für Musteranfang erstellen
         w2, w0, w2 hinzufügen; Startadresse dieses Musters erstellen
         addc w3, w1, w3
         ;
         ; Überspringe ganze Programmspeicherworte des Musters zu Punkt W3:W2
         ; zu dem Programmspeicherwort, das das anzuzeigende Bit enthält.
         ;
         mov Slice, w0 ; erhalte 0-N Slice-Nummer innerhalb dieses Musters
stupd_pwslice: ;Hierher zurück, um ganze Prog-Mem-Wörter zu überspringen
         cp w0, #24 ;vergleiche mit der Anzahl der Bits in einem Programmspeicherwort
         bra ltu, stupd_dpwslice ;Prog-Mem-Wort dieses Slice gefunden?
         sub #24, w0 ;nein, mache 0-N Anzahl von Bits innerhalb des nächsten Wortes
         addiere #2, w2 ;Aktualisiere Adresse zum nächsten Wort
         addc #0, w3
         jump stupd_pwslice ;zurück, um Slice innerhalb von Word erneut zu überprüfen
stupd_dpwslice: ;W0 ist 0-N Bit innerhalb des Wortes bei W3:W2
         ;
         ; W3:W2 ist die Adresse des gesamten Programmspeicherworts, das enthält
         ; das anzuzeigende Bit. W0 ist die 0-23 Nummer des Bits darin
         ; Wort.
         ;
         mov w3, Tblpag ; hohe Bits der Programmspeicheradresse zum Lesen setzen
         siehe w0, Nr. 16
         bra geu, stupd_hword ;Bit ist im oberen Wort ?
         tblrdl [w2], w1 ;nein, lies das niedrige Wort
         jump stupd_hbits ;Bitmuster haben
stupd_hword: ;das Bit ist im High-Word
         tblrdh [w2], w1 ;lesen Sie das hohe Wort
         sub #16, w0 ;bilde Bitnummer innerhalb dieses Teils des Wortes
stupd_hbits:
         ;
         ; W0 ist die 0-N-Nummer des Bits in W1, das angezeigt werden soll.
         ;
         lsr w1, w0, w1 ; verschiebt das ausgewählte Bit in das LSB von W1
         btsc w1, #0 ;bit ist aus ?
         jump stupd_don ;nein, das Bit ist eingeschaltet

         set_ledstat_off ;Anzeige dieses Slice
         Sprung stupd_recheck

stupd_don: ;Anzeige auf diesem Slice
         set_ledstat_on
         Sprung stupd_recheck

stupd_leave:
         Urlaub

////////////////////////////////////////////////// //////////////////////////////
//
// Makro PATTERN patt
//
// Erstellen Sie den Tabelleneintrag für ein Statusanzeigemuster. PATT muss a sein
// Folge von "*" und "-" Zeichen. "*" leuchtet die LED für diese Zeitscheibe
// und "-" macht es dunkel. PATT muss genau NSTBITS-Zeichen enthalten.
//
// Muster werden von links nach rechts angezeigt, wobei eine vollständige Sequenz anhält
// eine Sekunde.
//
// Dieses Makro gibt .PWORD-Anweisungen aus, um die Daten für das Muster zu definieren
// im Programmspeicher.
//
/ Makromuster
  /var local patt string = [qstr [arg 1]] ;erhält die Musterzeichenfolge
  /var local ind integer = 1 ;1-N Index in Musterzeichenfolge
  /var lokaler pchar-String; einzelnes Zeichen aus PATT extrahiert
  /var lokales Wort Integer ;aktuelles Programmspeicherwort, das erstellt wird
  /var local nbits integer ;Anzahl der im Programmspeicherwort gesetzten Bits
  /var local ii integer ;Scratch-Ganzzahl

  /set nbits 0 ;init auf keine gesetzten Bits im aktuellen Wort
  / setze Wort 16 #FFFFFF ; Initialisiere Bits im aktuellen Programmspeicherwort
  /loop ;Hier jedes neue Bit im Muster zurück
    /if [> ind nstbits] then ;done all bits ?
      /aufhören
      /endif

    /set pchar [sindx ind patt] ;Musterzeichen für dieses Bit erhalten
    /set ind [+ ind 1] ;aktualisiere den PATT-Index für das nächste Mal
    /if [nicht [oder [= pchar "*"] [= pchar "-"]]] dann
      /show 'Ungültiges Zeichen "'patt'" im Anzeigemuster'
         .Fehler "Patt-Zeichen"
         .Ende
      /stoppen
      /endif

    /if [= pchar "-"] then ;set this bit to off ?
      /set ii [shiftl 1 nbits] ;Maske für dieses Bit innerhalb des Wortes erstellen
      /set ii [~ ii] ;UND-Maske erstellen, um dieses Bit auszuschalten
      /set Wort [und Wort ii] ;wende die Maske an, um dieses Bit innerhalb von Wort auszuschalten
      /endif

    /set nbits [+ nbits 1] ;Zähle ein weiteres Bit, das im aktuellen Wort fertig ist
    /if [>= nbits 24] then ;müssen Sie ein ganzes Wort schreiben?
         .pword 0x[chars [int word "fw 6 lz base 16 usin"]]
      /set nbits 0 ;Zurücksetzen auf Beginn eines neuen Wortes
      /Wort setzen 16#FFFFFF ;Wort auf alle Bits zurücksetzen
      /endif
    /endloop ;zurück zum nächsten Eingabemusterbit

  /if [> nbits 0] then ;es gibt ungeschriebene Bits in WORD ?
         .pword 0x[chars [int word "fw 6 lz base 16 usin"]]
    /endif
  /endmac
Das ist genau das, wonach ich gesucht habe, mit verschiedenen LED-Mustern, um verschiedene Zustände der MCU anzuzeigen. Vielen Dank Oline!

Der Vorteil der Verwendung eines Hardware-Peripheriegeräts wie PWM oder eines Timers besteht darin, dass es einen Teil der Arbeit in Hardware erledigt und die MCU davon befreit, die Arbeit mit Anweisungen zu erledigen.

Der Nachteil der Verwendung eines Hardware-Peripheriegeräts zur Anzeige des Softwarestatus besteht darin, dass das Hardware-Peripheriegerät möglicherweise weiterarbeitet, nachdem die Software nicht mehr funktioniert, und dann würde die hardwaregesteuerte Statusanzeige einen irreführenden Status anzeigen.

Beispielsweise blinkt nach dem Einrichten der PWM eine LED ohne Eingriff der Software. Das ist schön, denn jetzt kann die Software einfacher sein, weil sie die LED nicht steuern muss. Das Hardware-PWM-Peripheriegerät funktioniert jedoch weiterhin, solange es einen Takt erhält. Dabei spielt es keine Rolle, ob die Software läuft oder abgestürzt ist. Diese PWM-gesteuerte LED ist also ein schlechter Indikator dafür, ob die Software läuft.

Das Umschalten der LED in einem Hardware-Timer-Interrupt vereinfacht die Software, da die Software die Zeit nicht verfolgen muss. Aber jetzt zeigt die blinkende LED nur an, ob dieser Hardware-Timer-Interrupt funktioniert. Die Hauptsoftwareschleife oder eine Aufgabe könnte blockiert sein, aber wenn der Interrupt noch bedient wird, blinkt die LED weiter. Diese interruptgesteuerte LED ist also kein guter Indikator dafür, ob die Software läuft.

Wenn Sie möchten, dass die blinkende LED wie ein Herzschlag ist, der anzeigt, dass die Software ordnungsgemäß ausgeführt wird, sollten Sie den LED-Blitz über die Software steuern. Und wenn Sie ein Multitasking-System mit mehreren Aufgaben haben, sollte die Software wahrscheinlich den Status jeder Aufgabe überprüfen, um festzustellen, ob die LED umgeschaltet werden sollte.

Ich habe PWM- oder Hardware-Timer verwendet, um LEDs zu blinken, die Zustände anzeigen (z. B. Alarmschwellenwerte), wobei das Blinken das Vorhandensein des Zustands anzeigt und das Aus das Fehlen des Zustands anzeigt. Die Software bestimmt immer noch das Vorhandensein oder Fehlen der Bedingung und versetzt die Hardware in den richtigen Modus, aber dann steuert die Hardware das LED-Blinkmuster, während die Bedingung vorhanden ist.

Erwägen Sie die Verwendung eines Watchdog-Resets, um nicht nur die Software im Falle eines Absturzes zurückzusetzen, sondern auch alle hardwaregesteuerten Anzeigen zurückzusetzen.

Der Hinweis auf den Hardware-Peripherie-Nachteil war ein toller Fang! Es hat den Zweck der Verwendung einer MCU-Status-LED vereitelt. Danke kkrabo!