ATmega328p PIN leyendo

1
int main(void)
{

DDRD = 0x00 ;
DDRB = DDRB | 0b00100000 ;
while (1)
{
     while(!(PIND & (1<<6))){
       PORTB |= 1<<PORTB5 ;  
    }
    while((PIND & (1<<6)))  {
        PORTB &= ~(1<<PORTB5) ;
    }

}
return 0;
}

Estoy tratando de crear un sistema de seguridad básico mediante el uso de un interruptor que PIND7 detecta cuando se rompe y luego establece PB5. Y vicd versa, cuando se establece el interruptor, PIND7 recoge la señal baja y luego borra el bit en PB5. El microcontrolador no tiene ningún problema cuando se establece el interruptor, borra el bit en PB5 inmediatamente, pero cuando el interruptor se rompe, toma alrededor de 30 segundos para que se establezca el bit en PB5. Gracias por cualquier ayuda que pueda dar, pido disculpas si mi código es descuidado, solo soy un principiante

    
pregunta Ecrooks

1 respuesta

1

Una tabla de verdad simple generalmente ayuda mucho.

Este es mi intento de descifrarlo a partir de tu texto:

PIND6 | PORTB5
  0   |   1
  1   |   0

Esta tabla de verdad simplemente dice, si PIND6 es 0, entonces PORTB5 debería ser 1, y "viceversa". En términos adecuados, PORTB5 es el NOT lógico de PIND6.

Esta es la ecuación matemática de lo que queremos:
PORTB5 =! PIND6 que es lo mismo que \ $ \ text {PORTB} _5 = \ overline {\ text {PIND} _6} \ $ .

No creo que quieras tener dos bucles while en tu bucle major while. Esa no es una buena manera de verificar un estado, ya que puede quedar atrapado en ellos. Como creo que estas recibiendo.

En su lugar, lo que debe hacer es usar una instrucción if o simplemente asignar PORTD, o usar cualquiera de ellos junto con una entrada de imputación. Les mostraré a los tres con un espacio entre ellos. No debes guardar los tres, debes elegir uno de ellos.

  • El one-liner hace que sea difícil de entender.
  • La instrucción if es mucho más fácil de entender.
  • El debouncer detecta cuando el interruptor cambia la entrada, la entrada puede cambiar rápidamente a una lógica 1, una lógica 0, cientos de veces en un par de microsegundos cuando se está realizando la transición, y no desea que su salida también cambie de esa manera. Entonces, en lugar de eso, detectamos un cambio y luego miramos un poco más tarde cuando el ruido de conmutación se ha calmado.

Aquí hay un código no probado:

int main(void)
{
    DDRD = 0x00 ;
    DDRB = DDRB | 0b00100000 ;
    unsigned int debounce = 0; //remove this line if you don't care about debouncing
    char old_PIND = PIND;//remove this line if you don't care about debouncing
    while (1)
    {
        ////////////////////////////////////////////////
        //You can do either this:
        ////////////////////////////////////////////////
        PORTB = (PORTB&(~(1<<PORTB5)))|(~((PIND&(1<<6))>>1));
        //(PORTB&(~(1<<PORTB5))) => PORTB but with a 0 on bit 5
        //(~((PIND&(1<<6))>>1)) => PIND, but only 6th bit, inverted and shifted 1 step ->
        //And then just OR them together
        //You could probably remove some parenthesis, but I prefer having more than fewer
        ////////////////////////////////////////////////
        //Or you can do this, it will give you the same result
        ////////////////////////////////////////////////
        if(PIND&(1<<6)){//If it's a 1
            PORTB &= ~(1<<PORTB5);//then set PORTB5 to 0
        }else{
            PORTB |= (1<<PORTB5); //if PIND6 is a 0, set PORTB5 to 1
        }

        ////////////////////////////////////////////////
        //Or you can do this if you want debouncing
        ////////////////////////////////////////////////
        if(debounce==0){
            if(old_PIND!=PIND){
                //if we're in here, it means that the input has changed
                //and that the input may bounce a lot for the next couple of microseconds. 

                //we want to wait some time and then use the value we get later
                //because that value will (hopefully) be stable, without any burst noise. 

                debounce = 10000;//This sets the debounce-timer
                //if you want to do this "properly", then you should use one of 
                //the built in timers that Atmega328P supports,
                //instead of using a variable like I do. But this will work.               
            }else{
                //if we're in here, it means that the input has stayed the same 
                //for one debounce-timer, so now it's stable.

                //same code as before: 
                if(PIND&(1<<6)){//If it's a 1
                    PORTB &= ~(1<<PORTB5);//then set PORTB5 to 0
                }else{
                    PORTB |= (1<<PORTB5); //if PIND6 is a 0, set PORTB5 to 1
                }
            }
            old_PIND = PIND;//update old_PIND so we can detect changes
        }else{
            debounce-=1;
        }


    }
    return 0;
}

Técnicamente, simplemente reemplaza tus sentencias while con sentencias if, aprende la palabra "inversión lógica" y estarás en el lado bueno.

Si desea ser piadoso al respecto, o "correcto", debe usar interrupciones junto con los temporizadores internos, ya que hacen que el código sea más eficiente. Pero este código resolverá el problema tal como lo ha presentado.

    
respondido por el Harry Svensson

Lea otras preguntas en las etiquetas