O que está fazendo com que meu programa de LEDs do microcontrolador pare de funcionar?


11

Então, eu sou um novato completo e absoluto na programação. Eu fiz algumas coisas básicas em Arduinos (alternando literalmente LEDs e exibindo algo em um LCD) e estou tentando me ensinar como programar em C. Sou engenheiro de hardware, mas me incomoda que não consiga faça qualquer parte do firmware / software e não há cursos noturnos para ensiná-lo, e gostaria de aprimorar minhas opções de carreira. Estou lutando para entender como alguns desses comandos se encaixam e se deparam com um problema que simplesmente não consigo entender por que não está funcionando.

Então, eu tenho uma entrada e uma saída. Minha saída está alternando o portão de um FET que acende um LED. A entrada é proveniente de um portão AND. Assim, meu LED está sempre aceso e, quando recebo um sinal de entrada da porta AND (duas condições foram atendidas), quero que a saída (alternância de LED) fique LOW (desligue o LED. Como a saída também está conectada a uma das entradas AND, isso também tornará o sinal de entrada LOW.

O que eu quero fazer: Eu só quero ler a entrada como 'condições atendidas' e desligar o LED. Ele deve ser desligado por 1 segundo e ligado novamente. Se a entrada for ALTA novamente, o processo será repetido. Estou usando um simples toque para fazer a troca como a outra entrada AND e medi que a saída (entrada MCU) fica alta quando o botão é pressionado, mas a alternância do LED (saída) não se apaga. Meu código é (acho) bem simples, mas claramente não entendo algo corretamente, pois simplesmente não está funcionando.

Portanto, este é o código que estou 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 para mim, isso parece lógico. No estado usual, a saída é ALTA. Se a entrada receber o sinal da porta AND, o LED se apagará por 1 segundo e depois acenderá novamente.

O que fiz de errado, pois parece a maneira lógica de fazê-lo e simplesmente não consigo entender por que isso não funciona?

Se ajudar, estou usando o Nucleo F103RB. Quando uso o código 'piscar' e apenas acendo e apagando o LED dessa maneira, ele funciona bem; é apenas quando adiciono a instrução 'if' que dá errado.

Este é o circuito simplificado:

esquemático

simular este circuito - esquemático criado usando o CircuitLab

PS: Sei que não os adicionei no esquema, mas os portões AND têm resistores de pulldown nas entradas e saídas.


Funciona se você colocar "condições atendidas" diretamente no IN?
Transistor #

Isso não. Eu apertei o botão direto para IN e ainda não funcionou #
1860 Curioso

1
É uma boa idéia marcar variáveis ​​de entrada como voláteis, ou o compilador pode fazer algumas otimizações estranhas assumindo que não está sendo alterado fora do código.
Dirk Bruere

3
@DirkBruere: Você espera que a definição de DigitalInjá inclua volatile.
MSalters

3
Apenas uma dica para a próxima vez: tente manter o botão pressionado ao ligar (ou redefinir) a CPU (ou microcontrolador). Agora o que acontece?
um CVn

Respostas:


26

Eu pensaria que você precisaria de um loop em torno do seu código -

while(1)
{

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

Antes que você tenha a chance de pressionar o botão, o código será finalizado e encerrado. Você precisa de um tempo para manter repetidamente a instrução if.


O que torna isso diferente do meu? Eu posso ver o 'tempo', mas o que isso faz? Desculpas por todas as perguntas, mas eu realmente estou começando com zero conhecimento!
Curioso

1
@curious Antes que você tenha a chance de pressionar o botão, seu código será finalizado e encerrado. Você precisa de um tempo para manter repetidamente a instrução if. Normalmente, esse é o caso, a menos que exista algo diferente no microcontrolador que você está programando.
HandyHowie

9
"Você poderia explicar por que isso funcionou" - tudo em um loop while é repetido até que a condição seja zerada. Qual é a condição, você pode perguntar; essa é a parte entre parênteses após a palavra-chave "while" e, como você pode ver, a condição é definida como 1, portanto nunca é zero e, portanto, é repetida indefinidamente. Sem o loop while, o código é executado apenas uma vez e após o qual o software termina, mas com o loop while, o código é executado repetidamente até você desligar o hardware.
Jurgy

14
Seu erro provavelmente decorreu de ir ao Arduino para mbed. No Arduino, você geralmente coloca o código do aplicativo loop(), mas a estrutura do Arduino adiciona código que se comporta aproximadamente int main() { setup(); while(1) { loop(); } }.
ris8_allo_zen0

1
@Curious Yours funcionou. Infelizmente, ele foi executado precisamente uma vez, imediatamente quando você o ligou. Demorou talvez um microssegundo para rodar, e foi isso. Se você deseja que ele continue verificando a entrada e configurando a saída, é necessário dizer a ela para continuar fazendo isso. "while (some_condition)" é executado enquanto "some_condition" for verdadeiro, o que na linguagem C significa diferente de zero. Portanto, "while (1)" continua verificando a entrada para sempre, ou pelo menos enquanto estiver ligada de qualquer maneira.
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?
}

O processador executa as instruções sequencialmente . Começa com um salto para main()dentro do código de inicialização da biblioteca mbed de DigitalIne DigitalOut.
Em seguida, realiza a comparação ip == 0, executa a instrução dentro do {}e então main()termina ... sem mais instruções ... O que faz?

Ele foi redefinido devido à localização de operandos ilegais na memória flash vazia. Ou ele pode travar em um manipulador de falhas e piscar o SOS como os mbeds fazem. Isso depende de como isso é implementado e provavelmente irá além de você agora.
Mas se você estiver curioso, poderá pesquisar o ARM Fault Handling ou descobrir de onde main()é realmente chamado.

Agora, como consertar isso?

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
}

