¿Qué está causando que mi programa LED de microcontrolador deje de funcionar?

11

Por lo tanto, soy un novato COMPLETO y absoluto en programación. He hecho algunas cosas básicas en Arduinos (literalmente alternando los LED y mostrando algo en una pantalla LCD) y estoy tratando de enseñarme a mí mismo cómo programar en C. Soy un ingeniero de hardware por profesión, pero me molesta que no pueda hacer cualquier parte del firmware / software y no hay cursos nocturnos para enseñarlo, y me gustaría ampliar mis opciones de carrera. Me cuesta entender cómo se combinan algunos de estos comandos y me he encontrado con un problema que no puedo entender por qué no funciona.

Entonces, tengo una entrada y una salida. Mi salida es alternar la puerta de un FET que enciende un LED. La entrada proviene de una puerta AND. Por lo tanto, mi LED siempre está encendido, y cuando recibo una señal de entrada de la compuerta AND (se han cumplido 2 condiciones) quiero que la salida (alternar LED) sea BAJA (apague el LED. Como la salida también está conectada a una de las entradas AND, esto también hará que la señal de entrada sea BAJA.

Lo que quiero hacer: solo quiero leer la entrada como 'condiciones cumplidas' y apagar el LED. Luego debe estar apagado durante 1 segundo y volver a encenderse. Si la entrada vuelve a ser ALTA, el proceso se repite. Estoy usando un simple impulso para hacer el cambio como la otra entrada de compuerta AND y he medido que la salida (entrada de MCU) sube cuando se presiona el botón, pero el interruptor LED (salida) no se apagará. Mi código es (creo) bastante simple, pero claramente no entiendo algo correctamente, ya que simplemente no funciona.

Entonces este es el código que estoy 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;
    }
}

Y para mí, eso parece lógico. En el estado habitual, la salida es ALTA. Si la entrada recibe la señal de la puerta AND, el LED se apagará durante 1 segundo y luego se encenderá nuevamente.

¿Qué es lo que he hecho mal ya que parece la forma lógica de hacerlo y no puedo entender por qué eso no funciona?

Si ayuda, estoy usando el Nucleo F103RB. Cuando uso el código de 'parpadeo' y simplemente enciendo y apago el LED de esa manera, funciona bien, es solo cuando agrego la declaración 'si' que sale mal.

Este es el circuito simplificado:

esquemático

simular este circuito : esquema creado con CircuitLab

PD: Sé que no los agregué en el esquema, pero las compuertas AND tienen resistencias pulldown en las entradas y salidas.

Curioso
fuente
¿Funciona si pones "condiciones cumplidas" directamente en IN?
Transistor
No es asi. Metí el botón directamente a IN y aún no funcionaba
Curioso
1
Es una buena idea marcar las variables de entrada como volátiles, o el compilador podría hacer algunas optimizaciones extrañas suponiendo que no se está cambiando desde fuera del código.
Dirk Bruere
3
@DirkBruere: Esperarías que la definición de DigitalInya incluya volatile.
MSalters
3
Solo una pista para la próxima vez: intente mantener presionado el botón cuando encienda (o reinicie) la CPU (o microcontrolador). Ahora que pasa?
un CVn

Respuestas:

26

Pensé que necesitarías un bucle alrededor de tu código.

while(1)
{

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

Antes de tener la oportunidad de presionar el botón, su código habrá terminado y salido. Necesita el tiempo para mantener la instrucción if ejecutándose repetidamente.

HandyHowie
fuente
¿Qué lo hace diferente al mío? Puedo ver el 'tiempo' pero ¿qué hace eso? ¡Disculpas por todas las preguntas, pero realmente estoy empezando con cero conocimiento!
Curioso
1
@curious Antes de tener la oportunidad de presionar el botón, su código habrá terminado y salido. Necesita el tiempo para mantener la instrucción if ejecutándose repetidamente. Este suele ser el caso, a menos que haya algo diferente sobre el microcontrolador que está programando.
HandyHowie
99
"¿Podría explicar por qué funcionó?" - Todo en un ciclo while se repite hasta que la condición se resuelve a cero. ¿Cuál es la condición? esa es la parte entre paréntesis después de la palabra clave "while" y, como puede ver, la condición se establece en 1, por lo que nunca es cero y, por lo tanto, se repite indefinidamente. Sin el bucle while, el código se ejecuta solo una vez y después de lo cual el software termina, pero con el bucle while el código se ejecuta repetidamente hasta que apague el hardware.
Jurgy
14
Su error probablemente se debió a ir a Arduino a mbed. En Arduino, usualmente ingresa el código de su aplicación loop(), pero el marco Arduino agrega código que se comporta más o menos como int main() { setup(); while(1) { loop(); } }.
ris8_allo_zen0
1
@Curious Yours funcionó. Desafortunadamente, se ejecutó precisamente una vez, inmediatamente cuando lo encendió. Tardó tal vez un microsegundo en ejecutarse, y eso fue todo. Si desea que siga comprobando la entrada y configurando la salida, debe indicarle que siga haciéndolo. "while (some_condition)" se ejecuta mientras "some_condition" sea verdadero, lo que en lenguaje C significa que no es cero. Entonces "while (1)" sigue verificando la entrada para siempre, o al menos mientras esté encendida de todos modos.
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?
}

