Forum: Mikrocontroller und Digitale Elektronik DDS-Funktionsgenerator mit Atmel AT90USB


von Eik (Gast)


Lesenswert?

Hallo liebe MC-Gemeinde

Wir brauchen für ein Studentenprojekt Rat:

Wir sollen mit einem Atmel AT90USB 1287 Mikrocontroller einen 
DDS-Funktionsgenerator realisieren. Ganz gut nochmal beschrieben in 
Kapitel 3 von A. Schwarz: www.mikrocontroller.net/wikifiles/5/51/Dds.pdf
Wir haben uns ein 8-Bit-Widerstandsnetzwerk auf einer Streifenplatine 
gelötet und an die Pins von Port A des Atmels verbunden. Wir haben noch 
das Masse-Pin des Ports A vom Atmel mit der Masse der Platine verbunden.

Mit einem C-Programm erstellen wir je eine 256-Werte-Tabelle für die 
Funktionen Sinus, Rechteck, Sägezahn und Dreieck.
Wir geben in einer Endlos-Schleife die Werte 0..255, fragen die 
Tabellenwerte ab und erhalten so endlos Rechteck-/Sinus-Werte und geben 
diese auf Port-A. Nach dem Anschluss des Platinenausgangs an ein 
Oszilloskop sollten wir nun analoge Rechteck-/Sinus-Spannungskurven 
sehen. Das klappt für Rechteck auch ganz gut...weil wir dort nur 0- oder 
255-Werte haben.

Für Sinus und die anderen Funktionen erhalten wir allerdings wirre 
Kurven. Die Signale sind zwar regelmäßig, aber der Sinus ist nach unten 
abgeschnitten und hat 8 Treppen pro Phase. Es scheint als ob die Werte 
zwischen 0 und 255 nicht ordentlich dargestellt werden. Wir haben als 
Test feste Werte auf Port A gegeben: 127 (0111 1111, 7 Bit gesetzt) 
führt zu einer höheren Spannung als 128 (1000 0000, nur 1 Bit gesetzt). 
Das darf aber nicht sein.

Wir haben unser C-Programm weiter überprüft und folgern dass der Fehler 
im Widerstands-Netzwerk liegt. Wir sehen auch mit Lupe keine Lötfehler 
und vermuten Störeinflüsse der Lötstellen, Kabel, oder der Widerstände. 
Wir sind aber keine Experten.

Hat vllt jemand hier das schon mal gemacht und kann uns einen Rat geben?

vielen Dank für eure Hilfe
Eik

von Simon B. (nomis)


Lesenswert?

Wie sieht denn euer Widerstandsnetzwerk aus? Ist es ein R2R-Netzwerk?

Viele Grüße,
        Simon

von me (Gast)


Lesenswert?

Hallo,


ich würde mal versuche, den Code so zu ändern, daß die 255 Stufen 
jeweils manuell oder sehr langsam (Sekunden pro Stufe) durchlaufen 
werden. So müsste man relativ einfach messen können, ob die CPU Pins in 
der korrekten Reihenfolge geschaltet werden.


Gruß


ich

von Skua (Gast)


Lesenswert?

Zeigt doch mal den Aufbau und das Programm.

von RateRunde-Teilnehmer (Gast)


Lesenswert?

Eik schrieb:
> Wir haben als
> Test feste Werte auf Port A gegeben: 127 (0111 1111, 7 Bit gesetzt)
> führt zu einer höheren Spannung als 128 (1000 0000, nur 1 Bit gesetzt).
> Das darf aber nicht sein.

Vorrausgesetzt das Netzwerk ist korrekt verdrahtet:

Welchen Wert haben die Widerstände? Falls die Ports mit zu hohen Strömen 
belastet werden, wäre dieser Effekt vielleicht damit erklärbar, daß 
mehrere auf High-Pgel liegende Ports in der Summe mehr Strom und damit 
eine höhere Spannung liefern können - ungeachtet ihrer Gewichtung.

Ein Schaltplan der mindestens das Port und das Netzwerk enthält und mit 
konkreten Wertangaben zu den Widerständen sowie zur am Ausgang des 
Netzwerkes angeschlossenen Last verfeinert ist, wäre zur Klärung gewiß 
hilfreich!

MfG

von Floh (Gast)


Lesenswert?

