Debouncing

Sezione dedicata ai Microcontrollori e ai Sistemi Embedded

Debouncing

Postby Barone » 21 Feb 2014, 12:25

Salve,

uso una stk500 com atmega1284p.
Cercando di risolvere il problema di debouncing ho trovato del codice su internet. Il problema del debouncing è risolto, ma come risultato ho anche un comportamento inaspettato. Riporto il codice:

Code: Select all
void disattiva_timer0(){
   TIMSK0=0x00;
}
void aziona_timer0(){
   TCCR0A= (1<<WGM10);
   TCCR0B=(1<<CS00);
   TIMSK0=(1<<OCF0A);
   OCR1A = 255;
}
void inizializza_porte(){
   
   DDRA = 0xff; //porta A in uscita
   PORTA = 0xff; //logica inversa
   DDRB=0x00; //porta B in entrata
   PINB = 0xff;  //toggle ai pin.
   DDRC = 0xff;// porta C in uscita
   DDRD = 0xff; // porta D in uscita
   PORTC = 0x00;
   PORTD = 0x00;
   
}

void inizializza_interrupt(){
   PCICR = (1<<PCIE1); //abilito gli interrupt per le PCINT1 (porta B)
   PCMSK1 = 0xff; //abilito gli interrupt relativi ad ogni pin della porta B per le PCINT1
}

ISR(TIMER0_COMPA_vect){
   
   if(cnt >0/*--f > 0*/){
      cnt --;
      //PORTC ^= 0xaa;
      TCNT0 = 0;
      //disattiva_timer0();
   }
   else{
      cnt = 19;
      static uint8_t key_state;      // debounced and inverted key state:
                static uint8_t ct0, ct1;      // holds two bit counter for each key
                uint8_t i;


  /*
   * read current state of keys (active-low),
   * clear corresponding bit in i when key has changed
   */
        i = key_state ^ ~PINB;   // key changed ?
 
  /*
   * ct0 and ct1 form a two bit counter for each key, 
   * where ct0 holds LSB and ct1 holds MSB
   * After a key is pressed longer than four times the
   * sampling period, the corresponding bit in key_state is set
   */
       ct0 = ~( ct0 & i );         // reset or count ct0
       ct1 = (ct0 ^ ct1) & i;       // reset or count ct1 
       i &= ct0 & ct1;             // count until roll over ?
       key_state ^= i;             // then toggle debounced state
 
  /*
   * To notify main program of pressed key, the correspondig bit
   * in global variable key_press is set.
   * The main loop needs to clear this bit
   */
      key_press |= key_state & i;   // 0->1: key press detect
   }
   
}


unsigned char ca=0;

int main (void)
{


     uint8_t count = 0;

      TCCR0A= (1<<WGM10);
      TCCR0B=(1<<CS00);
      TIMSK0=(1<<OCIE0A);
       OCR0A = 255;
       TCNT0 = 0;

        DDRA  = 0x00;                    // use all pins on PortD for input
        PORTB = 0xff;                    // with pull-up enabled

        DDRC  = 0xff;                    // use all pins on PortB for output
        PORTC = 0x00;                    // turn all LED off

        DDRC  = 0xff;                    // use all pins on PortB for output
        PORTD = 0x00;
   
   inizializza_timer1();
   inizializza_porte();
   inizializza_carichi();
   inizializza_interrupt();
   
   sei();
   
   while(1)
   {
      
      while (key_press & ~PINB )
      {
         
         pin = ~PINB;
         key_press = 0;
         
      }      
      PORTC = ca;
   }
   
   
}


quando premo lo switch, fintantoché è premuto, ho il comportamento desiderato. Ma nel momento in cui rilascio, torna nello stato di prima.
Nel caso che ho postato, mi aspetto che ogni volta che premo lo switch, la variabile ca venga incrementata e il suo valore passato alla PORTC a cui sono collegati dei led. Ma succede che ogni volta che lo premo ho sempre il valore 1 e quando rilascio i led si spengono.
Cosa sbaglio?
Saluti.
Barone
 
Posts: 13
Joined: 24 Aug 2013, 00:50

Re: Debouncing

Postby Fagos » 21 Feb 2014, 21:09

Ok, barone
hai la possibilità di mostrare il flow-chart del tuo debouncing?

Il codice di partenza è questo?
Code: Select all
*****************************************************************************/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

#ifndef CTC1
#define CTC1 WGM12              // for compatibility with ATmega
#endif


