El rebote de botones no funciona [cerrado]

-2

Quiero alternar un led con un botón y un ATMega16a, pero por alguna razón el comportamiento de alternar parece un poco aleatorio.

#include <avr/io.h>
#include <avr/interrupt.h>

/* if true we toggle PB0 */
volatile uint8_t toggle = 0;
/* contains last value of PD2 */
volatile uint8_t newval = 0;
volatile uint8_t oldval = 0;

int main(void) {
    /* set PB0 as output and PD2 as input */
    DDRB |=  (1 << PB0);
    DDRD &= ~(1 << PD2);

    /* enable timer such that we can pool every 16ms */
    TIMSK |= (1 << TOIE0);
    TCCR0 |= (1 << CS00) | (1 << CS01);

    sei();

    for (;;) {
        if (toggle) {
            PORTB ^= (1 << PB0);
        }
    }

    return 0;
}

ISR (TIMER0_OVF_vect) {
    /* get new input value */
    newval = PIND & (1 << PD2);

    /* only handles button presses */
    if (newval && !oldval) {
        if (toggle) {
            toggle = 0;
        } else {
            toggle = 1;
        }
    }

    oldval = newval;
}

¿Hay algún problema con el código o es un problema de hardware?

    
pregunta bodokaiser

4 respuestas

0

Encontré el problema: realmente no tenía nada que ver con el desalojo sino con el estado del pin de entrada. Necesitaba colocar la resistencia de activación interna del pin de entrada up PORTD |= (1 << PD2); .

    
respondido por el bodokaiser
2

Un interruptor de botón típico tendrá un rebote significativo, que puede durar muchas decenas de milisegundos, dependiendo del interruptor en particular.

Es perfectamente posible que cuando cierre el interruptor, en el momento en que el controlador ISR obtenga el control, el contacto del interruptor rebote. Debe realizar varias lecturas del conmutador (o rebotar externamente).

Estadísticamente, habrá algunas ocasiones en las que la interrupción del temporizador se produzca al mismo tiempo que el interruptor rebota.

    
respondido por el Peter Smith
0

Dependiendo de cómo esté configurado su hardware, siempre puede reducir el rebote con un circuito de condensador y resistencia. Similar a la imagen de abajo:

Esto será una constante de tiempo, pero podría ajustar su relación R y C para reducir el tiempo de subida / caída para satisfacer sus necesidades.

    
respondido por el Josh Jobin
0

Así es como hago el rebote en la interrupción del temporizador. El siguiente ejemplo también lee el codificador rotatorio y también devuelve los estados 'presionado' y 'liberado' del botón:


    //encoder on RA2-3, shaft button on RA1
uint8_t tmp;
static const int8_t const enc_states[] =         //encoder lookup table
    {0,ENCD_SIG,ENCI_SIG,0,ENCI_SIG,0,0,ENCD_SIG,ENCD_SIG,0,0,ENCI_SIG,0,ENCI_SIG,ENCD_SIG,0};

static uint8_t old_AB = 0;    //previous state of the encoder
static uint8_t debounce_state = 0U;
static uint8_t btn_debounced = 0U;

_T1IF = 0;                              /* clear interrupt */

tmp = PORTA;    //read encoder

//process encoder
old_AB >>= 2;                //remember previous state
old_AB |= ( tmp & 0x0c );  //add current state

if( enc_states[(old_AB & 0x0f)]) { //encoder changed state
    QACTIVE_POST_X_ISR((QActive *)&AO_Console,
        1, enc_states[(old_AB & 0x0f)], 0U);
}

/* read and debouce encoder shaft button */

tmp = EBUT_PIN;               /* read the shaft button */

switch (debounce_state) {
    case 0:
        if (tmp != btn_debounced) {
            debounce_state = 1U;        /* transition to the next state */
        }
        break;
    case 1:
        if (tmp != btn_debounced) {
            debounce_state = 2U;        /* transition to the next state */
        }
        else {
            debounce_state = 0U;          /* transition back to state 0 */
        }
        break;
    case 2:
        if (tmp != btn_debounced) {
            debounce_state = 3U;        /* transition to the next state */
        }
        else {
            debounce_state = 0U;        /* transition back to state 0 */
        }
        break;
    case 3:
        if (tmp != btn_debounced) {
            btn_debounced = tmp;        /* save the debounced button value */

            if (tmp == 0U) {            /* is the button depressed? */
                QACTIVE_POST_X_ISR((QActive*)&AO_Console, 1,
                    EBUT_PRESS_SIG, 0U);
            }
            else {
                QACTIVE_POST_X_ISR((QActive*)&AO_Console, 1,
                    EBUT_RELEASE_SIG, 0U);
            }
        }
        debounce_state = 0U;              /* transition back to state 0 */
        break;
}//switch(debounce_state...

QACTIVE_POST_X_ISR((QActive*)&AO_Console, 1,
    TICK_SIG, 0U);

QF_tickISR();                /* handle all armed time events in QF-nano */

    
respondido por el Oleg Mazurov

Lea otras preguntas en las etiquetas