Signalgenerator und Frequenzmessung         


Elektronik-Labor   Projekte   AVR 


Auszug aus dem Arduino Messlabor Kap. 5.

 Signalgenerator bis 8 MHz

Der Timer 0 mit einer Auflösung von 8 Bit kann zur Erzeugung eines symmetrischen Rechtecksignals verwendet werden. Zur Initialisierung wird TCCR0A=0x42 gesetzt. Das folgende Register stellt den Vorteiler ein. Mit TCCR0B=0x00 ist der Generator abgeschaltet, mit TCCR0B=0x01 erhält er den vollen Takt von 16 MHz. Weitere Vorteiler-Stufen reichen bis zu einem Verhältnis von 1024. Die genaue Frequenz wird mit OCR0A = 255  (/256, kleinste Frequenz) bis OCR0A = 0 (/1, größte Frequenz) eingestellt. Der Zähler zählt aufwärts und springt jeweils auf 0, wenn OCR0A erreicht wird. Gleichzeitig wird dann der Ausgang OC0A am Port D6 getoggelt. Dadurch ergibt sich die höchste Frequenz von 8 MHz. Die tiefste Frequenz ist 16 MHz/2/1023 /256 = 30,528 Hz.

 

  TCCR0A = 0x42;  //Timer0 Toggle OC0A
  TCCR0B = 0x00;  //aus
 
OCR0A = 255;  

Zur Einstellung der Frequenz müssen zwei Bytes für den Vorteiler und den Timer übertragen werden. Hierzu wurde das Kommando 90 festgelegt.
 

    if (c==90){     //OC0A Frequenz
      TCCR0B = USART_Receive();
      OCR0A = USART_Receive();
    }

 

Im User-Programm führt jede Änderung am Frequenzregler HScroll8 zu einer neuen Ausgabe. Für eine möglichst feinstufige Einstellung werden fünf Bereiche mit unterschiedlichem Vorteiler (1, 8, 64, 256, 1024) verwendet. Die ausgegebene Frequenz wird berechnet und auf der Oberfläche angezeigt.

Private Sub HScroll8_Change()
  d = HScroll8.Value
  If d = 0 Then pre = 0: n = 0
  If d > 0 Then
    pre = 5
    n = 256 - d
    If n > -1 Then f = 8000000 / 1024 / (n + 1)
  End If
  If d > 192 Then
    pre = 4
    n = 448 - d
    If n > -1 Then f = 8000000 / 256 / (n + 1)
  End If
  If d > 384 Then
    pre = 3
    n = 640 - d
    If n > -1 Then f = 8000000 / 64 / (n + 1)
  End If 

  If d > 608 Then
    pre = 2
    n = 864 - d
    If n > -1 Then f = 8000000 / 8 / (n + 1)
  End If
  If d > 832 Then
    pre = 1
    n = 1088 - d
    If n > -1 Then f = 8000000 / (n + 1)
  End If 

  If f < 100000 Then Label11.Caption = "D6 " + Str(Round(f)) + " Hz"
  If f >= 100000 Then Label11.Caption = "D6 " + Str(Round(f/ 1000)) + " kHz"
  SENDBYTE 90
  SENDBYTE pre
  SENDBYTE n
End Sub

 

 

 
Ausgabe und Anzeige eines Signals von 1000 Hz

 
Viele wichtige Frequenzen können genau eingestellt werden, die meisten Frequenzen sind jedoch krumme Teile von 16 MHz. Die Auflösung ist bei kleinen Frequenzen hoch und wird gegen Ende immer gröber. Die vier obersten Frequenzen sind 2 MHz, 2,667 MHz, 4 MHz und 8 MHz. Zum Vergleich: Der DDS-Generator hat überall eine Auflösung von ca. 1 Hz, reicht aber nur bis 5 kHz.

Mit dem Rechteckgenerator lassen sich Frequenzen weit oberhalb der Abtastrate des Oszilloskops einstellen. Zuverlässige Messungen mit dem Oszilloskop sind aber nur bis zur halben Abtastrate, also bis etwa 31 kHz möglich. In der Nähe der Abtastrate oder ihrer Vielfachen werden völlig falsche Bilder geliefert. Die doppelte Abtastrate ist 125 kHz. Stellt man den Rechteckgenerator auf 127 kHz ein, erscheint ein scheinbares Signal von 2 kHz, also die Differenzfrequenz. Dieses Problem kann prinzipiell bei jedem DSO beobachtet werden, während es bei einem analogen Oszilloskop niemals auftritt.

 

 
Messung von vermeintlichen 2 kHz bei tatsächlichen 127 kHz

 
Auffällig sind auch die schrägen Flanken im Oszillogramm trotz der tatsächlichen Rechteckform. Sie entstehen durch die endliche Abtastzeit des AD-Wandlers. Der Sample-And-Hold-Kondensator braucht eine gewisse Zeit, um sich auf die tatsächliche Spannung aufzuladen. Bei sehr hohen Frequenzen ändert sich der Zustand aber bereits innerhalb der Abtastzeit. Dadurch werden in den Übergängen Spannungen zwischen den Extremwerten gemessen. Bei sehr hohen Frequenzen werden sogar Dreieckspannungen angezeigt.

 

 Dreieckanzeige bei 308 kHz

 

Frequenzmessung

 