El procesador ejecuta las instrucciones secuencialmente . Comienza con un salto main()desde dentro del código de inicialización de la biblioteca mbed de DigitalIny DigitalOut.
Luego realiza la comparación ip == 0, ejecuta las instrucciones dentro de {}y luego main()termina ... no más instrucciones ... ¿Qué hace?

Podría restablecerse debido a la búsqueda de operandos ilegales en la memoria flash vacía. O podría colgarse en un controlador de fallas y parpadear SOS como lo hacen los mbeds. Esto depende de cómo se implemente, y probablemente irá más allá de usted en este momento.
Pero si tiene curiosidad, puede investigar ARM Fault Handling o averiguar de dónde main()se llama realmente.

Ahora, ¿cómo arreglar esto?

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
}
Jeroen3
fuente
Muchas gracias por la explicación. El ciclo while le permitió funcionar. Desafortunadamente, no puedo darte un +1 todavía porque mi reputación es demasiado baja, pero agradezco mucho la respuesta y la explicación
Curioso el
¡Ajá! ¡Ese tercer voto positivo sobre mi pregunta me ha permitido votar su respuesta! Gracias de nuevo
curioso el
1
@Curious Si quieres que esto sea más claro para ti, el programador, puedes escribir algo así en while(1 == 1)lugar de solo while(1). Este último es idiomático C, pero el primero es más obvio para un ser humano ya que "siempre se evaluará como verdadero". Cualquier compilador decente debería producir el mismo código binario para ambas variantes.
un CVn
2
@ MichaelKjörling No estaría de acuerdo, es más obvio para un humano. Al igual que su cerebro lee palabras por su forma en lugar de por carácter, para un programador experimentado estas expresiones idiomáticas se traducen directamente en conceptos en lugar de interpretar lo que está haciendo cada declaración individual. Al alejarse de las construcciones idiomáticas, obliga a las personas a comprometerse con su código en un nivel inferior al necesario para la comprensión; que sobre una base de código grande se suma a una gran cantidad de trabajo mental innecesario.
Chuu
1
@Chuu "por un ser humano [que no es un programador experimentado]"
usuario253751
2

Como otros han mencionado correctamente, un bucle permitiría que su código se ejecute repetidamente. Sin embargo, hay una forma integrada de hacer esto para Arduino sin la necesidad de un whilebucle. La loopfunción lo hace: su aplicabilidad a su problema depende de si usa el IDE de Arduino.

Debería verse más o menos así:

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

Su función principal ahora está oculta y solo se agrega a su programa cuando se compila. Aquí hay una buena discusión sobre esto: http://forum.arduino.cc/index.php?topic=379368.0

OLLEY102
fuente
Si. Originalmente hice cosas en un arduino, incluido esto, así que cuando cambié al núcleo y al IDE de mbed no pude entender por qué no funcionó.
Curioso
1
Esta respuesta se basa en el uso del sistema Arduino. mbed es un sistema / conjunto de bibliotecas diferente y las funciones loop()y setup()de Arduino no se usan en la mayoría de los sistemas. Como referencia, Arduino simplemente define un main()algo como esto:void setup(); void loop(); int main() { setup(); while (true) loop(); }
Cameron Tacklind
0

Si no eres muy hábil con el montaje, esto también podría estar un poco más en tu zona de confort:

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

}

Susmit Agrawal
fuente
3
Por favor, no use Goto en cualquier idioma por encima de montaje.
Jeroen3
¡No estoy familiarizado con el montaje, me temo!
Curioso
Lo sé pero eso es todo.
Curioso
@ Jeroen3 La pregunta a la que se vincula se responde con "los goto son apropiados en algunos lugares", "No hay nada malo con goto si se usa correctamente" y "No hay nada malo con goto en sí mismo". Estoy de acuerdo en que en los lenguajes que tienen Excepciones, goto es superfluo, pero especialmente en C, tiene sus usos.
glglgl
@glglgl: Como Chuu mencionó anteriormente, el código debería ser legible. goto** fuertemente ** sugiere "magia sucediendo aquí", posiblemente con la excepción de goto cleanup;. En el ejemplo aquí, el lector se quedará con la pregunta desconcertante "¿qué es tan especial que no while(1) { }usaste aquí?".
MSalters