Forum: Mikrocontroller und Digitale Elektronik PWM an atmega8


von Seb a. (seppelg85)


Lesenswert?

Guten Abend zusammen

Nachdem ich nun einige Tutorials und Beiträge zur PWM durchgelesen habe 
und leider immer noch nicht weiter bin, hoffe ich hier auf eine 
Problemlösung von erfahrenen Usern.
Das Coding rund herum funktioniert schon, nur die PWM bereitet mir 
Probleme.

Hier mal eine Erläuterung des kompletten Programms:
Ich nutze das myavr MK2 board mit LCD Anzeige und einem atMega8 
Prozessor. Auf der LCD Anzeige wird die Soll und Ist-Temperatur 
angezeigt. Die Soll Temperatur ist mit zwei vorhanden Tastern in 0,5er 
Schritten hoch oder runter zu regeln. Die IST-Temperatur soll irgendwann 
mittels Temperatursensor eingelesen werden. Zur Simulation nutze ich 
zurzeit ein Poti mit AD-Wandlung zur Einstellung der IST-Temperatur. 
Dann sollen zwei LED's an den PWM Ausgängen geregelt werden. Grüne LED 
für IST > SOLL und gelb für IST < SOLL. Je grösser der 
Temperaturunterschied desto heller die jeweilige LED.

Nunmal der Programm-Ausschnitt:

DDRB |= (1 << PB1 );  // PB1 als Ausgang für PWM
DDRB |= (1 << PB2 );    // PB2 als Ausgang für PWM
DDRB |= (1 << PB3 );  // PB3 als Ausgang für PWM

Habe alle 3 als Ausgang gesetzt weil ich auch schon versucht habe mit 
OCR2 zu arbeiten.

TCCR1A = 0b10100010;    // COM1A1-COM1A0 = Nicht invertierend ;
                        // COM1B1-COM1B0 = Nicht invertierend ;
                        // FOC1A und FOC1B = 0;
                        // WGM11 = 1, WGM10 = 0

TCCR1B = 0b00011001;    // WGM13 = 1, WGM12= 1 <<- Mode14, Fast PWM
                        //CS12-CS11-CS10 = 001 <<- Kein Vorteiler

ICR1   = 0x0040;        // Top Wert auf 64 setzen durch Mode14

if (e>0)                 //wenn e > 0 -->heizung an(gelbe LED)
{

OCR1A = y;               // vergleichwert für compare match y
OCR1B =0;                // Gegenwert zum "Schutz" auf 0
}

if (e<0)                 //wenn e < 0 -->lüftung an(grüne LED)
{
OCR1B =-y;               // vergleichwert für compare match y
OCR1A = 0;               // Gegenwert zum "Schutz" auf 0
}


Wo hab ich hier den Fehler? Denke ich da komplett Falsch?
Komme leider wirklich nicht weiter...


Vielen Dank schonmal für jede Hilfe

Mfg

von Seb a. (seppelg85)


Lesenswert?

Nachtrag:

Mit zusätzlichem OCR2 Timer bekomme ich ein besseres Ergebnis.

TCCR2  = 0b01100100;

if (e>0)                 //wenn e > 0 -->heizung an(gelbe LED)
{
OCR2  = 0;
OCR1A = y;               // vergleichwert für compare match y
OCR1B =0;                // Gegenwert zum "Schutz" auf 0
}

if (e<0)                 //wenn e < 0 -->lüftung an(grüne LED)
{
OCR1B =-y;               // vergleichwert für compare match y
OCR1A = 0;               // Gegenwert zum "Schutz" auf 0
OCR2  = -y ;
}

Die grüne LED wird allerdings scheinbar nicht voll aufgeregelt.
Hab ich trotzdem noch Fehler im Programm?

Danke im Voraus

von holger (Gast)


Lesenswert?

>Hab ich trotzdem noch Fehler im Programm?

Da kannst du deinen Arsch drauf verwetten;)

von Seb a. (seppelg85)


Lesenswert?

holger schrieb:
>>Hab ich trotzdem noch Fehler im Programm?
>
> Da kannst du deinen Arsch drauf verwetten;)

Das ist zumindest schonmal ein klitzekleiner Hinweis :D

Hoffe auf etwas präzisere Antworten.. Danke!

Gruß

von Seb a. (seppelg85)


Lesenswert?

Kann mir hier keiner einen verwendbaren Tip geben?
Wäre echt super..

Mfg

von dunno.. (Gast)


Lesenswert?

das die led in deiner schaltung überhaupt heller leuchten kann als das 
momentane maximum hast du verifiziert..?

also zb mal nen adc messwert an eine pwm durchreichen, und eine andere 
per code fest auf vollausschlag stellen..?

leider sind deine programmausschnitte ja nicht wirklich aussagekräftig.

zumindest erfährt man, das "e" angeblich negativ werden kann..?
was ist e, was ist y..?
was für nen wert hat y..

leider wird hier überhaupt nichts klar, sry.

am besten mal die sourcen in den anhang, und genauer erläutern, was du 
da versuchst..

mfg

von Seb a. (seppelg85)


Lesenswert?

Hallo dunno

Zu deiner ersten Frage. Ja, dass habe ich bereits verifiziert.

Ich dachte der Programmausschnitt würde reichen um einen Hinweis zu 
bekommen was mit der PWM nicht stimmt.

Hier mein C-Code Ausschnitt für die AD-Wandlung:
1
float Adwandlung()
2
{
3
  float result;                                                                     
4
  ADMUX = (1<<ADLAR);                      //Linksbündige Ausgabe
5
  ADCSRA = (1<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);
6
  ADCSRA |=  (1<<ADEN);
7
8
    ADCSRA |= (1<<ADSC);                                 //Wandlung starten 
9
    while(ADCSRA & (1<<ADSC)) ;                   //warten bis Wandlung fertig  
10
    result = ADCH;                      //AD Wandlungsergebnis in float result schreiben
11
  
12
13
return result;                      
14
                                      
15
}

