Hallo,
Also was ich vorhabe ist eigentlich trivial, dennoch treibt es mich fast
in den Wahnsinn.
Ich will eine Frequenz messen, genauer gesagt eine Periodendauer.
Ich lege eine Frequenz an meinen Mikrocontroller (ICP1)
dort sollte ja der Timer 1 mit einer Auflösung von 500ns (16MHz mit
Prescaler 8) die Zeit zwischen 2 Flanken messen.
Die Ausgabe ist hier nicht zu beachten, habe ich kurzfristig verändert.
weil mich das ergebnis verwundert hat. Hier sollte man ja eig 0 erwarten
wenn am Eingang ne gleichbleibende Frequenz anliegt.
die Bedingung ist allerdings mal erfüllt und mal nich.
Ich weiß nicht warum ich einfach nicht das erwartete Ergebnis bekommen.
Was ist falsch?
Ich bitte um Hilfe, is sicher iwo ein grobes Verständnisproblem
meinerseits.
Habe ich gestern schon versucht und die Tipps von einem Moderator
umgesetzt, es hilft aber nix.
hier mein Code:
1
voidInterrupt_init()
2
{
3
sei();
4
GICR|=(1<<INT1);
5
GIFR=(INTF1);
6
TIMSK|=(1<<TICIE1);
7
TCCR1A=0x00;
8
TCCR1B=(1<<ICNC1)|(1<<ICES1)|(1<<CS11)|(0<<CS10);
9
10
}
11
12
voidAusgabe()
13
{
14
while(1)
15
{
16
PORTA=0x00;//Startsignal - alle LED an
17
_delay_ms(1000);
18
}
19
if(u8_timerwert[1]-u8_timerwert[0]<90)
20
{
21
PORTA=0b00000101;
22
_delay_ms(400);
23
}
24
else
25
{
26
PORTA=0b00000001;
27
_delay_ms(400);
28
}
29
30
}
31
}
32
33
volatileuint8_tflag;
34
volatileuint8_ti=0;
35
ISR(TIMER1_CAPT_vect)
36
{
37
38
if(i>0)//ersten Wert verwerfen
39
{
40
u8_timerwert[i-1]=ICR1;//Array mit Timerwerten beschreiben
Wenn Du zwischen dem lesen von zwei Timerwerten durch einen Interrupt
unterbrochen wirst, erhälst Du zwei Werte, die nicht mehr zusammen
passen.
Du musst beim Lesen Interrupts sperren:
cli();
uint8_t a=u8_timerwert[1];
uint8_t b=u8_timerwert[0];
sei();
if (a-b<90) ...
Ok, aber bei meiner derzeitig verwendeten Frequenz von 20,8kHz sollte
das doch zeitunkritisch sein oder?
Ich habe dabei 48µs Zeit bis zum nächten Interrupt, und was ich während
dessen mache sollte doch nicht so lang dauern.
Oder verstehe ich hier etwas falsch?
Danke trotzdem für den Rat, ich versuch natürlich das umzusetzen.
sperrt denn cli(); wirklich in jedem Fall den Interrupt?
würde ich nicht machen. Wenn nämlich vor dem Aufruf die Interrupts schon
gesperrt waren, werden sie hier mit sei(); auf jeden Fall freigegeben.
Das heißt, daß nicht der vorherige Zustand wiederhergestellt wird.
Besser ist es so:
1
uint8_tsreg;
2
sreg=SREG;
3
cli();
4
...
5
...
6
SREG=sreg;
Dann wird nach dem Vorgang der vorherige Zustand wieder hergestellt.
> Ich habe dabei 48µs Zeit bis zum nächten Interrupt
Du sollst die Interrups im Hauptprogramm sperren. Da dieses keine
Rücksicht auf die Zeitpunkte der Interrupts nimmt, kann ein Interrupt
zwischen dem lesen der zwei Werte stören.
Die Interrupt-Routine ist schon Ok - jedefalls auf den ersten Blick.
Habs grad mal mit dem Oszi gemessen, also meine ISR läuft nur 1,6µs, das
heißt ja ein neuer Interrupt kommt mir während der Zeit der Verarbeitung
nicht dazwischen.
Aber mach ich vlt iwo beim setzen der Bits in den Registern was falsch?
Ich habe jetzt eine Frequenz von 20,8kHz anliegen und der Timer auf der
Empfängerseite läuft mit 2MHz (16MHz mit Prescaler 8)
also sollte doch ein Timerwert von 96=T1/T2 zu erwarten sein oder
zumindest 95-97.
Ich bekomm hier gleich ein Magengeschwür, also ehrlich.
cli(); stoppt den Interruptbetrieb nicht.
erst das bit INT0 im Register GICR 0 zu setzen stoppt meinen Interrupt.
Oooooooh man, das hat Nerven gekostet.
Hat vlt noch jemand ne plausible Erklärung dafür?
Einfach sowas wie, Input Capture Interrupt läuft unabhängig vom SREG und
das mit Beleg im Datenblatt?
Das wär Balsam für meine Seele!
Wer es testen möchte, hier der Code:
Mark Ziegler schrieb:> cli(); stoppt den Interruptbetrieb nicht.
In einer ISR ist der Interrupt sowieso disabled, d.h. beim Anspringen
der ISR wird "cli" quasi von der Hardware ausgeführt.
Das nochmalige "cli" innerhalb der ISR ändert also nichts. Aber beim
Verlassen der ISR wir der Interrupt in jedem Fall wieder eingeschaltet -
auch wenn Du das nicht ins Programm schreibst.
Gruß Dietrich
> Aber beim Verlassen der ISR wir der Interrupt in jedem Fall wieder> eingeschaltet - auch wenn Du das nicht ins Programm schreibst.
Falsch!
Beim Verlassen der ISR wird der Zustand wieder hergestellt, der
herrschte, als die ISR betreten wurde. Das heißt, wenn er vorher schon
ausgeschaltet war, ist er auch nach Verlassen der ISR ausgeschaltet.
ich schrieb:>> Aber beim Verlassen der ISR wir der Interrupt in jedem Fall wieder>> eingeschaltet - auch wenn Du das nicht ins Programm schreibst.>> Falsch!> Beim Verlassen der ISR wird der Zustand wieder hergestellt, der> herrschte, als die ISR betreten wurde. Das heißt, wenn er vorher schon> ausgeschaltet war, ist er auch nach Verlassen der ISR ausgeschaltet.
auch Falsch
wenn er vorher schon ausgeschaltet war, wird die ISR auch nicht
aufgerufen.
Sascha
Sascha Weber schrieb:> wenn er vorher schon ausgeschaltet war, wird die ISR auch nicht> aufgerufen.
Es sei denn, ein verirrter Prozessor kommt auf einem anderen Wege in die
ISR - z.B. durch einen Stack-Fehler.
Route_66 schrieb:> Sascha Weber schrieb:>> wenn er vorher schon ausgeschaltet war, wird die ISR auch nicht>> aufgerufen.>> Es sei denn, ein verirrter Prozessor kommt auf einem anderen Wege in die> ISR - z.B. durch einen Stack-Fehler.
Und beim Verlassen werden die Interrupts global eingeschaltet.
Denn diesen Unsinn macht er nicht:
ich schrieb:
> Falsch!
> Beim Verlassen der ISR wird der Zustand wieder hergestellt, der> herrschte, als die ISR betreten wurde. Das heißt, wenn er vorher schon> ausgeschaltet war, ist er auch nach Verlassen der ISR ausgeschaltet.
mfg.