Was bewirkt, dass mein Mikrocontroller-LED-Programm nicht mehr funktioniert?


11

Ich bin also ein VOLLSTÄNDIGER und absoluter Anfänger im Programmieren. Ich habe einige grundlegende Dinge mit Arduinos gemacht (buchstäblich LEDs umschalten und etwas auf einem LCD anzeigen) und ich versuche mir selbst beizubringen, wie man in C programmiert. Ich bin von Beruf Hardware-Ingenieur, aber es stört mich, dass ich nicht kann Machen Sie eine der Firmware- / Software-Seiten und es gibt keine Abendkurse, um sie zu unterrichten, und ich möchte meine Karriereoptionen fördern. Ich habe Probleme zu verstehen, wie einige dieser Befehle zusammenpassen, und bin auf ein Problem gestoßen, bei dem ich einfach nicht verstehen kann, warum es nicht funktioniert.

Ich habe also eine Eingabe und eine Ausgabe. Mein Ausgang schaltet das Gate eines FET um, der eine LED einschaltet. Der Eingang kommt von einem UND-Gatter. Meine LED leuchtet also immer und wenn ich ein Eingangssignal vom UND-Gatter erhalte (2 Bedingungen wurden erfüllt), soll der Ausgang (LED-Umschalter) auf LOW gehen (LED ausschalten. Da der Ausgang auch angeschlossen ist) Bei einem der UND-Eingänge wird auch das Eingangssignal auf LOW gestellt.

Was ich tun möchte: Ich möchte nur die Eingabe als "Bedingungen erfüllt" lesen und die LED ausschalten. Es sollte dann 1 Sekunde lang ausgeschaltet und wieder eingeschaltet sein. Wenn die Eingabe wieder auf HIGH geht, wird der Vorgang wiederholt. Ich benutze einen einfachen Druck, um den Schalter als anderen UND-Gatter-Eingang zu betätigen, und habe gemessen, dass der Ausgang (MCU-Eingang) hoch geht, wenn die Taste gedrückt wird, aber der LED-Schalter (Ausgang) nicht ausgeschaltet wird. Mein Code ist (glaube ich) verdammt einfach, aber ich verstehe etwas offensichtlich nicht richtig, da es einfach nicht funktioniert.

Das ist also der Code, den ich benutze:

#include "mbed.h"

DigitalIn ip(D7);
DigitalOut op(D8);

int main() {
    if (ip == 1){
        op = 0;
        wait (1.0);
        op = 1;
    }else{
        op = 1;
    }
}

Und das scheint mir logisch. Im Normalzustand ist der Ausgang HIGH. Wenn der Eingang das Signal vom UND-Gatter erhält, erlischt die LED 1 Sekunde lang und leuchtet dann wieder auf.

Was habe ich falsch gemacht, da dies logisch aussieht und ich einfach nicht verstehen kann, warum das nicht funktioniert?

Wenn es hilft, verwende ich den Nucleo F103RB. Wenn ich den "Blink" -Code verwende und die LED einfach so ein- und ausschalte, funktioniert das einwandfrei. Nur wenn ich die "if" -Anweisung hinzufüge, geht das schief.

Dies ist die vereinfachte Schaltung:

schematisch

simulieren Sie diese Schaltung - Schema erstellt mit CircuitLab

PS Ich weiß, dass ich sie nicht im Schaltplan hinzugefügt habe, aber die UND-Gatter haben Pulldown-Widerstände an den Ein- und Ausgängen.


Funktioniert es, wenn Sie "Bedingungen erfüllt" direkt in IN eingeben?
Transistor

Es tut nicht. Ich drückte den Knopf direkt auf IN und funktionierte immer noch nicht
Neugierig

1
Es ist eine gute Idee, Eingabevariablen als flüchtig zu markieren, oder der Compiler führt einige seltsame Optimierungen durch, indem er davon ausgeht, dass sie nicht von außerhalb des Codes geändert werden.
Dirk Bruere

3
@DirkBruere: Sie würden hoffen, dass die Definition von DigitalInbereits enthält volatile.
MSalters

3
Nur ein Hinweis für das nächste Mal: ​​Halten Sie die Taste gedrückt, wenn Sie die CPU (oder den Mikrocontroller) einschalten (oder zurücksetzen). Nun , was passiert?
Ein

Antworten:


26