#define XTAL      4000000L    // Crystal frequency in Hz
#define DEBOUNCE   200L      // debounce clock 200Hz = 5msec

/*
 * Module global variable, informs the main programm when a key is pressed.
 * This variable must be declared 'volatile, since it is accessed from
 * both interrupt und main loop.
 */
static volatile uint8_t key_press;      

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
  static uint8_t key_state;      // debounced and inverted key state:
  static uint8_t ct0, ct1;      // holds two bit counter for each key
  uint8_t i;


  /*
   * read current state of keys (active-low),
   * clear corresponding bit in i when key has changed
   */
  i = key_state ^ ~PIND;   // key changed ?
 
  /*
   * ct0 and ct1 form a two bit counter for each key, 
   * where ct0 holds LSB and ct1 holds MSB
   * After a key is pressed longer than four times the
   * sampling period, the corresponding bit in key_state is set
   */
  ct0 = ~( ct0 & i );         // reset or count ct0
  ct1 = (ct0 ^ ct1) & i;       // reset or count ct1 
  i &= ct0 & ct1;             // count until roll over ?
  key_state ^= i;             // then toggle debounced state
 
  /*
   * To notify main program of pressed key, the correspondig bit
   * in global variable key_press is set.
   * The main loop needs to clear this bit
   */
  key_press |= key_state & i;   // 0->1: key press detect

}

int main( void )
{
  uint8_t count = 0;
   
  TCCR1B = _BV(CTC1) + _BV(CS10);  // clear timer on compare match, no prescaler
  OCR1A  =  XTAL/DEBOUNCE;         // timer = 5 msec
  TIMSK  = _BV(OCIE1A);            // enable Output Compare 1 overflow interrupt

  DDRB  = 0x00;                    // use all pins on PortD for input
  PORTD = 0xff;                    // with pull-up enabled

  DDRB  = 0xff;                    // use all pins on PortB for output
  PORTB = 0xff;                    // turn all LED off
 
  sei();                           // enable interrupt

  for(;;)
  {
    if (key_press & _BV(2) )
    {
        // key 2 pressed, increment counter
        count++;
        PORTB = ~count;
       
        key_press = 0;
    }
    else if ( key_press & _BV(3) ) 
    {
        // key 3 pressed, decrement counter
        count--;
        PORTB = ~count;
       
        key_press = 0;
    }
  }
}
User avatar
Fagos
 
Posts: 100
Joined: 31 Aug 2011, 15:01

Re: Debouncing

Postby deluca » 21 Feb 2014, 21:15

Code: Select all
1        DDRA  = 0x00;                    // use all pins on PortD for input
2        PORTB = 0xff;                    // with pull-up enabled

3        DDRC  = 0xff;                    // use all pins on PortB for output
4        PORTC = 0x00;                    // turn all LED off

5        DDRC  = 0xff;                    // use all pins on PortB for output
6        PORTD = 0x00;


c'è una certa confusione nella configurazione delle porte di I/O, o mi sbaglio :o
i commenti sono diversi da quello che indichi negli stataments.....

Beh! però poi chiami "inizializza_porte();" ...
anche io concordo, meglio che posti il tuo flow-chart.
Ciao
Il mio sito: http://www.delucagiovanni.com ......e la chat: chat/
User avatar
deluca
Site Admin
 
Posts: 1104
Joined: 19 Jun 2011, 10:44
Location: 95123 - Catania (Italy)

Re: Debouncing

Postby Barone » 22 Feb 2014, 00:14

Salve,

il codice utilizzato è proprio quello che ha postato Fagos, l'ho trovato in rete e l'ho poi modificato secondo le mie esigenze, lasciando, senza accorgermene, i commenti inalterati.

- configuro porte: PINB (switches della scheda), PORTC (led)
- configuro gli interrupt
- configuro il timer 0 e lo faccio partire
- inizializzo contatore ca = 0
- leggo lo stato di PINB
- per ogni stato di PINB != 0xff, faccio ca++ e PORTC = ca
Per cui mi aspetto che i led sulla porta C mi facciano da contatore per il numero di volte che ho premuto gli switch, ma ciò che ottengo è che:
- ca = 0
- premo lo switch
- ca = 1 --> PORTC = 1
- rilascio lo switch
- led spenti
- ripremo lo switch
- ca = 1 --> PORTC = 1
- rilascio lo switch
- led spenti

Sono sicuro di non aver capito il codice che ho trovato per il debouncing. :oops:
Barone
 
