ATTiny85 Unterschied an welcher Stelle einer Schleife eine Rechenoperation steht??

Gast #2006985
Lesenswert?

Hallo zusammen,

ich kämpfe mit dem Problem, daß eine Variable in eine if- Abfrage 
aktualisiert wird und in der Hauptschleife weiterverarbeitet wird. 
Aufgabe ist eine Art P-Regelung. In der If-Abfrage wird der Zielwert 
festgelegt, in der Hauptschleife läuft der Stellwert dem Sollwert 
hinterher, zweck ist, daß sich der Stellwert nicht sprunghaft ändert, 
sondern schön sanft dem Sollwert folgt.
1
if ...
2
 {
3
    ziel=...;
4
 }
5
x=ziel*1000;
6
y += (ziel-y)/100;
7
Ausgabe=y/1000;

Wenn ich das so wie dargestellt programmiere läuft das Ganze. Wenn ich 
die zeile x=ziel*1000; mit in die If-Abfrage schreibe, eigentlich muß 
die Rechnung ja nur einmal ausgeführt werden, läuft nichts!

Kann mir das jemand erklären?
Gruß
Hochsitzcola
Persönliche Seite #2007004
Lesenswert?

Das Problem ist nicht ausschliesslich der gezeigte Codeausschnitt. Der 
sollte "laufen".

Du könntest sogar in dem Codeausschnitt die Zeile x=ziel*1000; weg 
lassen (was manche Compiler sogar beim Optimieren machen), weil x im 
sichtbaren Bereich des Ausschnitts nirgends weiter benutzt wird.

Du solltest auch überlegen, welchen Wert ziel bei der Berechnung von 
y hat, wenn der if-Anweisungsblock nicht ausgeführt wird.

Du solltest auch überlegen welchen Wert y beim Eingang in den 
gezeigten Codeabschnitt hat, weil in der Zeile y += (ziel-y)/100; auf 
y etwas aufaddiert wird, was selbst wieder von y abhängig ist.
Gast #2007044
Lesenswert?

hier der betreffende Code-Schnipsel:
1
     while(1) {
2
      ADCSRA |= (1<<ADSC);        // Wandlung starten
3
        while ( !(ADCSRA & (1<<ADIF)) );
4
        vact = ADCW;// AD-Wert auslesen 
5
          
6
    if (abs(vact-vacta)>15)
7
      {
8
      vacta=vact;
9
      if (vact>max){max=vact;}
10
        if (vact<min){min=vact;}
11
        for( i=0; i<7; i++ )
12
        {
13
         valt[i]=valt[i+1];
14
        }
15
      valt[7] = vact;
16

17
      if (flanke==0) //steigende Flanke suchen
18
      {
19
      z=0;
20
      for( i=0; i<7; i++ )
21
          {
22
        if (valt[i] < valt[i+1])
23
                      {
24
                      z++;
25
                      }
26
          }
27
        if (z==7)
28
                        {
29
            flanke =1;
30
                        }
31
      }
32
      if (flanke==1) //fallende Flanke suchen
33
        {
34
        z=0;
35
        for( i=0; i<7; i++ )
36
        {
37
        if (valt[i] > valt[i+1])
38
          {
39
          z++;
40
                 }
41
        }
42
        if (z==7)
43
                                {
44
                     flanke =0;
45
         delta=0;
46
        for( i=0; i<4; i++ )/
47
        {
48
        avedelta[i]=avedelta[i+1];
49
        }
50
        avedelta[4]=max-min;
51
        for( i=0; i<5; i++ )
52
        {
53
                                 delta+=avedelta[i];
54
        }
55
        delta/=20; 
56
        min=1024;
57
        max=0;
58
                              }
59
      }
60
    }
61

62
      ziel=delta*1000l;
63
      kruecke += (ziel-kruecke)/1000;
64
      aus = kruecke/1000;
65

66
      
67
      OCR0A = aus; //PWM aktualisieren
68

69
    }
70
    }

Hab den Code etwas eingekürzt. Es wird eine schwingende Spannung 
(kleiner 5 Hz) untersucht. Die Amplitude der Schwingung soll als PWM 
geglättet wieder ausgegeben werden. Die Amplitude wird über 5 
Schwingungen gemittelt.

Gruß
Hochsitzcola
Gast #2007089
Lesenswert?

Oh mein Gott, rück mal richtig deinen Code ein, da bekommt man ja 
Augenkrebs beim lesen :D

"Ziel" und "Aus" wird bestimmt "wegcompiliert"... Ist Ziel als long 
definiert? Als was ist "aus" definiert?

Das wäre dann Quasi so:

kruecke = krueke + ((delta*1000l)-kruecke)/1000);
OCR0A = kruecke/1000;

Dann lass uns mal mit einem Delta von 125 rechnen, und das Ziel liegt 
bei 512 Krueke ist bei 124:

Krueke = 124 + ((125*1000)-124)/1000); = 248,87 = int 249
OCR0A  = 125/1000;                     = 0,249  = int 0


Wohin soll denn dein OCR0A deinen Timer setzen wenn er im Grunde immer 
wieder auf 0 fällt?
Gast #2007092
Lesenswert?

Falsch Krueke müsste ja bei 386 liegen also nochmal neu Rechnen:

Krueke = 386 + ((125*1000)-386)/1000); = 510,61 = int 511
OCR0A  = 125/1000;                     = 0,510  = int 1

Behebt das Problem aber immer noch nicht ;)
Persönliche Seite #2007114
Lesenswert?

Du hast 15 { und 16 } im Codeausschnitt. Und keine Definitionen von 
Variablen aus denen ich sicher den Datentyp und die Initialwerte 
erkennen kann. Damit kann ich nur spekulieren:

1. Prüfe, ob du den Fall (abs(vact-vacta)<=15) ausreichend 
berücksichtigst

2. Prüfe deine Rechnungen auf Überläufe. Letztlich endet alles in einem 
uint8_t Wert (OCR0A = aus;)

3. Tipp für schlanke, schnelle Programme: Nutze Ganzzahlrechnungen und 
2er-Potenzen. Also z.B. 16 oder 32 statt 20, 1024 statt 1000 usw.
Gast #2007161
Lesenswert?

Hallo zusammen,

die Variablen sind glaub ich ausreichend groß definiert. So wie 
dargestellt läuft das ja auch. Ich hatte schon einigen Ärger mit 
Überläufen, die sind aber jetzt behoben. Das mal nehmen und wieder 
teilen mache ich um Fließkommazahlen zu vermeiden.

@Stefan: das mit den Klammern ist mir beim zusammenkürzen passiert, der 
Code ist so sicher nicht lauffähig. Danke für den Tip mit den 
2er-Potenzen.

@rubelus: sorry für den Augenkrebs, beim reinkopieren ist leider die 
Formatierung verlorengegangen.

hier noch die Variablen-Deklaration:
1
        unsigned int i = 0;//Schleifenzähler
2
  unsigned int z = 0;
3
  unsigned int max = 0;  //Maximalwert Spannung
4
  unsigned int min = 1024;  //Minimalwert Spannung
5
  unsigned long vact = 0;
6
  unsigned long vacta = 0;//Aktuelle Spannung
7
  unsigned int valt[8];//alter Spannungswert
8
  unsigned int avedelta[5];//verlauf Delta
9
  unsigned int delta = 0;
10
  unsigned int aus = 0;
11
  unsigned int flanke = 0;
12
  long ziel = 0;
13
  long kruecke= 0;

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren