This is an old revision of the document!


Lüliti väreluse elimineerimine

Vajalikud teadmised: [HW] Digitaalne moodul, [AVR] Sisendid-väljundid, [LIB] Viikude teek, [LIB] Viite teek, [PRT] Lülitite näide

Teooria

Lüliti kontaktide põrkumine

Nii nagu lüliteid tutvustavas peatükis öeldud, eksisteerib mehhaaniliste lülititega kontaktide põrkumise probleem. Kuna kontaktid on tehtud metallist, millel on teatav elastsus, siis kontaktide ühendamise või lahti-ühendamise hetkel need põrkuvad ning tulemusena tekib hulga väär-lülitusi. Lülituste arv ja kestvus sõltub lülitist, kuid enamasti jääb see mõne millisekundi piiresse. Kui lülitit kasutatakse mõne elektriseadme tööle lülitamiseks, siis pole see suur probleem, kuid kui lüliti on kasutusel seadme juhtimiseks võib mitmekordne vajutamine kahjulik olla.

Lüliti RC-filter

Põhiline sädelust välistav meetod on filtreerimine. Filtreerida saab nii elektriliselt kui tarkvaraliselt. Elektriliseks filtreerimiseks tuleb lüliti järgi lisada madalpääsfilter – näiteks RC filter - mis silub pingemuutusi ja sellest tulenevalt mikrokontrolleri viik ei omanda hetkelisi väärtusi. RC filtri on toodud kõrvalolev Tarkvaraline filtreerimine toimub põhimõttel, et viigu, kuhu lüliti on ühendatud, väärtust loetakse mitmel korral ja kui kõikidel kordadel on viigu väärtus sama, siis sellest järeldatakse, et lüliti omab kindlat asendit ning tegu pole sädelusega. Igasugusel filtreerimisel peab aga arvestama viitega, mis tekib oleku kindlaks määramisega.

Praktika

Kodulabori lülititel ei kasutada elektrilist filtreerimist, sest siis ei saaks harjutada tarkvaralist väärlülituste elimineerimise ülesannet. Harjutus koosneb kahest osast. Esimese ülesande eesmärk on demonstreerida digitaalse sisend-väljund mooduli nuppude kontaktide põrkumist. Selleks on järgmine programm, mis iga nupuvajutuse peale paneb põlema järgmise LED-i. Väär-nupuvajutuste tõttu süttivad LED-id aga mitmeid kordi ja näib, et lausa suvaliselt.

//
// Kodulabori digitaalse sisend-väljund mooduli
// nuppude põrkumise demonstreerimise programm.
//
#include <homelab/pin.h>
 
//
// LED-ide ja nupu viikude määramine
//
pin leds[3] = { PIN(C, 5), PIN(C, 4), PIN(C, 3) };
pin button  = PIN(C, 0);
 
//
// Põhiprogramm
//
int main(void)
{
	unsigned char new_value, old_value = 0;
	unsigned char index, counter = 0;
 
	// LED-ide viikude väljundiks seadmine
	for (index = 0; index < 3; index++)
	{
		pin_setup_output(leds[index]);		
	}
 
	// Nupu viigu sisendiks määramine
	pin_setup_input(button);
 
	// Lõputu tsükkel
	while (true)
	{
		// Nupu oleku lugemine
		new_value = pin_get_value(button);
 
		// Kontroll, kas nupp vajutati alla,
		// ehk kas uus olek on 1 ja vana 0
		if ((new_value) && (!old_value))
		{
			// Loenduri suurendamine ja mooduli 3 võtmine
			counter = (counter + 1) % 3;
 
			// Loenduri väärtusele vastava LED-i süütamine
			for (index = 0; index < 3; index++)
			{
				pin_set_to(leds[index], index != counter);
			}
		}
 
		// Peame vana olekut meeles
		old_value = new_value;
	}
}