Posts: 13
Joined: 24 Aug 2013, 00:50

Re: Debouncing

Postby Fagos » 22 Feb 2014, 10:57

barone con che tools stai compilando, ho provato con avrstudio4.19 ma non riesco a compilare il tuo codice.
potresti postare l'intero progetto zippato? cerco di darti una mano anche io. il debouncing interessa pure a me. ciao
User avatar
Fagos
 
Posts: 100
Joined: 31 Aug 2011, 15:01

Re: Debouncing

Postby Barone » 22 Feb 2014, 21:32

Uso Atmel studio 6, non compilava perché era preso direttamente da un progetto più vasto, ora posto il codice funzionante del problema:

Code: Select all
/*
 * Include header files for all drivers that have been imported from
 * Atmel Software Framework (ASF).
 */
#include <asf.h>


static volatile uint8_t key_press;   
unsigned char pin,pos;
unsigned char serve = 0;
void aziona_timer0();

void inizializza_porte(){
   
   DDRA = 0xff;
   PORTA = 0xff;
   DDRB=0x00;
   PINB = 0xff;
   DDRC = 0xff;
   DDRD = 0xff;
   PORTC = 0x00;
   PORTD = 0x00;
   
}

void inizializza_interrupt(){
   PCICR = (1<<PCIE1);
   PCMSK1 = 0xff;
}


void disattiva_timer0(){
   TIMSK0=0x00;
}
void aziona_timer0(){
   
   TCCR0A= (1<<WGM10);
   TCCR0B=(1<<CS00);
   TIMSK0=(1<<OCF0A);
   OCR1A = 255;
}




unsigned char cnt = 19;
long f = 20000;
bool gh = false;
ISR(TIMER0_COMPA_vect){
   
   if(cnt >0){
      cnt --;
      TCNT0 = 0;
   }
   else{
      cnt = 19;
      static uint8_t key_state;      // debounced and inverted key state:
        static uint8_t ct0, ct1;      // holds two bit counter for each key
        uint8_t i;


  /*
   * read current state of keys (active-low),
   * clear corresponding bit in i when key has changed
   */
        i = key_state ^ ~PINB;   // key changed ?
 
  /*
   * ct0 and ct1 form a two bit counter for each key, 
   * where ct0 holds LSB and ct1 holds MSB
   * After a key is pressed longer than four times the
   * sampling period, the corresponding bit in key_state is set
   */
     ct0 = ~( ct0 & i );         // reset or count ct0
      ct1 = (ct0 ^ ct1) & i;       // reset or count ct1 
      i &= ct0 & ct1;             // count until roll over ?
      key_state ^= i;             // then toggle debounced state
 
  /*
   * To notify main program of pressed key, the correspondig bit
   * in global variable key_press is set.
   * The main loop needs to clear this bit
   */
      key_press |= key_state & i;   // 0->1: key press detect
   }
   
}


unsigned char ca=0;

int main (void)
{


   uint8_t count = 0;
    TCCR0A= (1<<WGM10);
   TCCR0B=(1<<CS00);
   TIMSK0=(1<<OCIE0A);
   OCR0A = 255;
   TCNT0 = 0;
   inizializza_porte();
   inizializza_interrupt();
   
   sei();
   while(1)
   {
      while (key_press & ~PINB )
      {
         
         ca++;
         pin = ~PINB;
         key_press = 0;
      }      
      PORTC = ca;
      
   }
   
   
}
Barone
 
Posts: 13
Joined: 24 Aug 2013, 00:50

Re: Debouncing

Postby deluca » 23 Feb 2014, 09:21

Potresti postare l'HEX così da poterlo provare in simulazione?
Ciao
Il mio sito: http://www.delucagiovanni.com ......e la chat: chat/
User avatar
deluca
Site Admin
 
Posts: 1104
Joined: 19 Jun 2011, 10:44
Location: 95123 - Catania (Italy)

Re: Debouncing

Postby Leonardo » 23 Feb 2014, 11:12

Senza creare un progetto ASF è possibile compilare il codice sostituendo l' #include con

Code: Select all
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>


@Barone: hai provato a studiare con Atmel Studio il codice tramite il simulatore?
Il mio blog di elettronica: http://electro-logic.blogspot.it
User avatar
Leonardo
 
Posts: 502
Joined: 29 May 2013, 22:31
Location: Parma


Return to Microcontrollori e microprocessori

Who is online

Users browsing this forum: No registered users and 20 guests

cron