Forum: Mikrocontroller und Digitale Elektronik Mehrfachnutzung Timer


von Ahmet D. (closed_loop_stepper)


Lesenswert?

Servus ,

in meinem Programm nutze ich einen Timer zum Ansteuerung von 2 
Schrittmotoren. Nun würde ich gerne einen zweiten Timer nutzen um in 
einen festen Zeitintervall Wetre auszulesen. Das Programm zum auslesen 
der Werte über einen Timer hab ich geschrieben und Funktioniert auch 
blendend.

Das Problem ist jetzt folgendes, wenn ich beide Programme "verheirate" 
funktioniert das Auslesen der Werte ohne problme aber der Schrittmotor 
rattert und läuft nicht rund, bzw. nicht so wie er sollte.

Ich hab darauf geachtet die Timerinterrupt-Routine so kurz wie möglich 
zu halten. Die ganze Rechnenroutine hab ich in die main() verlagert die 
Interrupts holen sich nur die Varibale. Aber es funktionert torzdem 
nicht.
Die beiden Programme für sich allein Funktionieren einwandfrei, nachdem 
"verheiraten" wird auch keine fehlermeldung angezeift weswegen ich 
ziemlich ratlos bin.

Spaßes halber habe ich das ganze auch ohne den zweiten timer probiert, 
sondern hiermit:


void loop()
{
    int AktuelleZeit = millis();
    if(AktuelleZeit - VergangeZeit >= Zeitintervall)
    {
      VergangeZeit = AktuelleZeit;

// macht irendwas.....

    }
}

So Funktionieren es, ich würde es tortzdem ganz gerne über die Timer zum 
laufen kreigen.

von Falk B. (falk)


Lesenswert?

@Ahmet D. (closed_loop_stepper)

>Das Problem ist jetzt folgendes, wenn ich beide Programme "verheirate"
>funktioniert das Auslesen der Werte ohne problme aber der Schrittmotor
>rattert und läuft nicht rund, bzw. nicht so wie er sollte.

Dann stimmt wohl dein Konzept nicht. Oder dessen Umsetzung.

>Interrupts holen sich nur die Varibale. Aber es funktionert torzdem
>nicht.

Zeige uns deinen VOLLSTÄNDIGEN Quelltext als Anhang.

Beitrag #5504330 wurde von einem Moderator gelöscht.
von Ahmet D. (closed_loop_stepper)


Angehängte Dateien:

Lesenswert?

Hallo Falk,

mach ich gerne.

von c-hater (Gast)


Lesenswert?

Ahmet D. schrieb:

> Das Problem ist jetzt folgendes, wenn ich beide Programme "verheirate"
> funktioniert das Auslesen der Werte ohne problme aber der Schrittmotor
> rattert und läuft nicht rund, bzw. nicht so wie er sollte.

Entweder semantischer Fehler oder Verlassen der Echtzeit.

Ergo ist die Fehlersuchstrategie entweder:

1) Prüfung, dass das Geschriebene jederzeit passieren darf, ohne dass 
dadurch die Echtzeit verlassen werden muss.

Geht diese Prüfung positiv aus->semantischer Fehler.

2) Prüfung der Programmlogik.

Geht diese Prüfung positiv aus->Verlassen der Echtzeit

Man darf auch gerne beide Prüfungen anwenden. Wenn man was im Kopp hat, 
wird man das bei dem beschriebenen Fehlerbild sogar ganz sicher tun...

Wenn man noch mehr im Kopp hat: dann hätte man die Echtzeit-Constraints 
vorher geprüft, bevor man den zweiten Programmteil überhaupt angefangen 
hätte zu schreiben und man bräuchte dann nur noch nach semantischen 
Fehlern zu suchen...

> Ich hab darauf geachtet die Timerinterrupt-Routine so kurz wie möglich
> zu halten.

Drauf' geschissen.

"So kurz wie möglich" bedeutet halt niemals: "sicher kurz genug". Wenn's 
so einfach wäre, könnte man ja wirklich alles einfach in VB.net, C#, 
JavaScript oder Python schreiben und bräuchte sich niemals Gedanken um 
die Laufzeit von Code zu machen.

So isses aber eben nicht...

von Falk B. (falk)


Lesenswert?

@Ahmet D. (closed_loop_stepper)

Naja.

1.) in eine.h Datei (AMS5812.h) gehört KEIN ausführbarer Code, sondern 
nur #defines, Deklarationen, Funktionsprototypen etc.

