Hallo Zusammen,
ich möchte in meiner Interruptabfrage, welche bei steigender und
fallender Flanke ausgelöst wird, prüfen ob die Flanke fallend oder
steigend war. Das funktionier soweit.
Mein einziges Problem ist es nun, das meine Interruptpins sich je nach
Programmablauf verändern. Beispielsweise möchte ich manchmal auf PA4
prüfen und manchmal auf PA5.
Dazu habe ich mir Variable "empfangspin" angelegt, in der der int-Wert 4
oder 5 steht um diese während des Programmes verändern zu können. Das
funktioniert allerdings nicht. Mache ich die Abfrage allerdings mit PA4
oder PA5 statt der Variable "empfangspin" funktioniert die Abfrage
hervorragend.
An was liegt, bzw. wie kann ich das ändern?
1
ISR(PCINT0_vect)//ISR zum Empfangen
2
{
3
if(PINA&(1<<empfangspin))//Prüfen auf High, steigende Flanke
4
{
5
TCCR1B|=PRESCALER;
6
}
7
if(!(PINA&(1<<empfangspin)))//Prüfen auf Low, fallende Flanke
David Schuetze schrieb:> Dazu habe ich mir Variable "empfangspin" angelegt, in der der int-Wert 4> oder 5 steht um diese während des Programmes verändern zu können. Das> funktioniert allerdings nicht.
Das müsste eigentlich schon funktionieren.
Mal ganz davon abgesehen, dass man das eigentlich nicht machen will,
weil es den Compiler daran hindert, die eigentliche Pinabfrage zu
optimieren und so schnell zu machen.
> An was liegt, bzw. wie kann ich das ändern?
du könntest zb das ganze so machen
1
ISR(...)
2
{
3
uint8_tpinWert;
4
5
if(empfangspin==4)
6
pinWert=(PINA&(1<<PA4));
7
else
8
pinWert=(PINA&(1<<PA5));
9
10
if(pinWert)
11
TCCR1B|=PRESCALER;
12
else
13
TCCR1B=0;//Timer stoppen
14
15
...
16
}
es ist nicht ganz dasselbe, denn die Originallösung würde auf jeden Pin
am Port A losgelassen werden können und nicht nur auf die Pins 4 bzw. 5.
if(PINA&(1<<empfangspin))//Prüfen auf High, steigende Flanke
2
{
3
...
4
}
5
if(!(PINA&(1<<empfangspin)))//Prüfen auf Low, fallende Flanke
Wenn der Pin als High identifiziert wurde, dann wird der eine Pfad
genommen. Das Gegenteil davon ist ein else und nicht eine erneute
Abfrage des Pins. Ein Pin kann nur entweder 0 oder 1 sein. WEnn er nicht
1 ist, dann MUSS er 0 sein, es gibt keine andere Möglichkeit.
1
if(PINA&(1<<empfangspin))//Prüfen auf High, steigende Flanke
2
{
3
...
4
}
5
else
6
{
7
...
8
}
Du hast nämlich sonst 2 Abfragen hintereinander, für die du als
Programmierer verantwortlich bist, dass die zweite immer das Gegenteil
der ersten aussagt. Menschen machen aber Fehler. WEnn du genau dasselbe
mit nur einer Abfrage ausdrücken kannst, dann mach das auch. Denn
dadurch bist du automatisch diesen impliziten Zusammenhang zwischen 2
Abfragen los, den du 100% korrekt hinkriegen musst. 'else' implementiert
dir ganz von alleine diese "entweder - oder" Beziehung.
An Stelle variabler Shifts würde ich direkt die Maske speichern,
insbesondere bei AVRs. Also statt
empfangspin = PA4;
if (PINA & (1<<empfangspin))
besser
empfangspin = 1 << PA4;
if (PINA & empfangspin)
A. K. schrieb:> An Stelle variabler Shifts würde ich bei AVRs lieber direkt die Maske> speichern. Also statt> empfangspin = 4;> if (PINA & (1<<empfangspin))> besser> empfangspin = 1 << 4;> if (PINA & empfangspin)
dich denke nicht das das besser ist. Denn er weiß nicht wie viele Bits
in empfangspin gesetzt sind. Damit kann ich nicht ein Einzels Bit vom
Port abfragen.
Peter II schrieb:> dich denke nicht das das besser ist. Denn er weiß nicht wie viele Bits> in empfangspin gesetzt sind. Damit kann ich nicht ein Einzels Bit vom> Port abfragen.
Ich verstehe nicht, was du damit meinst. Nach
empfangspin = 1 << 4;
ist nach meinem Verständnis wirklich nur 1 Bit gesetzt.
Mir ging es allerdings eher darum, dass bei AVRs dynamische Shifts
ziemlich ineffizient sind. Und man sie völlig ohne Verlust durch eine
Maske ersetzen kann.
Ich denke mal, es handelt sich hier um einen AVR?! Wenn dem so ist, dann
musst du (laut Datenblatt!) vor dem Einlesen eines Pins ein NOP()
einfuegen!
z.B. Datenblatt des Mega2560, Kapitel 13.2.4 Reading the Pin Value,
Seite 72
"Independent of the setting of Data Direction bit DDxn, the port pin can
be read through the
PINxn Register bit. As shown in Figure 13-2 on page 71, the PINxn
Register bit and the preced-ing latch constitute a synchronizer. This is
needed to avoid metastability if the physical pin
changes value near the edge of the internal clock, but it also
introduces a delay. Figure 13-3 on
page 73shows a timing diagram of the synchronization when reading an
externally applied pin
value."
und auf Seite 74 der Beispielcode:
A. K. schrieb:> Ich verstehe nicht, was du damit meinst. Nach> empfangspin = 1 << 4;> ist nach meinem Verständnis wirklich nur 1 Bit gesetzt.
aber davon weiß die ISR nichts mehr, für sie ist empfangspin nur eine
variable.
Kaj schrieb:> Ich denke mal, es handelt sich hier um einen AVR?! Wenn dem so ist, dann> musst du (laut Datenblatt!) vor dem Einlesen eines Pins ein NOP()> einfuegen!
Nicht in jedem Fall, sondern nur dann, wenn sich der Zustand vom Pin
durch eine unmittelbar davor liegenden Änderung an irgendeinem
PORTx/DDRx geändert haben könnte. Das ist hier aber nicht der Fall.
Kaj schrieb:> Ich denke mal, es handelt sich hier um einen AVR?! Wenn dem so ist, dann> musst du (laut Datenblatt!) vor dem Einlesen eines Pins ein NOP()> einfuegen!
nein! Bitte richtig lese!
Nur wenn man die Datenrichtung ändert und dann liest.
Na und? Der variable Shift wird dadurch auf jeden Fall vermieden; es
wird eben ein AND gegen ein Register gemacht (das, is das empfangspin
geladen wirde). Das dauert 1 Tick.
Peter II schrieb:> aber davon weiß die ISR nichts mehr, für sie ist empfangspin nur eine> variable.
Und? Als Pinnummer 8 reinzuschreiben ist auch nicht besser als die Maske
0x30 reinzuschreiben.
Die Unterscheidung zwischen Nummer und Maske kann man über den Namen
eingabepinMaske
signalisieren.
Johann L. schrieb:> Na und? Der variable Shift wird dadurch auf jeden Fall vermieden; es> wird eben ein AND gegen ein Register gemacht (das, is das empfangspin> geladen wirde). Das dauert 1 Tick.
warum erst Optimierung und dann wieder ein Takt verschwenden? Dann kann
man es gleich so stehen lassen, es scheint ja kein Zeitproblem zu geben.
Peter II schrieb:> warum erst Optimierung und dann wieder ein Takt verschwenden? Dann kann> man es gleich so stehen lassen, es scheint ja kein Zeitproblem zu geben.
Hast du mal nachgesehen, was bei 1<<n rauskommt? Eine Schleife mit n
Durchläufen (vmtl n*4 Takte). Zusätzlich zu dem einen Takt fürs AND. Das
ist nichts, was ich völlig unnötig in eine ISR stecken würde.
A. K. schrieb:> Hast du mal nachgesehen, was bei 1<<n rauskommt? Eine Schleife mit n> Durchläufen.
wobei n = 4 ist.
und wo ist das Problem?
Er hat keine Probleme mit dem Timing, so Problem liegt woanders. Warum
wird wieder versucht eine Lösung für ein Problem zu finden was gar nicht
da ist?
Also die Variable war als volatile deklariert. Ich bin erst ziemlich neu
in der AVR-Programmierung. Es handelt sich um einen ATtiny20.
Jedenfalls funktioniert es jetzt hervorragend mit dieser Lösung:
ISR( ... )
{
uint8_t pinWert;
if( empfangspin == 4 )
pinWert = ( PINA & ( 1 << PA4 ) );
else
pinWert = ( PINA & ( 1 << PA5 ) );
if( pinWert )
TCCR1B |= PRESCALER;
else
TCCR1B =0; //Timer stoppen
...
}
Vielen Dank!!! :)
Peter II schrieb:> A. K. schrieb:>> Ich verstehe nicht, was du damit meinst. Nach>> empfangspin = 1 << 4;>> ist nach meinem Verständnis wirklich nur 1 Bit gesetzt.>> aber davon weiß die ISR nichts mehr, für sie ist empfangspin nur eine> variable.
Ja, und da es eine Variable ist, ist es für die Berechnung auch wurscht,
ob da nun genau ein Bit gesetzt ist oder mehrere. Die Assembler-Befehle
sbic/sbir zum Abfragen einzelner Bits in I/O-Registern, auf die du dich
vermutlich beziehst, gehen sowieso nur mit Immediate-Werten.
Besser ist die Variante von A.K. gegenüber der ursprünglichen auf jeden
Fall, da man sich wie er schon schreibt die Schleife in der ISR für die
Bit-Schieberei spart, die bei seiner Lösung komplett entfällt.
Peter II schrieb:> A. K. schrieb:>> Hast du mal nachgesehen, was bei 1<<n rauskommt? Eine Schleife mit n>> Durchläufen.>> wobei n = 4 ist.>> und wo ist das Problem?
Es werden unnötig Takte verbraten, ohne daß das auch nur im Geringsten
irgendeinen Vorteil hätte, und es ist sehr einfach zu vermeiden.
> Er hat keine Probleme mit dem Timing, so Problem liegt woanders.
Und? Darf man ihm deshalb keine Tipps geben, wie er sein Programm
verbessern kann?
Rolf Magnus schrieb:> Besser ist die Variante von A.K. gegenüber der ursprünglichen auf jeden> Fall, da man sich wie er schon schreibt die Schleife in der ISR für die> Bit-Schieberei spart, die bei seiner Lösung komplett entfällt.
schon klar das sie besser ist - nur trägt sie nicht zu Lösung das
eigentlichen Problems bei.
Er hat zwar jetzt ein Lösung gefunden, aber wo das Problem lagt ist
immer (mir) nicht bekannt.
Quack schrieb:> Peter II schrieb:>> pinWert wurde vorher nicht auf 0 gesetzt.>> Und jetzt auch nicht. Also?
bei den andere Lösung wird er immer gesetzt, bei deiner leider nicht.
Peter II schrieb:> bei den andere Lösung wird er immer gesetzt, bei deiner leider nicht.
Mein kleiner Spass bezog sich nur auf den zitierten Code, nicht auf den
Rest.
Peter Dannegger schrieb:> Das mit der Bit-Maske ist schon o.k.:
Die muss aber keineswegs volatile sein. Wenn die ISR aufgerufen wird,
kann der Compiler nie auf einen gecacheten Wert für die Maske
zurückgreifen, folglich muss er sie immer aus dem Hauptspeicher erst
einmal lesen, "volatile" oder nicht.
Jörg Wunsch schrieb:> Die muss aber keineswegs volatile sein. Wenn die ISR aufgerufen wird,> kann der Compiler nie auf einen gecacheten Wert für die Maske> zurückgreifen, folglich muss er sie immer aus dem Hauptspeicher erst> einmal lesen, "volatile" oder nicht.
das stimmt, aber im Hauptprogramm muss es noch nicht in den Ram
geschrieben wurden sein.
Jörg Wunsch schrieb:> Die muss aber keineswegs volatile sein. Wenn die ISR aufgerufen wird,> kann der Compiler nie auf einen gecacheten Wert für die Maske> zurückgreifen,
Ohne volatile kann es aber sein, dass der Inhalt nicht dort in die
Variable geschrieben wird, wo das Statement steht, sondern erst später.
Vielleicht zu spät.