Eik schrieb:
> Für Sinus und die anderen Funktionen erhalten wir allerdings wirre
> Kurven. Die Signale sind zwar regelmäßig, aber der Sinus ist nach unten
> abgeschnitten und hat 8 Treppen pro Phase. Es scheint als ob die Werte
> zwischen 0 und 255 nicht ordentlich dargestellt werden. Wir haben als
> Test feste Werte auf Port A gegeben: 127 (0111 1111, 7 Bit gesetzt)
> führt zu einer höheren Spannung als 128 (1000 0000, nur 1 Bit gesetzt).
> Das darf aber nicht sein.

Schreibt mal in die Endlosschleife rein, den Port immer um 1 zu erhöhen, 
also so was:

while(true)
{
  PORTA += 1;
}

Das müsste dann bei korrekter Verdrahtung des Netzwerks ein Rampensignal 
geben, ist ein Test dafür.
:-)

von Eik (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

vielen lieben Dank für eure Vorschläge. Ich habe ein Bild der Platine 
hochgeladen, das mag auf Experten bestimmt lustig wirken =)

Ja, es ist ein R2R-Netzwerk für 8 Bit, also mit 24 x 
8-kOhm-Widerständen. Also parallel je 2 Widerstände pro Bit und am 
unteren Bildrand in Reihe je ein Widerstand von Bit zu Bit hin zum 
Ausgang.

Je Eingang ist ein Kabel von der Platine zu einem Pin von Port A des 
Atmels gelötet, wir nutzen eine Steckverbindung. Der Atmel-Controller 
ist über USB angeschlossen und liefert am Oszilloskop max. ~1V Spannung. 
Wir haben natürlich überprüft, dass wir die Kabel in der richtigen 
Reihenfolge der Pins angeschlossen haben und jeweils Werte auf einzelne 
Pins gegeben und den Strom abgenommen, das sollte stimmen.

Das Bild "dreieck.jpg" soll eine ab- und aufsteigende Flanke eines 
Dreiecksignals darstellen. Leider wie gesagt, hat es absolut nichts von 
einer Rampenfunktion.

Unser Programm ist recht kompakt, um euch das runterladen zu sparen, 
steht der wichtige Teil nochmal unten.

Mit Masse und Last haben wir leider eher Halbwissen. Wir haben den 
Ausgang der Platine am unteren linken Bildrand mit dem Massepin von Port 
A verbunden. Es kann gut sein, dass wir dabei etwas noch nicht beachtet 
haben. Daher danke für Hilfe =)

lg
Eik



int delta = 1; // Phasenabstand
int time = 0; // Endloszähler
int current_function = 0; // Aktuelle Funktion 0..3, mit Joystick zu 
ändern
unsigned char functions[4][256]; // Vorberechnete Funktionswerte

int main(void) {
  init_functions(); // Berechne Funktionswerte

  for ( ; ; ) {
    function_generator(); // Gib nächsten Wert an Port A
  }
}

void function_generator(void) {
  time = (time + delta) % 256; // Erhöhe die Zeit um delta Schritte
  PORTA = functions[current_function][time];
}

void init_functions(void) {
  int i;

  for (i = 0; i < 256; ++i) {
    // sinus = functions[0]
    // rectangle = functions[1]
    // triangle:
    if (i < 128) { // Ansteigende Flanke, von 0..255
      functions[2][i] = (unsigned char)(2 * i + 1);
    } else { // Absteigende Flanke, von 255..0
      functions[2][i] = (unsigned char)(255 - (2 * (i - 128)));
    }

    // sawtooth = functions[3]
  }
}

von Simon B. (nomis)


Lesenswert?

In Eurem Code vermisse ich die Initialisierung des Ports.

D.h. vermutlich ist der noch als Input konfiguriert und ihr schaltet da 
die internen Pullups ein- und aus und kein einziges Element des 
R2R-Netzwerks wird auf 0 gezogen.
1
DDRA = 0xff;

Viele Grüße,
        Simon

von Eik (Gast)


Lesenswert?

Juhu, es funktioniert =)

Wir haben es nicht glauben können, aber wir hatten wirklich nur die 
Initialisierung des Ports vergessen. Da kommt aber nun wirklich kein 
Mensch drauf. Komisch, dass wir beim Messen der einzelnen Pin-Spannungen 
mit festen Werten trotzdem richtige Messergebnisse hatten. Vielleicht 
ging dann wirklich erst bei den Werten zwischen 0 und 255 alles drunter 
und drüber.

Wir haben die Rampenfunktion gleich ausprobiert, alles herrlich, auch 
Sinus, Sägezahn, Dreieck, Rechteck. Zum Glück war es doch nur ein 
Software-Fehler und wir mussten nicht nochmal alles auseinandernehmen.

vielen lieben Dank für die großartige Hilfe
Eik

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.