Forum: Mikrocontroller und Digitale Elektronik AVR Stürzt ab --> interner Reset Hilfe


von Micha (Gast)


Lesenswert?

Ich habe ein Gerät, welches ein PWM (250Hz) Singnal ausgibt.
Dieses möchte ich auswerten.
Das Singnal wird mit einem Transitor erzeugt der GND Durchschaltet.
Jetzt habe ich denn Port als eingang Deklariert und denn internen Pull 
up eingeschaltet.

gebe ich nun das singnal auf den Port macht der AVR einen internen 
Reset!!

Woran könnte das liegen.

Ziehe ich den eingang manuell auf GND oder + passiert nichts.

Bin für jede Idee dankbar.

von Benedikt K. (benedikt)


Lesenswert?

Vermutlich ein Softwarfehler.

von Micha (Gast)


Lesenswert?

//Port A und D Ausgang
DDRA = 0xFF;
DDRD = 0x1F;
// PortC als eingang alle Pull up Widerstände acktiviert
DDRC = 0x00;
PORTC = 0xFF;
PORTD = 0xE0;

Könnte es an der Init der Ausgänge liegen.

PortD 7 soll der Eingang sein ???

von Benedikt K. (benedikt)


Lesenswert?

Soweit passt alles.

von risu (Gast)


Lesenswert?

Hallo Micha,

wie Benedikt schon sagte, handelt es sich vermutlich um einen 
Software-Fehler -- es sei denn, der Reset-Pin wird auf 0 gezogen. 
Ursachen können sein:
1. undefinierter Interrupt-Vektor (PC springt an eine Adresse ohne 
Interrupt-Handler)
2. Stack-Überlauf
3. PC zeigt (z.B. wegen "2.") auf die "NOP"-Zellen nach dem Ende des 
Programms, läuft über und fängt wieder bei 0 (=Reset-Vektor) an.

Du musst schon mehr von Deinem Code zeigen, um effiziente Hilfe zu 
bekommen!

Gruß
  risu

von Micha (Gast)


Angehängte Dateien:

Lesenswert?

Das Programm.

von Micha (Gast)


Lesenswert?

Sobald ich an Pin 7 das Singnal lege, macht er einen Reset.

von Micha (Gast)


Lesenswert?

if((!(PIND & (1<<PIND7)))) // Wenn PinD 7 -> 0 ist dann
{
Pause++;
}

Wenn ich diese Zeile weglasse geht es.

Jedoch kann ich dann die Pausenlänge nicht mehr messen.

von Micha (Gast)


Lesenswert?

kann es sein das solange PinD7 0 ist er in der Interupt Rotine bleibt.

Und ein neuer Interupt vom timer Ausgelöst wird, wärend der Alte noch 
bearbeitet wird ?

von Spess53 (Gast)


Lesenswert?

Hi

Von welchem Controller redest du eigentlich? Weder hier noch im Programm 
ist eine Angabe dazu.

MfG Spess

von Micha (Gast)


Lesenswert?

ATMega8535
16 Mhz externer Quarz

von risu (Gast)


Lesenswert?

Hi,

1. Die Frage von Spess53 habe ich auch.
2. Die Variablen "PWM" und "Pause" müssen "volatile" sein.

Gruß
 risu

von Micha (Gast)


Lesenswert?

Was heist "volatile"???

von risu (Gast)


Lesenswert?

Hallo Micha,

> Was heist "volatile"???

http://www.netrino.com/node/80

Gruß

 risu

von Micha (Gast)


Lesenswert?

//-----
int volatile PWM;
int volatile Pause;

habe ich gemacht ändert garnix. :-(

von risu (Gast)


Lesenswert?

Woraus schließt Du, dass es zu einem "internen Reset" kommt?

von Micha (Gast)


Lesenswert?

Das PWM Singnal verschwimmpt. Also wird es wird überlagert.

Dies passiert nur wenn ich:

1.)
if((!(PIND & (1<<PIND7)))) // Wenn PinD 7 -> 0 ist dann
{
Pause++;
}
das ins Programm einfüge egal wo !

2.) ich extern einen Reset oft hindereinander auslöse

3.)
das PWM Singnal anschliese

von yalu (Gast)


Lesenswert?

Das Ganze macht einen ziemlich wirren Eindruck:

1. Das gepostete Programm nicht das sein, was auf deinem Controller
   läuft, weil es einen Syntaxfehler enthält (schließende Klammer am
   Ende von main() fehlt).

