Hallo Leute,
ich brauche wieeder mal wieder eure Hilfe. In meinem Programm
funktioniert alles einwandfrei, bis auf ein paar Kleinigkeiten.
Vermutlich sehe ich den Wald vor lauter Bäumen nicht.
In meinem Code habe ich die betroffenen Stellen markiert. Mein Programm
erstellt drei PWM-Signale. Außerdem beinhaltet der Code zwei Schleifen,
die jeweils eine Variable hoch zählen. Position eins und zwei markieren
die Stellen. Mit der Variable möchte ich ein Array abfragen und damit
das duty cycle in position 2 aktualisieren.
Probleme:
1. Die Variable tem zählt nur bis 64
2. Die zweite Schleife zählt gar nicht
Meine Tests:
Ich habe die if-Anweisungen in verschiedenen Schreibweisen ausprobiert.
Auch in verschachtelter Schreibweise und es hat dennoch nicht
funktioniert.
Getestet habe ich es mit einem Oszilloskop. Der Speicher vom Controller
ist auch nicht voll.
Ich wäre euch sehr dankbar für ein paar Tipps.
Viele Grüße,
Rachid
Der Anhang ist praktisch unlesbar. Probiers mal ohne Tabs, der einzige
Tab-Standard ist 8 (Unix), deiner wohl 2 oder so, und entsprechend
grauslich sieht es aus.
Warum .txt für .c? Um Andreas' Formatierer auszuhebeln?
Rachid E. schrieb:> 1. Die Variable tem zählt nur bis 64
Wieso "nur"?
Rachid E. schrieb:> Getestet habe ich es mit einem Oszilloskop.
Kanns Du kurz erklären, wie Du hast mit einem Oszi den Inhalt der
Variable tem gelesen hast?
Danke für eure Antwort. Ich bin jetzt nicht mehr im Labor. Ich werde die
Frage sobald wie möglich verständlicher stellen. Testen kann ich aber
leider erst morgen, da bis dahin das Labor geschlossen ist.
Und ehe du ein neues C-File postest, mach es mit Notepad auf, schau dir
die Formatierung an und korrigiere sie. So was wie da oben hat nur ganz
geringe Chance, dass irgendwer auch nur den Versuch machen wird da
durchzusteigen.
Karl Heinz Buchegger schrieb:> So was wie da oben hat nur ganz> geringe Chance, dass irgendwer auch nur den Versuch machen wird da> durchzusteigen.
Stimmt.
Eine Zeilenlänge von 1000 Zeichen können die wenigsten darstellen.
Gebräuchlich sind 80 .. 120 Zeichen.
Tabellen sollte man auf 10 oder 16 Werte je Zeile aufteilen.
Peter
Da fällt mir gerade ein, dass ich in diesem Thread
Beitrag "Re: Anfängerhilfe bei Input"
ein paar Tips gegeben haben (nur das allernotwendigste), die bei einer
vernünftigen Formatierung hilfreich sind.
Vergiss die Fragestellung und lies dir die 'Einführung' in Formatierung
durch. Das ist zwar nicht alles was es zu diesem Thema zu sagen gibt,
aber es ist schon mal ein erster brauchbarer Grundstock.
Danke für eure Komentare. Ich habe versucht, alles einzubeziehen. Ich
hoffe man kann jetzt was damit anfangen.
Noch kurz zum Programm:
Ich möchte mit dem Programm einen dreiphasigen Gleichstrommotor
ansteuern. Alles geht bis auf die zwei if-Anweisungen in der
while-Schleife.
if (tem>=60)
{
tem=0;
ii=ii+1;
}
if (ii>=20)
ii=0;
Um zu testen, habe ich die Variablen tem und ii und sin[ii] als
Vergleichswert für die duty cycle Einstellung genutzt. Dadurch müsste
sich das PWM-Signal ständig ändern. Mit der Variable tem geht es
einwandfrei. Doch mit ii und sin[ii] ändert sich gar nichts. Die
Änderungen habe ich am Oszilloskop dargestellt.
Ein weitere Sache die ich nicht verstehe ist, dass sobald ich eine Zahl
über 64 in der if-Anweisung schreibe, zählt die erste if-Anweisung auch
nicht.
Ich habe bereits int, long, double und float ausprobiert. Nichts hat
geholfen.
Ich verstehe zwar deine Fehlerbeschreibung nicht, sage aber trotzdem
auch was dazu:
1. C lernt man am besten nicht auf einem Controller und mit einer
Problemstellung, die man kaum überblickt, sondern besser auf einem PC
mit anfangs kleineren Aufgaben, die stückweise wachsen.
Das spart viel Frust.
Ein Debugger ist effizienter als ein Oszilloskop.
2. Ich stehe auch oft an einem Punkt, wo irgendwie nichts mehr
funktioniert und man nicht mehr weiß, warum.
Spätestens dann muß man sich eingestehen, daß man sich mit der
Komplexität übernommen hat (ja, das passiert jedem) und sein Problem
endlich aufteilen auf kleinere, lösbare Probleme.
Das wäre bei dir vielleicht:
- Ausgeben des PWM-Wertes
- Timer in den Griff bekommen
- AD-Werte einlesen
- PID-Regelung machen
- ...
Für jedes dieser Teilprobleme braucht man (erst für sich selbst,
und später ebenso für andere) eine klare Vorstellung, worum es geht,
was man zur Verfügung hat, was man möchte, und wie man dahin kommt.
Davon erledigt man eines nach dem anderen.
Die meisten Fehler tauchen in solchen kleinen, übersichtlichen
Programmen bereits auf und lassen sich dort erschlagen.
Die meisten solcher kleinen Probleme programmiert man auf dem PC,
wo man wesentlich besser debuggen kann und viel schneller die
Lösung hat.
Erst wenn diese Häppchen getestet sind und sicher funktionieren,
schraubt man daraus stückweise ein größeres Programm zusammen.
Nebenbei kommt man dann zu einem modularisierten Programm, in dem
nicht alles vermatscht ist (AVR-Register mitten in der
PID-Regelung?)
und dessen Teile man später auch wiederverwenden kann.
Wenn bei solchen Häppchen Probleme auftauchen, die man nicht
lösen kann, kann man sinnvollerweise andere um Hilfe fragen.
Ein Forum ist weniger hilfreich, wenn man als Nichtschwimmer in
einem Fluß badet, in dem sich Krokodile und Nilpferde tummeln,
Tausende Bakterien mutieren, von oben vollgekokste 12-Jährige
mit der AK-47 herumballern, kein Handy greifbar und das
Taschenmesser weg ist.
3. Wenn man in einem Forum Hilfe will, muß man den anderen eine
Chance geben, den Fehler nachvollziehen zu können.
Das heißt:
- den Fehler auf ein möglichst kleines, nachvollziehbares Beispiel
reduzieren
- klar beschreiben, wie es sich verhalten sollte
- klar beschreiben, was falsch läuft (schön, wenn du weißt, was
dir dein Oszilloskop zeigt; meines hat mit deinem Quelltext
keine Probleme!)
Dagegen bitte nicht:
- solange ein Programm sinnlos vollstopfen, bis man es nicht mehr
versteht (falls es jemals besser war)
- den ganzen unlesbaren Haufen in ein Forum schieben ohne
vernünftige Beschreibung
- "geht nicht"
- "helft mir"
Damit verschwendet man anderer Leute Zeit.
Was schert mich der ganze Regelkram und Timerzeugs, wenn es um
z.B. die Ausgabe eines Wertes geht?
4. Die Formatierung und Beschreibung ist schon deutlich besser
geworden, auch wenn es immer noch mühsam ist, einen Sinn im
Quelltext zu entdecken.
Wieso soll tem immer bis 60 gehen und dann bei 0 anfangen?
Dto. ii bis 20?
Gibt es keine aussagekräftigeren Namen als tem und ii?
5. Für Sachen wie "i = i + 1" gibt es in C gängige Abkürzungen ("i++").
Das macht ein Programm etwas übersichtlicher.
6. Wieso sollte man einen double-Wert aus sin[], der bis 600 geht,
an ein 8-Bit-Register zuweisen?
7. Das macht wenig Sinn:
1
duty=75,75;//ist der Wert für das duty cycle. Wird später mit dem PID-Regler geregelt.
Vielleicht meintest du eine Gleitkommazahl (75.75 mit einem Punkt).
Aber wieso gerade 75.75?
Und warum an eine ganzzahlige Variable eine Gleitkommazahl zuweisen?
8. Es ist sinnvoll, mit allen verfügbaren Compilerwarnungen
übersetzen zu lassen, und sich um die Warnungen auch zu kümmern.
Der Punkt 7 wäre dir dann schon selbst aufgefallen, damit müsstest
du nicht andere Leute belästigen.
9. Man sollte dringend Sachen auseinanderhalten, die nicht
zusammengehören.
Wenn in einer Schleife irgendwas geregelt wird, gehören da keine
Zugriffe auf irgendwelche Register rein.
Eher sollte man zum Setzen einer Stellgröße eine Funktion aufrufen, in
der dann das HW-Gefummel gemacht wird.
Ein PID-Regler in Hochsprache hat nichts mit OCRirgendwas zu tun.
10. Was um alles in der Welt haben deine sin-Werte mit einem Sinus zu
tun?
Und nicht zuletzt: schmeiss alles raus, was nichts mit dem Programm zu
tun hat.
Dein Programm macht
1
int main()
2
{
3
Hardware initialisieren
4
5
while( 1 ) {
6
7
ADC auslesen
8
9
ADC Wert auf 3 PWM ausgeben
10
}
11
}
dazu braucht es keine Funktion rechtskom, dazu braucht es keinen PID
Regler, dazu braucht es 60% deines Codes überhaupt nicht. Und den ADC
würde ich erst mal mit den Tutorial Funktion auslesen und nicht im im
Free-Running Modus.
Klaus Wachtler schrieb:> äh, hatte ich das noch vergessen? :-)
Ähm. Weiß nicht so genau :-) Ich denke du hast nicht.
Ich wollte nur nicht, dass das unter geht bei all den anderen
berechtigten Punkten, die du angemerkt hast.
Das ganze sieht mir nämlich wieder mal nach dem leidigen Problem aller
Einsteiger aus: Ich hab im vorletzten Übungsbeispiel einen Code
produziert und den behalte ich unter allen Umständen im Programm. Den
braucht zwar keiner, aber rauslöschen werd ich ihn auf keinen Fall.
Karl Heinz Buchegger schrieb:> Den> braucht zwar keiner, aber rauslöschen werd ich ihn auf keinen Fall.
Wäre ja auch noch schöner, extra ein VCS aufzusetzen, damit sich
das an den alten Code erinnert. ;-)
willst du nicht machen.
Über den double brauchen wir nicht lange debattieren. Das der Unsinn
ist, siehst du wohl selber.
Es geht um die 61.
Solche magische Zahlen willst du nicht im Code haben. Die Gefahr ist
viel zu groß, dass du dich verzählst oder +-1 verhaust. Ausserdem ist
das mühsam abzuzählen.
Denn: Das kann der Compiler auch für dich erledigen!
Und wenn du das dann auch noch ein wenig nett in Tabellenform anordnest,
dann kann man auch auf einen Blick erkennen, dass das eine lineare Rampe
ist und auch wieviele Werte das sind.
1
uint8_tsin[]={0,10,20,30,40,50,60,70,80,90,
2
100,110,120,130,140,150,160,170,180,190,
3
200,210,220,230,240,250,260,270,280,290,
4
300,310,320,330,340,350,360,370,380,390,
5
400,410,420,430,440,450,460,470,480,490,
6
500,510,520,530,540,550,560,570,580,590,
7
600
8
};
So.
Jetzt zählt der Compiler für dich die Zahlen ab und dimensioniert das
Array entsprechend gross. Fügst du einen Wert hinzu, macht der Compiler
das Array automatisch größer, nimmst du einen Wert raus, macht er es
automatisch kleiner.
Nur: WOher weiß jetzt dein Programm, wieviele Werte das sind?
Bisher hast du ja einfach 60 bzw. 61 in den Programmtext geschrieben.
Wenn der Compiler die Größe des Arrays festlegt, sind es ja keine 61
Werte mehr. Das müsste man daher anpassen.
Auch das kann dein Compiler für dich erledigen!
In C gibt es den sizeof() Operator. Der bestimmt die Größe in Bytes von
einer Variablen.
sizeof( sin ) gibt dir daher die Größe in Bytes, die das komplette
Array verbraucht. Dividiert man das durch die Größe von einem einzelnen
Arrayelement, dann erhält man logischerweise die Anzahl an Elementen.
Denn die komplette Größe errechnet sich ja durch
komplette_Größe = Anzahl_Einträge * Größe eines Eintrags
ein bischen Formel Umstellen und die Behauptung folgt daraus.
Das kann man aber auch in C schreiben
uint8_t nrSin = sizeof( sin ) / sizeof( sin[0] );
und schon hast du alles was du brauchst um diese magische Zahl aus dem
Programm zu verbannen.
1
intmain(void)
2
{
3
uint8_tsin[]={0,10,20,30,40,50,60,70,80,90,
4
100,110,120,130,140,150,160,170,180,190,
5
200,210,220,230,240,250,260,270,280,290,
6
300,310,320,330,340,350,360,370,380,390,
7
400,410,420,430,440,450,460,470,480,490,
8
500,510,520,530,540,550,560,570,580,590,
9
600
10
};
11
uint8_tnrSin=sizeof(sin)/sizeof(sin[0]);
12
uint16_tadx;
13
14
DDRD=0xFF;
15
//DDRA = 0x00;
16
DDRB=0xFF;
17
DDRC=0x2;//OC1B
18
DDRE=0x2;//OC0B
19
20
ad_conver();//Aufruf der Funktion zur initialisierung des AD.Wandlers
21
22
timer_init();//Aufruf der Funktion zur initialisierung der Timer
23
24
sei();
25
26
inttem,ii;
27
tem=0;
28
ii=0;
29
30
while(1)
31
{
32
tem++;
33
if(tem>=nrSin-1)
34
{
35
tem=0;
36
ii=ii+1;
37
}
38
39
if(ii>=20)
40
ii=0;
41
42
adx=ADCW;
43
44
OCR0B=sin[ii];// Vergleichswert für die Duty Cycle Einstellung
45
OCR1B=adx;// Vergleichswert für die Duty Cycle Einstellung
46
OCR1A=ii;// Vergleichswert für die Duty Cycle Einstellung
47
}
48
49
return0;
50
}
Im übrigen denke ich nicht, dass du da an der PWM großartig was sehen
wirst.
Zu deinen Kommentaren:
1
ad_conver();//Aufruf der Funktion zur initialisierung des AD.Wandlers
2
3
timer_init();//Aufruf der Funktion zur initialisierung der Timer
Gut dass du mir das alles im Kommentar erzählst. Da wär ich von alleine
nie drauf gekommen, dass timer_init()
* der Aufruf einer Funktion ist
* und dass diese Funktion höchst wahrscheinlich den Timer
initialisieren wird.
Aber: Wenn du dir bei ad_conver() dazuschreiben musst, dass das die
Funktion ist, die den ADC initisliert, dann solltest du soweit denken,
dass du dich fragst: wie müsste ich die Funktion nennen, damit ich eben
keinen Kommentar brauche!
Nenn die Funktion adc_init() und jedem ist klar, was dieser
Funktionsaufruf bewirkt.
Und so gibt es noch einige andere Kommentare in deinem Programm, die
reichlich sinnlos sind. Kommentiere nicht das, was ohnehin im
Programmtext steht! Du musst das kommentieren was keiner wissen kann,
wenn er sich nur den Programmtext ansieht! Kommentiere das "Warum" und
nicht das "Wie"! Das "Wie" steht im Code, aber das "Warum" existiert nur
in deinem Kopf. Also schreib es hin!
Benenne Variablen nach ihrer Bedeutung! Ein Variablenname tim oder ii
erzählt mir nichts.
Wenn in einem Programm steht
xyz = i + i * u;
dann sagt das einem Leser gar nichts. Wenn da aber steht
verkaufsPreis = nettoPreis + nettoPreis * Mehrwertsteuer;
dann erzählt mir diese Anweisung etwas! Da wird zu einem Preis die
Steuer berechnet und draufgeschlagen um den Preis zu erhalten um den
etwas verkauft wird. Da muss ich den Rest des Programmes gar nicht sehen
um zu wissen, dass bei
verkaufsPreis = nettoPreis - nettoPreis * Mehrwertsteuer;
etwas nicht stimmen kann und was da nicht stimmen kann.
Sorge immer dafür, dass dein 'Hauptkommentar' eines Programmes das
Programm selber ist! Dies macht man mit gut gewählten Funktionsnamen.
Dies macht man mit gut gewählten Variablennamen. Überleg dir bei jedem
Kommentar, den du hinschreiben willst, ob es nicht eine Möglickeit gibt
den Code so zu verändern, dass du den Kommentar NICHT brauchst. Denn der
beste Kommentar ist jener, den du nicht hinschreiben musst!
So ein Kommentar
int tem, ii; // Variablen für die if-Anweisung
tem=0;
ii=0;
ist komplett sinnlos. Was soll das sein "Variablen für die
if-Anweisung"? Was sagt mir das über die Bedeutung der Variablen? Was
repräsentieren sie? Richtig: Das sagt mir gar nichts. Und spätestens
wenn dann ein zweites if ins Program kommt, dann stimmt der Kommentar
sowieso schon nicht mehr.
Karl Heinz Buchegger schrieb:> uint8_t sin[]
Jetzt sollte man aber noch den Namen ändern. sin ist ein
reservierter Bezeichner, denn es ist eine mathematische Funktion
der Standardbibliothek.
"ramp" hätte deutlich mehr Sin(n) als Name hier. ;)
Man kann ja auch alle Werte vor dem Speichern durch 10 teilen. Damit
verliert man keine Information (zumindest im Beispiel von Karl Heinz)
und kann doch wieder uint8_t nehmen. :)
Das ganze Array ist Quatsch..
Statt
OCR0B = sin[ii]; // Vergleichswert für die Duty Cycle Einstellung
einfach
OCR0B = 10 * ii; // Vergleichswert für die Duty Cycle Einstellung
und das Array in die Tonne kloppen.
Wobei das auch nicht klappen wird. Denn bei allen AVRs (außer den Xmega)
die ich kenne ist TIMER0 ein 8 Bit Zähler. Also ist bei 255 Schluss.
P.S. Obwohl der Controller nicht genannt wird kann man aus den
Registernamen schließen, daß es sich um Modell der MegaAVR Reihe handeln
muss.
So, jetzt hab ich es geschaft alles nochmal umzuändern. Ich will mich
besonders für den Tip mit dem Array bedanken. Das ersparrt wirklich viel
Mühe. Ich hab jetzt versucht alles so gut es geht zu verbessern.
Ich habe meinen Programm in einzelnenTeilen gehackt und die Teile
einzeln getestet. Die Timer, der AD-Wandler und die if_Anweisungen
funtionieren alleine ganz gut. Wenn alles wieder eingesetzt wird, kommt
das gleiche Problem. Als vergleichswert für die PWMs werden die
Variablen a,b und x[b ] (neu benannt) jeweils eingesetzt. Am Oszilloskop
wird getestet wie sich das PWM-Signal verändert. Das PWM-Signal hat sich
gar nicht geändert.
Wird vom Programm der AD-Wandler entfernt, funktioniert alles
einwandfrei. Wenn ich so die PWMs am Oszilloskop darstelle, sieht man
eine kontinuierliche Veränderung des duty cycles.
Ich hoffe ich hab jetzt nichts vergessen. Der µC den ich benutze ist der
AT90PWM316.
Rachid E. schrieb:> So, jetzt hab ich es geschaft alles nochmal umzuändern.
Sieht schon besser aus, auch wenn ich mit a und b noch nicht glücklich
bin.
Aber das hier
ADCSRA |= (1<<ADIE); //Interrupt erlauben
muss raus!
Du hast keine ISR für diesen Interrupt
Super, ich danke dir. Jetzt geht alles eiwandfrei. Dass so ein kleiner
fehler schon so viel anstellen kann, machts einem nicht einfach.
Ich bin hier aber um eine Menge schlauer geworden. Und dafür noch ein
großes Danke, an alle die geholfen haben.
Ich wünsche Euch allen noch ein schönes Wochenende.
Viele Grüße,
Rachid
Rachid E. schrieb:> Super, ich danke dir. Jetzt geht alles eiwandfrei. Dass so ein kleiner> fehler schon so viel anstellen kann, machts einem nicht einfach.
Lass mich raten.
Du hast die ADC initialisierung einfach wo herkopiert.
Das mindeste was man in so einem Fall immer machen muss: Prüfen ob
irgendwo Interrupts freigegeben werden! Daher ist es auch nicht so
schlau, wenn man sich den Code so schreibt, dass man das möglichst
schlecht sieht. Ein freigegebener Interrupt ist eine wichtige Sache! Die
soll nach Möglichkeit rufen: "Hier, bitte ich!"
Ich habe die Initialisierung schon selber gemacht. Ich habe bis jetzt
blos noch nie einen Interrupt benutzt und wusste halt nicht dass es so
viel ausmacht wenn man ihn enabelt und nicht nutzt.
Mir kam am Anfang nicht der Gedanke, dass irgend etwas am AD-Wandler
falsch sein könnte. Der AD-Wandler hatte ja richtig funktioniert. Die
Wirkung war halt ganz wo anders.
Da ist doch noch ein Fehler drinne. Wenn ich
ADCSRA |= (1<<ADIE); //Interrupt erlauben
raus nehme oder auf Null setzte, macht der AD-Wandler nur eine Messung.
Das ist mir vorhin nicht eingefallen, da ich nur auf die if-Anweisungen
und der PWMs geachtet hatte.
Rachid E. schrieb:> Da ist doch noch ein Fehler drinne. Wenn ich>> ADCSRA |= (1<<ADIE); //Interrupt erlauben>> raus nehme oder auf Null setzte, macht der AD-Wandler nur eine Messung.
Du hast den auto trigger Modos (ADATE = 1) aktiv, nun musst du aber
mal konkreter werden, welcher Controllertyp das ist, damit man sich
die Triggerquelle nochmal ansehen kann.
Übrigens:
Das ist reichlich viel Code. Allein die ersten beiden Zeilen sind
zwei aufwändige no-ops. Der Compiler darf diese aber nicht weg
optimieren (weil ja auf IO-Registern gearbeitet wird), es wird also
jedesmal ADMUX gelesen und wieder ausgegeben. Schreib' das besser
jeweils in ein statement, und nicht als read-modify-write, sondern
als absolute Zuweisung:
1
/* ADMUX = 0; *//* keine Änderung nötig, kann weggelassen werden */
2
ADCSRB=/* no ADTS3 */(1<<ADTS2)/* no ADTS1, no ADTS0 */;
Danke fü die Tips. Ich kann jetzt leider nichts mehr testen bis Montag,
da das Labor bis dahin geschlossen ist. Als Controller benutze ich den
AT90PWM316 und das Board Stk500 mit das Ergänzungsboard Stk520. Beim
AD-Wandler versuche ich blos nur eine kontinuierliche Messung zu
erreichen.
Rachid E. schrieb:> Als Controller benutze ich den> AT90PWM316
Dort entspricht der Wert ADTS[3:0] = 0b0100 (den du programmierst)
der Triggerquelle "Timer/Counter 0 Overflow". Du musst also den
Timer 0 so programmieren, dass sein Überlauf der von dir gewünschte
ADC-Trigger-Rate entspricht. Du schreibst nicht, mit welcher
Taktfrequenz der Controller läuft, standardmäßig ist es 1 MHz.
Mit dem von dir gewählten ADC-Prescaler von 128 wird der ADC dann
schon ziemlich langsam, eine Wandlung dauert nach dem Anstoßen
stolze 2 ms. Vielleicht überdenkst du auch den Prescalerwert
nochmal.
Timer0 wird bei mir schon genutzt um ein drittes PWM-Signal zu erzeugen.
Ich weis nicht ob ich den timer0 gleichzeitig auch dafür benutzen kann.
Als Taktgeber benutze ich den internen Quarz. Wenn ich mich nicht irre
hat der 8 MHz. Den Adc-prescaller werde ich dann ändern.
Rachid E. schrieb:> Timer0 wird bei mir schon genutzt um ein drittes PWM-Signal zu erzeugen.> Ich weis nicht ob ich den timer0 gleichzeitig auch dafür benutzen kann.
Ja, natürlich.
Vielleicht postest du ja dann auch mal den kompletten Code.
> Als Taktgeber benutze ich den internen Quarz. Wenn ich mich nicht irre> hat der 8 MHz.
Wenn du die CKDIV8-Fuse nicht geändert hast, wird das trotzdem auf
1 MHz runtergeteilt.
Ich hab jetzt den ganzen Code hochgeladen. Wie schon geschrieben
funktioniert der AD-Wandler nicht ganz. Die if-Anweisungen
Funktionieren. Nur der AD-Wandler wandelt nur ein mal, beim Start des
Programms.
Ich möchte die höchstmögliche frequenz aus dem Controller haben. Einen
externe Quarz kann ich leider nicht benutzen, da der Quartzeingang
gleichzeitig der Ausgang für das PWM-Signal von Timer0 ist.
Ich bin euch auch sehr Dankbar wenn ihr mir einen Tip gibt, ob oder wie
ich eine Höhere Frequenz einstellen kann. Ich habe bereits den TOP-Wert
der Timer auf 100 runtergesetzt, damit ich meine jetzige 10kHz bekomme.
Den ADC-Prescaler habe ich schon korrigiert. Ich habe auch den ADTS
verändert und leider ohne erfolg getestet.
PS: Ich hab jetzt den Hacken von CKDIV8 in der Einstellung entfernt.
Jetzt habe ich eine Frequenz von 80kHz. Das ist nun mehr als ich
brauche. Danke für den Tip.
Rachid E. schrieb:> Ich hab jetzt den ganzen Code hochgeladen. Wie schon geschrieben> funktioniert der AD-Wandler nicht ganz. Die if-Anweisungen> Funktionieren. Nur der AD-Wandler wandelt nur ein mal, beim Start des> Programms.
Logisch. Du hast ja auch den Freerunnnig MOdus wieder abgeschaltet.
Tu dir doch selber einen Gefallen und benutze erst mal die ADC Routinen
aus dem AVR-GCC-Tutorial.
>> Ich möchte die höchstmögliche frequenz aus dem Controller haben.
Ja, ja. Das wollen sie alle,
Du hast noch einen langen Weg vor dir und im Endeffekt wird das
endgültige Programm mit dem jetzigen nicht mehr viel gemeinsam haben.
Das macht man nämlich alles ganz anders :-)
Vor allen Dingen macht man die Zeitsteuerung autonom mit einem Timer.
Das Stischwort lautet DDS.
Das hier
1
2
/* Die if-Anweisungen stellen die Geschwindigkeit, mit der sich der Vergleichswert für die PWMs ändert
3
Es sind zwei if-Anweisungen eingesetzt, damit kein zu hoher Zählwert in einer if-Anweisung eingesetzt werden muss*/
4
a=a+1;
5
if(a>=600)
6
{
7
a=0;
8
b++;
9
}
10
11
if(b>=nrx)
12
b=0;
ist doch Murks erster Güte.
Und das hier
1
c=adx*0.1;
ist schon mal ein kompletter Widerspruch zu der Forderung: so schnell
wie möglich.
Rachid E. schrieb:> Ich hab jetzt den ganzen Code hochgeladen. Wie schon geschrieben> funktioniert der AD-Wandler nicht ganz.
Genauer: es lässt sich nichtmal compilieren:
% avr-gcc -Os -mmcu=at90pwm316 -o Motor1.elf Motor1.c
Motor1.c:97:11: error: invalid suffix "b" on integer constant
Tu dir und uns einen Gefallen, und lade hier doch genau das hin, mit
dem du auch selbst experimentierst, und nicht eine irgendwie zurecht-
gestutzte Version. Andernfalls suchen wir andere Fehler als du.