Ich hätte gedacht, dass Sie eine Schleife um Ihren Code benötigen würden -

while(1)
{

    if (ip == 1){
       op = 0;
       wait (1.0);
       op = 1;}
    else {
       op = 1;}
}

Bevor Sie die Taste drücken können, ist Ihr Code fertig und wird beendet. Sie benötigen die Weile, um die if-Anweisung wiederholt auszuführen.


Was unterscheidet das von mir? Ich kann die "Weile" sehen, aber was macht das? Entschuldigung für alle Fragen, aber ich fange wirklich mit null Wissen an!
Neugierig

1
@curious Bevor Sie die Taste drücken können, ist Ihr Code fertig und wird beendet. Sie benötigen die Weile, um die if-Anweisung wiederholt auszuführen. Dies ist normalerweise der Fall, es sei denn, der von Ihnen programmierte Mikrocontroller weist etwas anderes auf.
HandyHowie

9
"Könnten Sie erklären, warum das funktioniert hat?" - Alles in einer while-Schleife wird wiederholt, bis die Bedingung auf Null aufgelöst ist. Was ist der Zustand, könnte man fragen; Dies ist der Teil in Klammern nach dem Schlüsselwort "while". Wie Sie sehen können, wird die Bedingung auf 1 gesetzt, ist also niemals Null und wird daher auf unbestimmte Zeit wiederholt. Ohne die while-Schleife wird der Code nur einmal ausgeführt und danach wird die Software beendet. Mit der while-Schleife wird der Code jedoch wiederholt ausgeführt, bis Sie die Hardware ausschalten.
Jurgy

14
Ihr Fehler ist wahrscheinlich darauf zurückzuführen, dass Sie nach Arduino zu mbed gegangen sind. In Arduino geben Sie normalerweise Ihren Anwendungscode ein loop(), aber das Arduino-Framework fügt Code hinzu, der sich ungefähr so ​​verhält int main() { setup(); while(1) { loop(); } }.
ris8_allo_zen0

1
@Curious Ihre hat funktioniert. Leider lief es genau einmal, sofort beim Einschalten. Der Lauf dauerte vielleicht eine Mikrosekunde, und das war es. Wenn Sie möchten, dass der Eingang weiterhin überprüft und der Ausgang eingestellt wird, müssen Sie ihn anweisen, den Vorgang fortzusetzen. "while (some_condition)" läuft so lange, wie "some_condition" wahr ist, was in der C-Sprache ungleich Null bedeutet. "While (1)" überprüft den Eingang also für immer oder zumindest so lange, wie er ohnehin eingeschaltet ist.
Graham

21
#include "mbed.h"

DigitalIn ip(D7);
DigitalOut op(D8);

int main() {
    if (ip == 1){
        op = 0;
        wait (1.0);
        op = 1;
    }else{
        op = 1;
    }
    // and now the program ends? What to do?
}

Der Prozessor führt die Anweisungen nacheinander aus . Es beginnt mit einem Sprung main()aus dem Initialisierungscode der mbed-Bibliothek von DigitalInund DigitalOut.
Führt dann den Vergleich durch ip == 0, führt die Anweisung innerhalb der aus {}und main()endet dann ... keine weiteren Anweisungen ... Was macht es?

Es könnte zurückgesetzt werden, weil unzulässige Operanden im leeren Flash-Speicher gefunden wurden. Oder es könnte in einem Fehlerbehandler hängen und SOS blinken, wie es mbeds tun. Dies hängt davon ab, wie dies implementiert wird, und wird wahrscheinlich im Moment über Sie hinausgehen.
Wenn Sie jedoch neugierig sind, können Sie nach ARM Fault Handling suchen oder herausfinden, woher der main()Anruf tatsächlich stammt.

Wie kann man das beheben?

int main() {
    // Add a while(1) infinite loop
    while(1){
        if (ip == 1){
            op = 0;
            wait (1.0);
            op = 1;
        }else{
            op = 1;
        }
    }
    // Program never gets here
}

Vielen Dank für die Erklärung. Die while-Schleife ermöglichte es zu arbeiten. Leider kann ich Ihnen noch keine +1 geben, da mein Repräsentant zu niedrig ist, aber ich schätze die Antwort und Erklärung sehr
Neugierig

Aha! Diese dritte Gegenstimme zu meiner Frage hat mich Ihre Antwort abstimmen lassen!
Neugierig

