Huhu, ich versuche gerade für ein Arduino-Projekt eine Software-PWM mit
dem Timer2 des AtMega238 zu programmieren. Ich bin Anfänger, daher habe
ich mir die Registerkonfiguration so aus dem Internet gesucht (mit
Datenblatt weitesgehend nachvollzogen) und nur die paar Zeilen drum rum
geschrieben. Wenn ich die Eingabe über ein Poti am Analogport weglasse
und den PWM-Wert einfach nur in Zeile 3 vorgebe, dann klappt alles super
(bei pwm = 0 ist die LED aus, bei pwm=255 leuchtet sie am hellsten).
Mein Problem liegt nun darin, dass ich bei Heilligkeitverstellung über
ein angeschlossenes Poti (zwischen 0 und 5V, Schleifer am Analogeingang)
einen sonderbaren Effekt habe: Ich kann die Helligkeit zwar verstellen,
regel ich sie aber herunter und beende die Drehung, dann dimmt die LED
wieder sichbar auf. Ich bekomme sie also nicht ganz auf Null.
Also hab ich versucht, mir den aktuellen pwm-Wert über den seriellen
Monitor ausgeben zu lassen, um der Sache auf den Grund zu gehen. Füge
ich aber die letzte auskommentierte Zeile in den Code ein, dann arbeitet
das Programm nicht mehr... Ich habe keine Ausgabe im seriellen Monitor
und die Helligkeit der LED lässt sich nicht verstellen...
Wenn ich dagegen das Beispielprogramm "Basics - Read Analog Voltage"
öffne und aufspiele, dann kann ich mir über den seriellen Monitor schön
eine Spannung zwischen 0 und 5V anzeigen lassen, inklusive der beiden
Extremwerte.
Bevor jemand auf die Idee kommt, ich könnte ja einfach die Hardware-PWM
verwenden: Nein, leider nicht. Das ist eine Aufgabe für die Schule und
da benötige ich 14 über PWM dimmbare Ausgänge^^
1
intled=11;
2
bytezaehler=0;
3
intpwm=100;
4
5
6
voidsetup()
7
{
8
pinMode(led,OUTPUT);
9
Serial.begin(9600);
10
11
cli();//stop interrupts
12
13
TCCR2A=0;// set entire TCCR2A register to 0
14
TCCR2B=0;// same for TCCR2B
15
TCNT2=0;//initialize counter value to 0
16
// set compare match register for 100khz increments
Wenn du es mit dem Arduino-Framework erstellst, ist es keine gute Idee,
die Timer-Register manuell zu anzupassen. Aausser du weisst ganz genau
was du machst und welche du verwenden darfst, ohne dass sie mit den
Arudino-Funktionen kollidieren.
Da verwendest du besser eine der zahlreichen Librarys, z.B.:
http://code.google.com/p/rogue-code/wiki/SoftPWMLibraryDocumentation
Oder du machst alles selber, und ohne das Arduino-Framework. Dann siehst
du hier ein gutes Beispiel:
http://www.mikrocontroller.net/articles/Soft-PWM
EGSler schrieb:> int pwm = 100;
Sollte volatile sein weil ein Zugriff innerhalb und ausserhalb eines
Interrupts erfolgt.
EGSler schrieb:> Füge> ich aber die letzte auskommentierte Zeile in den Code ein, dann arbeitet> das Programm nicht mehr
Wahrscheinlich weil du deine Zahl nicht in einen String umwandelst und
diesen dann verschickst. Oder macht das die Arduino-Library automatisch
für dich?
Marcel schrieb:> Oder macht das die Arduino-Library automatisch> für dich?
Ja macht sie. Aber der Code wird so leider extrem unverständlich, wenn
man sich mit der Arduino Lib nicht auskennt.
Macht pwm = analogRead(A5/4); denn das richtige, was ist A5? Die
Funktion erwartet laut Doku die Pinnummer des Analogeinganges.
Vielleicht liest du einfach nicht den richtigen Pin ein bzw übergibst
ein ungültiges Argument.
Gerhard W. schrieb:> Marcel schrieb:>> Oder macht das die Arduino-Library automatisch>> für dich?>> Ja macht sie.
Aber sie liest sicher nicht vom Pin, dessen Nummer sich ergibt, indem
man die Pinnummer A5 durch 4 dividiert.
Gemeint war wohl eher, dass das Ergebnis vom analogRead durch 4
dividiert werden soll.
Karl Heinz schrieb:> Gemeint war wohl eher, dass das Ergebnis vom analogRead durch 4> dividiert werden soll. pwm = analogRead(A5) / 4;
Ich danke euch für die Antworten, Karl Heinz tatsächlich Recht. Was ein
dummer Fehler, natürlich möchte ich nicht den Pin A5/4 einlesen, sondern
den Pin A5 und diesen Wert dann durch vier teilen (um die Werte des
10bit ADC auf 8bit zu reduzieren). Mit der Division außerhalb der
Klammer klappt dann auch allles ;)
Allerdings erklärt das noch nicht, aus welchem Grund der serielle
Monitor in dem Programm zum Absturz führt. Den brauch ich jetzt zwar
grad nicht mehr, da der Fehler gefunden wurde, aber es irritiert mich ;/
EGSler schrieb:> Allerdings erklärt das noch nicht, aus welchem Grund der serielle> Monitor in dem Programm zum Absturz führt. Den brauch ich jetzt zwar> grad nicht mehr, da der Fehler gefunden wurde, aber es irritiert mich ;/
Ist das ein e Sodtware-Serielle?
Wenn ja, dann überprüf mal, ob die nicht den Timer 2 benötigt.
Ah, ich habs. Am Timer2 lag es nicht, aber Serial.println brauchte
zuviel Rechenzeit und die Interrupts kamen zu häufig. Mit niedriger
Interruptfrequenz läufts sauber.
Volatile möchte ich eigentlich nicht verwenden, es ist mir nicht so
wichtig, dass die Werte nun hoch aktuell sind, es läuft ohne volatile
sauber und ich spare mir die Zeit, in der der µC die Daten zwischen Ram
und Flash hin und herschiebt.
Ein weiteres Problem durch die häufigen Interrupts kam mit allen 14
Kanälen parallel noch dazu: digitalWrite brauchte viel zu lange, um den
Pin zu setzen. Ich habs jetzt durch eine Veroderung wie beim setzen der
Register gelöst, so läufts wieder flüssig.
EGSler schrieb:> Volatile möchte ich eigentlich nicht verwenden, es ist mir nicht so> wichtig, dass die Werte nun hoch aktuell sind, es läuft ohne volatile> sauber und ich spare mir die Zeit, in der der µC die Daten zwischen Ram> und Flash hin und herschiebt.
Na ja, wenn es sauber ohne volatile läuft, dann hast du die Optimierung
nicht eingeschaltet. Kann man machen, aber dann darfst du dich über zu
lange Laufzeiten auch nicht beschweren.
Es geht da auch nicht um "nicht ganz aktuell". Wenn du die Optimierung
einschaltest, wird es ohne volatile überhaupt nicht mehr funktionieren.
Also mach die Variablen volatile, und schalte die Optimierung ein.
Oliver
Oliver schrieb:> Na ja, wenn es sauber ohne volatile läuft, dann hast du die Optimierung> nicht eingeschaltet. Kann man machen, aber dann darfst du dich über zu> lange Laufzeiten auch nicht beschweren.
Ihm kommt das Arduino Modell zu gute, wonach der Schleifenteil der
Hauptschleife ausserhalb von loop() liegt.
Dem Compiler bleibt aber sowieso nichts anderes übrig, als alle
Nebeneffekte, wie zb gecachte Variablen mit Funktionsende zu beenden, so
dass der nächste Aufruf von loop() wieder bei 0 startet und Variablen
auf jeden Fall aus dem Speicher nachgeladen werden müssen.
Kann man machen. Solange man sich an das Arduino Modell hält. Sobald man
aber sich die Hauptschleife selber in loop() reinzieht, kommt es dann zu
den tollsten Effekten.
EGSler schrieb:> Volatile möchte ich eigentlich nicht verwenden, es ist mir nicht so> wichtig, dass die Werte nun hoch aktuell sind, es läuft ohne volatile> sauber und ich spare mir die Zeit, in der der µC die Daten zwischen Ram> und Flash hin und herschiebt.
Oh Herr, laß' Hirn wachsen. Biiitte...
EGSler schrieb:> Volatile möchte ich eigentlich nicht verwenden, es ist mir nicht so> wichtig, dass die Werte nun hoch aktuell sind, es läuft ohne volatile> sauber
Macht nichts. Du wirst ein paarmal auf die Schnauze fliegen weil du,
sobald dein Programm mehr als 10 Zeilen hat, irgendwelche total
unerklärlichen Fehler haben wirst die auftauchen oder verschwinden wenn
du ganz woanders etwas modifizierst. Selbst wenn du die Compileroptionen
änderst, oder einen anderen Compiler benutzt. Dann wirst du volatile auf
einmal sehr gern benutzen.