Ich weiß, bestimmt eine dumme Frage:
ich arbeite mit einem Tiny2313 - wenn ich einen PCINT auslöse, gibt es
da ein Flag Register (ähnlich dem EIFR für den Interrupt) in welchem der
ausgelöste PCINT bzw. Pin steht? Im Datenblatt finde ich dazu leider
nichts (Seite 61)
Vielen Dank schonmal für die Hilfe.
Verdammt, ich ahnte es... :/
Da bleibt mir im Grunde garnichts anderes übrig als entweder drei if
oder eine Switch/Case Anweisung in die Interruptroutine zu bringen?!
Nicht sehr schön und sauber. Ich hab das mal so gelöst auf die schnelle:
(Achtung ist MikroC)
1
volatileintPinChangeHistory=0xff;
2
3
voidmain(){
4
5
// Portsettings:
6
DDRB=0b11111000;// Set In/Out (in) PB0,PB1,PB2 - for Servosignal
7
DDRA=0b00000011;// Set In/Out (out) PA0,PA1 - Out1,Out2
8
DDRD=0b00111100;// Set In/Out (out) PD2,PD3,PD4,PD5 - Out3-5
Draco schrieb:> volatile int PinChangeHistory = 0xff;> int PinChanges;
Als erstes würd ich das (und alles andere was nur 8 Bit benötigt) als
uint_8t deklarieren, also grundsätzlich keinesfalls unnötig größer als
die native Registergröße der verwendeten CPU. Bedenke daß das ein
8-Bit-Prozessor ist, es erzeugt unnötige Verrenkungen im Code mit 16 Bit
herumzuhantieren, da braucht er jedesmal 2 Register statt einem, der
erzeugte Code wird spürbar größer und entsprechend langsamer, vor allem
in einer ISR willst Du sowenig wie möglich Register verschwenden und
auch nicht unnötig Zeit verplempern um unbenutzte Nullen
herumzuschieben.
Bernd K. schrieb:> Draco schrieb:>> volatile int PinChangeHistory = 0xff;>> int PinChanges;>> Als erstes würd ich das (und alles andere was nur 8 Bit benötigt) als> uint_8t deklarieren, also grundsätzlich keinesfalls unnötig größer als> die native Registergröße der verwendeten CPU. Der erzeugte Code wird> spürbar kleiner und entsprechend schneller.
Außerden wäre es sinnvoll, PinChangeHistory innerhalb der ISR als static
und ohne volatile zu definieren.
Die ifs lassen sich (wenn PinChanges auf 8 Bit reduziert wird), in einem
AVR sehr effizient über die Skip-Befehle umsetzen.
Weiterhin sollte PINB nur genau einmal gelesen werden:
Erstmal vielen Dank Bernd und Rolf,
ich habe eure Vorschläge berücksichtigt und bin, zugegeben, sehr
überrascht! In MikroC ist uint8_t gleich unsigned short (1 byte). Auch
das ich PortB nur einmal auslesen lasse verringert den Flash Bedarf um
satte 20 Bytes. Das ist bei solch einem kleinen Tiny schon sehr viel und
die kleinen Änderungen bringen den benötigten Platz um satte drei
Prozent nach unten. Ich sollte mich da echt mehr einlesen um solche
"Fallen" gleich beizeiten auszumerzen.
MikroC lässt ein direkte zuweißung in der ISR (uint_8t pinbx = PORTB)
nicht zu. Das muss ich separat machen.
Auch über den Skip Befehl hab ich mich mal kurz drüber gemacht. So wie
ich das gerade verstanden habe, kann ich via ASM mit dem Skip (SBRS,
SBIS) den nächsten Befehl überspringen. Aber da muss ich mich erst näher
einlesen um dies in die IF besser zu integrieren.
1
voidmain(){
2
3
// Portsettings:
4
DDRB=0b11111000;// Set In/Out (in) PB0,PB1,PB2 - for Servosignal
5
DDRA=0b00000011;// Set In/Out (out) PA0,PA1 - Out1,Out2
6
DDRD=0b00111100;// Set In/Out (out) PD2,PD3,PD4,PD5 - Out3-5
Draco schrieb:> ich habe eure Vorschläge berücksichtigt und bin, zugegeben, sehr> überrascht! In MikroC ist uint8_t gleich unsigned short (1 byte).
Das ist aber eigentlich nicht konform. short muß laut ISO C eigentlich
mindestens 16 Bit breit sein.
> MikroC lässt ein direkte zuweißung in der ISR (uint_8t pinbx = PORTB)> nicht zu. Das muss ich separat machen.
Hmm, merkwürdig.
> Auch über den Skip Befehl hab ich mich mal kurz drüber gemacht. So wie> ich das gerade verstanden habe, kann ich via ASM mit dem Skip (SBRS,> SBIS) den nächsten Befehl überspringen.
Ja, und zwar abhängig davon, ob in einem Register ein bestimmtes Bit
gesetzt ist oder nicht. Das ist eben für genau solche Fälle, wie du es
hier brauchst, effizienter als eine Und-Verknüpfung, ein Vergleich und
ein bedingter Sprung.
> Aber da muss ich mich erst näher einlesen um dies in die IF besser zu> integrieren.
Die muss der Compiler integrieren, nicht du.
Draco schrieb:> In MikroC ist uint8_t gleich unsigned short (1 byte)
short ist aber eigentlich mindestens 16 bit, alles andere wäre wirklich
schräg und nicht standardkonform, ich glaube da bist Du irgendwo in der
Zeile verrutscht.
nimm explizit uint8_t (oder notfalls unsigned char). überhaupt würd ich
bei 8- und 16-bittern grundsätzlich auf die "schwammigen" typen
verzichten und stattdessen nur die posix typen mit den knallhart
definierten Bitbreiten nehmen, und auch bei breiteren CPUs schadet das
nicht und vermeidet potentiellen Ärger in der Zukunft.
Karl H. schrieb:> Draco schrieb:>>> pinbx = PORTB;>> PINB!>> Du willst vom PINB Register lesen und nicht von PORTB
Ja... war im zweiten Listing glaube ich schon korrigiert. Spätestens
wenn die Maske leer gewesen wäre, wäre die erste verwunderung wieder da
gewesen :D Hat es noch rechtzeitig gesehen. Aber danke schön :)
Draco schrieb:> PinChanges = PINB ^ PinChangeHistory;> PinChangeHistory = PINB;
Theoretisch könntest du hier beim 2. Zugriff auf PINB ein anderes
Ergebnis bekommen, als beim 1. ten Zugriff.
Du willst bei solchen Dingen, das bewusste Register immer nur ein
EINZIGES mal auslesen und dann mit diesem garantiert gleichbleibendem
Wert weiter operieren.
STK500-Besitzer schrieb:> Draco schrieb:>> in welchem der>> ausgelöste PCINT bzw. Pin steht?>> Neín. Das gibt es nicht. Das musst du selber verwalten.
dachte ich auch schon,
aber warum alle PCINT in einer ISR erfassen wollen?
ich dachte eher so:
ISR(PCINT2_vect)
da hast du doch jeden PCINT gleich passend.
Joachim B. schrieb:> STK500-Besitzer schrieb:>> Draco schrieb:>>> in welchem der>>> ausgelöste PCINT bzw. Pin steht?>>>> Neín. Das gibt es nicht. Das musst du selber verwalten.>> dachte ich auch schon,>> aber warum alle PCINT in einer ISR erfassen wollen?>> ich dachte eher so:>> ISR(PCINT2_vect)>> da hast du doch jeden PCINT gleich passend.
JAIN
PCINT2_vect ist der PinChangeInterrupt eines anderen Port... Beim 2313
gibt es den PinChangeInterrupt "nur" an PortB. Wenn ein anderer AVR z.b.
PinChangeInterrupts an mehreren Ports hat (PortC, PortD....) dann hat
jeder eigene Port seinen Interrupt Vector. Das hat nichts mit den
PortPins (PB1, PB2...PE1,PE2....) zu tun.
Karl H. schrieb:> Draco schrieb:>>> PinChanges = PINB ^ PinChangeHistory;>> PinChangeHistory = PINB;>> Theoretisch könntest du hier beim 2. Zugriff auf PINB ein anderes> Ergebnis bekommen, als beim 1. ten Zugriff.>> Du willst bei solchen Dingen, das bewusste Register immer nur ein> EINZIGES mal auslesen und dann mit diesem garantiert gleichbleibendem> Wert weiter operieren.
Ja das war noch das alte aus MikroC - ich habe mich entschlossen das im
AVR Studio zu machen... moment... so siehts aus:
1
ISR(PCINT_vect)
2
{
3
4
uint8_tpinb=PINB;
5
uint8_tpinChanges;
6
7
pinChanges=pinb^pinChangeHistory;
8
pinChangeHistory=pinb;
9
10
if(pinChanges&(1<<PINB0))
11
{
12
if(TCNT0>100)
13
{
14
Timer[0]=TCNT0;
15
}
16
TCNT0=0;
17
}
18
19
if(pinChanges&(1<<PINB1))
20
{
21
Timer[1]=TCNT0;
22
TCNT0=0;
23
}
24
25
if(pinChanges&(1<<PINB2))
26
{
27
Timer[2]=TCNT0;
28
TCNT0=0;
29
}
30
31
outGo=1;
32
}
Wobei ich da grad noch am rumexperimentieren bin WO ich am besten den
kurzen PWM Nippel rausfiltere, entweder direkt in der ISR bevor er
überhaupt übergeben wird oder später in der normalen "Arbeitsroutine" -
das ist so nen Zwiespalt: Ich will ja die ISR so schlank wie möglich
halten, aber da ist das rausfiltern einfach angenehmer.
Draco schrieb:> Ich will ja die ISR so schlank wie möglich> halten
so schlank wie möglich heisst nicht, dass man gar nichts machen darf. Im
Zweifel sieht man sich das Assembler Listing an und entscheidet, ob es
ok ist, wenn da 10 oder 15 Takte mehr verbraucht werden.
So mal am Rande... da ich die Timer Werte ja in einer Matrix abspeicher,
wäre meine Idee nun, warum kann ich nicht gleich die Variable
"pinChanges" dazu benutzen die Matrixposition anzulaufen?! Ich hab mir
da mal so meine Gedanken gemacht:
1
// Alter Stand vom ehemaligen Input
2
// z.b.: 10010000
3
4
uint8_tpinChangeHistory;
5
6
7
8
// Aktueller Port Stand in die Variable schreiben:
9
// z.b.: 10010001 (Pin0 bekommt input)
10
11
uint8_tpinb=PINB;
12
13
14
15
// XOR Anweisung zum setzen der aktiven Bits in beiden Variablen:
16
// z.b.: 10010000 ^ 10010001 = 00000001 in pinChanges
17
18
pinChanges=pinb^pinChangeHistory;
Da steht ja dann eine Dezimal Zahl von "1" bei PinB1 wäre das dann die
"2" bei PinB2 die "4" usw.... Kann man das vernünftig und schnell
shiften das man daraus eine 0,1,2,3 etc... bekommt?!
Draco schrieb:> Da steht ja dann eine Dezimal Zahl von "1" bei PinB1 wäre das dann die> "2" bei PinB2 die "4" usw.... Kann man das vernünftig und schnell> shiften das man daraus eine 0,1,2,3 etc... bekommt?!
nein, da auch in pinChanges eine 3 oder 7 oder 155 oder jede andere
Bitkombination aus 8 Bits enthalten sein kann. Nämlich immer dann wenn
die PinChange ISR aufgerufen wurde weil sich zum Beispiel gleichzeitig
mehrere Eingänge geändert haben.
Davon abgesehen steht in pinChanges immer dann eine 1 in den Bits wenn
sich der PIN geändert hat. D.h. auch wenn er vorher auf HIGH Pegel war
und nun auf LOW Pegel umgeschaltet wurde. Wenn du zB. nur auf einen
Pegelwechsel reagieren möchtest wenn der Eingangspin auf HIGH Pegel
geändert wurde dann musst du sowohl pinChanges als auch pinb zusammen
abfragen, Zb. per UND-Verküpfung beider Variablen.