Forum: Mikrocontroller und Digitale Elektronik ATTiny85 Unterschied an welcher Stelle einer Schleife eine Rechenoperation steht??


von hochsitzcola (Gast)


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

von Falk B. (falk)


Lesenswert?


von someone (Gast)


Lesenswert?

Das wird wohl an dem if und der ganzen schleife liegen ... poste den 
ganzen Code.

von Stefan B. (stefan) Benutzerseite


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.

von Hochsitzcola (Gast)


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

von Rubelus (Gast)


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?

von Rubelus (Gast)


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 ;)

von Stefan B. (stefan) Benutzerseite


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.

von Hochsitzcola (Gast)


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;

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.