Der Digitalzähler verwendet den Timer 1 mit einer Auflösung von 16 Bit. Weil man damit nur bis 65535 zählen kann, wird bei jedem Überlauf ein Interrupt ausgelöst, um einen zusätzlichen Zähler zu erhöhen. Das widerspricht zwar dem Grundsatz, dass es nur einen aktiven Interrupt geben soll, um die laufende DDS-Ausgabe nicht zu stören. Allerdings tritt der Timer1-Interrupt nur extrem selten auf und nur dann, wenn gerade Frequenzen über 65 kHz gemessen werden.

ISR (TIMER1_OVF_vect)
{
  fh1++;
}
… 

  TCCR1A = 0x00;
  TCCR1B = 0x07;  //Timer1 Input
  TIMSK1 = 0x01;  //Timer1 Overflow Interrupt
 
TCCR1C = 0;

 
Zur Initialisierung wird der Zähler an den Eingang T1 am Port D5 gelegt. Zusätzlich wird der Interrupt freigegeben. Zur Steuerung der Torzeit wird der Timer2-Interrupt mitverwendet. Hier wird ein Zeitzähler t eingerichtet. Bei t = 0 wird der Timer1 zusammen mit seinem externen Highbyte fh1 zurückgesetzt. Bei t = 1 wird der Timer gestartet. Und genau eine Sekunde später wird er gestoppt und ausgelesen.

ISR (TIMER2_OVF_vect)
{
  PORTB |= 1;
  …
  t++;
  if(t==0){ TCCR1B = 0x00; TCNT1=0; fh1=0;}
  if(t==1){ TCCR1B = 0x07;}
  if(t==62501){ TCCR1B = 0x00;f=TCNT1; fh2=fh1;}
 

  PORTB &= ~1;
}

Die unteren 16 Bit befinden sich dann in f. Zusätzlich gibt es die oberen 8 Bit in fh2. Zur Übertragung an den PC wurde das Kommando 91 definiert. 

     if (c==91){       //Timer 1 Frequenz
      USART_Transmit(fh2);
      USART_Transmit(f>>8);
      USART_Transmit(f & 0xFF);  
    }

Im Userprogramm wird die Frequenz einmal pro Sekunde neu angezeigt. Dazu muss der Messwert innerhalb der Timerfunktion ausgelesen werden.  Insgesamt drei Bytes werden zu einer 24-Bit-Zahl zusammengefügt.

CLEARBUFFER
 SENDBYTE 91
 f = READBYTE
 f = 256 * f
 f = f + READBYTE
 f = 256 * f
 f = f + READBYTE
 
Label9 = "D5 " + Str(f) + " Hz"

 
Der Frequenzmesser arbeitet permanent im Hintergrund ohne die DDS-Ausgabe und das Oszilloskop zu stören. Verbindet man den Eingang D5 mit dem Ausgang D9 (= B0), kann die Abtastrate und der regelmäßige Aufruf der Timer2-Interruptfiunktion überwacht werden. Hier werden zuverlässig 62500 Hz angezeigt. Sollte jemals in Folge einer Firmware-Erweiterung diese Frequenz schwanken oder absinken, weist dies auf einen Fehler hin, der durch zu viel Zeit im Interrupt verursacht wurde.

 

 

Messung der Abtastfrequenz an D8

 

 

Messung der DDS-Ausgangsfrequenz von 1000 Hz

 

Zur Messung der DDS-Frequenz eignet sich am besten der Rechteck-Ausgang D7 bzw. D4. Hier findet man teilweise Abweichungen von einem Hertz, die teilweise durch Rundungsfehler entstehen. Üblicherweise schwankt das unterste Digit eines Frequenzzählers, weil die Signalfrequenz meist völlig asynchron zur Zeitbasis des Zählers ist.

Die Frequenz von 1 kHz wird in diesem Fall auch durch das Oszilloskop bestätigt, mit dem gleichzeitig das entsprechende Sinussignal gemessen wird. Allerdings kann das Oszilloskop nur Frequenzen unterhalb 31 kHz messen. Der Frequenzzähler arbeitet dagegen bis 8 MHz.

 

 

Messung von 8 MHz an D6

 

Bei der höchsten Messfrequenz von 8 MHz wird eine Abweichung von 4 Hz gemessen. Diese Abweichung ist durch Rechenzeit in der Timer2-Funktion begründet, die zu einer geringfügigen Verlängerung der Torzeit führen. Genauer lässt sich dieser Zeitfehler auf 0,5 µs eingrenzen.

Insgesamt hat ein Frequenzzähler scheinbar eine hervorragende Genauigkeit. Man muss allerdings bedenken, dass alle gemessenen Signale vom gleichen Takt abgeleitet sind, nämlich vom Systemtakt des Arduino. Leider verwendet der Controller keinen Quarz, sondern einen Keramik-Resonator mit 16 MHz. Genaue Messungen zeigen, dass dieser eine Abweichung bis zu rund 0,3% aufweisen kann, also etwa 50 kHz bei 16 MHz. Bei der angezeigten Frequenz von 8 MHz ist also ein Fehler bis 25 kHz möglich.

Diese Toleranzen müssen bei jeder Frequenzmessung berücksichtigt werden. Es gibt allerdings oft Aufgaben, bei denen es nur auf eine relative Genauigkeit oder die Beobachtung von Frequenzänderungen ankommt. In anderen Fällen kann man überlegen, den Keramikresonator auszubauen und durch einen Quarz zu ersetzen.

 

 

 


Elektronik-Labor   Projekte   AVR