Pin Change Interrupt - miért így működik?
Pin Change Interrupt - miért így működik?
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?
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?
Re: Pin Change Interrupt - miért így működik?
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.
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.
Re: Pin Change Interrupt - miért így működik?
Na szerintem kicsit félreértettük egymást
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
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
Re: Pin Change Interrupt - miért így működik?
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.
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.
Re: Pin Change Interrupt - miért így működik?
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:
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
Re: Pin Change Interrupt - miért így működik?
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.
Természetesen nem atombombabiztos és az általam említetteket lehet produkálni, de nem biztos, hogy van értelme az átírásnak.
Re: Pin Change Interrupt - miért így működik?
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.
Re: Pin Change Interrupt - miért így működik?
Hmm, nem is rossz ötlet. Köszönöm mindenkinek!
Re: Pin Change Interrupt - miért így működik?
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! 
Re: Pin Change Interrupt - miért így működik?
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.
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.
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.
Re: Pin Change Interrupt - miért így működik?
Már egyszer leírtam, de úgy látom, elsiklott a rengeteg információ között.
Melyik a gyorsabb:
Vagy:
Assemblyben (elnagyolva, jelenlegi):
Assemblyben (elnagyolva, az általatok javasolt):
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.
Az általatok javasolt megoldás nemcsak lassabb az ATMEL megoldásánál, de simán eseményt is veszíthet.
Melyik a gyorsabb:
Kód: Egész kijelölése
PCIFR = _BV(PCIF0); // jelenlegi működés
Kód: Egész kijelölése
PCIFR &= !_BV(PCIF0); // miért ne nullát írnánk bele
Kód: Egész kijelölése
ldi r24, _BV(PCIF0);
out PCIFR, r24
Kód: Egész kijelölése
in r24, PCIFR
cbi r24, PCIF0
out PCIFR, r24
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
Re: Pin Change Interrupt - miért így működik?
A fenti példából következik, hogy
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); // tipikus programozói hiba
Ebben az esetben az |= szigorúan tilos.
Helyes:
Kód: Egész kijelölése
PCIFR = _BV(PCIF0);
Re: Pin Change Interrupt - miért így működik?
" 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
szóval nekem is át kellene írnom a PCIFR |= 0x01; sort PCIFR=1-re?
De hát ha 0-val VAGY-olsz, akkor változatlan marad az érték.
MOD: na közben leesett
szóval nekem is át kellene írnom a PCIFR |= 0x01; sort PCIFR=1-re?
Re: Pin Change Interrupt - miért így működik?
É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.