Forum: Mikrocontroller und Digitale Elektronik Interrupt wieder ausschalten (?)


von Benedikt W. (pocky)


Lesenswert?

Hallo,

Ich habe ein kleines Problem mit meinem kleinen attiny2313 (8Mhz 
intern):
Vorweg, ich bin alles andere als Profi in Sachen µC!
Also ich versuche einen Frequenzzähler zu bauen, der ant INT0 einfach 
misst wie oft ein Puls ankommt, und das per internem Timer dann nach 1 
Sekunde zu analysieren. Klappt soweit auch sehr gut, nur ab ~170 kHz 
hängt sich mein 2313 auf.
Ich hab dem guten stück schon gesagt, mach ab 150 kHz INT0 aus, weil ich 
dachte das einfach zu wenig zeit für andere Sachen bleibt wenn der 
ständig Interrupts scheißt, aber das löst mein Problem nicht, das ganze 
hängt immernoch...
1
PCMSK &=~ (1 << PIND2);
2
GIMSK  &=~ (1 << INT0);

An dem Problem bastel ich jetzt schon 2 Tage und find auch nix tolles 
über Google, wobei ich dazu auch sagen muss, das mir dazu die richtigen 
Suchbegriffe Fehlen...
Wäre echt klasse wenn mir jemand einen Tipp geben kann.


Hier noch mein ganzer Code:

http://nopaste.info/483b7e8ee5.html

Ich weiß, der Code ist unübersichtlich, schlecht kommentiert und 
stellenweise sogar blödsinn und zuviel, aber es ist ja noch kein Meister 
vom Himmel gefallen :D
Verbessrungsvorschläge erwünscht!

von spess53 (Gast)


Lesenswert?

Hi

>Verbessrungsvorschläge erwünscht

>PCMSK &=~ (1 << PIND2);

PCMSK hat absolut nichts mit INT0 zu tun. Die Bits in PCMSK heißen auch 
nicht PINDn sondern PCINTn. Kannst du also weglassen.

MfG Spess

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

Benedikt W. schrieb:
> wenn der ständig Interrupts scheißt

netter Verschreiber ;-)

von Stefan Frings (Gast)


Lesenswert?

Deine Interrupt Routine enthält eine ganze Menge Multiplikationen und 
Divisionen. Schau Dir mal an, wieviel Assembler Code dabei heraus kommt!

Das ist für 125 kHz einfach viel zu viel Mathematik.

Versuche, eine andere Methode zu finden, bei der die Interrupt-Routine 
VIEL simpler ausfällt.

Du könntest z.B. einen Hardware-Zähler nutzen, der die externen Impulse 
zählt. Und wenn er über läuft, incrementierst Du eine Variable.

Wenn der Hardware Zähler z.B. 16 Bit hat und deine Variable 16 Bit hat, 
dann erhälst Du so insgesamt 32 Bit Auflösung, kannst also bis etwa 4 
Millionen Zählen.

Nun brauchst Du noch einen zweiten Timer, der die Zählung nach einer 
Sekunde (oder so) stoppt.

Im Hauptprogramm wartest Du, bis der Zweite Timer das Ende der Sekunde 
signalisiert und dann dividierst Du (NACH der Messung!) 1 Sekunde durch 
den Zählwert, was die Frequenz ergibt. Danach setzt Du den 
Hardware-Zähler, die Zähl-Variable und den Sekunden-Timer wieder auf 0 
und startest die nächste Messung.

von Benedikt W. (pocky)


Lesenswert?

Ok, das ganze jetzt mal langsam für Leute die keine Ahnung haben (wie 
ich)...
Ich kommte mit dem Counter gerade überhaupt nicht klar...

Meinen Timer1, um die Inputs zu zählen initalisiere ich so:
1
TIMSK = (1 << TOIE0) | (1 << ICIE1); //timer0 für sekunden zählen, und ICIE1 um PD6/ICP zu zählen
2
TCCR1B = (1 << CS10) | (1 << ICES1); //kein vorteiler + ansteigende flanke soll TCNT1 + 1 machen
3
TCNT1 = 0;

Ist das erstmal richtig so?

Weiterhin ist das ganze sehr seltsam, ich hab das ganze jetzt so weiter 
gemacht:
1
ISR(TIMER1_OVF_vect) //Wenn der Timer1 überläuft
2
{
3
  pre++; //Das passiert leider nie, warum auch immer
4
}
5
6
ISR(TIMER1_CAPT_vect) //Wenn ich die Funktion nicht mit reinschreib hänt sich der Chip auf, warum auch immer
7
{
8
}


