Hallo an alle,
ich habe eine kleine Frage:
kann ich einen Pin, der als PCINT-Pin festgelegt wurde als Output
definieren?
ich habe vor, 5 SRF05 im Modus 2(also nur mit einem Pin) zu betreiben.
Also muss ich zum Auslösen eines Messvorgangs den Pin auf high setzen.
Um nich meine Zeit mit warten zu vertrödeln, soll das ganze
Interruptgesteuert umgesetzt werden. Leider ist die Platine dafür schon
fertig und die Pins damit festgelegt.
uC ist ein mega2560
US0: PB6
US1: PB1
US2: PB7
US3: PB3
US4: PB5
Der Code würde dann ungefähr so aussehen:
Zum Auslösebefehl senden:
1
voidstartUS(uint8_tnum)
2
{
3
switch(num)
4
{
5
case0:
6
DDRB|=(1<<US0);
7
PORTB|=(1<<US0);
8
//warten
9
PORTB&=~(1<<US0);
10
DDRB&=~(1<<US0);
11
break;
12
case1:
13
DDRB|=(1<<US1);
14
PORTB|=(1<<US1);
15
//warten
16
PORTB&=~(1<<US1);
17
DDRB&=~(1<<US1);
18
break;
19
case2:
20
DDRB|=(1<<US2);
21
PORTB|=(1<<US2);
22
//warten
23
PORTB&=~(1<<US2);
24
DDRB&=~(1<<US2);
25
break;
26
case3:
27
DDRB|=(1<<US3);
28
PORTB|=(1<<US3);
29
//warten
30
PORTB&=~(1<<US3);
31
DDRB&=~(1<<US3);
32
break;
33
case4:
34
DDRB|=(1<<US4);
35
PORTB|=(1<<US4);
36
//warten
37
PORTB&=~(1<<US4);
38
DDRB&=~(1<<US4);
39
break;
40
default:
41
break;
42
}
43
}
sowie die PCINT0-Interrupt:
1
ISR(PCINT0_vect)
2
{
3
staticuint16_tval[5];
4
if(PINB&(1<<PB1))//1 high
5
{
6
val[1]=TCNT3;
7
}
8
elseif(!(PINB&(1<<PB1)))//1 low
9
{
10
us[1]=(TCNT3-val[1]);
11
}
12
elseif(PINB&(1<<PB6))//0 high
13
{
14
val[0]=TCNT3;
15
}
16
elseif(!(PINB&(1<<PB6)))//0 low
17
{
18
us[0]=(TCNT3-val[0]);
19
}
20
elseif(PINB&(1<<PB7))//2 high
21
{
22
val[2]=TCNT3;
23
}
24
elseif(!(PINB&(1<<PB7)))//2 low
25
{
26
us[2]=(TCNT3-val[2]);
27
}
28
elseif(PINB&(1<<PB3))//3 high
29
{
30
val[3]=TCNT3;
31
}
32
elseif(!(PINB&(1<<PB3)))//3 low
33
{
34
us[3]=(TCNT3-val[3]);
35
}
36
elseif(PINB&(1<<PB5))//4 high
37
{
38
val[4]=TCNT3;
39
}
40
elseif(!(PINB&(1<<PB5)))//4 low
41
{
42
us[4]=(TCNT3-val[4]);
43
}
44
}
ist soweit der Code ok? gerade die Interrupt-Methode?
Geht das so überhaupt?
Bin für alles dankbar.
ich hab sowieso wieder was vergessen, also einfach fragen ;)
The External Interrupts are triggered by the INT7:0 pin or any of the PCINT23:0 pins. Observe
2
that, if enabled, the interrupts will trigger even if the INT7:0 or PCINT23:0 pins are configured as
3
outputs. This feature provides a way of generating a software interrupt.
Ergo: Ja, aber eine Flanke ist eine Flanke, und löst den Interrupt aus,
egal, ob die von aussen kommt, oder vom Pin selber erzeugt wird. Willst
du das nicht, musst du die Interrupts vorher disablen.
Oliver
Lass die Finger vom SREG, das brauchst du als C-Programierer nie
anzufassen.
Lösch das PCINT-Enable-Bit, bevor du den Pin auf Ausgang schaltest, und
nachdem du zurück auf Eingang geschaltet hast, lösch das zugehörige
ISR-Flag, bevor du PCINT wieder setzt, und gut ist.
Oliver
Oliver schrieb:> Willst> du das nicht, musst du die Interrupts vorher disablen.
Den Pending-Flags ist es wurscht, ob Interrupts gerade gesperrt sind.
Das wäre auch schlimm, denn dann würde man Interrupts verlieren.
Du mußt erst den Pin als Ausgang pulsen, dann auf Eingang setzen und
danach darfst Du das Maskenbit freigeben!
Der PORTB ist ungünstig, damit kriegst Du Meßfehler, wenn noch andere
Interruptquellen zuschlagen können.
Besser sind die ADC-Eingänge, denn die kann man auf die ICU routen.
Damit kriegt man keine Fehler durch die Latenz, die Messungen sind auf
den CPU-Zyklus genau.
Und laß diese Copy&Paste Monster.
Der Code ist für alle Sensoren gleich, nur die Bitmaske ist eine andere.
Also braucht man nur eine Funktion der man die Bitmaske übergibt.
Peter Dannegger schrieb:> Den Pending-Flags ist es wurscht, ob Interrupts gerade gesperrt sind.> Das wäre auch schlimm, denn dann würde man Interrupts verlieren.
Was man aber durchaus möchte. Wenn der Pin als Ausgang gesetzt ist, und
dann auch mal "Pingewackel" von sich gibt (sonst müsste man ihn ja nicht
als Ausgang nutzen), dann setzt das das ISR-Flag. Ob man die so erzeugte
Interruptanforderung sinnvoll per ISR abarbeiten will oder nicht, hängt
von der Anwendung ab.
Oliver
Peter Dannegger schrieb:> Besser sind die ADC-Eingänge, denn die kann man auf die ICU routen.> Damit kriegt man keine Fehler durch die Latenz, die Messungen sind auf> den CPU-Zyklus genau.
ADCs sind leider alle 16 belegt. Und wie gesagt, die Pins sind so
vorgegeben, die Platine liegt schon fertig vor mir.
Oliver schrieb:> Lass die Finger vom SREG, das brauchst du als C-Programierer nie> anzufassen.
Warum? Wenn man einen Block Interruptfest machen will sollte man doch
das Statusregister sichern bevor man das I-Bit löscht?! Oder hab ich da
was falsch verstanden?
Es geht ja nicht darum, einen Block interruptfest zu machen, sondern zu
verhindern, daß PCINT-Interrupts durch den Ausgang ausgelöst werden. Das
ist eine andere Aufgabenstellung, die man dadurch löst, daß man genau
den betroffenen PCINT disabled. Ein Atomic-Block würde nur verindern, da
der Interrupt innerrhalb des Blocks dazwischenfunkt. Verhindert wird der
dadurch nicht, er würde dann halt direkt nach Verlassen des Blocks
ausgeführt.
Zum Thema Automic-Block und SReg hast du prinzipiell recht. Allderings
hat avr-gcc dafür die entsprechenden ATOMIC - Funktionen, so daß man da
auch nicht unbedingt selber ans SReg muß.
Deine ersten beiden SReg-Operationen allerings sind unnötig. Lesen des
Registers hat überhaupt keine Auswirkung auf irgendwas. Beim zweiten
Block mit dem cli() ist es richtig, der ist ab cli() atomic bis zum
zurückschreiben des SReg.
Allerdings sollte man bei dem Verfahren schon sicher sein, daß sich in
dem Atomic-Block keine anderen Flags im SREG verändern, die dan später
noch gebraucht würden. Denn dann schießt man sich mit dem Vorgehen
selber ins Knie.
Oliver
Danke an alle für die Erläuterung, besonders Oliver.
Das mit dem Atimic wusste ich noch nicht, bzw. habe es nie für nötig
gehlaten. Ist das bei anderen Compilern auch vorhanden?
Mein Problem löst man einfach durch:
1
PCMSK0&=~(1<<PCINTx);
(Wenn ich es richtig verstanden habe)
Peter Dannegger schrieb:> Der PORTB ist ungünstig, damit kriegst Du Meßfehler, wenn noch andere> Interruptquellen zuschlagen können.
Wie war das noch gemeint? auf dem Port liegt nichts anderes, was soll
die Messfehler verschulden?
Aber erstmal Danke, ihr habt mir sehr, und vor allem schnell geholfen!