Cosa sta causando l'interruzione del mio programma LED del microcontrollore?


11

Quindi, sono un principiante COMPLETO ed assolutamente programmatore. Ho fatto alcune cose di base sugli Arduinos (letteralmente alternando i LED e mostrando qualcosa su un LCD) e sto cercando di auto-insegnarmi come programmare in C. Sono un ingegnere hardware di professione, ma mi dà fastidio che non posso fare qualsiasi parte del firmware / software e non ci sono corsi serali per insegnarlo, e vorrei migliorare le mie opzioni di carriera. Faccio fatica a capire come alcuni di questi comandi vanno insieme e si sono imbattuti in un problema che non riesco proprio a capire perché non funziona.

Quindi, ho un input e un output. La mia uscita sta attivando il gate di un FET che accende un LED. L'ingresso proviene da un gate AND. Quindi, il mio LED è sempre acceso e quando ricevo un segnale di ingresso dalla porta AND (sono state soddisfatte 2 condizioni) voglio che l'uscita (interruttore a LED) diventi BASSA (spengo il LED. Poiché anche l'uscita è collegata a uno degli ingressi AND, questo trasformerà anche il segnale di ingresso BASSO.

Cosa voglio fare: voglio solo leggere l'ingresso come "condizioni soddisfatte" e spegnere il LED. Dovrebbe quindi essere spento per 1 secondo e riaccendere. Se l'ingresso torna di nuovo ALTO, il processo si ripete. Sto usando una semplice spinta per fare il cambio come l'altro ingresso della porta AND e ho misurato che l'uscita (ingresso MCU) diventa alta quando si preme il pulsante, ma il LED (uscita) non si spegne. Il mio codice è (penso) dannatamente semplice, ma chiaramente non capisco qualcosa di corretto in quanto semplicemente non funziona.

Quindi questo è il codice che sto usando:

#include "mbed.h"

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

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

E a me sembra logico. Nel solito stato, l'uscita è ALTA. Se l'ingresso riceve il segnale dalla porta AND, il LED si spegne per 1 secondo, quindi si riaccende.

Che cosa ho fatto di sbagliato in quanto sembra il modo logico per farlo e non riesco proprio a capire perché non funziona?

Se aiuta, sto usando il Nucleo F103RB. Quando uso il codice "lampeggio" e accendo e spengo il LED in quel modo, funziona bene, è solo quando aggiungo l'istruzione "if" che va storto.

Questo è il circuito semplificato:

schematico

simula questo circuito - Schema creato usando CircuitLab

PS So di non averli aggiunti nello schema, ma le porte AND hanno resistori a discesa sugli ingressi e sull'uscita.


Funziona se metti "condizioni soddisfatte" direttamente in IN?
Transistor

Non è così. Ho bloccato il pulsante direttamente su IN e ancora non ha funzionato
Curioso

1
È una buona idea contrassegnare le variabili di input come volatili, altrimenti il ​​compilatore potrebbe fare alcune strane ottimizzazioni supponendo che non venga modificato dall'esterno del codice.
Dirk Bruere,

3
@DirkBruere: speri che la definizione DigitalInincluda già volatile.
MSalters,

3
Solo un suggerimento per la prossima volta: prova a tenere premuto il pulsante quando accendi (o ripristini) la CPU (o il microcontrollore). Ora che succede?
un CVn

Risposte:


26

Avrei pensato che avresti bisogno di un ciclo attorno al tuo codice -

while(1)
{

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

Prima che tu abbia la possibilità di premere il pulsante, il codice sarà terminato ed uscito. È necessario un po 'di tempo per mantenere ripetutamente in esecuzione l'istruzione if.


Cosa lo rende diverso dal mio? Riesco a vedere il "while" ma cosa fa? Mi scuso per tutte le domande, ma sto davvero iniziando con una conoscenza zero!
Curioso

1
@curious Prima di avere la possibilità di premere il pulsante, il codice sarà terminato ed uscito. È necessario un po 'di tempo per mantenere ripetutamente in esecuzione l'istruzione if. Questo è normalmente il caso, a meno che non ci sia qualcosa di diverso nel microcontrollore che stai programmando.
HandyHowie,

9
"Potresti spiegare perché ha funzionato" - Tutto in un ciclo while viene ripetuto fino a quando la condizione non si risolve a zero. Qual è la condizione, potresti chiedere; questa è la parte tra parentesi dopo la parola chiave "while" e come puoi vedere, la condizione è impostata su 1, quindi non è mai zero e quindi si ripete all'infinito. Senza il ciclo while il codice viene eseguito solo una volta e dopo di che il software termina, ma con il ciclo while il codice viene eseguito ripetutamente fino a quando non si gira l'hardware.
Jurgy,

14
Il tuo errore probabilmente deriva dall'andare ad Arduino su mbed. In Arduino di solito inserisci il codice dell'applicazione loop(), ma il framework Arduino aggiunge codice che si comporta in modo approssimativo int main() { setup(); while(1) { loop(); } }.
ris8_allo_zen0

1
@Curious Yours ha funzionato. Sfortunatamente ha funzionato esattamente una volta, immediatamente quando l'hai acceso. Ci volle forse un microsecondo per funzionare, e basta. Se vuoi che continui a controllare l'input e a impostare l'output, devi dirlo per continuare a farlo. "while (some_condition)" funziona fino a quando "some_condition" è vero, che nel linguaggio C significa diverso da zero. Quindi "while (1)" continua a controllare l'input per sempre, o almeno fino a quando rimane acceso.
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?
}

Il processore esegue le istruzioni in sequenza . Inizia con un salto main()all'interno del codice di inizializzazione della libreria mbed di DigitalIne DigitalOut.
Quindi esegue il confronto ip == 0, esegue le istruzioni all'interno {}e quindi main()termina ... non più istruzioni ... Cosa fa?

Potrebbe ripristinarsi a causa della ricerca di operandi illegali nella memoria flash vuota. Oppure potrebbe bloccarsi in un gestore degli errori e lampeggiare SOS come fanno i mbeds. Questo dipende da come viene implementato e probabilmente andrà oltre te in questo momento.
Ma se sei curioso puoi cercare ARM Fault Handling o scoprire da dove main()viene effettivamente chiamato.

Ora, come risolvere questo?

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
}