Und hier meine PWM mit integrieter PI-Regelung:
1
void pi_regler(float temp_sensor_value_var,float temperature_var)
2
{
3
4
5
PORTC &= 0b00110001;                    // turn off all leds
6
7
DDRB |= (1 << PB1 );                    // PB1 als Ausgang für PWM
8
DDRB |= (1 << PB2 );                    // PB3 als Ausgang für PWM
9
DDRB |= (1 << PB3 );                    // PB3 als Ausgang für PWM
10
11
12
TCCR1A = 0b10100010;                          //COM1A1 = 1 ; COM1A0 = 1; COM1B1=1;COM1B0 = 1
13
TCCR1B = 0b00011001;                           //WGM13=0 - WGM12=1 - Vorteiler=64
14
15
ICR1   = 0x0040;
16
17
TCCR2  = 0b01100100;
18
19
//TCCR2  = 0b00101001;                    // OCR2 für PWM einstellen    
20
//OCR2=0x0040;
21
22
float iwert=0,pwert=0,e=0;                //I-Anteil, P A-Anteil  
23
int y=0;
24
float ki= 1.5;                                       //Integrationsbeiwert(verstärkung der itegration)                                
25
float kp = 0.5;                                      //Proportionalanteil 
26
float ta = 0.01;                                     //Abtastzeit 10ms
27
float esum=0;
28
29
30
e = temperature_var - temp_sensor_value_var;                 //aktuelle Regelabweichung bestimmen
31
/*if (e>50)                                     //e Begrenzen auf +50°
32
  {
33
  e=50;
34
  }
35
if (e<-50)                                          //e begrenzen auf -50°
36
    {
37
    e=-50;
38
    }
39
*/
40
pwert=(kp*e);                                //P-Anteil ausrechnen
41
iwert=(ki*ta*esum);                              //I-Anteil ausrechen
42
y=pwert+iwert;                                //Stellgröße ausrechnen
43
44
if (y<50)                              //Integration nur in diesen bereich ausrechen
45
{                                          //Wenn kein abweichnung da ist Inegration Einfrieren
46
esum=esum+e;                                        //Integration I anteil
47
}
48
if (y>-50)                                 //Wenn stellgröße negativ ist PRÜFEEENNNN!!!!!!!!!!!!!!
49
  {
50
  esum=esum-e;
51
  }
52
if (y==0)                                           //wenn die stellgröße gleich 0 ist           
53
    {
54
    esum=0;                                  //Setz Integration zurück 
55
    }
56
57
if (e>0)                                            //wenn e größer 0 ist muss die heizung angehen
58
      {
59
      
60
      OCR1A = y;                                    //vergleichwert für compare match y
61
      OCR2  = 0;                                    //wenn heizung an soll der lütfter aus sein
62
      OCR1B = 0;
63
      
64
      }
65
if (e<0)                                            //wenn e kleiner 0 ist muss die lüftung angehen
66
        {
67
68
        OCR1A = 0;
69
        OCR2  = -y;                           //vergleichwert für compare match y
70
        OCR1B=-y;
71
        
72
        }
73
74
}

Ich hoffe das ist nun alles Aussagekräftiger und würde mich sehr über 
Lösungsansätze freuen.

p.s: Das die Werte alle NICHT unbedingt float sein 
sollten/müssten/dürften :-) ist mir bewusst.

von dunno.. (Gast)


Lesenswert?

okay, da ich sowas wie regelungstechnik nich hab, kann ich zu deinem 
algorithmus nix sagen...


allerdings macht mir dein zahlenhandling bauchschmerzen.. du bekommst 
einen adc messwert als unsigned char, interpretierst den dann ohne cast 
als float,
rechnest damit irgendwas lustig rum, gehst dann davon aus, das das 
problemlos in einen integer geht, und gibst das dann an deine OCR 
register aus, die sicher weniger als 16bit haben..

ich würd zu gerne da mal in den speicher gucken, und schauen was da für 
werte rauskommen, aus dem gerechne..

sicher nix sinnvolles mehr..

keine ahnung, wie man da am professionellsten vorgeht, ich würd 
zumindest mal sicher gehen wollen, was da für ergebnisse rauskommen..

generell halt ich es für ungünstig da mit float und integers zu 
rechnen..
wahrscheinlich fährst du mit ner look up table o.ä. besser..

mfg

von dunno.. (Gast)


Lesenswert?

achso, hab den fehler im algorithmus wohl doch.. =)

wozu genau ist eigentlich deine esum gut?

also, nicht nur das die irgendwie durch die ifs mehrmals umgeschrieben 
werden kann..
[ wenn y==0 ist, wird y auch <50 sein..? ]
vom negativen bereich mal ganz zu schweigen.
da wäre die tante else wohl ganz sinnvoll platziert.

außerdem:

dein esum ist immer 0, in der berechnung. damit sollte dein iwert immer 
=0 sein. wenn dein iwert 0 ist, ist dein pwert immer 0.5*e.

y=pwert=0.5e

e ist die differenz der 2 ad-wandelergebnisse(denke ich).
also kann y nie größer als 128 werden.

also ist mit deiner pwm alles in ordnung. ;)

mfg

von Seb a. (seppelg85)


Lesenswert?

Danke schonmal für deine Antwort dunno.

du bekommst einen adc messwert als unsigned char <-- Ist das so? Die 
Wandlung wird ja in result geschrieben welches als float deklariert ist. 
Oder ist der generelle ADC - Wert immer unsigned char?

Des Weiteren (was mich aber auch wundert) meckert mein Compiler darüber 
nicht! Also wenn ich den Wert nicht caste..

Wenn ich die ORCL und OCRH Register nutze habe ich doch 16 Bit oder? 
Damit habe ich es bereits versucht...Leider auch ohne Erfolg!

Muss natürlich auch als blutiger Anfänger sagen, dass ich mich da noch 
son bisschen durchwühle.

Nichts desto trotz werde ich da nochmal gezielt drauf schauen und 
nachsehen, welche Zahlen dementsprechend dann im Speicher stehen. 
Vielleicht bringt mich das ja etwas weiter...

Gruß

von dunno.. (Gast)


Lesenswert?

ja, aus dem adc kommen erstmal so 8 bit raus, die kannst du gerne als 
float interpretieren, aber das ergibt keinen sinn..

übrigens machts auch keinen sinn H und L zu nutzen, denn der adc kann 
nur 10 bit.

das der compiler nicht meckert, liegt wohl daran das es ihm erstmal 
völlig egal ist, was für zahlen du da hast. sind ja nur nullen und 
einsen in einem (bzw mehreren) register(n), wie die jetzt interpretiert 
werden sollen, das ist dein problem.

ich bin mir auch garnicht so sicher, ob casten alleine dich jetzt aus 
der misere zieht, da kann vielleicht jemand anders noch was dazu sagen..

mfg

von Seb a. (seppelg85)


Lesenswert?

Hi dunno

Das mit H und L war nicht auf die AD-Wandlung sondern auf die PWM 
bezogen.

E ist die Differenz zwischen Soll und Ist Wert. Der eine Wert kommt aus 
der AD-Wandlung (IST) und Soll wird über Taster hoch bzw. 
runtergestellt.

Mit esum immer 0 hast du für den obigen Code recht. Jedoch ( sorry, mein 
Fehler) wird der Wert durch die Main Routine (Endlosschleife) verändert.