2.) Die Abfrage deines Sensor  AMSSensor() in ISR(TIMER5_COMPA_vect) ist 
wahrscheinlich zu langsam. Denn dort ist nicht nur eine Menge I2C-Kram 
(wire) drin, auch viele Fließkommaberechnungen und Divisionen. Das alles 
kostet Zeit. Zeit, in der der andere Interrupt nicht bedient wird.

Lösung. Die Abfrage deines Sensor aus der ISR entfernen und in die 
Hauptschleife (Loop() ) verlagern. GGf. von Fließkomma auf 
Festkommaarithmetik umbauen, denn Fließkomma brauchst du hier nicht 
wirklich.

3.) Auch wenn du die ganzen UART-Ausgaben auskommentiert hast, sie 
gehören nicht in dieser Funktion. Schreibe eine 2. Funktion nur zur 
Ausgabe der Rohdaten bzw. Zwischenergebnisse. Das ist auch praktischer 
für die Fehlersuche.

4.) Der Reset der Timer5 Register ist Unsinn, die haben definierte 
Resetwerte. Außerdem kann man die normal setzen, als mit  TCCR5B =  ...

5.) Wo ist die Initialisierung von Timer 1 und des Interrupts?

von Veit D. (devil-elec)


Lesenswert?

Hallo,

eine Anmerkung. Beim Arduino wie hier, müsste ein Mega2560 sein, muss 
man von selbst genutzten Timern die Register manuell reseten. Die sind 
durch PWM Funktionen wie analogWrite oder Zeitfunktionen wie millis 
vorbelegt. Gültig wenn man in der Arduino IDE oder Atmel Studio mit 
Plugin programmiert. Also die Arduino IDE Ressourcen nutzt. Programmiert 
man klassisch muss man das nicht machen. Klassisch geht auch in der 
Arduino IDE ohne setup/loop mit main und while. Nur fehlen einem dann 
die fertigen Komfortfunktionen. Das so nebenbei.

von Ahmet D. (closed_loop_stepper)


Lesenswert?

Hallo c-hater,

c-hater schrieb:
> Entweder semantischer Fehler oder Verlassen der Echtzeit.

semantischer Fehler sind klar, aber was mienst du mit verlassen der 
Echtzeit.
ich nehme mal an das du damit meintst das die Hardware nicht hinterher 
kommt.

Zu dem Punkt hab ich mir mal gedanken gemacht wie schnell der Timer für 
den Schrittmottor ausschlägt. Der Timer hat keinen vorteiler aktive und 
braucht zwischen 833 und 5000 takte. Mit 16MHZ also 62,5 Nano Sekunden 
pro Takt, bedeutet das der Timmer alle 52000 bis 312.500 Nano Sekunden 
braucht.

Der zweite Timer schlägt soll jede 1/10 Sekunde ausschlgen.

und meinst du mit:

c-hater schrieb:
> Wenn man noch mehr im Kopp hat: dann hätte man die Echtzeit-Constraints
> vorher geprüft,

Was meinst du mit Kopp und Echtzeit-Constraints.
Wenn du mit Kopp, Kopf meinst machts Sinn, sonst wäre eine Erklärung 
sehr schön.

vielen Dank im Voraus

von Ahmet D. (closed_loop_stepper)


Lesenswert?

Falk B. schrieb:
> Wo ist die Initialisierung von Timer 1 und des Interrupts?

in der Drive.cpp.

von c-hater (Gast)


Lesenswert?

Ahmet D. schrieb:

> semantischer Fehler sind klar, aber was mienst du mit verlassen der
> Echtzeit.
> ich nehme mal an das du damit meintst das die Hardware nicht hinterher
> kommt.

Eher: das Programm (bzw. der Programmteil) ist zu langsam. Die Hardware 
ist niemals Schuld, denn deren Eigenschaften sind immer vorab bekannt. 
Es ist also Aufgabe des Programms, jederzeit schnell genug zu sein. 
Genauer: Es ist Aufgabe des Programmierers, dafür zu sorgen, dass sein 
Programm das ist...

> Wenn du mit Kopp, Kopf meinst machts Sinn

Ja, ich bin mitteldeutsch->Kopp=Kopf. Scheint aber fast deutschlandweit 
durchzugehen. Sogar die Migranten in Berlin-Kreuzberg und anderswo 
verstehen auf Anhieb, was "Kopp" bedeutet, benutzen das Wort teilweise 
sogar aktiv selber. Aber: Ist natürlich kein klassisch geprägtes 
Oberschichten-Schul-Deutsch. Nächstes Mal werde ich die sechs Zentimeter 
bis zur "f"-Taste zurücklegen, damit es auch für Neudeutsche völlig 
unmissverständlich wird...

von Ahmet D. (closed_loop_stepper)


Lesenswert?

Hallo Falk,