2. Du greifst auf die Variable PWM sowohl im Interrupthandler als auch
   im Hauptprogramm lesend und schreibend zu. Hast du dir Gedanken
   gemacht, was passiert, wenn an der ungeschicktesten Stelle im
   Hauptprogramm dieses unterbrochen wird und der Interrupthandler PWM
   ändert? Da PWM aus zwei Bytes besteht, kann die Unterbrechung sogar
   innerhalb eines Zugriffs auf die Variable passieren.

3. Die Zeile

     OCR1A = 64;

   hat wenig Sinn, da du den Timer im Normalmodus (nicht CTC-Modus)
   betreibst, wo er immer bis zum Maximalwert von 65535 hochzählt. So
   dürftest du nur eine Interrupfrequenz von 244Hz und damit eine
   PWM-Frequenz von etwa 0,5Hz erhalten. Oder habe ich da etwas
   übersehen? Wahrscheinlich möchtest du aber den CTC-Modus. Dazu müssen
   in auch TCCR1A die entsprechenden Bits gesetzt werden.

> Das PWM Singnal verschwimmpt. Also wird es wird überlagert.

Kannst etwas genauer beschreiben, wie das Signal aussieht?

von Micha (Gast)


Angehängte Dateien:

Lesenswert?

CH2 input Singnal das ich messen will !!

Messung also abfrage
if((!(PIND & (1<<PIND7)))) // Wenn PinD 7 -> 0 ist dann
{
Pause++;
}

ist acktiviert

von Micha (Gast)


Angehängte Dateien:

Lesenswert?

Singnal liegt weiterhin am Eingang !!

Jedoch habe ich jetzt die Abfrage deaktiviert.



Was mache ich nur falsch.

Kann ich das PWM Singnal auch anders erzeugen.
Es muß 250 HZ haben !!


Oder wie könnte ich die Auswertung anders machen.

Ist irgendwas mit dem Interrupt Aufruf falsch ??

von Micha (Gast)


Lesenswert?

//Timer einstellen
//TCCR1B = (1<<CS10) | (1<<CS11);       //setzt den Prescaler 64
TCCR1B = (1<<CS10) | (0<<CS11);         //setzt den Prescaler 1
TCCR1A = (1<<WGM12) | (1<<WGM13);        //CTC MODE
OCR1A = 400;                         //setzt den Vergleichswert
TCNT1 = 0;                             //startewert des Counters
TIMSK = 1<<OCIE1A;                     //Compare-Int aktivieren
sei();                                 //globale Ints aktivieren

Wenn ich denn Vergleichswert erhöhe geht es ab ca. 400. Warum?

von yalu (Gast)


Lesenswert?

> Was mache ich nur falsch.

Wenn der Timer im CTC-Modus läuft und OCR1A=64 ist, generiert er alle 64
Taktzyklen einen Interrupt. Der Aufruf und die Ausführung des
Interrupthandlers dauert im worst Case etwa 59 Zyklen. Somit bleiben dem
Hauptprogramm zwischen zwei Interrupts gerade einmal 7 Zyklen. In dieser
Zeit kann aber nur ein Bruchteil eines vollen Durchlaufs der
Hauptschleife stattfinden. D.h. zwischen der Ausführung der Zeile
1
    if (PWM == Prozent) // 0 bis 500

in zwei aufeinanderfolgenden Schleifendurchläufen werden gleich mehrere
Interrupts ausgelöst, von denen jeder zur Inkrementierung der Variable
PWM führt. Bei der Auswertung der Bedingung PWM==Prozent hat also PWM in
einem Schleifedurchlauf bspw. den Wert 100, im nächsten (nach vielleicht
fünf Interrupts) aber schon 105. Liegt der Wert von Prozent dazwischen,
wird die ==-Bedingung nicht wahr, und es erfolgt in der aktuellen
PWM-Periode kein Wechsel von low nach high. Deswegen erhältst du im
Ausgangssignal die vielen Aussetzer.

Der Wechsel von high nach low passiert dagegen immer, weil du dort
klugerweise auf PWM>=500, und nicht auf PWM==500 abfragst.

Um das Problem etwas einzudämmen, kannst du auch in der ersten Abfrage
ein >= anstelle des == verwenden, also
1
    if (PWM >= Prozent) // 0 bis 500

Das löst aber nicht das eigentliche Problem, nämlich die fast
vollständige Auslastung der CPU mit den Interrupts. Außerdem besteht
immer noch das Problem des simultanen Zugriffs auf 16-Bit-Variablen im
Hauptprogramm und im Interrupthandler. Die kann man zwar durch Einfügen
von Interruptsperren an den entsprechenden Stellen im Hauptprogramm
beseitigen, dadurch wird aber das erste Problem noch verschärft, und es
kann zu Interruptstaus kommen, weil der jeweils nächste Interrupt schon
eintrifft, bevor der aktuelle abgearbeitet ist.