Deshalb hier auch mal mein Main Part + die Funktion für die LCD-Anzeige: 
( sorry, hätte ich auch direkt posten können)
1
int main(void)
2
{
3
  /*
4
  Current port assignment:
5
  PORTC0 = Poti.1
6
  PORTC1 = green led
7
  PORTC2 = yellow led
8
  PORTC3 = red led
9
  PORTC4 = taster 2
10
  PORTC5 = taster 1
11
  */  
12
  
13
  lcd_init();                          // lcd test
14
  
15
  lcd_string("SOLL-Wert: ");                  // set lcd text
16
    lcd_setcursor( 0, 2 );
17
    lcd_string("IST-Wert: ");
18
19
  DDRC = 0b00111110;
20
  PORTC = 0b00110001;
21
  // set input for window sensor (PINB5)
22
  DDRB |= 0b00000001;
23
  PORTB &= 0b11111110;
24
25
  float temperature = 20.0;                  // temperature (SOLL)
26
  float temp_sensor_value;                  // temperature sensor value (IST)
27
  unsigned taster1State = 0;
28
  unsigned taster2State = 0;
29
  
30
  writeTemperature(temperature, 1);
31
  while(1){
32
    // taster 1 push (negative = push)
33
    if(!(PINC & (1<<PINC5)) && !taster1State)
34
    {
35
      taster1State = 1;
36
      temperature += 0.5;
37
      writeTemperature(temperature, 1);          // write float SOLL value to lcd display
38
    }
39
40
      // taster 1 release
41
      if((PINC & (1<<PINC5)) && taster1State)
42
        {
43
        taster1State = 0;
44
        }
45
46
      // taster 2 push (negative = push)
47
      if(!(PINC & (1<<PINC4)) && !taster2State)
48
      {
49
        taster2State = 1;
50
        temperature -= 0.5;
51
        writeTemperature(temperature, 1);        // write float SOLL value to lcd  
52
      }
53
54
              // taster 2 release
55
              if((PINC & (1<<PINC4)) && taster2State){
56
                taster2State = 0;
57
              }
58
        
59
    temp_sensor_value = Adwandlung();                //read analog temp value from Adwandlung and save into temp_sensor_value 
60
    writeTemperature(temp_sensor_value, 2);              //write out float IST temperature to lcd display    
61
62
    // check if window is open
63
    if(WINDOW_SENSOR_PORT_ARRAY & (1<<WINDOW_SENSOR_PORT))
64
    {
65
      PORTC &= 0b00110001;                    // turn off all leds
66
      PORTC |= (1 << PORTC3);                    // turn on red led
67
      continue;                          // skip next steps
68
    }
69
70
    pi_regler(temp_sensor_value,temperature);        // Werte an Funktion pi_regler übergeben
71
  }
72
  
73
  return 0;
74
}
75
76
void writeTemperature(float temp, int line)
77
{  
78
  lcd_setcursor( 10, line );
79
  lcd_data(' ');
80
  if(temp<0)
81
  {
82
    lcd_setcursor( 10, line );
83
    lcd_data('-');
84
    temp = temp*-1;
85
  }
86
87
  int normal = temp;
88
  int decimal = (temp-normal)*1000.0;
89
90
  char buffer[4];
91
  itoa(normal, buffer, 10);
92
  lcd_string(buffer);
93
  lcd_data('.');
94
  itoa(decimal, buffer, 10);
95
  lcd_string(buffer);
96
}

Ich hoffe ich werde für meine "Programmierkünste" nicht gesteinigt :-)!

Danke schonmal Dunno!

Gruß

von dunno.. (Gast)


Lesenswert?

@ H/L

richtig, die pwm kannst du mit H/L auf 16 bit bringen, der adc hat aber 
eine maximale auflösung von 10 bit.. es gibt ja auch ADCH und ADCL ;)



und das esum in deiner main irgendwie verändert werden KANN, bezweifle 
ich stark. zum einen sehe ich esum da nirgends, zum anderen ists lokal 
definiert.

abgesehen davon, wenn es verändert werden WÜRDE, würde float esum=0; bei 
funktionsaufruf das unter garantie wieder auf 0 ändern. ;)

von dunno.. (Gast)


Lesenswert?

ach gott, irgendwann muss ich mich hier doch mal fest anmelden..
ergänzung zu dem von grade...


dir ist klar, das dein ad wandler immer werte von 0..255 liefern wird.?
du musst das erstmal auf ne temperatur umrechnen.

also sagen wir, du misst bei 20 grad einen wert von 128, und dein soll 
ist 20.0 (weil float)

dann hast du ja in e eine differenz von 108.....

schau dir lieber nochmal an, wie das mit temperatursensoren und 
temperatur gemacht wird.. ;)

von Seb a. (seppelg85)


Lesenswert?

Hi dunno

Danke für deine Bemühungen. Ich bin dadurch mal wieder etwas von der PWM 
weggekommen und habe nochmal "versucht" alles zu prüfen :-).
Mit esum hast du natürlich absolut Recht. Ich habe die Regelung mal 
etwas abgewandelt...

Einige Fragen dazu:
Wenn ich esum lokal so definiere -> float esum;
Hab ich keinen definierten Wert anfangs oder? Ich geh langsam am Stock 
hier..mir fallen die einfachsten Sachen nicht mehr ein :-/
Wie löse ich das?

Des Weiteren muss ich beim debuggen feststellen, dass die Berechnungen

pwert=(kp*e);                                //P-Anteil ausrechnen
iwert=(ki*ta*esum);

wenn ich Schrittweise debugge übersprungen werden. Warum?
Weiss das jemand?
1
void pi_regler(float temp_sensor_value_var,float temperature_var)
2
{
3
4
5
PORTC &= 0b00110001;                    // turn off all leds
6
7
DDRB |= (1 << PB1 );                    // PB1 als Ausgang für PWM
8
DDRB |= (1 << PB2 );                    // PB3 als Ausgang für PWM
9
DDRB |= (1 << PB3 );                    // PB3 als Ausgang für PWM
10
11
12
TCCR1A = 0b10100010;                          //COM1A1 = 1 ; COM1A0 = 1; COM1B1=1;COM1B0 = 1
13
TCCR1B = 0b00011001;                           //WGM13=0 - WGM12=1 - Vorteiler=64
14
15
ICR1   = 0x0040;
16
17
TCCR2  = 0b01100100;
18
19
//TCCR2  = 0b00101001;                    // OCR2 für PWM einstellen    
20
//OCR2=0x0040;
21
22
float pwert=0, iwert =0;                //I-Anteil, P A-Anteil  
23
float e=0;
24
float y=0;
25
float ki= 1.5;                                       //Integrationsbeiwert(verstärkung der itegration)                                
26
float kp = 0.5;                                      //Proportionalanteil 
27
float ta = 0.01;                                     //Abtastzeit 10ms
28
float esum;
29
30
31
e = temperature_var - temp_sensor_value_var;                 //aktuelle Regelabweichung bestimmen
32
/*if (e>50)                                     //e Begrenzen auf +50°
33
  {
34
  e=50;
35
  }
36
if (e<-50)                                          //e begrenzen auf -50°
37
    {
38
    e=-50;
39
    }
40
*/
41
42
pwert=(kp * e);                                //P-Anteil ausrechnen
43
iwert=(ki*ta*esum);                              //I-Anteil ausrechen
44
y=pwert+iwert;                                //Stellgröße ausrechnen
45
46
if (y<50)                              //Integration nur in diesen bereich ausrechen
47
{                                          //Wenn kein abweichnung da ist Inegration Einfrieren
48
//esum=esum+e;                                        //Integration I anteil
49
e=esum+e;
50
}
51
if (y>-50)                                 //Wenn stellgröße negativ ist PRÜFEEENNNN!!!!!!!!!!!!!!
52
  {
53
//  esum=esum-e;
54
  e=esum-e;
55
  }
56
/*
57
  else if(y==0)                                           //wenn die stellgröße gleich 0 ist           
58
    {
59
    esum=0;                                  //Setz Integration zurück 
60
    }
61
*/
62
if (e>0)                                            //wenn e größer 0 ist muss die heizung angehen
63
      {
64
      
65
      OCR1A = y;                                    //vergleichwert für compare match y
66
      OCR2  = 0;                                    //wenn heizung an soll der lütfter aus sein
67
      OCR1B = 0;
68
      
69
      }
70
if (e<0)                                            //wenn e kleiner 0 ist muss die lüftung angehen
71
        {
72
73
        OCR1A = 0;
74
        OCR2  = -y;                           //vergleichwert für compare match y
75
        OCR1B=-y;
76
        
77
        }
78
79
}