und zu deinem zweiten Punkt

Falk B. schrieb:
> 2.) Die Abfrage deines Sensor  AMSSensor() in ISR(TIMER5_COMPA_vect) ist
> wahrscheinlich zu langsam. Denn dort ist nicht nur eine Menge I2C-Kram
> (wire) drin, auch viele Fließkommaberechnungen und Divisionen. Das alles
> kostet Zeit. Zeit, in der der andere Interrupt nicht bedient wird.

Die Berechung habe ich in einer Funktion ausgeglidert. Auf gerufen wird 
sie aber in der main(). Das ergeniss der Brechnung speicher ich in einer 
globalen Variable. Der Timer macht nichts anderes als sich die Variable 
zu ziehen. In der TimerRoutine wird nichts berechnet.

Deswegen weiß ich nicht was du mit in die main() verlagern meinst.

von Falk B. (falk)


Lesenswert?

@ Ahmet D. (closed_loop_stepper)

>> 2.) Die Abfrage deines Sensor  AMSSensor() in ISR(TIMER5_COMPA_vect) ist
>> wahrscheinlich zu langsam. Denn dort ist nicht nur eine Menge I2C-Kram
>> (wire) drin, auch viele Fließkommaberechnungen und Divisionen. Das alles
<> kostet Zeit. Zeit, in der der andere Interrupt nicht bedient wird.

>Die Berechung habe ich in einer Funktion ausgeglidert.

Nö. Ich rede von

ISR(TIMER5_COMPA_vect)

> Auf gerufen wird
>sie aber in der main(). Das ergeniss der Brechnung speicher ich in einer
>globalen Variable. Der Timer macht nichts anderes als sich die Variable
>zu ziehen. In der TimerRoutine wird nichts berechnet.

Doch

>Deswegen weiß ich nicht was du mit in die main() verlagern meinst.

Das was ich oben geschrieben habe. Die Rede ist von 
ISR(TIMER5_COMPA_vect). Du aber redest von ISR(TIMER1_COMPA_vect).

von Ahmet D. (closed_loop_stepper)


Lesenswert?

Falk B. schrieb:
> Nö. Ich rede von
>
> ISR(TIMER5_COMPA_vect)
>
>> Auf gerufen wird
>>sie aber in der main(). Das ergeniss der Brechnung speicher ich in einer
>>globalen Variable. Der Timer macht nichts anderes als sich die Variable
>>zu ziehen. In der TimerRoutine wird nichts berechnet.
>
> Doch
>
>>Deswegen weiß ich nicht was du mit in die main() verlagern meinst.
>
> Das was ich oben geschrieben habe. Die Rede ist von
> ISR(TIMER5_COMPA_vect). Du aber redest von ISR(TIMER1_COMPA_vect).



endweder stehe ich auf dem schlau oder ich verstehs nicht.



ISR(TIMER5_COMPA_vect) { // für den sensor AMS5812 //  ISR_NOBLOCK vlt

  int Druck = GetAMSSensor();

}

int GetAMSSensor()
{
  return GetWert;
}

Also ich sehe hier einfach nur wie der Timer in int Druck den Wert der 
variable GetWert setzt. Das aht dich mit dem I2C nichts zu tun oder ?

von Falk B. (falk)


Lesenswert?

@Ahmet D. (closed_loop_stepper)

>endweder stehe ich auf dem schlau oder ich verstehs nicht.

>ISR(TIMER5_COMPA_vect) { // für den sensor AMS5812 //  ISR_NOBLOCK vlt

>  int Druck = GetAMSSensor();

>}

Ok, mein Fehler! Ich habe die beiden Funktionen verwechselt, weil sie 
sehr ähnlich heißen.

Aber damit ist die Anweisung sinnlos, denn du machst nichts mit dem Wert 
in der ISR. Was passiert, wenn du die Zeile auskommentierst, die ISR 
also leer ist?

von Ahmet D. (closed_loop_stepper)


Lesenswert?

Kein Ding ^^

Ich will später die in der variable Druck gespeicherten werte als 
Regelgröße für die anstehende regelung verwenden


Aber wie war das mit reset von TCCR5B = ...
Am integer und I2C hat nicht gelegen

von Veit D. (devil-elec)


Lesenswert?

Hallo,

Beitrag "Re: Mehrfachnutzung Timer"

sind dir die Unterschiede klar?
1
Bsp.
2
3
TCCR5A = 0;
4
TCCR5A = (1<<COM1B1);
5
TCCR5A |= (1<<COM1B1);

Du programmierst doch in der Arduino IDE oder?

