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
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
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ß
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
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
floatAdwandlung()
2
{
3
floatresult;
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
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.
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
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
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ß
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
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
intmain(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
floattemperature=20.0;// temperature (SOLL)
26
floattemp_sensor_value;// temperature sensor value (IST)
27
unsignedtaster1State=0;
28
unsignedtaster2State=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
@ 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. ;)
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.. ;)
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?
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!!
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.
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.
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
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.
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!
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.
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.
> 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ß
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.
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
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.
> 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
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?
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ß
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ß
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ß
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
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.
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ß
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
elseif(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ß
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
unsignedcharvalue;
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
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.
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:
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ß
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?