Dunno, sieht es so etwas besser aus?

Übrigens, über die Sache mit den Berechnungen bin ich mir im klaren. Das 
würde dann angepasst wenn wir wirklichen mit einem Sensor arbeiten.

Bis auf die ganzen floats natürlich... :-)

Danke!!

von Karl H. (kbuchegg)


Lesenswert?

Lös doch mal deine PWM von der Regelung und teste sie seperat.

Du willst 2 LED gegengleich dimmen.
Das sollte sich doch mit einem kleinen Testprogramm erstmal losgelöst 
von allem anderen realisieren lassen.
Dann weißt du schon mal, dass die PWM grundsätzlich funktioniert.

von Karl H. (kbuchegg)


Lesenswert?

Seb astian schrieb:

> Einige Fragen dazu:
> Wenn ich esum lokal so definiere -> float esum;
> Hab ich keinen definierten Wert anfangs oder?

richtig

> Ich geh langsam am Stock
> hier..mir fallen die einfachsten Sachen nicht mehr ein :-/
> Wie löse ich das?

Wie hast du es denn bei den anderen Variablen gemacht?

Aber abgesehen davon, ist das immer noch Quatsch, weil du ja nicht bei 
jedem Aufruf der Regelfunktion ein neues esum haben willst, sondern ein 
esum, dessen Wert mehrere Aufrufe übersteht. Sonst hat das ja keinen 
Sinn.

Also: entweder esum als globale Variable machen oder die Variable static 
machen.


Mach doch dein Lüfter/Heizungs Spielchen erst mal ohne den PI-Regler.
Ein simpled 2-Punkt Regler:

Wenn die Temperatur kleiner als die Solltemperatur - 1Grad, dann Lüfter 
aus und Heizung ein
Wenn die Temperatur größer als die Solltemperatur + 1 Grad, dann Heizung 
aus und Lüfter an.

Das ganze garniert mit den LED


Und wenn das dann läuft, dann beschäftigst du dich mit dem PI Regler.

von Karl H. (kbuchegg)


Lesenswert?

Seb astian schrieb:

> Dunno, sieht es so etwas besser aus?

No.

Deine Formatierung ist ein Graus.

Wozu muss man in der Regelgungsfunktion ständig die Timer neu 
konfigurieren und die Ports auf Ausgang stellen?
Stell die Dinge EINMAL ein und belasse es dann dabei!

Das generelle Layout eines Programms sieht so aus
1
....
2
3
4
int main()
5
{
6
7
    Einstellen der Hardware.
8
    Eingänge festlegen, Ausgänge festlegen, Pullup einschalten
9
10
    Timer intialisieren
11
12
    ev. sei, wenn mit Interrupts gearbeitet wird
13
14
    while( 1 ) {
15
16
      jetzt wird gearbeitet
17
18
    }
19
}

von dunno. (Gast)


Lesenswert?

ganz recht, esum hat so keinen definierten wert. kannst du also so auch 
nicht machen.

ne einfache lösung, wenn du keine pointer nutzen willst, wäre, die 
funktion jeweils die aktuelle esum zurückgeben zu lassen, und dann eben 
den nächsten aufruf mit dem alten wert als parameter machen...
dann speicherst du das quasi in main.

ansonsten gäbe es da noch static.

warum deine berechnungen übersprungen werden..? keine ahnung was du mit 
übersprungen meinst, aber nen grund dafür kann ich mir grad nich 
vorstellen.. in den variablenwerten müsste man allemal ne veränderung 
sehen..

und y>-50 ist auch immernoch wahr, wenn y<50 ist.

ich kann nur immer wieder meine alte tante else erwähnen..

oh, und was noch ziemlich komisch ist, das du versuchst, die pwm ganz am 
ende mit -y zu beschreiben.. denn die hardware wird den wert ganz sicher 
als unsigned interpretieren.... und DAS ist nun wirklich nicht was du 
willst.

von dunno. (Gast)


Lesenswert?

edit: verdammt, ist der herr buchegger schnell. ^^

von Seb a. (seppelg85)


Lesenswert?

Also...

@ Karl Heinz Buchegger

Eine simple 2-Punkt Regelung hatte ich bereits laufen. Das war so weit 
OK.
Dabei habe ich natürlich die Regelung und die PWM weggelassen.

Das mit der seperaten PWM werde ich gleich noch einmal machen.

Esum wollte ich in der Tat returnen! Das hab ich im ganzen Wusel 
wirklich vergessen..Nur war mir dabei auch nicht klar ob der Wert dann 
jedes mal an den Funktionsanfang gegeben wird?? Wenn das bei der 
definition float esum; so ist, dann ist es genau das was ich 
brauche/will!

Sorry für diese Formatierung. Das hab ich schon des öfteren gehört 
:-/..Muss ich mir dringend angewöhnen.

@ Dunno..

ne einfache lösung, wenn du keine pointer nutzen willst, wäre, die
funktion jeweils die aktuelle esum zurückgeben zu lassen, und dann eben
den nächsten aufruf mit dem alten wert als parameter machen...
dann speicherst du das quasi in main.  <-- Hm warum speicher ich das in 
main? In main brauche ich den Wert ja gar nicht!!


oh, und was noch ziemlich komisch ist, das du versuchst, die pwm ganz am
ende mit -y zu beschreiben.. denn die hardware wird den wert ganz sicher
als unsigned interpretieren.... <-- Das hab ich mir auch gedacht. Nur 
was zum Teufel soll ich daran anders machen? Das ist nunmal mein 
Vergleichswert ...

Danke für eure Hilfe!

von dunno. (Gast)


Lesenswert?

Seb astian schrieb:
> Hm warum speicher ich das in
> main? In main brauche ich den Wert ja gar nicht!!

ganz einfach, du speicherst den in der main, weil der wert in der 
funktion bei jedem beenden der funktion gnadenlos aus dem speicher 
fliegt. du kannst natürlich auch global arbeiten, aber das wird 
allgemein als mieser stil gesehen.. (okay okay, hier spricht der student 
und nicht der praktiker..)

in der main bliebe der wert die ganze zeit gespeichert.

alternative ist static, hier stellt sich aber wohl das problem mit dem 
initialisieren beim 1. start... bin mir nicht sicher, ob man das =0 
setzen darf, dann.


zur pwm..

naja, musst dir halt deinene werte berechnen.. so wirds nicht klappen, 
mit dem gegengleich.

von Karl H. (kbuchegg)


Lesenswert?

dunno. schrieb:
> Seb astian schrieb:
>> Hm warum speicher ich das in
>> main? In main brauche ich den Wert ja gar nicht!!
>
> ganz einfach, du speicherst den in der main, weil der wert in der
> funktion bei jedem beenden der funktion gnadenlos aus dem speicher
> fliegt. du kannst natürlich auch global arbeiten, aber das wird
> allgemein als mieser stil gesehen.. (okay okay, hier spricht der student
> und nicht der praktiker..)

:-)
Im Prinzip richtig.
Aber auf einem kleinen µC gelten ein klein wenig andere Gesetze. Hab ich 
auch erst lernen müssen.
Zum einen sind Programme klein genug, dass globale Variablen noch nicht 
so das Problem sind.
Viel wichtiger aber ist, dass du eine ziemlich konkrete Vorstellung 
davon hast, wieviel RAM für Vairablen drauf geht. Mit globalen Variablen 
geht das am besten und einfachsten.

> alternative ist static, hier stellt sich aber wohl das problem mit dem
> initialisieren beim 1. start... bin mir nicht sicher, ob man das =0
> setzen darf, dann.

Kann man.
Die Initialisierung wird dann nur beim ersten mal ausgeführt.
static ist in dieser Form wie eine globale Variable, die nur in einer 
Funktion sichtbar ist.

> naja, musst dir halt deinene werte berechnen.. so wirds nicht klappen,
> mit dem gegengleich.

Ich bin mir noch nicht mal sicher, ob y überhaupt vom Wertebereich her 
zu einer PWM passt. Ist halt immer das gleiche: Ohne Möglichkeit zum 
Ausgeben von Werten ist das oft ein Stochern im Nebel.

von Seb a. (seppelg85)


Lesenswert?

> Kann man.
> Die Initialisierung wird dann nur beim ersten mal ausgeführt.
> static ist in dieser Form wie eine globale Variable, die nur in einer
> Funktion sichtbar ist.

Danke! Variable ist nun auf static gesetzt!
Einige Änderungen bezgl. der ganzen if's sind nun auch passiert. Else 
wurde eingefügt!

>> naja, musst dir halt deinene werte berechnen.. so wirds nicht klappen,
>> mit dem gegengleich.
>
> Ich bin mir noch nicht mal sicher, ob y überhaupt vom Wertebereich her
> zu einer PWM passt. Ist halt immer das gleiche: Ohne Möglichkeit zum
> Ausgeben von Werten ist das oft ein Stochern im Nebel.

Das ist wirklich wahr. Leider habe ich die Möglichkeit nicht.
Mein Problem bezgl. PWM ist ganz ehrlich folgendes, dass an 1000 Stellen 
die Initialisierung einer PWM beschrieben wird. Diese sollte auch 
wirklich stimmen bei mir. Die Vergleichswerte ( wie genau die Variablen 
verglichen werden) und welcher Wertebereich akzeptiert wird steht nicht 
wirklich gut beschrieben. Ausserdem ist mir auch nicht klar ob ich 2 
oder 3 Timer brauche um die LED's gegengleich zu beleuchten :-(

Gruß

von Karl H. (kbuchegg)


Lesenswert?

Seb astian schrieb:

>> zu einer PWM passt. Ist halt immer das gleiche: Ohne Möglichkeit zum
>> Ausgeben von Werten ist das oft ein Stochern im Nebel.
>
> Das ist wirklich wahr. Leider habe ich die Möglichkeit nicht.

Tja.
Darum entwickelt man Software auch gerne auf Entwicklungsboards. Denn 
dort hat man dann die Möglichkeiten. Oder aber man baut sich in seine 
Hardware von vorne herein zb eine UART/MAX232 ein, die nur dazu dient, 
damit man während der Entwicklungszeit eine Möglichkeit zur Ausgabe hat. 
Oder man hat eine kleine Zusatzplatine, auf der ein MAX232 sitzt, die 
man während der Entwicklungszeit 'fliegend' mit der Hardware verbindet.

Du musst damit rechnen, dass du beim Entwickeln Fehler machst. Du musst 
damit rechnen, dass du eine Ausgabemöglichkeit brauchst. Alles andere 
ist dumm und Stochern im Nebel.

> Mein Problem bezgl. PWM ist ganz ehrlich folgendes, dass an 1000 Stellen
> die Initialisierung einer PWM beschrieben wird. Diese sollte auch
> wirklich stimmen bei mir. Die Vergleichswerte ( wie genau die Variablen
> verglichen werden) und welcher Wertebereich akzeptiert wird steht nicht
> wirklich gut beschrieben.

Da gibts auch nicht viel zu beschrieben.
Eine 8-Bit PWM hat einen Wertebereich von 0 bis 255. Warum? Weil mit 8 
Bit von 0 bis 255 gezählt werden kann.
Eine 10 Bit PWM hat einen Wertebereich von 0 bis 1023. Warum? Weil man 
mit 10 Bit von 0 bis 1023 zählen kann.
Eine 9 Bit PWM hat einen Wertebereich von 0 bis 511. Warum? WEil man mit 
9 Bit von 0 bis 511 zählen kann.
Eine Custom PWM, bei der man die Obergrenzer mittels ICR Register 
festlegen kann, hat einen Wertebereich von 0 bis zu eben dieser 
Obergrenze.

> Ausserdem ist mir auch nicht klar ob ich 2
> oder 3 Timer brauche um die LED's gegengleich zu beleuchten :-(

Du brauchst 2 PWM Stufen. Ob die jetzt mit 1 Timer oder mit 2 gemacht 
werden, hängt davon ab, was die Timer können. Wenn 1 Timer 2 Stück PWM 
erzeugen kann, dann reicht einer.

von Seb a. (seppelg85)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Seb astian schrieb:
>
>>> zu einer PWM passt. Ist halt immer das gleiche: Ohne Möglichkeit zum
>>> Ausgeben von Werten ist das oft ein Stochern im Nebel.
>>
>> Das ist wirklich wahr. Leider habe ich die Möglichkeit nicht.
>
> Tja.
> Darum entwickelt man Software auch gerne auf Entwicklungsboards. Denn
> dort hat man dann die Möglichkeiten. Oder aber man baut sich in seine
> Hardware von vorne herein zb eine UART/MAX232 ein, die nur dazu dient,
> damit man während der Entwicklungszeit eine Möglichkeit zur Ausgabe hat.
> Oder man hat eine kleine Zusatzplatine, auf der ein MAX232 sitzt, die
> man während der Entwicklungszeit 'fliegend' mit der Hardware verbindet.
>
> Du musst damit rechnen, dass du beim Entwickeln Fehler machst. Du musst
> damit rechnen, dass du eine Ausgabemöglichkeit brauchst. Alles andere
> ist dumm und Stochern im Nebel.
>
>> Mein Problem bezgl. PWM ist ganz ehrlich folgendes, dass an 1000 Stellen
>> die Initialisierung einer PWM beschrieben wird. Diese sollte auch
>> wirklich stimmen bei mir. Die Vergleichswerte ( wie genau die Variablen
>> verglichen werden) und welcher Wertebereich akzeptiert wird steht nicht
>> wirklich gut beschrieben.
>
> Da gibts auch nicht viel zu beschrieben.
> Eine 8-Bit PWM hat einen Wertebereich von 0 bis 255. Warum? Weil mit 8
> Bit von 0 bis 255 gezählt werden kann.
> Eine 10 Bit PWM hat einen Wertebereich von 0 bis 1023. Warum? Weil man
> mit 10 Bit von 0 bis 1023 zählen kann.
> Eine 9 Bit PWM hat einen Wertebereich von 0 bis 511. Warum? WEil man mit
> 9 Bit von 0 bis 511 zählen kann.
> Eine Custom PWM, bei der man die Obergrenzer mittels ICR Register
> festlegen kann, hat einen Wertebereich von 0 bis zu eben dieser
> Obergrenze.

Das habe ich verstanden! Ich habe bei mir nun Fast-PWM 8 Bit gesetzt! 
TopWert also 255!

>
>> Ausserdem ist mir auch nicht klar ob ich 2
>> oder 3 Timer brauche um die LED's gegengleich zu beleuchten :-(
>
> Du brauchst 2 PWM Stufen. Ob die jetzt mit 1 Timer oder mit 2 gemacht
> werden, hängt davon ab, was die Timer können. Wenn 1 Timer 2 Stück PWM
> erzeugen kann, dann reicht einer.

Gut! Mein Timer1 kann direkt auf OC1A und OC1B zugreifen.
Deiner Beschreibung nach würde dieser Timer also ausreichen.

Welcher Mode muss aber für meine Funktion gesetzt werden?

Also wie COM1A1 - COM1A0 setzen?

00 = Normale Operation = Quatsch!
01 = Toggle bei Compare Match = ?
10 = Löscht OC1A / OC1B bei compare match = ?!
11 = Setzt OC1A / OC1B bei compare match  = ?!


Wenn y nun im Wertebereich von 0..255 liegt müsste es doch OK sein.
-y kann natürlich unter 0 liegen. Wie krieg ich den Wert hin für die 
PWM?

Danke

von Karl H. (kbuchegg)


Lesenswert?

Seb astian schrieb:


> Gut! Mein Timer1 kann direkt auf OC1A und OC1B zugreifen.
> Deiner Beschreibung nach würde dieser Timer also ausreichen.

Yep

>
> Welcher Mode muss aber für meine Funktion gesetzt werden?
>
> Also wie COM1A1 - COM1A0 setzen?
>
> 00 = Normale Operation = Quatsch!
> 01 = Toggle bei Compare Match = ?
> 10 = Löscht OC1A / OC1B bei compare match = ?!

entweder diesen

> 11 = Setzt OC1A / OC1B bei compare match  = ?!

oder diesen, je nachdem wie deine LED angeschlossen sind.

Beim einen wird die LED heller, je höher der Wert ist. Bei der anderen 
wird sie mit steigendem Wert dunkler

> Wenn y nun im Wertebereich von 0..255 liegt müsste es doch OK sein.
> -y kann natürlich unter 0 liegen. Wie krieg ich den Wert hin für die
> PWM?

Du kannst ja zb die eine PWM auf MOdus 10 und die andere auf Modus 11 
stellen. Dann laufen sie schon per Hardware gegengleich bei gleichem y 
Wert.

Oder die eine setzt du auf y und die andere auf 255 - y

Aber es muss sichergestellt sein, dass y auch wirklich im Bereich 0 bis 
255 bleibt. Zur Not muss man sich dann eben eine kleine Umrechnung 
ausdenken, die das gewährleistet. AUch wenn die kleinen AVRs jetzt nicht 
gerade die Rechenkünstler sind, ein bischen addieren, subtrahieren, 
multiplizeren und wenn es sein muss auch dividieren können sie gut 
genug. Und mehr braucht man dann auch meistens nicht.

Und genau deswegen liebe ich kleine Testprogramme, mit denen man 
einzelne Aspekte eines Projektes unabhängig vom Rest austesten, 
probieren und damit Erfahrung sammeln kann.

von Seb a. (seppelg85)


Lesenswert?

> Du kannst ja zb die eine PWM auf MOdus 10 und die andere auf Modus 11
> stellen. Dann laufen sie schon per Hardware gegengleich bei gleichem y
> Wert.

Das ist mir vollkommen Schleierhaft.
Warum?
Ich habe zwei Register:
TCCR1A= COM1A1 COM1A0 COM1B1 COM1B0 FOC1A FOC1B WGM11 WGM10
TCCR1B= ICNC1  ICES1     -   WGM13  WGM12 CS12  CS11  CS10

Mit der Zusammensetzung der 4 WGM Bits setze ich den Modus.
Wie also kann ich zwei verschiedene machen?
>


> Oder die eine setzt du auf y und die andere auf 255 - y
>
> Aber es muss sichergestellt sein, dass y auch wirklich im Bereich 0 bis
> 255 bleibt. Zur Not muss man sich dann eben eine kleine Umrechnung
> ausdenken, die das gewährleistet. AUch wenn die kleinen AVRs jetzt nicht
> gerade die Rechenkünstler sind, ein bischen addieren, subtrahieren,
> multiplizeren und wenn es sein muss auch dividieren können sie gut
> genug. Und mehr braucht man dann auch meistens nicht.
>
> Und genau deswegen liebe ich kleine Testprogramme, mit denen man
> einzelne Aspekte eines Projektes unabhängig vom Rest austesten,
> probieren und damit Erfahrung sammeln kann.

Da werde ich wohl um eine Umrechnung nicht drum herum kommen...

Vielen Dank schonmal für die super Hilfe hier!!

Gute nacht

von Karl H. (kbuchegg)


Lesenswert?

Seb astian schrieb:
>> Du kannst ja zb die eine PWM auf MOdus 10 und die andere auf Modus 11
>> stellen. Dann laufen sie schon per Hardware gegengleich bei gleichem y
>> Wert.
>
> Das ist mir vollkommen Schleierhaft.
> Warum?
> Ich habe zwei Register:
> TCCR1A= COM1A1 COM1A0 COM1B1 COM1B0 FOC1A FOC1B WGM11 WGM10
> TCCR1B= ICNC1  ICES1     -   WGM13  WGM12 CS12  CS11  CS10
>
> Mit der Zusammensetzung der 4 WGM Bits setze ich den Modus.
> Wie also kann ich zwei verschiedene machen?

Timer 1 kann 2 PWM Ausgänge versorgen. Den 'A' Ausgang und den 'B' 
Ausgang. Drum gibt es ein

   COM1A1 + COM1A0

und es gibt

   COM1B1 + COM1B0

Deshalb gibt es ein OCR1A und es gibt ein OCR1B, es gibt .... (jeweils 
ein 'A' Register und ein 'B' Register, einen Pin am µC der für den Timer 
1 ein A im Namen hat und einen der ein B im Namen hat)


Vielleicht doch mal das Datenblatt etwas genauer studieren?

von Seb a. (seppelg85)


Lesenswert?

Ergänzung zum vorigen Post.

Mit meinem 2 Timer OCR2 kann ich nur WGM20 und WGM21 setzen.
Daher also dort auch nicht die Möglichkeit Modus 10 oder 11 ein 
zustellen.

Hatte ich gerade vergessen zu erwähnen!

Gruß

von Seb a. (seppelg85)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Timer 1 kann 2 PWM Ausgänge versorgen. Den 'A' Ausgang und den 'B'
> Ausgang. Drum gibt es ein
>
>    COM1A1 + COM1A0
>
> und es gibt
>
>    COM1B1 + COM1B0
>
> Deshalb gibt es ein OCR1A und es gibt ein OCR1B, es gibt .... (jeweils
> ein 'A' Register und ein 'B' Register, einen Pin am µC der für den Timer
> 1 ein A im Namen hat und einen der ein B im Namen hat)
>
>
> Vielleicht doch mal das Datenblatt etwas genauer studieren?

