Hallo in die Runde.
Im Anhang findet sich das gewünschte Ausgangssignal (Schema schnell
hingeschmiert mit der Hand) einer H-Brücke, dass mit dem Atmega8A über
entsprechende Halbbrückentreiber erzeugt werden soll.(50Hz Sinus)
Ich benutze das myAVR board MK2 und AVR Studio 6.1.
Die Taktfrequenz wird über ein externes Quarz mit 3,6864Mhz beziffert.
Ich hab jetzt mal einen C-Code generiert der den Timer1 und Fast Pwm
Mode nutzt, um an Port B1 und B2 über 2 LEDs die beiden Signale
auszugeben.
Ich habe jetzt auf ziemlich umständliche Art probiert meine beiden
Ausgänge über Interrupts und diverse Zähler nacheinander auszugeben,
aber irgendwie klappt das nicht so recht.
Ich werde jetzt einfach mal den Code nachfolgend reinkopieren.
Vielleicht kann mir ja einer von euch weiterhelfen.
Ah ok hab grad nachgelesen, dass Variablen in ISRen als volatile
deklariert werden müssen danke.
Das Blinken der LEDs sieht jetzt annähernd abwechselnd aus. Aber vom
gewünschten Ausgangssignal bin ich wohl noch kilometer weit entfernt
oder?
@ Peter A. (elkopeter)
> WP_20130910_001.jpg> 1 MB, 25 Downloads
Naja, das könnte man auch ein wenig kleiner hinkriegen ,zumal es
unscharf ist.
>Ich hab jetzt mal einen C-Code generiert der den Timer1 und Fast Pwm>Mode nutzt, um an Port B1 und B2 über 2 LEDs die beiden Signale>auszugeben.>Ich habe jetzt auf ziemlich umständliche Art probiert meine beiden>Ausgänge über Interrupts und diverse Zähler nacheinander auszugeben,
In der Tat.
>aber irgendwie klappt das nicht so recht.
Vieleicht alles mal einfach versuchen?
Wie funktioniert sowas denn normalerweise? Die Samples/PWM-Werte werden
in einem festen Zeitraster ausgegeben, je nach Anwendung ist das
Zeitraster sogar ein ganzzahliges Vielfaches der PWM-Periodendauer.
Man braucht also nur einfach einen Timer, indem bei jedem Durchlauf ein
neuer Wert aus einem Array in die PWM geschrieben wird und der Index auf
das Array hochgezählt wird.
Ich hab einfach mal den Overflow-Interrupt der PWM genutzt, hier erfolgt
also der Update nach jedem PWM-Durchlauf. Will man das langsamer haben,
muss man dort noch einen Zähler in Software reinbauen, und nur bei jedem
Nten Durchlauf einen Update machen.
Danke für die Antwort. Allerdings war der Zweck meines umständlichen
Codes die beiden Ausgänge nacheinander zu schalten und der Duty-Cycle
sollte von 0% bis x% und wieder zurück auf 0% Prozent während einer
Halbwelle laufen (für nur einen Ausgang).
Mir fällt gerade auf, dass meine Arrayauswahl mit array[1] beginnt, dass
muss natürlich array[0] sein für die erste Position (verwechselt mit
Matlab).
So wie´s in deinem Code aussieht schalten in der ISR beide Comparewerte
nach 20 maligem Schleifendurchlauf für beide Kanäle um. Beide Kanäle
werden also parallel gleichzeitig ausgegeben.
@ Peter A. (elkopeter)
>Danke für die Antwort. Allerdings war der Zweck meines umständlichen>Codes die beiden Ausgänge nacheinander zu schalten und der Duty-Cycle>sollte von 0% bis x% und wieder zurück auf 0% Prozent während einer>Halbwelle laufen (für nur einen Ausgang).
Auch das ist kein Problem, das kann man auch in die ISR packen.
>nach 20 maligem Schleifendurchlauf für beide Kanäle um. Beide Kanäle>werden also parallel gleichzeitig ausgegeben.
Niemand hintert dich, mit ein BISSCHEN Logik die Indizes der beiden
Kanäle verschieden laufen zu lassen. Das ist eine Öbung för den
Schööööööler. ;-)
Der faule Schöler wird sich hierzu was überlegen.
Nochmal zu den Arraywerten eine Frage:
Nehm ich jetzt meine Taktfrequenz 3,6864 Mhz und eine Timerauflösung von
9Bit, dann hab ich eine PWM Frequenz von ~7,2 kHz. (zumindest bei fast
pwm)
Wenn ich mir jetzt einen 50Hz Sinus erzeugen will und meine beiden
Transistorpaare jeweils 10ms lang pulsen sollen, dann Teile ich
sozusagen
meine 10ms/(1/7,2kHz) und erhalte 72. Ich kann also 72 mal meine
Comparewerte pro Halbwelle ändern. D.h. also 72 Comparewerte für das
Array.
Ist meine Überlegung korrekt oder trampele ich da wieder fernab jeder
Logik?
Ok also soweit sieht das LED Blinken ganz gut aus.
Ich hab jetzt mal alles in die ISR gepackt.
Allerdings für die Weiterschaltung der Comparewerte muss ich mir noch
etwas eine elgantere Lösung einfallen lassen. Für Vorschläge/Kritik
stehe ich gerne bereit.
#define F_CPU 3686400L // Externes
Quarz -> 3,6864 MHz
#include <avr/io.h> // Einbindung
der Bibliotheken
#include <avr/interrupt.h>
// 50Hz
Sinus-Ausgangssignal (Grundschwingung)
// -> T/2 = 10ms
uint16_t array [36]; // 9-Bit
Timer1-Auflösung -> f_PWM = 7,2 kHz
// 10ms/(1/7,2kHz)= 72
-> 72 Änderungen
// des Comparewertes je
Halbwelle
volatile uint8_t n1 = 0; //
Comparewert wird hoch- und runergezählt
volatile uint8_t n2 = 0; // -> 36
Arraywerte (512/36 = 14,2 ->14)
volatile uint8_t x = 0; // ->
Duty_max = 490/512 = 95,7%
void InitPWM() //
Initialisierung der PWM-Modi/Prescaler
{
TCCR1A |= (1<<WGM12) | (1<<WGM11) | (1<<COM1A1) | (0<<COM1A0)
|(1<<COM1B1) | (0<<COM1B0); // Aktivieren des Fast-PMW Modus des Timer1
9-Bit-Breite(512).
TCCR1B |= (1<<CS10); // Abschalten
der Ausgänge beim Erreichen des Compare-
DDRB |= (1<<PORTB1) | (1<<PORTB2); //
Wertes. Prescaler = 1. PortB1 u. PortB2 als Ausgänge
// festlegen.
}
int main()
{
InitPWM();
for(uint8_t i=0; i<36; i++) //
Schleife füllt array;
{
array[i] = array[i-1]+14;
}
TIMSK |= (1<<TOIE1); //
Freischalten des OverflowInterrupts
// für beide Compare-Register
sei(); // globale
Interruptfreigabe
for(;;)
{
}
return 0;
}
ISR(TIMER1_OVF_vect) // ISR für
Overflowinterrupt
{
//static uint16_t cnt; // cnt
verlangsamt die Comparewertumschaltung
OCR1A = array[n1]; //
Comparewert1 wird überschrieben
OCR1B = array[n2]; //
Comparewert2 wird überschrieben
// x als Zählvariable für die Einteilung in T/4
//cnt++;
//if(cnt==19) // Vorteiler für
die Comparewert Weiterschaltung
// {
x++;
// cnt=0;
if(x<=35) // Hochzählen des
Comparewertes für Q1/Q4
{
n2 = 0;
n1++;
}
if((x>35)&&(x<=71)) //
Runterzählen des Comparewertes für Q1/Q4
{
n2=0;
n1--;
}
if((x>71)&&(x<=107)) // Hochzählen
des Comparewertes für Q2/Q3
{
n1=0;
n2++;
}
if((x>107)&&(x<=143)) //
Runterzählen des Comparewertes für Q2/Q3
{
n1=0;
n2--;
}
if(x==144) // Rücksetzen von
x nach dem letzten Comparewert
{
x=0;
}
//}
}
@ Peter A. (elkopeter)
>Ich hab jetzt mal alles in die ISR gepackt.>Allerdings für die Weiterschaltung der Comparewerte muss ich mir noch>etwas eine elgantere Lösung einfallen lassen. Für Vorschläge/Kritik>stehe ich gerne bereit.
Poste deine Quelltexte als Anhang, dann gibt es auch keine komischen
zeilenumbrüche und der Quelltext bleib lesbar. Oder nutze die Markierung
für Quelltext [ c ] [ /c ].
Soweit ist dein Programm OK. Ich würde aber im letzten if sowohl n1 als
auch n2 definiert setzen.
Das mit der C-Code Formatierung tut mir leid. Ich werds zukünftig
berücksichtigen.
Das mit n1 und n2 werde ich noch abändern.
Ich hab mir vorhin mal die beiden Ausgagnssignale aufm Oszi angeschaut
und bin positiv überrascht. Das sieht schon ganz gut aus bisher (mal
sehen wie´s dann mit H-Brückentreiber aussieht).
Was mir noch ein Rätsel ist:
Beim Ausgeben des Ausgang1 bzw. Ausgang2 Signals habe ich immer einen
kurzen peak im anderen Ausgang. Das ganze ist direkt in der Mitte.
z.B.
_|-----|_ Ausgang1
___/\____ Ausgang2
Ich werd mal morgen Bilder mit dem Oszi aufnehmen. Dann sieht man´s
besser.
An was kann das liegen?
Also ich hab jetzt meinen Code abgeändert und wiedermal versucht eine 50
Hz Sinusfrequenz(Grundschwingung) zu erzeugen.
Allerdings weiß ich nicht warum meine beiden Ausgangssignale ab und an
gleichzeitig Schalten (siehe Bild vom Oszi).
Was mir noch Kopfweh bereitet ist meine Berechnung der Schrittweite über
eine float Variable (Schritt) = 512/Anzahl der Arraywerte. Diese wird
dann ins Array geschrieben und mit den Timer1 Werten verglichen. Geht
das so ohne weiteres oder liegt hier der Fehler.
An was kann das liegen? Hier der Code:
@ Peter A. (elkopeter)
>>Was mir noch Kopfweh bereitet ist meine Berechnung der Schrittweite über>eine float Variable (Schritt) = 512/Anzahl der Arraywerte.
Mir auch. Macht kein Mensch so. Denn der Tabellenindex kann am Ende nur
ganzzahlig sein. Schau duir mal das Thema DDS an, dort sieht man,
wie es geht. Oder, wenn du nur eine feste Frequenz erzeugen willst,
nutze ein passende Tabelle mit passender Länge, die exakt EINMAL pro
Periode ausgegeben wird. Dann braucht man auch keine Mehrfachvergleiche,
sondern nur einen einfachen Tabellenzugriff.
512 ist ein integer.
arraysize(samples) liefert einen Integer
Damit wird diese Division als Integer-Division durchgeführt.
Und erst das Ergebnis davon wird dann auf float umgewandelt, damit es an
den float zugewiesen werden kann.
>
mit dieser Einstellung bedeutet ein OCR Wert von 0 NICHT, dass die
jeweilige PWM komplett abgeschaltet ist. Auch ein PWM Wert von 0 erzeugt
kleine Spikes. Denn der Ausgang wird beim Erreichen der 0 in TCNT auf
jeden Fall eingeschaltet. Selbst dann wenn ihn der nachfolgende Compare
Match sofort wieder abschaltet.
Wenn das stört (wie bei dir), dann musst du den inverting mode nehmen
und die OCR Werte entsprechend anpassen
Danke für die Antworten.
Hmm also bei DDS verstehe ich gerade noch Bahnhof.
Ich erzeuge mir einen Phasenakkumulator von 0-2^m-1 Werten.
In den oberen Bit Werten soll meine Adresse für meine Lookup Tabelle
stehen und in den unteren Bit Werten die Nachkommastellen.
Wie erzeuge ich mir jetzt meine Look-up Tabelle und wo wird diese
gespeichert? Muss meine Look-up Tabelle die gleiche Anzahl an Werten
haben , wie die Anzahl an Adressen des Phasenakkumulators?
Wie erzeuge ich mir meinen Phasenakkumulator und wie greift dieser auf
meine Look-up Tabelle zu?(Pointer?)
Mit der Schrittweite meines Phasenmodulators kann ich meine Frequenz
einstellen.
Peter A. schrieb:> Ich erzeuge mir einen Phasenakkumulator von 0-2^m-1 Werten.
gut
> In den oberen Bit Werten soll meine Adresse für meine Lookup Tabelle> stehen und in den unteren Bit Werten die Nachkommastellen.
Auch gut
> Wie erzeuge ich mir jetzt meine Look-up Tabelle und wo wird diese> gespeichert?
Genauso wie jetzt auch
> Muss meine Look-up Tabelle die gleiche Anzahl an Werten> haben , wie die Anzahl an Adressen des Phasenakkumulators?
nur wie der Teil vom Phasenakkumulator, den du zur Adressierung benutzt.
> Wie erzeuge ich mir meinen Phasenakkumulator und wie greift dieser auf> meine Look-up Tabelle zu?(Pointer?)
Genau wie jetzt auch.
Dir scheint die Idee nicht klar zu sein.
Bringen wir das ganze mal aus dem Binärsystem ins Dezimalsystem.
Du hast eine Lookuptabelle mit 5 Einträgen.
Dazu hast du noch eine Variable (den Phasenakkumulator), der dir sagt,
welcher Wert als nächstes auszugeben ist.
uint8_t Werte[5];
uint8_t nextWert;
nextWert muss offenbar immer von 0 bis 4 durchzählen ...
1
Werte[0]
2
Werte[1]
3
Werte[2]
4
Werte[3]
5
Werte[4]
6
Werte[0]
7
Werte[1]
8
...
... den du möchtest ja mit einer bestimmten Frequenz die Werte an den
Ausgang legen und bei einer bestimmten Frequenz mag das eben bedeuten,
dass man im Takt einen Wert nach dem anderen an die Ausgänge legt.
soweit so gut. Jetzt möchtest du die Frequenz erhöhen. Dazu
'überspringst' du immer einen der Werte aus der Lookup Tabelle. nextWert
wird also nicht mehr um 1 erhöht, sondern um 2.
nextWert nimmt also die Werte an
1
0, 2, 4, 1, 3, 0, 2, 4
und dementsprechend werden auch die jeweiligen Werte aus der Lookup
Tabelle ausgegeben.
Tja. Das Problem ist nur: dadurch hast du die Frequenz verdoppelt! Um
eine kleinere Frequenzerhöhung zu erreichen, dürftest du nextWert nicht
um 2 erhöhen sondern nur um, sagen wir mal 1.001
Nur: das geht natürlich nicht bei einem uint8_t. Der ist ganzzahlig und
ist auch immer ganzzahlig.
Aber du kannst was anderes machen.
Du kannst sagen: nextWert soll bei mir nicht Werte von 0 bis 4 annehmen,
sondern er soll Werte von 0 bis 4000 annehmen. Zum addressieren in die
Lookup Tabelle benutzt ich dann eben nextWert nicht direkt, sondern ich
teile den Wert erst durch 1000. d.h. egal ob nextWert den tatsächlich
Wert 68 oder 920 hat, es wird dafür immer der Tabellenwert Werte[0]
ausgegeben. Sinngemäss auch für alle anderen Bereiche.
Aber: dadurch habe ich erreicht, dass ich nextWert nicht nur um 1 oder
um 2 (respektive um 1000 bzw. 2000) erhöhen kann, sondern zb auch um
1.5, indem ich 1500 zu nextWert dazuzähle.
Bei 1500 nimmt nextWert dann nacheinander die Werte an
0, 1500, 3000, 4500, 1000, 2500, 4000, 500, 2000, 3500, ...
und dementsprechend werden dann ausgegeben
1
Werte[0] // weil 0 / 1000
2
Werte[1] // weil 1500 / 1000
3
Werte[3] // weil 3000 / 1000
4
Werte[4] // weil 4500 / 1000
5
Werte[1] // weil 1000 / 1000
6
Werte[2] // weil 2500 / 1000
7
Werte[4] // weil 4000 / 1000
8
Werte[0] // weil 500 / 1000
9
Werte[2] // weil 2000 / 1000
10
Werte[3] // weil 3000 / 1000
11
...
was du damit erreichst hast ist, dass du in guter Näherung die
Lookuptabelle mit der 1.5 fachen 'Geschwindigkeit' der Aufruffrequenz
ausgibst.
Nur das du das ganze natürlich nicht mit einem Vielfachen von 10 machst,
sondern einem Vielfachen von 2. Denn dadurch wird die Division für den
µC wieder trivial.
Aber an der Größe der Lookup Tabelle hat sich deswegen nichts geändert.
Und auch nicht, wie sie benutzt wird. Du hast dir im Grunde mit der
Konvention, alle Zahlen mal 1000 zu nehmen, 3 Stück künstlicher
Kommastellen eingeführt, die du brauchst um den nächsten jeweils
auszugebenden Werte 'mit einem Index zu berechnen, der auch Kommastellen
hat'. Um dann tatsächlich aufs Array zuzugreifen wirst du dann ganz
einfach die 'Kommastellen' wieder los, indem du geeignet dividierst.
Erstmal danke für die ausführliche Erklärung.
Ich hoffe ich habs jetzt richtig verstanden.
Ich habe meine feste Wertetabelle mit z.B. 36 Werten. Also laufen meine
Indizes von 0..35.
Meine Indizes müssen also jetzt auf eine Zahl mit der Basis 2
umgeschlüsselt werden.
D.h. ich nehme eine Schrittweite von 2^8.
Meine Indizes werden jeweils mit 2^5 multipliziert.
Im Schleifenlauf wird jetzt der Zähler um 2^8 erhöht.
Die Indizes erhält man dann über ein Schieberegister <<5.
Peter A. schrieb:> Erstmal danke für die ausführliche Erklärung.> Ich hoffe ich habs jetzt richtig verstanden.>> Ich habe meine feste Wertetabelle mit z.B. 36 Werten. Also laufen meine> Indizes von 0..35.> Meine Indizes müssen also jetzt auf eine Zahl mit der Basis 2> umgeschlüsselt werden.> D.h. ich nehme eine Schrittweite von 2^8.> Meine Indizes werden jeweils mit 2^5 multipliziert.> Im Schleifenlauf wird jetzt der Zähler um 2^8 erhöht.> Die Indizes erhält man dann über ein Schieberegister <<5.
Ich würde mir die Sache einfach machen, (da die Tabellenindizes nur von
0 bis 35 laufen) und ganz einfach alles mal 256 nehmen :-)
Dann hast du einen 16 Bit Index, von dem das obere Byte (High_Byte)
direkt der Index ist, mit dem du ins Array gehst. Dann braucht auch
nichts geschoben werden und eine 16 Bit Addition stellt einen AVR noch
nicht vor massive Probleme in der Laufzeit.
Karl Heinz Buchegger schrieb:> Ich würde mir die Sache einfach machen, (da die Tabellenindizes nur von> 0 bis 35 laufen) und ganz einfach alles mal 256 nehmen :-)>> Dann hast du einen 16 Bit Index, von dem das obere Byte (High_Byte)> direkt der Index ist, mit dem du ins Array gehst. Dann braucht auch> nichts geschoben werden und eine 16 Bit Addition stellt einen AVR noch> nicht vor massive Probleme in der Laufzeit.
Ah ok klasse Idee.
Jetzt muss ich doch ganz blöd fragen, wie ich auf das Highbyte der
16-Bit Integer Werte zugreifen kann ohne das zu schieben >>8?
Zu zwei anderen Fragen:
Ab welcher Lookup Tabellenauflösung ist mein Sinussignal halbwegs
verwendbar? Ich möchte Pwm-Frequenzen von 20-40kHz erzeugen.
Du hast vorhin erwähnt, dass mein PWM-Modus(Ausschalten der Ausgänge bei
erreichen der Comparewerte) mir die Probleme mit den peaks im anderen
Ausgang bescheren. Einfach den Modus tooglen und den niedrigsten
Comparewert anpassen oder?
@ Peter A. (elkopeter)
>Jetzt muss ich doch ganz blöd fragen, wie ich auf das Highbyte der>16-Bit Integer Werte zugreifen kann ohne das zu schieben >>8?
Schieb einfach. Der GCC ist meist schlau genug zu erkennen, dass er
einfach direkt auf das high Byte zugreifen kann.
>Ab welcher Lookup Tabellenauflösung ist mein Sinussignal halbwegs>verwendbar? Ich möchte Pwm-Frequenzen von 20-40kHz erzeugen.
256 wurden schon mehrfach genannt, da wird wohl was dran sein.
Fetischisten nehmen das Doppelte oder Vierfache.
>Du hast vorhin erwähnt, dass mein PWM-Modus(Ausschalten der Ausgänge bei>erreichen der Comparewerte) mir die Probleme mit den peaks im anderen>Ausgang bescheren. Einfach den Modus tooglen und den niedrigsten>Comparewert anpassen oder?
Nimm den Phase correct Mode, dann hast du das Problem nicht.
Also ich hab mir heut den ganzen Tag den Kopf zerbrochen, aber irgendwie
scheitere ich an der Umsetzung der DDS. Ich hab das Ganze auf einen
PWM-Ausgang beschränkt aber es will partout nicht klappen.
Hier nochmal der code:
@ Peter A. (elkopeter)
>Also ich hab mir heut den ganzen Tag den Kopf zerbrochen, aber irgendwie>scheitere ich an der Umsetzung der DDS. Ich hab das Ganze auf einen>PWM-Ausgang beschränkt aber es will partout nicht klappen.
Was geht denn nicht. Der Code ist auf den ersten Blick OK.
> if(phaseaccu>=65536)> {> phaseaccu =0;> }
Das ist unsinnig und unnötig, ein Überlauf passiert allein. Kan man
weglassen.
> samples[i] = i*512.0/128;
Was soll das? Ein Fließkommaarechung bringt hier exakt NULL Vorteile,
nur viel Flash-Verbrauch.
samples[i] = i*4;
macht EXAKT das Gleiche.
Ich stell bei der Veränderung der Schrittweite keinen
Frequenzunterschied fest. Wenn ich den Ausgang an eine LED hänge, dann
bleibt diese dauerhaft an.
i als uint8_t ist IMMER kleiner als 256. Der maximale Wert, den i
annehmen kann ist 255. Bei der nächsten Erhöhung wird i dann 0 und ist
somit wieder kleiner als 256
D.h. das hier ist eine Endlosschleife.
PS: dir ist schon klar, dass dein Timer läuft, sobald er einen Vorteiler
hat?
D.h. nach Aufruf von InitPWM läuft der Timer bereits und generiert
frisch fröhlich eine PWM vor sich hin.
-> es ist immer gut, wenn man eine gewisse Reihenfolge im Programm
einhält. Dazu muss man sich klar machen, was von wem abhängt. Da der
Timer, bzw. die zu erzeugende PWM von den SampleWerten abhängt, wäre es
vielleicht nicht verkehrt die SampleWerte fertig zu haben, ehe man die
PWM einschaltet.
Hab folgendes geändert:
Gleitkommazahl berechnung geändert auf i*4, j*4
If-Anweisung in der ISR gelöscht.
Abbruch-Bedingung der for-Schleife zu i==255 geändert.
InitPWM vor die Dauerschleife der main-Funktion gesetzt.
Wenn ich jetzt eine Schrittweite von 2 definiere dimmt sich meine LED
ca. alle 5sek herab und schnellt dann wieder auf volle Helligkeit.
Ich schau mir das Ganze jetzt mal aufm Oszi an.
Danke an Herrn Brunner und Herrn Buchegger für ihre Geduld mit mir und
die tatkräftige Unterstützung bei meinen Problemen.
Peter A. schrieb:> Wenn ich jetzt eine Schrittweite von 2 definiere dimmt sich meine LED> ca. alle 5sek herab und schnellt dann wieder auf volle Helligkeit.> Ich schau mir das Ganze jetzt mal aufm Oszi an.
Ja, das deckt sich auch ungefähr mit meinen Berechnungen über die zu
erwartende Zykluszeit.
> alle 5sek herab und schnellt dann wieder auf volle Helligkeit.
Das könnte damit zusammenhängen:
> Abbruch-Bedingung der for-Schleife zu i==255 geändert.
Wenn da jetzt steht
1
for(i=128,j=128;i==256;i++,j--)
2
********
dann ist das klar. Denn dann wird die Schleife nie ausgeführt.
Peter A. schrieb im Beitrag #3324703:
> Hmm ok also hab´s gedebugged und die Schleife wird nich ausgeführt.> Hab die Bedingung auf i<=255geändert. Nur hab ich dann kein
Welche Werte kann i annehmen?
Was gilt für alle diese Wert in Bezug auf die Bedingung <=255 ?
Hinweis:
1
i < x
ist exakt dasselbe wie
1
i <= ( x - 1)
Die Bedingung
1
i < 7
ist für genau die gleichen Werte TRUE, für die auch gilt
Ah ok. Habs gedebugged und die Schleife wird übersprungen.
Ich hab dann die Bedingung wieder auf i<=255 geändert und eine
if-Anweisung mit i==255 -> break eingebaut.
Peter A. schrieb:> Ah ok. Habs gedebugged und die Schleife wird übersprungen.> Ich hab dann die Bedingung wieder auf i<=255 geändert und eine> if-Anweisung mit i==255 -> break eingebaut.
Oh Mann.
Du könntest zb so vorgehen
1
for(i=0;i<128;i++)// Schleife füllt 256 Werte von 0-512-0
2
{
3
samples[i]=i*4;
4
}
5
for(i=0,j=128;i<127;i++,j--)
6
{
7
samples[i+128]=j*4;
8
}
oder so
1
for(i=0;i<128;i++)// Schleife füllt 256 Werte von 0-512-0
2
{
3
samples[i]=i*4;
4
}
5
for(i=128,j=128;i!=0;i++,j--)// Hier wird der Overflow von i ausgenutzt, i wird 0 nachdem es bei 255 inkrementiert wird
Sorry ich bin manchmal völlig von der Rolle, was Programmierung angeht.
Die Variante mit i!=0 erscheint mir die beste. Danke für die unendliche
Geduld.
Falk Brunner schrieb:> Andere Leute hätten einfach die Variabeln von i und j als uint16> definiert . . .
Wäre natürlich auch eine simple Methode gewesen.
Zu einem anderen Thema:
So wie ich aktuell meine samples-Werte berechne geht bei samples[128]
etwas schief, da mein Timer ja nur bis Top=511 läuft.
Ich hab das jetzt mal folgendermaßen abgeändert:
1
2
for(i=0;i<128;i++)// Schleife füllt 256 Werte von 3-511-3
3
{
4
samples[i]=i*4+3;
5
}
6
for(i=128,j=128;i!=0;i++,j--)
7
{
8
samples[i]=j*4-1;
9
10
}
Ist das passabel oder schüttelt ihr da nur mit dem Kopf?
@Peter A. (elkopeter)
>So wie ich aktuell meine samples-Werte berechne geht bei samples[128]>etwas schief,
Was denn?
Nochmal. Mit Fast-PWM kann man beim AVR keine PWM mit alles Null und
alls HIGH erzeugen, es bleibt immer ein Kurzer Puls übrig. Wenn man den
weghaben will und bei PWM=0 das Pin dauerhaft auf Null sowie PWM=max das
Pin dauerhaft auf High haben will, muss man den Phase Correct PWM Modus
benutzen. OK, dann ist die PWM-Frequnez halbiert, aber damit muss man
halt leben. mit CTC und PWM kombiniert kriegt man das aber hin.
> da mein Timer ja nur bis Top=511 läuft.> Ich hab das jetzt mal folgendermaßen abgeändert:> for(i=0; i<128; i++) // Schleife >füllt 256
Werte von 3-511-3
> {> samples[i] = i*4+3;> }
Soweit OK.
> for(i=128,j=128; i!=0;i++,j--)> {> samples[i] = j*4-1;> }>Ist das passabel oder schüttelt ihr da nur mit dem Kopf?
Letzteres. Dein Index muss bis 255 gehen, dann ist Schluss, Jaja, der
alte Hackertrick mit dem Überlauf geht, ist aber sehr unsauberer
Programmierstil. Sowas bringt einem meist mehr Probleme als es löst.
Ausnahmen bestätigen die Regel.
Also nimm uint16_t Variablen und mach es solide.
Ok dann werde ich uint16_t verwenden und die Abbruchbedingung als i<256
setzen. Den Phase Correct Modus werde ich dann auch einstellen.
Ist das mit der Werteanpassung von 3-511-3 in Ordnung? D.h. ich kann
dann keinen Duty-Cycle von 0% einstellen (bsw. je nach COMA/COMB
Einstellungen 100% Duty-Cycle).
@ Peter A. (elkopeter)
>Ist das mit der Werteanpassung von 3-511-3 in Ordnung? D.h. ich kann>dann keinen Duty-Cycle von 0% einstellen (bsw. je nach COMA/COMB>Einstellungen 100% Duty-Cycle).
Menschenskinder, bist du so lernresistent? Gerade mit Phase Correct
PWM-Mode KANN man PROBLEMLOS 0-511 als PWM nutzen und deine Anpassung
mit 3-511-3 ist NICHT nötig!
Der Lernresistente meldet sich nochmal. So ich verwende den
Phase-Correct-PWM Modus sonst ist eig. alles beim Alten geblieben. Keine
Anpassung mehr. Ich zeig jetzt mal die Oszi Bilder. Schrittweite 256.
Ist die Signalausgabe so korrekt?
Oszi ist schön.
Aber eine LED ist besser zum debuggen.
Häng eine LED an, mach deine OCR Updates ganz langsam und sieh nach, ob
die LED auch tatsächlich komplett aus geht (ja, man sieht mit freiem
Auge ob eine PWM tatsächlich aus ist, oder ob da noch kurze Spikes sind.
Raum abdunkeln und bei den kleinen Leveln auf den Chip in der LED sehen.
Er muss ganz ausgehen. Nicht dunkel, nicht sehr dunkel, sondern komplett
aus)
Ansonsten: wie ist das Helligkeitsverhalten der LED. Gibt es Sprünge in
der Helligkeit in der falschen Richtung? Also: Wenn die LED eigentlich
heller werden sollte, wird sie zwischendurch mal eine Stufe dunkler? Und
umgekehrt: Wenn die Helligkeit auf dem abnehmenden Ast ist, wird sie
dann zwischendurch bei irgendeinem Schritt mal heller?
Bei den großen Helligkeiten kann es schwierig sein das festzustellen,
weil unser Auge da die UNterschiede nicht mehr gut auflösen kann. Aber
bei den kleinen Helligkeiten sieht man das sehr gut.
Sei ein bischen kreativer! Auch in den Methoden, wie du dein Programm
kontrollieren kannst! Ja, manchmal muss man auch dazu ein wenig um die
Ecke denken und experimentieren. Aber so ist das nun mal. Im Berufsleben
kannst du auch nicht wegen jedem 10-Zeiler zu deinen Kollegen laufen und
fragen ob das stimmt.
Karl Heinz Buchegger schrieb:> Oszi ist schön.> Aber eine LED ist besser zum debuggen.>> Häng eine LED an, mach deine OCR Updates ganz langsam und sieh nach, ob> die LED auch tatsächlich komplett aus geht (ja, man sieht mit freiem> Auge ob eine PWM tatsächlich aus ist, oder ob da noch kurze Spikes sind.> Raum abdunkeln und bei den kleinen Leveln auf den Chip in der LED sehen.> Er muss ganz ausgehen. Nicht dunkel, nicht sehr dunkel, sondern komplett> aus)> Sei ein bischen kreativer! Auch in den Methoden, wie du dein Programm> kontrollieren kannst! Ja, manchmal muss man auch dazu ein wenig um die> Ecke denken und experimentieren. Aber so ist das nun mal. Im Berufsleben> kannst du auch nicht wegen jedem 10-Zeiler zu deinen Kollegen laufen und> fragen ob das stimmt.
Ich werde mich in zukunft zurückhalten mit meiner Fragerei. Ich bin
einfach in Sachen C-Programmierung und Microcontroller eingerostet, da
ich damit zuletzt vor 2 Jahren etwas zu tun hatte. Aber nochmals ein
großes Lob an Herrn Buchegger und Herrn Brunner, die mir jetzt zum
Schluss am liebsten den Kopf abgerissen hätten.