Tarkvaraliseks filtreerimiseks on mitmeid meetodeid. Seda võib teha lihtsalt ja keeruliselt, mõlemal juhul omade eeliste ja puudustega. Kui programm on selline, et nupuvajutusi oodatakse harva, võib peale nupu allavajutamise registreerimist lisada pika pausi mis välistab reageerimise põrkumisest tekkinud-lülitustele. Samas tuleb sellise lahenduse puhul arvestada, et kui kasutaja hoiab nuppu pikalt all, reageerib programm ka nupu lahtilaskmisel tekkinud väär-lülitustele. Töökindlam on programm, mis kontrollib nupu olekut teatud aja jooksul mitu korda (mida rohkem ja mida pikema aja jooksul seda kindlam). Järgnevalt on toodud digitaalse sisend-väljund laiendusmooduli nupu filtreeritud väärtuse lugemise funktsioon:

//
// Funktsioon mõne IO laiendusplaadi lüliti filtreeritud väärtuse lugemiseks
//
unsigned char pin_get_debounced_value(pin button)
{
	unsigned char buffer = 0xAA;	
	unsigned char timeout = 100;
 
	// Ootame kuni nupu olek on selgunud või oleku selgitamine aegunud
	while (timeout-- > 0)
	{
		// 8 kohalise (bitise) olekupuhvri pidamine
		// Kõik eelmised olekud (bitid) nihutatakse vasakule
		// ja paremale lisatakse uus olek (bitt).
		buffer <<= 1;
		buffer |= (pin_get_value(button) ? 0x01 : 0x00);
 
		// Kui kõik 8 bitti on kõrged siis
		// nupp on kindlasti alla vajutatud
		if (buffer == 0xFF)
		{
			return 1;
		}
 
		// Kui kõik 8 bitti on madalad siis
		// nupp on kindlasti üleval
		if (buffer == 0x00)
		{
			return 0;
		}
 
		// Paus 1 millisekund
		// See funktsioon sisaldub kodulabori teegis
		sw_delay_ms(1);
	}
 
	// Kui olekut ei õnnestunud välja selgitada siis oletame,
	// et nuppu ei vajutatud
	return 0;
}

See funktsioon kasutab viite tekitamise funktsiooni millest räägib lähemalt vastav harjutusülesanne. Siinkohal pole viite funktsiooni kohta vaja suurt midagi teada peale selle, et see tekitab 1 millisekundilise viite iga nupu oleku lugemise tsükli lõpus. Kui nupp on kaheksal lugemise korral samas asendis, tagastab see loetud asendi. Kogu protseduur võib nupu ebastabiilsuse korral kesta kuni 100ms. Funktsioon juba sisaldub viikude teegis, nii et näite läbimiseks ei pea seda oma programmi lisama. Selle proovimiseks tuleb ülesande esimest poolt natukese muuta – kaasata programmi viite tekitamise teek ja kohas kus nupu väärtust otse loeti, kasutada filtriga funktsiooni. Tulemus on järgmine:

//
// Kodulabori digitaalse sisend-väljund mooduli
// nuppude põrkumise filtreerimise programm.
//
#include <homelab/delay.h>
#include <homelab/pin.h>
 
//
// LED-ide ja nupu viikude määramine
//
pin leds[3] = { PIN(C, 5), PIN(C, 4), PIN(C, 3) };
pin button  = PIN(C, 0);
 
//
// Põhiprogramm
//
int main(void)
{
	unsigned char new_value, old_value = 0;
	unsigned char index, counter = 0;
 
	// LED-ide viikude väljundiks seadmine
	for (index = 0; index < 3; index++)
	{
		pin_setup_output(leds[index]);		
	}
 
	// Nupu viigu sisendiks määramine
	pin_setup_input(button);
 
	// Lõputu tsükkel
	while (true)
	{
		// Nupu oleku lugemine
		new_value = pin_get_debounced_value(button);		
 
		// Kontroll, kas nupp vajutati alla,
		// ehk kas uus olek on 1 ja vana 0
		if ((!new_value) && (old_value))
		{
			// Loenduri suurendamine ja mooduli 3 võtmine
			counter = (counter + 1) % 3;
 
			// Loenduri väärtusele vastava LED-i süütamine
			for (index = 0; index < 3; index++)
			{
				pin_set_to(leds[index], index != counter);
			}
		}
 
		// Peame vana olekut meeles
		old_value = new_value;
	}
}

Kui nüüd programmi proovida, siis LED-id süttivad täpselt sellises järjekorras nagu kasutaja nupp-lülitit vajutab.

et/examples/digi/switch_debounce.1261347888.txt.gz · Last modified: 2020/07/20 09:00 (external edit)
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0