Pin Change Interrupt - miért így működik?

Processing/Wiring (illetve C) nyelvű programozási fogások, tippek. (AVR-Duino, Arduino, EthDuino, Diecimila, Severino, Nano, LilyPad)
Válasz küldése
holex
Biztosítékgyilkos
Hozzászólások: 70
Csatlakozott: 2013. október 29. kedd, 1:35

Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: holex »

Egy olyan programot csinálok, ahol négy nyomógomb a B portra van kötve, és hozzárendeltem a B porthoz egy Pin change interruptot. Ez eddig műköik is, semmi gond.A nyomógombok prell-mentesítését úgy oldottam meg, hogy a megszakítási rutin elindulásakor letiltja a B port pin change interruptját és elindítja a timer5-öt. A timer5 túlcsorduláskor szintén megszakítást generál, amiben ismét engedélyezem a B port interruptját, leállítom a timer5-öt és ha közben jött még B porthoz pin change interrupt (ami nyilván jött a prell miatt), azt kiütöm. Igen ám, de hogy kell kiütni?

Van ez a PCIFR regiszter, annak alegutolsó bitje jelenti azt hogy történt-e a B porton interrupt. Ennek az értéke alapból az adatlap szerint 0. Ez a leírás van hozzá:
When a logic change on any PCINT7:0 pin triggers an interrupt request, PCIF0 becomes set
(one). If the I-bit in SREG and the PCIE0 bit in PCICR are set (one), the MCU will jump to the
corresponding Interrupt Vector. The flag is cleared when the interrupt routine is executed. Alternatively,
the flag can be cleared by writing a logical one to it.

Én ezt úgy értelmezem, hogy ha megnyomok egy gombot, akkor ezt a bitet 1-esre állítja, lefut a rutin és visszaállítja 0-ra. Tehát az 1-es állapot azt jelenti, hogy történt megszakítás, a 0 pedig azt, hogy nem. Akkor mi az istenért úgy tudom kiütni a megszakítást, hogy 1-es írok oda és nem pedig 0-t? Ezt elmagyarázná valaki?
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: csabeszq »

Ez így működik, ez van a speckóban. Túl sokat filozofálni nem érdemes a dolgon. Nem az Atmel az első cég, amelyik ezt csinálja, C64 esetén is rengeteg hasonló megoldás volt. A lényeg, hogy mindenféle varázslás nélkül tudj megszakítást kiütni. Ha 4-et írsz be, akkor a PC2-n lévő megszakítást leállítja. Nem kell kiolvasnod a regiszter értékét, szimplán beírod, hogy 4 és törlődik.

A te megoldásod elvileg rossz, mert eseményeket veszthetsz.

A timer befejeződése után neked meg kellene nézned, hogy volt-e változás. Mert ha igen, akkor azt elvesztetted az interrupt lekapcsolása miatt.
holex
Biztosítékgyilkos
Hozzászólások: 70
Csatlakozott: 2013. október 29. kedd, 1:35

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: holex »

Na szerintem kicsit félreértettük egymást :D Szóval: éppen az a lényeg, hogy elvesszenek azok az események, ugyanis nyomógomb prell mentesítését akarom megoldani. A kérdés csak az, hogy a PCIFR utolsó bitje:
1, ha történt esemény
0, ha nem.

Mivel prell mentesítést akarok, az a célom, hogy a timer futásának ideje alatt történt események elvesszenek, így amikor a timer túlcsordul és lefut a túlcsordulási emgszakítás, el akarom felejttetni a kontrollerrel, hogy a timer futása alatt esemény történt. Erre az lenne a logikus megoldás, hogy a PCIFR utolsó bitjét 0-ra állítom, hiszen az jelenti azt, hogy nem történt esemény. De mégis 1-re kell! Ezt nem értem, hogy ez miért így működik
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: csabeszq »

Bővebben kifejtem.

1-be átmegy a bit -> megszakítás
Letiltod 30 ms-re
Eközben 0 és 1 között változik, majd megáll 0-án
Letelik a 30ms, engedélyezed, nincs pin change pedig 0-án vagy.