1
@Curious Wenn Sie möchten, dass dies für Sie als Programmierer klarer wird, können Sie so etwas wie while(1 == 1)nur schreiben while(1). Letzteres ist idiomatisch C, aber Ersteres ist für einen Menschen offensichtlicher, da "immer als wahr bewertet wird". Jeder anständige Compiler sollte für beide Varianten den gleichen Binärcode erzeugen.
Ein Lebenslauf vom

2
@ MichaelKjörling Ich würde nicht zustimmen, dass es für einen Menschen offensichtlicher ist. So wie Ihr Gehirn Wörter nach ihrer Form anstatt nach ihrem Charakter liest, werden diese Redewendungen für einen erfahrenen Programmierer direkt in Konzepte übersetzt, anstatt zu interpretieren, was jede einzelne Aussage tut. Indem Sie sich von idiomatischen Konstrukten entfernen, zwingen Sie die Menschen, sich auf einer niedrigeren Ebene mit Ihrem Code zu beschäftigen, als dies für das Verständnis erforderlich ist. was über eine große Codebasis zu einer Menge unnötiger mentaler Arbeit führt.
Chuu

1
@Chuu "von einem Menschen [der kein erfahrener Programmierer ist]"
user253751

2

Wie von anderen richtig erwähnt, würde eine Schleife es Ihrem Code ermöglichen, wiederholt ausgeführt zu werden. Es gibt jedoch eine integrierte Möglichkeit, dies für Arduino zu tun, ohne dass eine whileSchleife erforderlich ist. Dies geschieht durch die loopFunktion - ihre Anwendbarkeit auf Ihr Problem hängt davon ab, ob Sie die Arduino IDE verwenden.

Es sollte ungefähr so ​​aussehen:

#include "mbed.h"

DigitalIn ip(D7);
DigitalOut op(D8);

void setup() {
    // any code before loop is run
}

void loop() {
    if (ip == 1){
        op = 0;
        wait (1.0);
        op = 1;
    }else{
        op = 1;
    }
}

Ihre Hauptfunktion ist jetzt ausgeblendet und wird erst beim Kompilieren zu Ihrem Programm hinzugefügt. Hier ist eine gute Diskussion dazu: http://forum.arduino.cc/index.php?topic=379368.0


Ja. Ich habe ursprünglich Dinge auf einem Arduino gemacht, einschließlich dieser. Als ich zum Nucleo und zur mbed IDE wechselte, konnte ich nicht verstehen, warum es nicht funktionierte!
Neugierig

1
Diese Antwort basiert auf der Verwendung des Arduino-Systems. mbed ist ein anderes System / Satz von Bibliotheken und die Funktionen loop()und setup()von Arduino werden in den meisten Systemen nicht verwendet. Als Referenz definiert Arduino einfach so main()etwas:void setup(); void loop(); int main() { setup(); while (true) loop(); }
Cameron Tacklind

0

Wenn Sie mit der Montage vertraut sind, kann dies auch in Ihrer Komfortzone etwas mehr sein:

int main () {

//A label or function similar to assembly

label:

    if (ip == 1){

        op = 0;

        wait (1.0);

        op = 1;

    }else{

        op = 1;

    }

// Goto used same as "jmp" in assembly

goto label;

// Program never gets here

}}


3
Bitte verwenden Sie goto in keiner der oben genannten Sprachen.
Jeroen3

Ich fürchte, ich bin überhaupt nicht mit Montage vertraut!
Neugierig

Ich weiß davon, aber das ist es auch!
Neugierig

@ Jeroen3 Die Frage, auf die Sie verlinken, wird mit "goto's sind an einigen Stellen angemessen", "goto ist nicht falsch, wenn es richtig verwendet wird" und "goto an sich ist nichts falsch" beantwortet. Ich stimme zu, dass in Sprachen mit Ausnahmen goto überflüssig ist, aber insbesondere in C hat es seine Verwendung.
glglgl

@glglgl: Wie oben erwähnt, sollte Code lesbar sein. goto** stark ** schlägt vor, dass "Magie hier vor sich geht", möglicherweise mit Ausnahme von goto cleanup;. Im Beispiel hier bleibt dem Leser die rätselhafte Frage "Was ist so besonders, dass Sie es hier nicht verwendet while(1) { }haben?".
MSalters
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.