Pfad: Home => AVR-DE => Anwendungen => Sinusgeneratoren => Sinusgenerator m324   This page in English: Flag EN Logo
DAC8 Tutorial zum Erlernen der AVR Assembler-Sprache von
AVR-Einchip-Prozessoren
von ATMEL anhand praktischer Beispiele.

Sinusgeneratoren mit einem R/2R-Netzwerk
Sinusgenerator mit ATmega324

Sinusgenerator mit ATmega324

Wenn Du einen Sinusgenerator mit in weiten Grenzen einstellbaren Frequenzen brauchst, bist Du hier richtig. Er hat die folgenden Eigenschaften:
  1. 1x8-LCD für Anzeige der Frequenz in Hz,
  2. zwei Potentiometer für die separate Einstellung der Auflösung und der Zeitverzögerung = maximale Flexibilität,
  3. aktive Taste für den Update der vorgenommenen Einstellungen, keine automatische Verstellung,
  4. 8-Bit-R/2R-Netzwerk,
  5. wählbarer und konfigurierbarer Quarz als Taktgeber,
  6. entweder 256, 128, 64, 32, 16 oder 8 Auflösungsschritte,
  7. großer 16-Bit-Verzögerungszähler, für sehr niedrige Frequenzen geeignet,
  8. sehr schneller Algorithmus (Minimum Zyklendauer = 17 Takte).

Hardware

Schaltbild des Sinusgenerator mit ATmega324 Das hier ist das Schaltbild.

Der Generator hat Der ATmega324 wurde deswegen ausgewählt, weil er
  1. zwei komplette Ports mit je 8 Bits hat, einen für den bidirektionalen LCD-Datenbus und einen für das R/2R-Netzwerk, und
  2. die Möglichkeit für den Quarzbetrieb hat, und
  3. er AD-Wandler-Eingänge bereithält, und
  4. weil er an geeigneter Stelle auch einen externen INT-Pin hat, dessen Interrupt auf fallende Flanken eingestellt werden kann (INT2).
ATmega324PA Der PA-Untertyp des ATmega324 wurde wegen seines niedrigen Preises ausgewählt, zumindest bei meinem bevorzugten Händler.

Das LC-Filter filtert die rechteckigen Reste des R/2R-Netzwerks. Es wird so ausgelegt, dass es bei der niedrigsten zu erzeugenden Frequenz wirksam wird und auch die höchste Frequenz noch ungedämpft passieren kann. Wer die große mögliche Bandbreite des Generators nutzen will, muss mehrere Filter umschaltbar anordnen.

Platinenlayout

Platinenlayout Sinusgenerator m324 Kupferseite Platinenlayout Sinusgenerator m324 Bestueckungsplan Das ist das Platinenlayout der Schaltung auf 80x100 mm. Dargestellt sind 2:1 verkleinerte Kopien der Originale. Originalgröße kriegt man durch Klicken auf die Bilder, Download mit Rechtsklick und Speichern unter ....

Die roten Punkte im Bestückungsplan sind 0,8mm-Bohrungen, die violetten sind 1,0mm. Statt der 10µH-Drossel im Schaltplan habe ich 22µH verwendet. Mein L ist 3,3mH, mein C ist 150nF. Das Cout habe ich mit 470nF bestückt.

Wer Linux kann, kann mit tgif die Originale bearbeiten. Die Kupferseite und alle Komponenten mit Farblayern sind hier, der Bestückungsplan hier verfügbar.

Achtung! In der ersten Version des Schaltplans waren die LCD-Kontrollanschlüsse anders belegt.

Konfiguration

Wenn der Controller startet, startet er mit der im Programm vorgegebenen Frequenz. Wenn dann die Taste an INT2 gedrückt wird, bestimmen die zwei Potis an ADC0 und ADC1 die Frequenz.

Frequenz beim Start