Grazie mille per la spiegazione. Il ciclo while gli ha permesso di funzionare. Sfortunatamente non posso darti un +1 ancora perché il mio rappresentante è troppo basso ma apprezzo molto la risposta e la spiegazione
Curioso

Aha! Quel terzo voto sulla mia domanda mi ha permesso di votare la tua risposta! Grazie ancora
Curioso il

1
@Curious Se vuoi che questo sia più chiaro per te, il programmatore, potresti scrivere qualcosa di simile while(1 == 1)anziché solo while(1). Il secondo è C idiomatico, ma il primo è più ovvio per un essere umano in quanto "valuterà sempre come vero". Qualsiasi compilatore decente dovrebbe produrre lo stesso codice binario per entrambe le varianti.
un CVn

2
@ MichaelKjörling Non sono d'accordo è più ovvio per un essere umano. Proprio come il tuo cervello legge le parole in base alla loro forma anziché al carattere, per un programmatore esperto questi idiomi si traducono direttamente in concetti piuttosto che nell'interpretazione di ciò che ogni singola affermazione sta facendo. Allontanandosi dai costrutti idiomatici costringi le persone a interagire con il tuo codice a un livello inferiore a quello necessario per la comprensione; che su una grande base di codice si aggiunge a molto lavoro mentale inutile.
Chuu,

1
@Chuu "di un essere umano [che non è un programmatore esperto]"
user253751

2

Come correttamente menzionato da altri, un ciclo consentirebbe l'esecuzione ripetuta del codice. Tuttavia, esiste un modo integrato per farlo per Arduino senza la necessità di un whileloop. Questo viene fatto dalla loopfunzione: la sua applicabilità al tuo problema dipende dall'uso dell'IDE di Arduino.

Dovrebbe assomigliare a qualcosa di simile a questo:

#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;
    }
}

La tua funzione principale è ora nascosta e viene aggiunta al tuo programma solo quando compilata. Ecco una buona discussione su questo: http://forum.arduino.cc/index.php?topic=379368.0


Si. Inizialmente avevo fatto cose su un arduino, incluso questo, quindi quando passavo al nucleo e all'IDE mbed non riuscivo a capire perché non funzionasse!
Curioso,

1
Questa risposta si basa sull'uso del sistema Arduino. mbed è un sistema / set di librerie diverso e le funzioni loop()e setup()di Arduino non sono utilizzate nella maggior parte dei sistemi. Per riferimento, Arduino definisce semplicemente main()qualcosa del genere:void setup(); void loop(); int main() { setup(); while (true) loop(); }
Cameron Tacklind,

0

Se hai familiarità con il montaggio, questo potrebbe essere un po 'più nella tua zona di comfort:

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
Si prega di non usare goto in nessuna lingua sopra il montaggio.
Jeroen, 3

Non ho alcuna familiarità con il montaggio, temo!
Curioso,

Lo so ma questo è tutto!
Curioso,

@ Jeroen3 Alla domanda a cui ti colleghi viene risposto "goto è appropriato in alcuni punti", "Non c'è niente di sbagliato in goto se usato correttamente" e "Non c'è niente di sbagliato in goto in sé". Concordo sul fatto che nelle lingue con Eccezioni, goto è superfluo, ma soprattutto in C, ha i suoi usi.
glglgl

@glglgl: Come ha già detto Chuu, il codice dovrebbe essere leggibile. goto** fortemente ** suggerisce "la magia sta succedendo qui", possibilmente con l'eccezione di goto cleanup;. Nell'esempio qui, il lettore verrà lasciato con la domanda sconcertante "cosa c'è di così speciale che non hai usato while(1) { }qui ???".
Salterio,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.