Das verstehe ich! Den Modus 10 oder 11 setze ich aber durch die WGM Bits 
und nicht durch COM1A1 oder COM1B1.

Gruß

von Seb a. (seppelg85)


Lesenswert?

Guten Morgen

War anscheinend schon zu spät gestern. WIr haben völlig aneinander 
vorbei geredet..( oder ich an dir :-/)

Du meinst natürlich die Modis COM1A1 und COM1B1. Ich habe es verwechselt 
mit PWM Mode 10 ( ZEHN ) und 11 ( ELF )....Sorry

Werde gleich an einer seperaten PWM arbeiten und dann versuchen -y 
definitiv in einen korrekten Wertebereich zu bekommen.

Wenn das erledigt ist werde ich den pi regler part + PWM nochmals 
posten.

Danke und Gruß

von dunno.. (Gast)


Lesenswert?

na ihr habt ja gestern noch gut gerödelt..

wärs aber nicht sinnvoller, y wirklich sichergestellt auf 8 bit zu 
quetschen?

dann kannste dein gegengleich einfach mit 255-y hinbekommen.. das wär 
nämlich auch mein ansatz gewesen..

mfg

von Seb a. (seppelg85)


Lesenswert?

Morgen dunno.

Ja, zu erst dachte ich heute morgen ich könnte y einfach iint8_t 
definieren. Dann fiel mir aber ein das wir ja dann den Wertebereich der 
PWM wieder verlassen.
Als uint8_t gehts allerdings auch nicht wirklich, da y auch  negativ 
sein kann.

Das heisst, dass ich im Falle von e<0 y in eine positive Zahl umrechnen 
müsste, oder? Die richtige Idee hatte ich noch nicht.

von Seb a. (seppelg85)


Lesenswert?

So, morgen nochmal :-)


1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <stdlib.h>
4
5
int main(void)
6
{
7
8
DDRB |= (1 << PB1 );                    // PB1 als Ausgang für PWM
9
DDRB |= (1 << PB2 );                    // PB2 als Ausgang für PWM
10
11
DDRC  = 0b00111110;
12
PORTC = 0b00110001;
13
14
uint8_t gelb, rot;
15
16
ADMUX   = (1<<ADLAR);                    // Linksbündig                      
17
ADCSRA  = (1<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);        // Teilerfaktor 16
18
ADCSRA |= (1<<ADEN);                    // ADC Enable
19
20
TCCR1A = 0b10110001;                          
21
TCCR1B = 0b00001100;
22
23
while (1)
24
  {  
25
    ADCSRA |= (1<<ADSC);                                           
26
    while(ADCSRA & (1<<ADSC)) ;                   
27
    rot = ADCH;
28
29
    ADCSRA |= (1<<ADSC);                                 
30
    while(ADCSRA & (1<<ADSC)) ;                   
31
    gelb = ADCH;
32
    
33
    OCR1A = rot;
34
    OCR1B = gelb;
35
36
  }
37
38
return(0);
39
}

Das ist nun meine AD-Wandlung mit PWM völlig losgelöst vom Rest. Und? 
Sie funktioniert ;-)
Die LED's werden gegengleich geregelt.
So, wie Karl Heinz Buchegger es geschrieben hat, habe ich Mode 10 und 11 
verwendet.

Trotzdem bekomme ich es beim anderen Programm nicht hin. Es ist zum 
Mäuse melken.


Gruß

von Seb a. (seppelg85)


Lesenswert?

Übrigens sieht meine PI-Regelung nun folgendermaßen aus:
1
void pi_regler(float temp_sensor_value_var,float temperature_var)
2
{
3
4
5
PORTC &= 0b00110001;                    // turn off all leds
6
7
DDRB |= (1 << PB1 );                    // PB1 als Ausgang für PWM
8
DDRB |= (1 << PB2 );                    // PB3 als Ausgang für PWM
9
DDRB |= (1 << PB3 );                    // PB3 als Ausgang für PWM
10
11
12
TCCR1A = 0b10110001;                          //COM1A1 = 1 ; COM1A0 = 1; COM1B1=1;COM1B0 = 1
13
TCCR1B = 0b00001100;                           //WGM13=0 - WGM12=1 - Vorteiler=64
14
15
//ICR1   = 0x0040;
16
17
//TCCR2  = 0b01100100;
18
19
//TCCR2  = 0b00101001;                    // OCR2 für PWM einstellen    
20
//OCR2=0x0040;
21
22
float pwert=0, iwert =0;                //I-Anteil, P A-Anteil  
23
float e=0;
24
float y;
25
float ki= 1.5;                                       //Integrationsbeiwert(verstärkung der itegration)                                
26
float kp = 0.5;                                      //Proportionalanteil 
27
float ta = 0.01;                                     //Abtastzeit 10ms
28
static float esum=0;
29
30
31
e = temperature_var - temp_sensor_value_var;                 //aktuelle Regelabweichung bestimmen
32
33
34
if (e>50)                                     //e Begrenzen auf +50°
35
  {
36
  e=50;
37
  }
38
if (e<-50)                                          //e begrenzen auf -50°
39
    {
40
    e=-50;
41
    }
42
43
44
pwert=(kp * e);                                //P-Anteil ausrechnen
45
iwert=(ki * ta * esum);                              //I-Anteil ausrechen
46
y=pwert+iwert;                                //Stellgröße ausrechnen
47
48
if (y>0)                              //Integration nur in diesen bereich ausrechen
49
{                                          //Wenn kein abweichnung da ist Inegration Einfrieren
50
esum=esum+e;                                        //Integration I anteil
51
}
52
else if (y<0)                                 //Wenn stellgröße negativ ist PRÜFEEENNNN!!!!!!!!!!!!!!
53
  {
54
esum=esum-e;
55
  }
56
else
57
{
58
esum=0;
59
}
60
61
if (e>0)                                            //wenn e größer 0 ist muss die heizung angehen
62
      {
63
      
64
      OCR1A = y;                                    //vergleichwert für compare match y
65
      //OCR2   = 0;                                    //wenn heizung an soll der lütfter aus sein
66
      OCR1B = 0;
67
      
68
      }
69
if (e<0)                                            //wenn e kleiner 0 ist muss die lüftung angehen
70
        {
71
                          
72
        OCR1A = 0;
73
        //OCR2   = -y;                           //vergleichwert für compare match y
74
        OCR1B =-y;
75
        
76
        }
77
}

Ich hoffe ich habe eure Anmerkungen nun soweit richtig geändert.
Verglichen mit der "obigen eigenen" PWM, kann mir jemand Hilfestellung 
leisten mit dieser PWM im Regelprogramm?

Danke und Gruß

von dunno.. (Gast)


Lesenswert?

Seb astian schrieb:

1
if (e<0){                  //wenn e kleiner 0 ist muss die lüftung angehen
2
    
3
    OCR1A = 0;
4
    //OCR2   = -y;                   //vergleichwert für compare match y
5
    OCR1B =-y;    
6
}

