Interfaz de botones AVR

1

Soy un principiante del microcontrolador y tengo el kit para AVR. Actualmente estoy usando un ATMega16 para aprender lo básico. He intentado algunos experimentos sencillos con este microcontrolador utilizando LED. Ahora quería hacer una interfaz de hardware y encontré un proyecto interesante.

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

Por favor, ayúdame con esto, ya que he estado atascado en esto durante bastante tiempo. Parece ser el problema con el "debouncing" pero no estoy completamente seguro 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;
        }


    }  

   }

}
    
pregunta dreamcoder

3 respuestas

3

Debates es algo con lo que debes estar familiarizado cuando usas botones. Cuando un contacto se cierra, no solo se cierra, sino que rebota unas cuantas veces hasta que finalmente se instala en su posición cerrada.

Dependiendo de qué tan rápido sea el 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 de rebote. Busca en www.avrfreaks.net para encontrar anuncios y encontrarás muchas publicaciones. La mayoría de los subprocesos recientes contienen un enlace a algunos ejemplos / estrategias bastante buenos que puedes usar.

Es posible que este no sea el único problema con su código, pero solo lo podemos saber cuando hemos visto el código. Publícalo aquí o en avrfreaks y podremos ayudarte.

    
respondido por el Christoph
1

¿Está habilitando resistencias de pullup internas para sus entradas o está utilizando pullups externos?

Conecta tu botón de esta manera:

MCU pin PB0 - > botón - > GND

El 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
  }
}

Ten en cuenta que esta no es una buena manera adecuada de hacerlo, es la forma más sencilla y segura de comenzar. Una vez que haya superado esto, busque numerosas técnicas adecuadas de eliminación de botones y haga preguntas más específicas aquí.

    
respondido por el miceuz
1

Para comenzar, un botón normalmente se conectaría a tierra cuando se presiona. El pin del microcontrolador debe configurarse como una entrada con la resistencia de activación interna habilitada. No hay necesidad de usar componentes externos aquí. Si el pin lee LO, entonces el botón fue presionado. Normalmente utilizo pequeños botones táctiles en mis diseños, y nunca los he atado por más de unos pocos milisegundos. Teniendo esto en cuenta, 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 PRINCIPAL. Cuando se presiona un botón, el programa se retrasará durante un período de tiempo específico antes de volver a marcar 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 prensa, establecería una marca global antes de un bucle while final para alertar una rutina en un ISR de temporizador. Este ISR contará hasta que se suelte el botón. Después de tanto tiempo, una acción diferente puede tener lugar. Por ejemplo (en MAIN, en lugar del bucle 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 ISR con temporizador de 1 ms, haría algo como lo siguiente. Si contará hacia atrás desde el tiempo especificado "MS_HOLD". Si después de ese tiempo, el botón aún está presionado, realice una acción adicional de "pulsación prolongada". Esto se puede hacer en lugar de la pulsación corta, o se puede repetir indefinidamente siempre que se mantenga presionado el botón, como al presionar 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
    } 
  }
}
    
respondido por el Kurt E. Clothier

Lea otras preguntas en las etiquetas