A program azt gondolja, hogy a bit 1-ben van, eközben az értéke simán lehet nulla, akár egy órán keresztül is.
Elvesztetted a változást.
holex
Biztosítékgyilkos
Hozzászólások: 70
Csatlakozott: 2013. október 29. kedd, 1:35

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: holex »

Köszönöm, így már érthetőbb!

Akkor te hogy oldanád meg ezt a prelles dolgot? Most így néz ki a program:

Kód: Egész kijelölése

ISR(PCINT0_vect){
	PCICR &= 0xFE;				//letiltjuk a PCINT0 megszakitast
	TCNT5 = 0;					// Reset timer5 value
	TCCR5B |= 0x03;				//64-es eloosztas --> 0,26 masodpercenkent csordul tul
	TIMSK5 |= 0x01;				// enable Timer1 overflow interrupt
	if (PINB & 0x08) pushEsc();
	else if (PINB & 0x04) pushEnter();
	else if (PINB & 0x02) pushLeft();
	else if (PINB & 0x01) pushRight();
}

ISR(TIMER5_OVF_vect)
{
	TCCR5B &= 0xF8;				//kikapcsoljuk a Timer5-ot
	PCIFR |= 0x01;				//torli a regiszterbol, hogy PCINT0 megszakitas jott
	PCICR |= 0x01;				//engedelyezzuk a PCINT0 megszakitast
}