Edit:
diese muss man selbst behandeln bzw. reseten
TCCR5A
TCCR5B
TCCR5C
TIMSK5

diese bei Bedarf wenn man sie benutzt, dann erfolgt sowieso eine 
Grundeinstellung
OCR5A
OCR5B
OCR5C

TCNT5 kann man nullen, muss man nicht, man macht es aus Gewohnheit

Wie gesagt, muss man im Zusammenhang mit oben geschriebenen sehen.

: Bearbeitet durch User
von Ahmet D. (closed_loop_stepper)


Lesenswert?

Als erstes ich hab doch noch zum laufen gebracht.
Ja mit dem Arduino Mega2560.



Veit D. schrieb:
> Hallo,
>
> Beitrag "Re: Mehrfachnutzung Timer"
>
> sind dir die Unterschiede klar?Bsp.
>
> TCCR5A = 0;
> TCCR5A = (1<<COM1B1);
> TCCR5A |= (1<<COM1B1);
>
> Du programmierst doch in der Arduino IDE oder?


ich denke eher unzureichend.

TCCR5A ist ein Kontrollregister "timer control register A" ^^. Druch das 
setzen von bits kann man dan bestimmte Funktionen aktiverien (00; 01; 
10; 11) die dan so tolle namen wie COM1B1 haben.

Eine Frage müsste es nicht COM1"A"1 sein?
> TCCR5A = (1<<COM1A1);
> TCCR5A |= (1<<COM1A1);

https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR

Wäre cool wenn du es mir in deinen Worten erklären könntest.

von spess53 (Gast)


Lesenswert?

Hi

>Eine Frage müsste es nicht COM1"A"1 sein?

Kommt darauf an, welche Kanäle du in TCCR5A ansprechen willst:

Bit 7:6 – COM5A1:0 Compare Output Mode for Channel A
Bit 5:4 – COM5B1:0 Compare Output Mode for Channel B
Bit 3:2 – COM5C1:0 Compare Output Mode for Channel C

MfG Spess

von Ahmet D. (closed_loop_stepper)


Lesenswert?

Also gings nur darum das,

> TCCR5A = 0;

unprofessionell aussieht ?

von Einer K. (Gast)


Lesenswert?

Ahmet D. schrieb:
> Also gings nur darum das,
>
>> TCCR5A = 0;
>
> unprofessionell aussieht ?

Nein!
> TCCR5A = (1<<COM1A1);
Vollkommener Stuss. Unsinnig, und damit ein gefährlicher Irrtum.

Du meinst:
>TCCR5A = (1<<COM5A1)

Wenn es auch bei diesen konkreten Timer gerade klappt, dann wirst du bei 
anderen Timern/µC mit einer solchen Schlampigkeit auf die Nase fallen.

Entschuldige bitte, die harten Worte.
Ich möchte bei dir den "Finger auf Herdplatte Effekt", also das "lernen" 
daraus, anstoßen.

Denn nach solchen Fehlern, kann man sich dull und dusselig suchen, da es 
ja plausibel aussieht, keine Meldungen wirft, und das eigene Hirn es 
gerade bügelt. Der Fehler liegt gerne außerhalb des Fokus.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ja war ein Tippfehler mit der 1 statt 5. Entschuldigung.
War nur ein Bsp. für das Verständnis / Unterschied von
= 0                oder
=  bestimmtes Bit  oder
|=
also was mit dem Inhalt des Registers dabei passiert.

Ich empfehle dir einmal in aller Ruhe die Timerregister im Datenblatt 
anzuschauen. Die Namen sind eindeutig. Die der Register und dessen Bits.

Bei allen anderen Unklarheiten fehlt mir die konkrete Frage um darauf 
eindeutig antworten zu können.

Eine Frage an dich habe ich noch die du dir selbst beantwortest. Die 
Timerregister werden durch die Arduino IDE vorbelegt. Wenn du nun einen 
Timer selbst verwendest und die Register die du für deine Verwendung 
nicht benötigst nicht nullst, was passiert dann mit dem Timer im 
Gesamten? Also wie verhält er sich? Macht er das was du möchtest oder 
macht er was anderes?

von Ahmet D. (closed_loop_stepper)


Lesenswert?

Veit D. schrieb:
> Eine Frage an dich habe ich noch die du dir selbst beantwortest.

Also mit dem Nullen läufts defenetiv besser.

von Ahmet D. (closed_loop_stepper)


Lesenswert?

Leute ich hätte ein Weiters Problem das eure Hilfe benötigt.

ich will jetet eine Regelung drauf setzen.

Nun wie ich mir das ganze Vorstelle.