Muito obrigado pela explicação. O loop while permitiu que ele funcionasse. Infelizmente, não posso dar-lhe um +1 apenas ainda como meu representante é muito baixo, mas eu aprecio muito a resposta e explicação
Curious

Aha! Esse terceiro voto positivo na minha pergunta me permitiu votar sua resposta! Obrigado novamente
Curioso

1
@Curious Se você quiser que isso seja mais claro para você, o programador, você pode escrever algo como em while(1 == 1)vez de apenas while(1). O último é C idiomático, mas o primeiro é mais óbvio para um ser humano, pois "sempre será avaliado como verdadeiro". Qualquer compilador decente deve produzir o mesmo código binário para ambas as variantes.
um CVn

2
@ MichaelKjörling Eu discordo que é mais óbvio para um humano. Assim como seu cérebro lê as palavras pela forma e não pelo caráter, para um programador experiente, esses idiomas traduzem diretamente conceitos, em vez de interpretar o que cada afirmação individual está fazendo. Ao se afastar das construções idiomáticas, você força as pessoas a se envolverem com seu código em um nível inferior ao necessário para a compreensão; que, em uma grande base de código, resulta em muito trabalho mental desnecessário.
Chuu

1
@Chuu "por um ser humano [que não é um programador experiente]"
user253751 19/17/17 /

2

Como mencionado corretamente por outras pessoas, um loop permitiria que seu código fosse executado repetidamente. No entanto, existe uma maneira integrada de fazer isso no Arduino sem a necessidade de um whileloop. Isso é feito pela loopfunção - sua aplicabilidade ao seu problema depende de você usar o IDE do Arduino.

Deve ser algo como isto:

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

Sua função principal agora está oculta e só é adicionada ao seu programa quando compilada. Aqui está uma boa discussão sobre isso: http://forum.arduino.cc/index.php?topic=379368.0


Sim. Originalmente, eu fiz as coisas em um arduino, incluindo isso, então, ao mudar para o núcleo e o mbed IDE, não consegui entender por que não funcionou!
Curioso

1
Esta resposta depende do uso do sistema Arduino. O mbed é um sistema / conjunto de bibliotecas diferente e as funções loop()e setup()do Arduino não são usadas na maioria dos sistemas. Para referência, o Arduino simplesmente define main()algo parecido com isto:void setup(); void loop(); int main() { setup(); while (true) loop(); }
Cameron Tacklind 19/10/19

0

Se você está familiarizado com a montagem, isso também pode ser um pouco mais na sua zona de conforto:

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
Por favor , não use goto em nenhum idioma acima do assembly.
Jeroen3

Eu não estou familiarizado com a montagem, eu tenho medo!
Curioso

Eu sei disso, mas é isso!
Curioso

@ Jeroen3 A pergunta à qual você se vincula é respondida com "goto's são apropriados em alguns lugares", "nada está errado com goto se for usado corretamente" e "não há nada errado com goto em si". Concordo que em idiomas com exceções, o goto é supérfluo, mas especialmente em C, ele tem seus usos.
glglgl

@glglgl: Como Chuu mencionou acima, o código deve ser legível. goto** fortemente ** sugere "mágica acontecendo aqui", possivelmente com exceção de goto cleanup;. No exemplo aqui, o leitor ficará com a pergunta intrigante "o que há de tão especial que você não usou while(1) { }aqui ???".
MSalters
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.