int main()
{
        .......
	PCICR |= 0x01;				//engedelyezzuk a PCINT0 megszakitast
	PCMSK0 |= 0x0F;				//megadjuk, hogy a PCINT0 elso 4 laba valthasson ki megszakitast
	sei();						//Enable Global Interrupt

Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: csabeszq »

Minthogy a felengedést nem vizsgálod, csak azt, hogy lenyomódott-e, így a kód működőképes.

Természetesen nem atombombabiztos és az általam említetteket lehet produkálni, de nem biztos, hogy van értelme az átírásnak.
Avatar
SzLacus
Tranzisztorgyógyász
Hozzászólások: 175
Csatlakozott: 2012. május 20. vasárnap, 6:00

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: SzLacus »

A prell kiküszöbölésére létezett egy céláramkör, ami valahogy úgy működött, hogy egy shiftregiszterbe léptette a változást, és csak akkor talált ki a regiszterből a bemenetre adott jel, ha már x órajel óta (ahány cellából áll a regiszter) stabil volt. Ennek alapján szerintem célravezető lehet, ha ahányszor beüt a megszakításod a gombról, annyiszor újra indítod az időzítődet és várod a következő pattanás. Amikor megszűnt a pattogása a kontaktnak, akkor nem fogod már többször elindítani, és az adott idő múlva lejár az időzítőd. Amikor lejárt, akkor olvasod a gombodat, és tuti stabil pillnatban fogod beolvasni. Az időzítőt meg leveheted annyira rövidre, ami biztosan hosszabb, mint két pattanás között eltelhető idő, és akkor nem kell lamentálni azon, hogy az időzítés alatt beütött-e még megszakítás a gombról, és mit csináljak vele. Akár meg is számolhatod, hányat pattan az érintkező, mielőtt stabil lett.
holex
Biztosítékgyilkos
Hozzászólások: 70
Csatlakozott: 2013. október 29. kedd, 1:35

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: holex »

Hmm, nem is rossz ötlet. Köszönöm mindenkinek!
Avatar
kapu48
Elektronbűvölő
Hozzászólások: 3375
Csatlakozott: 2008. augusztus 29. péntek, 6:00

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: kapu48 »

A fentebb vázolt megoldásnak csak az a hibája, hogy a mai kapcsolók már inkább elengedéskór preleznek többet! :?
Avatar
SzLacus
Tranzisztorgyógyász
Hozzászólások: 175
Csatlakozott: 2012. május 20. vasárnap, 6:00

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: SzLacus »

Szegény holex arra még nem kapott választ, hogy miért így működik (mert a téma felvetésben ez a kérdés szerepel) viszont van számos tanácsa arra nézvést, hogyan kezelje le. :D Most megtoldom mégeggyel. A kontaktussal párhuzamosan egy soros RC tag jelentősen le tudja csillapítani a mechanikus jelenség elektromos következményét. Az R-t nem kifelejteni, mert ez fogja korlátozni azt az áramot, ami a kondi kisütésekor a kontaktuson folyik. Nélküle a kontaktus igen hamar be fog égni. Az RC időállandóját pedig figyelembe illik venni a késleltetési idő meghatározásánál. És akkor HW és SW együtt azon dolgozik, hogy a meckanikusan tökéletlen kapcsoló közelítsen az ideális kapcsolóhoz.
De ha valaki tudja, hogy miért úgy kell a beesett megszakítást törölni, ahogyan, azt én is szívesen olvasnám. A miértekre kapott válasz az mindíg megalapozottabbá teszi a tudást. Így lesz a betanított munkásból szakember.
A hozzászólást 1 alkalommal szerkesztették, utoljára SzLacus 2013. december 9. hétfő, 14:47-kor.
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: csabeszq »

Már egyszer leírtam, de úgy látom, elsiklott a rengeteg információ között.

Melyik a gyorsabb:

Kód: Egész kijelölése

PCIFR = _BV(PCIF0); // jelenlegi működés
Vagy:

Kód: Egész kijelölése

PCIFR &= !_BV(PCIF0); // miért ne nullát írnánk bele
Assemblyben (elnagyolva, jelenlegi):

Kód: Egész kijelölése

ldi r24, _BV(PCIF0);
out PCIFR, r24
Assemblyben (elnagyolva, az általatok javasolt):

Kód: Egész kijelölése

in r24, PCIFR
cbi r24, PCIF0
out PCIFR, r24
A két példából látható, hogy az értékadás egyrészt olcsóbb, mint nullázgatni a regiszter bitjeit, de ennél egy sokkal nagyobb bajt is orvosol. Ugyanis kinullázással nagyon komoly szinkronizálási hibák lehetnek.

Kód: Egész kijelölése

in r24, PCIFR // itt beolvasod a PCIFR-t, kizárólag PCIF0 van beállítva:  00000001
cbi r24, PCIF0 // itt kinullázod a bitjét: 00000000

// itt történik egy másik PIN CHANGE, mondjuk PCIF1, a regiszter értéke most 00000011, mert 2 PCINT volt

out PCIFR, r24 // minthogy r24-ben nulla van, ezért egyszerre lenullázod a PCIF0-t és a PCIF1-et
Az általatok javasolt megoldás nemcsak lassabb az ATMEL megoldásánál, de simán eseményt is veszíthet.
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: csabeszq »

A fenti példából következik, hogy

Kód: Egész kijelölése

PCIFR |= _BV(PCIF0); // tipikus programozói hiba
az összes interruptot PCIFR-ben kinullázza. Az OR művelet miatt ahol a regiszterben eredetileg 1-es szerepelt, az törlésre kerül.
Ebben az esetben az |= szigorúan tilos.

Helyes:

Kód: Egész kijelölése

PCIFR = _BV(PCIF0);
holex
Biztosítékgyilkos
Hozzászólások: 70
Csatlakozott: 2013. október 29. kedd, 1:35

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: holex »

" Az OR művelet miatt ahol a regiszterben eredetileg 1-es szerepelt, az törlésre kerül."

De hát ha 0-val VAGY-olsz, akkor változatlan marad az érték.

MOD: na közben leesett :D
szóval nekem is át kellene írnom a PCIFR |= 0x01; sort PCIFR=1-re?
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: Pin Change Interrupt - miért így működik?

Hozzászólás Szerző: csabeszq »

Érdemes a jó módszert átvenni és használni. Ez tipikusan olyan hibák forrása, hogy 3 hétig keresheted rá a megoldást. Ritkán jön elő a probléma, de akkor nagy bajt csinál.
Válasz küldése