Ich will die Drezhal der Schrittmotoren über den Druck reglen.
Dazu hab ich ein Array in dem ich bestimmte Schwelllenwerte deklariert 
habe. Die Drezahl soll sich so lange erhöhen oder verringen bis der 
Schwellenwert erreicht wurde.
Ist der Schwellenwert erreicht worden wird das nächst Schwellenwert vom 
Array hergezogen und das ganze geht von vorne los. Wenn der letzte Wert 
vom Array heranggezogen wird, soll der Feldzähler des Arrays wieder auf 
das erste Feld zeigen, damit das ganze von vorn los geht.
Den Druckwert der von Sensor gelsen wird stelle ich über den Barometer 
ein den ich mittel Silikonschläuchen und einer Großen Sprizte einstelle. 
Barometer und Sensor sind mit der Sprizte parallel verzeigt verbunden, 
deswengen stellt sich bei beiden der gleiche Druck ein

Die Drehzahl beeinfluss über den Timer, oder genauer über die Funktion
Setspeed(). Der Timer zieht sich nur den Wert aus der Funktion
Setspeed() ins Regsiter und löst danach aus und macht dan eine Step für
beide Motoren.
Der Wert den sich der Timer zieht liegt zwischen 3200 bis 22.400.

Der Code steht nocht nicht so wie oben beschreiben und befindet sich 
noch in der entwicklungspahse aber es gint schon erste probleme

Meine erste Frage:

Also ich lasse in der Main die unten genannte Funktion laufen. Mein 
Problem wenn ich am Barometer den gewünschten Druck einstelle, ziehn die 
motoren die Drehzahl an bis sie hangen bleiben egal on sie Unterhalb, 
Oberhalb oder genau im Druckberech liegen.
Wenn ich aber die ber die Auskommentierten Prints einkommentire sehe ich 
am Seriellem monitor das, er Arduino genau das macht was er machen soll. 
leigt darüber runterzählen... liegt darunter hoch zählen .....  ....


void ReglerStellen()
{
    if(InputDruck <= (SetponitArray[Setpointzeahler]-15))         // 
SetponitArray[Setpointzeahler] entspricht 100.
    {
     Steller= Steller + 50;                  // Steller wird der 
Funktion Setspeed() über geben.
     //Serial.println("Hochzählen");
    }
    if(InputDruck >= (SetponitArray[Setpointzeahler]+15))         // 
SetponitArray[Setpointzeahler]  entspricht 100.
    {
    Steller = Steller - 50;                   // Steller wird mit 3200 
deklaiert,Steller hat sollte nicht weit über unter 3200 und 22400 
liegen.
    //Serial.println("Runterzählen");
    }

    if( (InputDruck >= (SetponitArray[Setpointzeahler]-15) ) && 
(InputDruck <= (SetponitArray[Setpointzeahler]+15) ) )
    {
      //Serial.println("Eingependelt");
    }
}


ich verstehe nicht warum das so ist ??? echt ratlos?? vlt ist es auch 
was einfachs und ich sehs nur net, HOFFENTLICH  :)




Meine zweite frage:

ich hab nach PID Libraries gesucht und keine passenden gefunden der von 
Brett Beauregard <PID_v1_h> ist zwar genial aber der geeignet sich nicht 
, weil dieser ja so Funktionert das er einen Inpunt einen einliest und 
versucht einen Output entsprechend dem Setpoint  zu reglen......
Mein Output der zu Regeln ist ist ein interner rechneter wert von 
Setpeed.
Und so weit ich den jetzt einschätzen drufte bracht die Libraries einen 
PIN als Output.

An dieser Stelle wen iht eine Libraries kennt die dazu passt bitte 
nennen.
Oder hab ich Bertts Librarie falsch genutzt.

ich hoffe ihr könnt mir weiter helfen. Und sorry für die Schlechte 
Darstellung ist das erste mal das ich was  hier Poste

von Einer K. (Gast)


Lesenswert?

https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h
Habe mir gerade mal das Interface angesehen...
Da wird kein Pin genutzt/übergeben.

Du siehst Geister.

von Ahmet D. (closed_loop_stepper)


Lesenswert?

Arduino Fanboy D. schrieb:
> Habe mir gerade mal das Interface angesehen...
> Da wird kein Pin genutzt/übergeben.
>
> Du siehst Geister.

 zu dieser späten Stunde kann gut möglich sein ^^

ich hab eher mit dem Beispiel Basic getestet und da hab er mir den wert 
0 oder 255 ausgegeben. dait nicht viel anfangen. es sei den mann kann 
den Output auf einen Werteberetch begrenzen das wäre gigantisch

Beitrag #5508590 wurde von einem Moderator gelöscht.
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.