Interfaz de botón AVR

Soy principiante en el microcontrolador y tengo el kit para AVR. Actualmente estoy usando un ATMega16 para aprender los conceptos básicos. He probado algunos experimentos simples con este microcontrolador usando LED. Ahora quería hacer algunas interfaces de hardware y encontré un proyecto interesante.

Quiero usar 6 botones para contar hasta 2500 y mostrarlo en los LED de siete segmentos multiplexados. 3 botones para contar hacia arriba, es decir, (100's, 10's y 1's). Por ejemplo, si tengo que mostrar 1532, presionaré el botón de 100 15 veces, el botón de 10 3 veces y el botón de 1 dos veces. Del mismo modo, para la cuenta regresiva, quiero usar 3 botones. Probé un código que utiliza declaraciones condicionales para verificar el estado del pin, pero ninguno de ellos parece funcionar.

Por favor, ayúdenme con esto, ya que he estado atascado en esto durante bastante tiempo. Parece ser el problema con el "antirrebote", pero no estoy del todo seguro acerca de ese concepto.


Estoy tratando de contar la cantidad de veces que se presionó el interruptor (PB0) y cuando llega a 5, quiero encender un LED (PD0). El siguiente código no funciona.

int main(void)
{
 unsigned char count=0;

TCCR0 = (1<<WGM01)|(1<<CS02)|(1<<CS00); // Timer0 Mode 2: CTC-Prescaler 1024
TCNT0 = 0;
OCR0 = (((XTAL / 1024.0)*10e-3)-1); // For 10ms
TIMSK = 1<<OCIE0;           // enable T0 interrupt

DDRB = 0x00;                // PB0 input
PORTB = 0x00;               // external pullup

DDRD = 0x01;                // PD0 LED output
PORTD = 0x00;               // LEDs off

sei();

while(1)
{                               // main loop
    if(!(PINB & _BV(PB0)))
    {
        count++;

        if(count>=5)
        {
            PORTD|= (1<<PD0);   // SET LED on keypress
            _delay_ms(10);
            count = 0;
        }


    }  

   }

}

Respuestas (3)

La eliminación de rebotes es algo con lo que debe estar familiarizado al usar botones. Cuando un contacto se cierra, no solo se cierra, sino que rebota varias veces hasta que finalmente se asienta en su posición cerrada.

Dependiendo de qué tan rápido sea su código de muestreo, el código puede contar muchas pulsaciones de botones, aunque solo movió el dedo una vez. Hay una serie de estrategias antirrebote alrededor. Busque en www.avrfreaks.net para eliminar rebotes y encontrará muchas publicaciones. La mayoría de los hilos recientes contienen un enlace a algunos buenos ejemplos/estrategias que puedes usar.

Es posible que este no sea el único problema con su código, pero solo podemos saberlo cuando hayamos visto el código. Publícalo aquí o en avrfreaks y quizás podamos ayudarte.

El concepto es bastante claro, pero quería ayuda sobre cómo implementarlo en el código. Busqué en los foros pero no encontré nada que explicara mi problema actual.

¿Está habilitando resistencias pullup internas para sus entradas o usando pullups externos?

Conecte su botón de esta manera:

MCU pin PB0 -> botón -> GND

Algo como esto debería funcionar:

DDRB &= ~_BV(PB0); //set PB0 to input
PORTB |= _BV(PB0); //enable pullup on input

while(1) {
  if(!(PINB & _BV(PB0))) { //PINB will have PB0 set to 0 on button press

    //do whatever you like

    _delay_ms(150);//wait a bit while the button is bouncing
    while(!(PINB & _BV(PB0))); //do nothing while the button is still pressed
  }
}

Tenga en cuenta que esta no es una buena manera adecuada de hacerlo, es solo la forma más simple e infalible de comenzar. Después de pasar por esto, busque numerosas técnicas adecuadas para eliminar el rebote de los botones y haga preguntas más específicas aquí.

He probado un código similar y este código también. Ninguno de los dos funcionó. Todavía estoy atascado con la interfaz del botón. Consulte mi código a continuación y dígame cuál podría ser el error. Quiero contar la cantidad de veces que se presionó el interruptor y cuando alcanzó el límite predefinido (en este ejemplo, 5), quiero ENCENDER un LED.
@AshishKoujalgi edite su pregunta e ingrese su código en la pregunta.

Para empezar, un botón normalmente se conecta a tierra cuando se presiona. El pin del microcontrolador debe configurarse como una entrada con la resistencia pull-up interna habilitada. No hay necesidad de usar componentes externos aquí. Si el pin dice LO, entonces se presionó el botón. Usualmente uso pequeños botones táctiles en mis diseños, y nunca los he tenido atados por más de unos pocos milisegundos. Con eso en mente, también es fácil saber cuánto tiempo se ha presionado un botón para que pueda tener diferentes acciones para una pulsación corta o larga. Para un ejemplo simple, en el siguiente código, el estado de un conjunto de pines se sondea continuamente en MAIN. Cuando se presiona un botón, el programa se retrasará durante un período de tiempo específico antes de volver a verificar los botones y hacer algo útil.

#define MS_DEBOUNCE    10   // Time in ms to debounce button
DDRC = 0x00;                // Set All as Inputs
PORTC = 0xFF;               // Inputs: Pulls Ups Enabled

if(!(PINC & BUTTON){        // If Some Button is pressed...
  delay_ms(MS_DEBOUNCE);        //   Delay to debounce button
  if(!PINC & BUTTON){           //   If Button is Still Pressed...
    //... Do Something useful here ...
  }
}
while(!(PINC & BUTTON)); // This will loop until the button has been released.

Este es un ejemplo muy simple que siempre me ha funcionado bien. Para contar realmente la duración de la pulsación, configuraría una bandera global antes de un ciclo while final para alertar a una rutina en un temporizador ISR. Este ISR luego contaría hasta que se haya soltado el botón. Después de tanto tiempo, puede tener lugar una acción diferente. Por ejemplo (en PRINCIPAL, en lugar del ciclo while anterior):

stat_flag |= BUTTON_PRESS;          //   Set Bit to enter loop
duration_cnt = MS_HOLD;             //   Preset duration counter
while(stat_flag & BUTTON_PRESS);    //   Loop until button released

Luego, en un temporizador ISR de 1 ms, haría algo como lo siguiente. Si contará hacia atrás desde el tiempo "MS_HOLD" especificado. Si después de ese tiempo, el botón todavía está presionado, realice una acción adicional de "pulsación prolongada". Esto podría hacerse en lugar de presionar brevemente, o podría repetirse indefinidamente mientras se mantenga presionado el botón, como mantener presionado un botón de volumen, el volumen aumentará cada tantos ms.

if(duration_cnt){               // Button was pressed
  if(--duration_cnt == 0){        // Counter has expired
    if(PINC != DEFAULT_PINS){       // Some button is still pressed
        //... Do something useful for long press
    }
    else{                          // No Buttons being pressed
      stat_flag &= ~BUTTON_PRESS;  // Reset flag to exit delay loop
    } 
  }
}