das kann doch niemals was werden... bitte schau dir an, worin sich eine 
vorzeichenbehaftete, und eine unsigned zahl unterscheiden, in der binär- 
darstellung.

die OCR register erwarten unsigned werte!!

wenn deine pwms wirklich so eingestellt sind wie im standalone beispiel, 
braucht y auch garnicht negativ zu sein..?

übrigens, zu deinem standalone beispiel.. du hast doch nur 1 adc kanal, 
den du liest..? dann sollte das hier reichen:
1
unsigned char value;
2
while (1){  
3
4
    ADCSRA |= (1<<ADSC);                                           
5
    while(ADCSRA & (1<<ADSC)) ;                   
6
    value = ADCH;
7
    
8
    OCR1A = value;
9
    OCR1B = value;
10
}

und bitte sei so nett und gewöhn dir ne einrückung an. macht alles 
lesbarer.

mfg

von Karl H. (kbuchegg)


Lesenswert?

Seb astian schrieb:
> Morgen dunno.
>
> Ja, zu erst dachte ich heute morgen ich könnte y einfach iint8_t
> definieren. Dann fiel mir aber ein das wir ja dann den Wertebereich der
> PWM wieder verlassen.
> Als uint8_t gehts allerdings auch nicht wirklich, da y auch  negativ
> sein kann.


y gleich 0 bedeutet bei dir, dass weder die Heizung noch der Lüfter 
eingeschaltet ist. Richtig?


Na dann zähl zu y einfach 128 dazu. dann hast du einen Wert, der genau 
in der Mitte des LED-PWM Bereichs liegt und bei dem beide LED gleich 
hell leuchten.

Wird y negativ, sagen wir mal -64, dann hast du nach der Addition von 
128 einen Wert von +64 für die eine LED und (255-64 = 191) für die 
andere LED. Die eine wird also dunkel sein und die andere hell.
Ist dein y auf der anderen Seite gleich +64, dann hast du nach der 
Addition von 64 fpr die eine LED einen Wert von 191 und für die andere 
einen Wert von (255-191 = 64). Ergo wird diesmal die eine LED die helle 
sein und die andere Led die dunklere.

Natürlich mit fliessenden Übergängen dazwischen, je nach Wert von y.

Alles was du noch tun musst, ist dafür zu sorgen, dass dein original y 
Wert den Bereich -128 bis +128 nicht verlassen kann.


Manchmal muss man sich eben selber ein bischen die Mathematik ausdenken, 
die man benutzen möchte. Meistens reicht ein bischen Addieren, 
Subtrahieren und das was man in der Grundschule gelernt hat.

von Seb a. (seppelg85)


Lesenswert?

Nabende zusammen

Da war irgendwie ziemlich der Wurm drin. Ich bin die Funktion pi_regler 
nochmal komplett durchgegangen. Schrittweises debuggen zeigt gute 
Ergebnisse.

So sieht das ganze nun aus:
1
void pi_regler(float temp_sensor_value_var,float temperature_var)
2
{
3
4
5
PORTC &= 0b00110001;                    // turn off all leds
6
7
DDRB |= (1 << PB1 );                    // PB1 als Ausgang für PWM
8
DDRB |= (1 << PB2 );                    // PB3 als Ausgang für PWM
9
DDRB |= (1 << PB3 );                    // PB3 als Ausgang für PWM
10
11
12
TCCR1A = 0b10100001;                          //COM1A1 = 1 ; COM1A0 = 1; COM1B1=1;COM1B0 = 1
13
TCCR1B = 0b00001100;                           //WGM13=0 - WGM12=1 - Vorteiler=64
14
15
16
float e=0;
17
float y;
18
float ki= 1.5;                                       //Integrationsbeiwert(verstärkung der itegration)                                
19
float kp = 0.5;                                      //Proportionalanteil 
20
float ta = 0.01;                                     //Abtastzeit 10ms
21
static float esum=0;
22
23
24
e = temperature_var - temp_sensor_value_var;                 //aktuelle Regelabweichung bestimmen
25
26
esum=esum+e;
27
28
if (esum < -400) 
29
{
30
  esum = -400;
31
}               
32
if (esum > 400) 
33
{
34
  esum = 400;
35
}
36
37
y=(kp*e + ki*ta*esum);                                //P-Anteil ausrechnen                            
38
39
if (y>0)                                            //wenn y größer 0 ist muss die heizung angehen
40
  {
41
  if (y>255)
42
    {
43
    y=255;
44
    }
45
46
  OCR1A = y;                                                                            
47
  OCR1B = 0;
48
    
49
  }
50
if (y<0)                                            //wenn y kleiner 0 ist muss die lüftung angehen
51
  {
52
  y = -y;
53
  if (y>255)
54
    {
55
    y=255;
56
    }
57
                                                
58
  OCR1A = 0;             
59
  OCR1B = y;
60
        
61
  }
62
if (y==0)
63
  {
64
  OCR1A = 0;
65
  OCR1B = 0;
66
  }
67
}

Das Problemchen das ich nun habe:
Wenn Soll wert beispielsweise 20° ist, der IST war aber maximum (255) 
wegen 8-Bit, habe ich eine Ausgangsspannung von ca. 2,5 Volt. Wenn ich 
nun mit dem Soll-Wert in den negativen Bereich gehe wird der Unterschied 
natürlich größer und damit auch die Spannung. Ich brauche aber keinen 
Negativen Soll-Wert Bereich. Was muss ich nun einstellen, damit mein µC 
weiss, dass wenn Soll=0 und Ist=255 die PWM auf 100% stehen muss?

Die Begrenzung habe ich nicht verstanden bzw. habe auch keine Idee wie 
ich diese dann im Coding einbauen soll.

Über Hilfe wäre ich sehr denkbar.. (auch wenn ich schon viel Hilfe 
bekommen habe ;-) Danke dafür...)

Gruß

von Karl H. (kbuchegg)


Lesenswert?

Seb astian schrieb:

> Wenn Soll wert beispielsweise 20° ist, der IST war aber maximum (255)
> wegen 8-Bit, habe ich eine Ausgangsspannung von ca. 2,5 Volt. Wenn ich
> nun mit dem Soll-Wert in den negativen Bereich gehe wird der Unterschied
> natürlich größer und damit auch die Spannung. Ich brauche aber keinen
> Negativen Soll-Wert Bereich. Was muss ich nun einstellen, damit mein µC
> weiss, dass wenn Soll=0 und Ist=255 die PWM auf 100% stehen muss?

Wie würdest du es denn mit der Hand rechnen?
Man kann kein Programm für ein Problem schreiben, das man nicht 
zumindest im Prinzip auch mit der Hand und Papier und Bleistift lösen 
kann.

Also setz dich hin, schreib dir Zahlenwerte auf von denen du dir 
versprichst, dass sie dir Einsicht ins Problem geben, überlege was 
deiner Meinung nach bei welchen Soll- Ist-Werte für ein Ergebnis 
rauskommen müsste und dann such nach mathematischen Zusammenhängen. Die 
sind meistens ganz einfache Zusammenhänge.

> Die Begrenzung habe ich nicht verstanden bzw. habe auch keine Idee wie
> ich diese dann im Coding einbauen soll.

Du kennst ein if?

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.