Osetreni zakmitu tlacitka na ext preruseni

Prosim o radu jak korektne osetrit zakmit tlacitka pro externi preruseni. Napsal jsem tohle, ale nepomaha :[code]

ISR ( INT4_vect )
{

_delay_ms(30);

if (bit_is_clear(PINE,4)){
.
.
.
}

}[/code]

V C moc nedělám, nicméně strkat do přerušení zpožďovací smyčku není moc dobré řešení. U ext. přerušení je lepší odstranit zákmity hardwarově. Můžeš skusit na konci obsluhy přerušení vynulovat příznak vnějšího přerušení. Zákmity trvají kolem 10ms záleží na typu tlačítka. Pokud trváš na funkci delay v obsluze zkus ji dát nakonec obsluhy a za ní ještě natvrdo nulování toho příznaku. Ono jev možné že první hrana vyvolá přerušení, ale již během obsluhy přerušení příjde další která opět nastaví příznak a po skočení první oblsuhy se obsluha zavolá znova. Proto nakonci nuluj příznak. Ale jak jsem již napsal není to úplně správné řešení.

Do přerušení nemůžeš strkat dlouhý čekání. 30ms je pro mcu věčnost. Pokud chceš řešit tlačítko pomocí externího přerušení, je nejrozumnější řešit to na HW úrovni (viz. příloha). Používám externí přerušení pro rotační kodér a funguje to spolehlivě. Kondenzátory dávám 100n a odpory 100R a funguje to spolehlivě. Tlačítko tady nemá HW řešené zákmity a odpor je tam jenom proto, že je to vytažené ze schématu, kde používám stejný pin mcu pro tlačítko do mcu a pro data SPI z mcu. Jinak odpor k tlačítkům nedávám. Zapnuté interní pull-up rezistory jsou předpokladem.
Osetreni_zakmitu.png

Dekuji, zkusim tedy kondik :slight_smile:

Zákmit není problém řešit i jen softwarově - jen je potřeba použít ještě přerušení od časovače. Přerušení od tlačítka nastaví proměnnou s čítačem necitlivosti, přerušení od hodin proměnnou dekrementuje (je-li != 0). Přerušení od tlačítka nahodí flag stisku tlačítka pouze v případě, že proměnná je nula, tj. uplynul dostatečný čas od minulého přerušení. (prodlevu do přerušení rozhodně nedávat!)

Ještě doplním ke svému příspěvku: Ke tlačítkům odpor nedávám v případě, že řeším zákmity pomocí SW a pin mcu slouží pouze pro snímání toho tlačítka. V tomto přípdadě pin slouží jako vstup tlačítka a zároveň jako výstup dat pro SPI komunikaci a odpor tam zajišťuje, aby se data neuzemnila tlačítkem, pokud je stisknuté. V tomto případě je vhodné použít odpor alespoň 1k. Pokud u tlačítek řeším zákmity na úrovni HW, pak tam samozřejmě ten odpor dávám také. A když tak na to koukám, tak si nejsem jistý, jestli jsem se nespletl u hodnoty toho kondíku. Jestli tam nemá být jen 10n. Odpoledne to ověřím a dám Ti sem ještě vědět.

Jinak samozřejmě i při použití externího přerušení pro tlačítka lze řešit zákmity pomocí SW, jak psal Panda38.

K hodnotám kondenzátorů : pro odstranění zákmitů u rotačního kodéru používám kondenzátory 10n a odpory 68 nebo 100 ohmů. Podle toho, co bylo po ruce.

Bezva prcnu tam 10n, ted tam mam 100n a neni to uplne idealni, diky :slight_smile:

[code]//interupt na PE4 - tlacitko pro zapnuti vystupu - zelena LED, je-li zapnut prenos nemuze generovat

ISR ( INT4_vect )
{
// spusti casovac

TIMSK = (1 << OCIE1A);
TCCR1A = (0<<WGM11)|(0 << WGM10);
TCCR1B = (0<<WGM13)|(1<<WGM12);
TCCR1B |= (1<<CS12)|(0<<CS11)|(1<<CS10);
TCCR1C = 0;
OCR1A = 200;		 

}

ISR ( TIMER1_COMPA_vect )
{

		if (zmacknuto_prenos == false){
			if (zmacknuto_gen){ 
			  zmacknuto_gen = false;
			  PORTE &= ~(_BV(7));			//vynuluje, zhasne cervenou LED na PE7
			  lcd_clrscr();
			  menu_start();
			  vrstva_menu = 0;
			}			
			else{					
			  zmacknuto_gen = true;
			  PORTE |= _BV(7);			//nastavi, rozne LED	
			  lcd_clrscr();
			  lcd_gotoxy(1,1);		
			  lcd_puts("PROBIHA GENEROVANI");
			}
		}

}[/code]

Bylo to mysleno takto Panda38?

sw ošetření zákmitů tlačítka? Ne, nějak takhle (program jen symbolicky). Časovač běží neustále, stejně je často potřeba pro měření intervalů, může čítat např. po 1 milisekundě. Reakce na tlačítka by měla být v hlavním programu a ne v přerušení, protože může být potřeba volat jiné funkce, některé i s prodlevami, to by se mohlo z přerušení špatně používat. A také by hrozila kolize kdyby k zařízením chtěl přistupovat hlavní program. Proto je vhodnější aby přerušení předávalo jen flagy a bylo co nejkratší.

[code]volatile char btn1_byl_stisk = 0; // priznak, ze byl stisk tlacitka btn1
char btn1_citac = 0; // citac doby po kterou tlacitko nereaguje na novy stisk
volatile unsigned short citac_casu = 0; // citac casu po 1 ms (není potreba pro tlacitka)

ISR ( preruseni od tlacitka )
{
if (btn1_citac == 0) btn1_byl_stisk = 1;
btn1_citac = 200;
}

ISR ( preruseni casovace 1 ms )
{
if (btn1_citac != 0) btn1_citac–;
citac_casu++;
}

char StiskBtn1(void) // byl stisk tlacitka btn1 ?
{
char ok = btn1_byl_stisk;
btn1_byl_stisk = 0;
return ok;
}

int main(void)
{
while(1)
{
if (StiskBtn1())
{
// … tady je nejaka akce na stisk tlacitka Btn1
}
}
}
[/code]
Doplňkově příklad použití měření času čítačem:

[code]unsigned short CasMs(void) // dej aktualni cas v ms (pozor - povoli preruseni!)
{
unsigned short cas;
cli();
cas = citac_casu;
sei();
return cas;
}

// presne cekani po dany pocet ms (pozor - povoli preruseni!)
// jen na ukazku pouziti mereni casu, spis se pouzije podobne
// v programu paralelne s jinymi procesy, napr. pro mereni time-outu

void CekejMs(unsigned short ms)
{
unsigned short stary_cas = CasMs();
while(CasMs() - stary_cas < ms) {}
}

// nebo v programu:
unsigned short ubehly_cas;
unsigned short stary_cas = CasMs();
while (1)
{
if (… nejaka udalost)
{
ubehly_cas = CasMs() - stary_cas;
stary_cas += ubehly_cas; // posun casove znacky pro pristi test
}

// nebo pro zjisteni timeoutu udalosti, napr. vypadek spojeni:
if (CasMs() - stary_cas >= TIMEOUT)
{
	// obsluha timeoutu udalosti
}

}[/code]

dekuji, aplikuji