Um die Startfrequenz festzulegen, gibt es folgende Möglichkeiten:
  1. die Frequenz in mHz wird als Konstante fest vorgegeben, der Assembler ermittelt daraus die Auflösung cRes und die Verzögerungskonstante cDel, oder
  2. die Frequenz und die Auflösung cResol werden fest vorgegeben (256/128/64/32/16/8), daraus ermittelt der Assembler die Verzögerungskonstante cDel, oder
  3. die Frequenz und die Verzögerungskonstante (1 bis 65536, 65536 entspricht cDel=0!), wofür der Assembler dann die Auflösung ermittelt, oder
  4. die Auflösung cResol und die Verzögerungskonstante cDelay werden festgelegt, woraus der Assembler dann die Frequenz errechnet.
Das heißt: aus den gewünschten Kombinationen im Kopf des Quellcodes, im Abschnitt Einstellbar bestimmt der Assembler die erzeugte Frequenz in mHz. Unterschiede zwischen der gewünschten Frequenz und der effektiven können daraufhin beurteilt werden, ob die Abweichung noch akzeptabel ist. Dazu muss man nur im Listing des Assemblers an dessen Ende im Abschnitt Symbols nachsehen, was da als Frequenz herauskommt. Das kriegt man aber nur, wenn man mit gavrasm oder mit avr_sim assembliert, andere Assembler bieten diese Informationen nicht an. Hier kriegt man die Angaben nur mit Tricks, von hinten durch die Brust ins Auge, heraus.

Bitte beachten, dass die Namen der Konstanten cFreq und cFrequency, cDel und cDelay sowie cRes und cResol absichtlich doppelt gewählt sind. cResol und cDelay behalten die Auswahl des Users bei und die beiden kürzeren Namen sind daraus berechnet. Das stellt sicher, dass mit .IFDEF und .IFNDEF auch beim zweiten Assemblierdurchlauf richtig gerechnet wird.

Ändern der Frequenz mit den Potentiometern

Wenn der User die Taste drückt, wird die Sinusausgabe beim nächsten Nulldurchgang unmittelbar unterbrochen und die Spannung an den beiden Analogeingängen wird gemessen. Die Spannung am AD-Eingabe-Pin ADC0 wird linear in die sechs Sektionen der Auflösung (Grundfrequenz mal 1, mal 2, mal 4, mal 8, mal 16, mal 32) eingeordnet. Dazu wird das 16-Bit-Resultat zunächst zwei mal nach rechts geschoben, um einen 8-Bit-Wert zu erhalten. Dann wird der Addierer auf 1 gesetzt. Vom AD-Resultat werden dann immerzu 44 abgezogen. Wenn das Carry nicht gesetzt ist wird der Addierer um eine Position nach links geschoben. Bei gesetztem Carry ist der Algorithmus fertig.

Die Wandlung des ADC1-Resultats in den Delay-Wert ist etwas aufwändiger. Um die AD-Werte in Verzögerungswerte umzurechnen, gibt es die Tabelle DelayTable:. Diese hat Einträge für alle 1.024 AD-Werte.

Frequenzbereiche Das sind die Frequenzen, die im Basisfall (R/2R mit 8 Bit, 256 Stufen) einstellbar sind. Der Frequenzbereich umfasst vier Dekaden, mit dem Vervielfältiger noch eine bis zwei Dekaden mehr.

Die etwa logarithmische Kennlinie kriegt man mit zwei Methoden in den Griff:

Nachdem das Einlesen und Auswerten der ADC-Werte erfolgt ist, wird die Frequenz berechnet und angezeigt. Abschließend wird der Tasteneingang für 250 ms lang abgefragt und gewartet, bis dieser inaktiv ist.

Frequenz-Anzeige

LCD 1x8 Pinbelegung Da ich eine sehr kleine LCD mit acht Stellen in einer einzigen Zeile vorgesehen habe, braucht diese Wahl etwas erhöhten Aufwand bei der Zahlenausgabe.

