Hallo zusammen
Ich habe versucht mit einem Atmega 8 einen Rechteck Generator zu
programmieren (als Anfänger).
Die Tutorials mit delay bringen zwar eine LED zum blinken, helfen aber
nicht wirklich weiter.
Dann habe ich es über Timer versucht, vielversprechend.
Ich habe mittlerweile aber schon 230 Codezeilen für einen
Rechteckgenerator in C geschrieben. Das kann es doch nicht sein.
Vermutlich denke ich einfach falsch.
Mega8 = 6 MHZ
fout = 0,01 - 350 Khz
Es giebt im Internet genau so etwas als .asm und als .hex.
nutzt mir aber nichts weil ich es nicht verstehe.
eventuell weiss ja einer wo man sich mal ein c (Ablauf)Programm ansehen
kann.
Marko
Hi,
"Wo gibt es ein Beispiel" ist als Frage vermutlich nicht so zielführend.
Schreib doch wo die Probleme sind, wie Dein Konzept ist usw.
Vielleicht erstmal mit einer einfacheren Version, feste Frequenz z.B..
Dann sieht man sich Deinen Code hier sicherlich auch durch und sagt Dir,
wo das daneben ist (oder auch nicht).
Gruß,
Norbert
Wo ist denn der Code, den wir uns anschauen sollen? Bitte auch einen
Schaltplan. Ein Rechecksignal sollte sich via PWM in relativ wenig
Codezeilen bauen lassen. Aber für ne variable Frequenz klingen 230
Zeilen noch nicht besorgniserregend.
Hallo Norbert
Konzept ist ja erstmal Rechtekgenerator programmieren.
Eckdaten:
fout = 0,01 - 350 Khz
Mein Problem ist ja nicht das ich es nicht hinkriege nur meine 230
codezeilen scheinen mir etwas viel. Wenn man googelt giebt es ein
Beispiel in asm welches ich aber nicht verstehe, daher meine frage nach
einem Beispiel in C. Das verstehe ich besser.
Marko
Ich hänge mal meine C-Datei an. Aber erschlage mich bitte nicht.
Ich bin Anfänger.
Marko
Habe deinen Code grade nur überflogen. 230 Zeilen sind nicht viel dafür,
du machst ja auch noch eine LCD-Anzeige dafür, da kannst du bei deinem
Beispiel bestimmt 10% der Zeilen schon mal abziehen, sind doch locker 20
LCD-Funktionen die du da aufrufst.
Dann fiel mir noch was auf: Überlege dir mal was du auf dem LCD anzeigen
willst. Wenn du zum Beispiel immer in Zeile 2 zu Beginn ein "f: " stehen
hast kannst du das auch in die LCD-Initialisierung packen und es kann
aus jeder if-Anweisung rausfliegen oder anders gefragt: Warum schreibst
du y ins Display an die Stelle x an der y schon steht? ;)
Marko E. schrieb:> daher meine frage nach> einem Beispiel in C. Das verstehe ich besser.
Da ist nichts dran ehrenrührig. Anbei mal mein Rechteckgenerator in C,
diesmal mit Mega 8515. Der Name 'Konstanz' kommt von der Beschriftung
der ehemaligen (MCS-51) Hardware - war ein Zeitnehmer aus dem
Lehrmittelbetrieb mit grossem 2*20 Zeichen LCD. Und 'ne Uhr ist mit
drin, die ich hauptsächlich zum Abgleich des Quarzes benutzt habe.
Marko E. schrieb:> Ich hänge mal meine C-Datei an. Aber erschlage mich bitte nicht.
Ist nicht weiter schlimm.
Zu dem was Michael Köhler angeführt hat, möchte ich noch eine Sache
ergänzen, die wichtig ist.
In deinem Code gibt es immer wieder mehr oder weniger gleiche Sequenzen,
die ganz spezifische Aufgabenstellungen lösen. Zum Beispiel hier
1
....
2
ultoa(f,Buffer,10);
3
lcd_setcursor(0,1);
4
lcd_string("f: ");
5
lcd_string(Buffer);
6
....
das kommt immer wieder mehr oder weniger genau gleich. Die angestrebte
Funktionalität lässt sich aber ganz leicht zusammenfassen. Du willst
hier an eine bestimmten POsition am LCD einen Zahlenwert (als unsigned
long) ausgeben, wobei du noch eine Beschriftung davor stellen willst.
Das ist gut so und auch legitim.
Was aber nicht gut ist, das ist das du dieselbe Funktionalität immer
wieder ausprogrammierst. Genau an dieser Stelle kommen Funktionen ins
Spiel. Spätestens dann, wenn die gleiche Funktionalität nur mit anderen
Zahlen und/oder Variablen immer wieder auftaucht, spätestens dann ist es
Zeit dafür eine Funktion zu schreiben. In deinem Beispiel ganz einfach
Das verkürzt nicht nur den Code, es hilft dir auch, dich hier im main
auf das wesentliche zu konzentrieren. Denn wesentlich hier ist ja wie
sich die Frequenz verändert und welcher OCR Wert sich daraus ergibt. Das
ist das, was du hier sehen möchtest und was hier wichtig ist. Die
Details der Ausgabe sind hier recht unwichtig, die willst du an dieser
Stelle aus dem Code raushaben. Wenn sie dich interessieren, dann kannst
du immer noch in der Funktion nachsehen. Aber erstmal gibst du dich an
dieser Stelle im Code damit zufrieden, dass ein lcd_label_uint32 dir
einen 32 Bit Wert mit Beschriftung an eine bestimmte Stelle am LCD malt.
Mehr musst du hier an dieser Stelle nicht wissen, weil es hier nicht
wesentlich ist, wie das passiert. Wenn doch -> in der Funktion
nachsehen.
Man könnte hier ja auch noch weiter gehen.
Denn wenn eine Frequenz erhöht wird oder wenn sie erniedrigt wird, dann
ist das ja immer der gleiche Ablauf. Warum soll sich das dann nicht zb
so schreiben
Merkst du was?
Deine ganzen Kommentare sind plötzlich eigentlich überflüssig. Denn das
hier zum Beispiel die Taste 1 gedrückt wurde, das sehe ich auch im Code.
Der Begriff 'KEY1' kommt da ja an der betreffenden Stelle recht
prominent vor. (Und das einer deiner Kommentare eigentlich falsch ist,
das ist jetzt auch deutlich ersichtlich. Denn im letzten Fall ist es die
Taste 4 und nicht die Taste 3. Falsche Kommentare sind noch schlimmer
als keine Kommentare)
Und das hier die Aktion darin besteht, dass die Frequenz um 1Hz erhöht
wird, auch das kann ich dort leicht ablesen. Genau das ist ja die
Bedeutung von
1
f++;
Wenn du die Variable nicht f sondern zb 'frequency' gennant hättest,
dann würde da beispielsweise (an anderer Stelle) stehen
1
frequency=frequency+100;
und das ist nun wirklich schon fast ein vollständiger, komplett
verständlicher Satz. Denk dir die Sonderzeichen durch Wörter ersetzt,
dann steht da praktisch im Klartext "Die Frequenz wird erhöht, indem 100
zur Frequenz dazugezählt werden". Da braucht es keinen Kommentar mehr,
der mir genau dasselbe im deutschen Satz sagt. Die Anweisung im Code
spricht für sich selbst. Im Deutschen würde man vielleicht kürzer sagen
"Die Frequenz wird um 100 erhöht", die C Schreibweise dafür wäre
1
frequency+=100;
Als Nebeneffekt der Funktionen hast du 3 Seiten Code auf eine halbe
Seite + die Funktionen eingedampft. Was dann auch noch den Nebeneffekt
hat, dass du, sollte sich die Berechnung der kritischen Werte abhängig
von der Frequenz einmal ändern, oder sich an der Anzeige etwas ändern,
dies nur an einer einzigen Stelle tun musst. Nämlich hier
Kurz und gut: Funktionen sind eine deiner Waffen, wie du Code
vereinheitlichen, verkürzen, übersichtlicher und gleichzeitig leichter
wartbar (veränderbar) machen kannst.
Die gesparte Zeit investierst du lieber darin, deinen Code leicht lesbar
zu machen. Es gibt keinen Grund alle Zeichen knirsch an knirsch
aneinander zu kleben. Seit du 6 Jahre alt bist, hast du dein Gehirn
darauf trainiert, dass zwischen einzelnen Wörtern in einem Text ein
Leerraum steht. Dein Gehirn hat das gelernt und ermöglicht dir so
leichteres Lesen, weil du nicht erst umständlich die Wörter
identifiziern musst. Ein
1
f=f+100;
ist für dein Gehirn mit viel weniger Anstrengung zu lesen, als ein
1
f=f+100;
> Ich bin Anfänger.
Das wird schon. Es ist noch kein Meister vom Himmel gefallen. Programme
zu strukturieren will auch gelernt sein.
Hallo Karl
Von Deiner Antwort bin ich überwältigt.
Da möchte ich hin.
Das es mit Funktionen besser gehen sollte habe ich bemerkt. Aber leider
nicht hin bekommen.
Dein erstes Beispiel hat mir sehr geholfen. Ich hatte es auch schon in
der Art versucht aber es gab immer Probleme mit Datentypen. const char*
ist mir neu, funktioniert aber.
Jetzt muss ich erstmal DoKu lesen.
Herzlichen Dank für Deine ausfürliche Beschreibung.
PS
Den Rest Deiner Beschreibung versuche ich natürlich auch noch
umzusetzen.
Dauert aber etwas.
Marko
>void setNewFrequency( uint32_t frequ )
Noch eine kleine Anmerkung zur Dokumentation von Funktionsparametern.
Hier kann es nützlich sein, wenn man in den Parameternamen gleich die
Einheit mit hinein packt.
Marko E. schrieb:> Leider vertehe ich nicht so viel. Wird sich aber ändern.
Da bin ich sicher. Verwirrend ist vermutlich, das da noch ein STDIN und
STDOUT auf der UART initialisiert wird (siehe das Tutorial des 'grossen'
Beispiels in der avr-lib) und das da eben noch eine Uhr mitläuft.
Timer 0 macht die Uhr, Timer 1 ist der Rechteckgenerator (mit CTC wie
bei dir). Ich schalte abhängig vom Bereich den Prescaler mit um und
benutze das EEPROM, um den gewünschten Einschaltzustand zu speichern.
Peter Fleurys LCD Lib fehlt im Download, aber die gibts im Internet.
Die Uhr habe ich dazu benutzt, um mittels Trimm-C den Quarzoszillator
möglichst genau hinzuziehen. Dazu habe ich einmal am Tag die Abweichung
gemessen und mit dem Trimmer nachgezogen.
>f = f - 100;>setNewFrequency( f );
Mir drängt sich da eine Frage auf: Es mögen gerade 5 Hz erzeugt werden
und dann drückt jemand auf die "100 Hz weniger"-Taste. ...?
>void setNewFrequency( uint32_t f_MHz )
Ob sich das bei der Handvoll MHz-Frequenzen, die der µC bei FOSC = 6 MHz
erzeugen kann (nämlich 1, 1.2, 1.5, 2 und 3 MHz), lohnt?
Ich halte es für klug, das mit dem "setNewFrequency" überhaupt mal
generell zu überdenken. Weil man OCR-Register nur auf ganzzahlige Werte
setzen kann.
LostInMusic schrieb:> Ob sich das bei der Handvoll MHz-Frequenzen, die der µC bei FOSC = 6 MHz> erzeugen kann (nämlich 1, 1.2, 1.5, 2 und 3 MHz), lohnt?
Das war von Chris nur als Beispiel gedacht. Es geht halt darum, dass man
generell dem Parameter einen Namen geben sollte, der seine Funktion
beschreibt.
LostInMusic schrieb:> Mir drängt sich da eine Frage auf: Es mögen gerade 5 Hz erzeugt werden> und dann drückt jemand auf die "100 Hz weniger"-Taste. ...?
Ich würde daher einen Bereichstest mit in die Funktion aufnehmen:
Nochmals vielen Dank für alle Antworten.
Es ist aber im Moment etwas viel. Ich muss die Antworten ja auch erst
einmal verstehen. Kann ich nicht so schnell.
Karl Heinz hat wunderbare Anregungen gegeben. Die muss ich mir aber
erstmal alle einverleiben.
@ LostInMusic
Das man das OCR nur auf ganzzahlige Werte setzen kann war mir klar, ich
hatte aber beim programmieren nicht daran gedacht das es ab 3 Khz
Probleme macht. Ich möchte das Konzept aber dennoch verfolgen da ich im
Moment eine Menge lerne.
Vermutlich kann man die eigentliche Signalerzeugung ja später noch
ändern.
@peda
Bereichsumschaltung habe ich versucht aber diese Beschränkung vom OCR
auf 16 bit bleibt ja. Wie bekomme ich eine Auflösung von 1 Hz hin?
Ich versuche jetzt erst einmal alle Eure Anregungen zu verstehen.
Vielen Dank.
PS: Ich hätte nicht gedacht dass es so schwierig ist einen
Rechteckgenerator zu programmieren.
Marko
Marko E. schrieb:> Wie bekomme ich eine Auflösung von 1 Hz hin?
Gar nicht. Zumindest nicht über den kompletten Bereich. Im unteren
Bereich kann es aber schon klappen, dafür musst du dann nicht nur das
OCR anfassen sondern auch den Clock-Prescaler des zugehörigen Timers
ändern.
Hallo LostInMusic
Alles was Du schreibst habe ich mittlerweile auch schon bemerkt, ausser
dass meine Tabelle etwas länger ist und etwas anders aussieht.
Ich muss erst mal die Anregungen von euch umsetzen wie man überhaupt
programmiert.
Drehimpulsgeber hatte ich gerade nicht, es klappt ja noch nicht einmal
mit Tastern zufriedenstellend.
Mich würde natürlich trotzdem interessieren wie man einen Timer als
einstellbaren Rechteckgenerator mit einer Auflösung von 1 Hz
programmieren kann.
Kann man 2 Timer "hintereinander schalten" so dass die Auflösung höher
wird?
Erschwerend kommt hinzu dass ich mir dachte, man könnte später versuchen
das Tastverhältniss zu ändern.
Ist das Unsinn?
nochmal an LostInMusic
Der Lernwert ist enorm
ich weiss jetzt wie man datenreihen in LibreOffice erstellt,
desweiteren Diagramme
und Formeln aus Datentabellen generiert.
nutzt nur leider nichts für meinen Rechteckgenerator.
Marko E. schrieb:> Kann man 2 Timer "hintereinander schalten" so dass die Auflösung höher> wird?
Das kann man schon, aber er wird dann aber nur länger - du kannst noch
tiefere Frequenzen erzeugen.
Marko E. schrieb:> nutzt nur leider nichts für meinen Rechteckgenerator.
Doch, warum nicht? Du kannst ja mal eine Formel erstellen, die die für
eine gewünschte Ausgangsfrequenz die CTC und Prescalerwerte errechnet.
Als Ausgangspunkt ist es natürlich am besten, eine 'magische'
Taktfrequenz zu nehmen, die dir im Timer z.B. genau 100µs Zyklen
erzeugt, das sind dann für 1Hz genau 5000 Zyklen (CTC toggelt ja,
deswegen die Hälfte der Dauer in CTC). Für 2Hz dann 2500 Zyklen. Und
dann fängts schon an. 3Hz wären 1666,66 Zyklen und das kriegt man nicht
hin. Für genaue 3Hz müsste man 2 Perioden mit 1667 Zyklen fahren und 1
mit 1666.
Ok, dann rechnet man mal statt mit 100µs mit 25µs Zyklen und schaut, ob
das besser wird.
Und so weiter. Rechne mal ein bisschen und spiele mit den Taktfrequenzen
und Vorteilerfaktoren in deiner Tabelle.
In meinem Generator bin ich den umgekehrten Weg gegangen. Ich setze CTC
und Vorteiler von aussen und auf dem LCD errechnet mir der MC, welche
Frequenz da gerade rauskommt.
LostInMusic schrieb:> Alle ganzzahlig-exakten Output-Frequenzen für FOSC = 6000000 Hz.> In Klammern jeweils der OCR-Wert + 1 sowie der Prescaler-Wert.
Du könntest die Werte noch erweitern indem du nicht nur den
Timer-Prescaler änderst sondern auch den Systemclock-Prescaler…aber
schon eine schöne Erklärung, dank dafür. Sieht man eher weniger, dass
sich jemand diese Mühe macht ;)
Hallo Mattias
Ich habe schon mit meiner Tabelle rumgespielt.
Herausgekommen ist dass ich den CTC für kleine Frequenzen sehr genau
setzen kann. Funktioniert.
Bei höheren Frequenzen bin ich auch Deinen beschriebenen Weg gegangen
dass ich mir die Frequenz fürs LCD und Ausgangsfrequenz aus dem CTC
berechne. Funktioniert auch.
Marko
Ich möchte mich ganz herzlich bei allen Bedanken die mir mit Ihrem Rat
zur Seite standen. Auch wenn mein Vorhaben nicht geklappt hat so habe
ich doch eine Menge gelernt.
Eigentlich brauche ich nur mal einen Testgenerator mit 100 oder 200 khz.
Der Rechteckgenerator erzeugt die Frequenzen die ich benötige und es war
eine Spinnerei von einem Anfänger 1 Hz genau einstellen zu wollen.
Marko E. schrieb:> Der Rechteckgenerator erzeugt die Frequenzen die ich benötige und es war> eine Spinnerei von einem Anfänger 1 Hz genau einstellen zu wollen.
Überhaupt nicht. Ist doch völlig normal, dass hierbei die Neugier
geweckt wird und man schaut was man noch so bekommen kann ;)