Eliminant rebots a les entrades

Un problema que ens podem trobar quan volem llegir una entrada digital, és el fenomen dels rebots: si el pin està connectat a un botó a algun altre accionador mecànic aquest pot generar rebots al senyal, que vol dir que no es genera un pols quadrat i perfecte si que no quan es genera un pols aquest vagi acompanyat per d’altres polsos més petits i espuris.

Aquest efecte pot provocar que el nostre codi compti més polsos dels que realment s’haurien de comptar i tenir un sistema erroni.

Per solucionar-ho, a part d’afegir certa circuiteria addicional al voltant del pin d’entrada, es pot desenvolupar codi que tingui en compte aquesta situació. Aquesta mena de codi es coneix com “debouncing“. Aquests algorismes normalment es basen en llegir vàries vegades el pin implicat i veure quan deixa de canviar.

Un altre forma de fer-ho, potser més senzilla és la de un cop detectat un primer flanc, deixar de llegir l’entrada fins passat un temps. Això es pot fer fàcilment controlant un Timer des de la ISR d’entrada del pin.

Exemple de debouncer per EFM32

Primer cal configurar el Timer per què compti un cert temps i generi una IRQ un cop transcorregut aquest temps. Per això configurem el valor Top tal com ja vàrem fer a l’exemple de Timer anterior.

En aquest cas es configura el valor top per que estigui comptant 100 mil·lisegons fent un càlcul molt similar al de l’altre exemple amb Timers.

#define DEBOUNCE_VALUE (1367)

void timer_debouce_Init(void) {
 TIMER_Init_TypeDef timerInit ={ 
  .enable = false,
  .debugRun = false,
  .prescale = timerPrescale1024,
  .clkSel = timerClkSelHFPerClk,
  .fallAction = timerInputActionNone,
  .riseAction = timerInputActionNone,
  .mode = timerModeUp,
  .dmaClrAct = false,
  .quadModeX4 = false,
  .oneShot = true,
  .sync = false };

 CMU_ClockEnable(cmuClock_TIMER1, true);

 TIMER_IntEnable(TIMER1, TIMER_IF_OF);
 NVIC_EnableIRQ(TIMER1_IRQn);

 TIMER_TopSet(TIMER1, DEBOUNCE_VALUE);

 TIMER_Init(TIMER1, &timerInit);
}

També preparem la ISR pel Timer1 de la següent manera:

void TIMER1_IRQHandler(void) {
 uint32_t flags;

 /* Clear flag for TIMER1 */
 flags = TIMER_IntGet(TIMER1);
 TIMER_IntClear(TIMER1, flags);

 timer_running = false;

 if (GPIO_PinInGet(gpioPortD, 8) == 1) {
   dry_contact_event++;
 }
}

La variable timer_running es defineix com una variable booleana (i volàtil) amb valor per defecte a false. A aquesta ISR es comprova el valor desitjat de l’entrada i si és el cas, s’actualitza el comptador.

volatile bool timer_running = false;

Per últim a la ISR del GPIO corresponent inserim el codi següent per engegar el Timer quan es detecti un flanc al senyal (un canvi al seu valor):

...
 if (!timer_running) {
   timer_running = true;
   TIMER_TopSet(TIMER1, DEBOUNCE_VALUE);
   TIMER_Enable(TIMER1, true);
 }
...

D’aquesta manera tant senzilla evitarem els molests rebots i, de fet, tindrem filtrats tots els polsos que considerem massa ràpids pel nostre sistema.

Anuncis

Un pensament sobre “Eliminant rebots a les entrades

Deixa un comentari

Fill in your details below or click an icon to log in:

WordPress.com Logo

Esteu comentant fent servir el compte WordPress.com. Log Out /  Canvia )

Google photo

Esteu comentant fent servir el compte Google. Log Out /  Canvia )

Twitter picture

Esteu comentant fent servir el compte Twitter. Log Out /  Canvia )

Facebook photo

Esteu comentant fent servir el compte Facebook. Log Out /  Canvia )

S'està connectant a %s

Aquest lloc utilitza Akismet per reduir els comentaris brossa. Apreneu com es processen les dades dels comentaris.