Das ist die Pinbelegung der LCD EA8081-A3N, von oben in der Draufsicht gesehen. Der Pinabstand ist 2,54mm. Dafür ist auch das Layout der Platine ausgelegt.

Berechnung der Frequenz

Die Berechnung erfolgt nach dieser Formel
fSinus = fTakt / Auflösung / (4*Verzögerung + 13)

Da der Term Takt / Aufl&aouml;sung mit 20 MHz / 8 am größten wird, müssen Zahlen bis 160.000.000 im Zähler verarbeitet werden. Das sind bis zu 32 Bits. Um das Ergebnis in mHz zu erhalten, braucht der Divisor mindestens 24 Bits, effektiv ebenfalls 32 Bits. Um alle Zahlen durch Division verarbeiten zu können, benötigt der Divident 32 + 32 = 64 Bits und muss 32 Divisionsschritte ausführen.

Die Berechnung geht so vor sich. Zuerst wird die Taktfrequenz, multipliziert mit 1000 (damit mHz herauskommen) und geteilt durch 256 (8-Bit-Ausgabe) in einen 64 Bit umfassenden Registerbereich geschrieben. Der Addierer, der über die nach jeder Ausgabe erfolgende Addition der Leseadresse bestimmt, wird so oft nach rechts in das Carry geschoben, bis dieses Eins wird. Für jeden erfolgreichen Schiebevorgang wird der Registerbereich um eine Stelle nach links geschoben. Damit ist der Dividend komplett.

Der Verzögerungswert wird in einen 32 Bit breiten Registerbereich geschrieben. Dieser wird mit vier multipliziert (zwei mal links schieben) und 13 wird addiert. Dies ist dann der Divisor.

Die Division liefert ein 32 Bit breites Resultat in mHz. Dieses wird dann in eine Dezimalzahl umgewandelt und an der drittletzten Stelle das Komma eingefügt. Das sieht dann beispielsweise so aus:
0001234567.123 ; Alle drei Dezimalziffern sind nicht Null
0001234567.120 ; Die letzte Dezimalziffer ist Null
0001234567.100 ; Die letzten beiden Dezimalziffern sind Null
0001234567.000 ; Alle drei Dezimalziffern sind Null
0123456789.123 ; Die Zahl ist größer als 99.999

Formatieren der anzuzeigenden Frequenz

Im ersten Schritt werden alle Null-Zeichen hinter dem Komma entfernt. Sind alle drei Null, wird auch das Komma entfernt. Das Entfernen erfolgt, indem alle Ziffern aus der nächsten, übernächsten oder aus der vierten Stelle davor überschrieben werden und der verbleibende Speicherbereich mit ASCII-Nullen beschrieben wird. Die Zahlen sehen jetzt so aus:
0001234567.123 ; Alle drei Dezimalziffern sind nicht Null
00001234567.12 ; Die letzte Dezimalziffer war Null
000001234567.1 ; Die letzten beiden Dezimalziffern waren Null
00000001234567 ; Alle drei Dezimalziffern waren Null
0123456789.123 ; Die Zahl ist größer als 99.999


Dann werden alle führenden Nullen in Leerzeichen umgewandelt. Wenn das erste Zeichen, das nicht in ein Leerzeichen umgewandelt wurde, an den Positionen 1 bis 6 der Zahl liegt (die Zahl hat mehr als acht Zeichen), dann werden von rechts her Ziffern entfernt. Handelt es bei der höchsten entfernten Ziffer um eine 5 oder mehr, wird die rechtliche Zahl um Eins aufgerundet.

Die acht fertigen Ziffern werden danach auf die LCD geschrieben.

Inbetriebnahme-Hilfe

Testsoftware Für diverse Hilfszwecke habe ich eine Software geschrieben, mit der die Einzelteile der Schaltung stufenweise und separat getestet und in Betrieb genommen werden können. Den Quellcode dafür gibt es hier. Wenn auch die LCD getestet werden soll, braucht man noch die Include-Datei lcd.inc im gleichen Ordner.