> Wenn ich denn Vergleichswert erhöhe geht es ab ca. 400. Warum?

Dann bleiben dem Hauptprogramm 341 statt 7 Zyklen bis zum jeweils
nächsten Interrupt. In dieser Zeit schafft es wahrscheinlich sogar
mehrere Schleifendurchläufe. Eigentlich sollte es schon mit weniger als
400 funktionieren. Hast du beim Compiler vielleicht die Optimierung
nicht eingeschaltet?

> Kann ich das PWM Singnal auch anders erzeugen. Es muß 250 HZ haben !!
>
> Oder wie könnte ich die Auswertung anders machen.

Zum Glück hat der ATmega8535 sowohl für die PWM-Generierung als auch die
Pulsbreitenmessung des Eingangssignals spezielle Hardwareeinheiten, die
diese Aufgaben (fast) ohne das Mitwirken der CPU erledigen. Sie heißen
"Input Capture Unit" (für die Zeitmessung) und "Output Compare Unit"
(für die PWM-Generierung) und sind jeweils in einem eigenen Abschnitt im
Datenblatt beschrieben.

Damit kannst du alle der beschriebenen Probleme auf einen Schlag
beseitigen, und die CPU hat wieder Luft, um noch andere nützliche Dinge
zu tun. Dazu musst du allerdings das Eingangssignal nicht an PD7,
sondern an PD6 (ICP1) anschließen und das Ausgangssignal nicht von PD1,
sondern von PD4 (OC1B) abnehmen. Vielleicht kannst du das in deiner
Schaltung ja noch ändern.

von Micha (Gast)


Lesenswert?

Ja,PD7 auf PD6 legen ginge eventuell mit ner Zinnbrücke.

Aber die AVR Kontroller sind doch schnell !!

Der AVR läuft mit 16 Mhz!
Das sind 16000000 Befehle pro Sekunde.

Und ich will nur ein Signal von 250 Hz erzeugen.

Und gleichzeitig eins messen.

Das muss doch zu schaffen sein!

Könntest du mir ein Beispiel geben, wie ich das einstelle mit PD6.

von Niels H. (monarch35)


Lesenswert?

Micha wrote:

> Der AVR läuft mit 16 Mhz!
> Das sind 16000000 Befehle pro Sekunde.

Nein, sind es nicht.

von yalu (Gast)


Lesenswert?

> Und ich will nur ein Signal von 250 Hz erzeugen.

Die 250Hz sind, für sich gesehen, nicht das Problem, aber die 250Hz in
Verbindung mit der PWM-Auflösung von 500 Schritten. Um diese Auflösung
softwaremäßig zu erreichen, muss die Software 250*500=125000 Mal pro
Sekunde aktiv werden. Dann hat sie genau 128 Taktzyklen Zeit, das
Eingangssignal zu verarbeiten und das Ausgangssignal zu generieren. Wie
Niels andeutete, benötigen viele Befehle nicht einen, sondern zwei
Zyklen, einige sogar noch länger.

Wenn man's geschickt anstellt, geht das trotzdem, auch softwaremäßig.
Ich vermute aber, dass das Programm, bis es fertig ist, noch ein paar
Dinge mehr tun soll. Bei der Softwarelösung bist du dann ständig am
Zyklenzählen, um sicherzustellen, dass der Zeittakt auch unter den
ungünstigsten Bedingungen eingehalten wird.

Was soll dein Programm denn außer der Pulslängenmessung und der
PWM-Generierung sonst noch tun? Irgendetwas muss ja bspw. mit der
gemessenen Pulslänge getan werden. Und du hättest sicher keinen
40-Füßler genommen, wenn mit den anderen Ports nicht auch noch etwas
gemacht würde.

> Könntest du mir ein Beispiel geben, wie ich das einstelle mit PD6.

Ich habe gerade nichts fertiges im Zugriff, schon gar nicht für den
ATmega8535. Es sollte aber genügend Beispiele hier im Forum, in den
Tutorials und sonstwo im Netz geben, die du entsprechend anpassen
kannst.

Da fällt mir gerade ein: Wieso möchtest du überhaupt die PWM in 500
Schritten auflösen? Das Tastverhältnis wird doch, wenn ich das richtig
gesehen habe, von Port C als ganze Zahl von 0 bis 100 eigelesen. Damit
genügt es, nur 100*250=25000 Mal den Interrupt zu generieren und du hast
640 CPU-Zyklen zwischen zwei Interrupts zur Verfügung. So dürfte es auch
bei softwaremäßiger PWM keine Probleme geben.

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.