Ich dachte immer ich kann halbwegs programmieren, aber diese fiesen µC 
bringen mich zur verzweiflung :P

von Karl H. (kbuchegg)


Lesenswert?

Benedikt W. schrieb:


> ISR(TIMER1_CAPT_vect) //Wenn ich die Funktion nicht mit reinschreib hänt
> sich der Chip auf, warum auch immer

Nicht "warum auch immer"


Ein freigegebener Interrupt, wie zum Beispiel der Capture Interrupt, den 
du hier freigibst

TIMSK = ...... (1 << ICIE1);

benötigt eine ISR. Schreibst du selber keine ISR, dann kommt ein 
Standardhandler zum Zug, welcher den µC resettet.

Daher: Man gibt keinen Interrupt frei, für den man keine ISR hat!

von Karl H. (kbuchegg)


Lesenswert?

> ISR(TIMER1_OVF_vect) //Wenn der Timer1 überläuft

Lies noch mal hier, und diesmal genau(!) was da steht

TIMSK = (1 << TOIE0) ...
1
TOIE0
2
_T_imer _O_verflow _I_nterrupt _E_nable vom Timer _0_
0, wieso 0? Du willst doch mit dem Timer 1 arbeiten!


Etwas mehr Sorgfalt und etwas weniger "warum auch immer".

von oldmax (Gast)


Lesenswert?

Hi
>Ich dachte immer ich kann halbwegs programmieren, aber diese fiesen µC
>bringen mich zur verzweiflung :P
Na ja, ich dachte immer, wer programmieren kann, der kann auch lesen, 
aber diese fiesen Programmierer bringen mich zur Verzweiflung
Sorry, das ist nicht ernst gemeint und mangels geeigneter Smilies muß 
ich die Entschuldigung eben so nachliefern. Aber was ich damit sagen 
will: es gibt m.W. für jeden Controller Datenblätter, wo auch die 
Register und Bits erklärt sind. Bisher hab ich dazu auch Beispielcode in 
Asm. und C gesehen. Lad dir doch einfach mal das Datenblatt herunter und 
schau dir an, wie die Timerarbeiten und wozu die entsprechenden Bits da 
sind.
Da ich kein C kann (und vermutlich auch nicht mehr erlerne mangels 
verbleibender Lebenszeit...) kann ich dir nur mit diesem Tip helfen. Des 
weiteren merke:
Interrupts sollten nur sehr wenige Aufgaben erledigen. Berechnungen 
gehören nicht dazu denn: wie schnell kannst du lesen ? Im mSek. Bereich? 
Sicherlich nicht. Also reicht es, deine Anzeige vielleicht alle 
hundertstel oder gar nur zehntel Sekunden zu aktualisieren und da hast 
du Ewigkeiten Zeit, einen gültig berechneten Wert der Anzeige verfügbar 
zu machen.
Gruß oldmax

von Svenska (Gast)


Lesenswert?

Benedikt W. schrieb:
> ISR(TIMER1_OVF_vect) //Wenn der Timer1 überläuft
> {
>   pre++; //Das passiert leider nie, warum auch immer
> }

Du musst pre auch als "volatile" deklarieren, da der Compiler dir das 
Increment für die Hauptschleife sonst gnadenlos wegoptimiert.

von Stefan Frings (Gast)


Lesenswert?

Der Compiler optimiert das Increment nicht weg. Aber zwischen zwei 
Lesezugriffen kann die Änderung unsichtbar bleiben, weil der Compiler 
die Lesezugriffe optimiert. Beispiel:

1. Lesezugriff: Kopiert pre in irgendein Register
2. Variable pre wird durch den Interrupt incrementiert
3. Lesezugriff: Der Wert wird aus dem Register gelesen, statt (wie 
erwartet) aus der Variablen.

Das kann passieren, muss aber nicht. Durch "volatile" sagst Du dem 
Compiler, daß Zugriff auf diese Variable nicht durch irgendwelche 
Caching Mechanismen optimiert werden dürfen. Ein pre++ incrementiert 
also wirklich sofort die Variable und ein Lesezugriff liest immer aus 
der Variable.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Benedikt W. schrieb:
> Ich dachte immer ich kann halbwegs programmieren, aber diese fiesen µC
> bringen mich zur verzweiflung :P
sieh das mal von der MC Seite:
"Ich dachte immer, ich kann halbwegs arbeiten, aber diese fiesen 
Programmierer bringen mich immer zum Reset"

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.