Im Abschnitt Debugging tests des Quellcodes kann man einstellen, welche Tests ausgeführt werden sollen (den entsprechenden Test mit Yes einstellen).

Durchgeführt werden können die folgenden Tests:
  1. testR2R: Auf dem R2R-Port wird diejenige Zahl ausgegeben, die mit dem Parameter testR2ROut eingestellt ist.
  2. testSine: Der mit den beiden Parametern testSineRes und testSineDly eingestellte Sinus wird auf dem R/2R-Port ausgegeben.
  3. testKey: Das testet die angeschlossene Taste. Ist sie offen (PB2 ist high), dann gibt das R/2R-Netzwerk eine Spannung von 3 V ab. Im geschlossenen Zustand (PB2 ist low) sind es 2 V.
  4. testAdc0, testAdc1: Die R/2R-Spannung folgt dem AD-Wandler-Ergebnis am Eingang.
  5. testPortC: Der Datenport zur LCD wird als Ausgang geschaltet und alle Pins auf High gestellt.
  6. testLcd: Die LCD wird initiiert und der Text "SineM324" ausgegeben.
In der englischen Version sind noch weitere Testarten zum Debuggen realisiert. Die kann man aber nur gebrauchen, wenn man wesentliche Teile des Quellcodes ändern will. Für die englische Version einfach dem Link im Kopf folgen.

Noch ein Hinweis: Bei meiner Inbetriebnahme weigerte sich die LCD auch nur einen Mucks von sich zu geben. Nach etlichen Stunden erfolgloser Suche in der Software habe ich die Ursache schließlich gefunden: die verwendete Buchsenleiste und die LCD-Pins passten nicht zusammen, immer hatte mindestens einer der Pins keinen Kontakt. Ich habe dann die Schott-Buchsenleiste ausgelötet und eine gedrehte Fassung eingelötet. Kaum macht man's richtig, schon geht's (Robert Müller, Rodau).

Die Software

Die Software ist in Assembler-Quellcode-Format hier verfügbar. Lade diese herunter und lade in das gleiche Verzeichnis auch die LCD-Include-Datei lcd.inc. Nun muss der Operationsverstärker ausgewählt werden, denn dessen Charakteristika sind entscheidend für die verwendete Sinustabelle. Falls ein 741 oder ein CA3140 verwendet werden soll, muss nur der betreffende Parameter im Kopf des Quellcodes im Abschnitt Einstellbar ausgewählt werden.

Weiterer Operationsverstaerker Falls ein anderer Operationsverstärker zum Einsatz kommen soll, muss im Rechenblatt Sinustabelle im LibreOffice-Calc Dokument hier
  1. ein entsprechender Eintrag in den Spalten G bis I hinzugefügt werden (wie man die Linearitätsgrenzen des OpAmp ermittelt ist weiter unten beschrieben),
  2. diesen Eintrag in der Zelle B2 mit dem Dropdown-Feld einstellen,
  3. die daraus generierte Sinustabelle im Zellbereich von F9 bis F42 markieren und mit Strg-C in die Zwischenablage kopieren,
  4. die kopierte Tabelle am Ende des Quellcodes mit einem weiteren Auswahlparameter (wie z. B. mit .ifdef cMeinOpAmp einfügen, und
  5. diesen Auswahlparameter anstelle von cOpAmp741 und cOpAmpCA3140 im Abschnitt Einstellbar des Quellcodes aktivieren.
Damit ist sichergestellt, dass die Grenzen des eigenen OpAmp eingehalten werden.

Auch die anderen Einstellungen im Abschnitt Einstellbar sollten noch mal kontrolliert werden, auch diejenigen für die LCD (falls da ein anderer Typ oder eine geänderte Pinzuordnung eingestellt werden muss).

Fuses des ATmega324 Dann assembliere man den Quellcode und brenne die Hexdaten in das Memory des Controllers. Nicht vergessen, die