Arduino Rechteckgenerator

Von Patrick Kaiser 




Für viele Anwendungen wünscht man sich ein pulsierendes Signal - zum Beispiel für Basteleien mit TTL-Gattern der 74HCT-Reihe oder Bausteine, die Clock-Signale benötigen. Aber auch zur einfachen Erzeugung von Tönen ist das hier vorgestellte Programm nützlich. Wie im Beispiel 10.9 aus dem Buch nutze ich den Befehl "tone" bzw. die Bibliothek (dazu später mehr). Hier soll allerdings die Frequenz einfach über den eingebauten "Serial-Monitor" eingegeben werden können. Alternativ könnte man zur Steuerung auch das mitgelieferte Poti nutzen. Um Ungenauigkeiten zu vermeiden, habe ich aber hier darauf verzichtet. Es kann ein beliebiger Pin verwendet werden als Signalausgang verwendet werden. Auf diesem liegt dann ein Rechtecksignal zwischen 0 und 5 Volt an.

// Frequenz-/Rechteckgenerator

#define INLENGTH 5 //maximale Größe der Zahl
#define INTERMINATOR 'H' //'H' von 'Hz'

char inString[INLENGTH+2];
int inCount;

#define MinFreq 33
#define MaxFreq 65535
#define Ausgangspin 13 //muss kein PWM-Pin sein

unsigned int Frequenz = 100; //Hz (Maximum: 65535 Hz)

void setup(){

Serial.begin(9600);
Serial.println("Bitte angeben wieviel Hz ausgegeben werden sollen (mit 'Hz')!");

tone(Ausgangspin, Frequenz);
}

void loop(){
Eingabe(); //Eingabe-Funktion, die Eingabe-String entgegennimmt

//Zeichenkette -> Zahl
//Alternative: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1176289764
Frequenz=atol(inString);

//Bereich prüfen
Frequenz=constrain(Frequenz, MinFreq, MaxFreq);

Serial.print("Es wird gesetzt: ");
Serial.print(Frequenz,DEC);
Serial.println("Hz!");

tone(Ausgangspin, Frequenz);
}

void Eingabe(){
inCount=0; //Ziffern-Zähler rücksetzen

do
{
while (Serial.available()==0);
inString[inCount] = Serial.read();
if(inString[inCount]==INTERMINATOR) break;
if((inString[inCount]<'0')||(inString[inCount]>'9')){
//continue; //geht nicht
inCount--; //-> Workaround
}
}
while(++inCount < (INLENGTH+1));
Serial.flush();
}
Download p_frequenzgen3.zip



Seit der neuen Version 0019 der Entwicklungsumgebung wird außerdem eine Bibliothek "Tone" mitgeliefert. Alternativ kann man sie sich unter https://code.google.com/p/roguecode/wiki/ToneLibraryDocumentation herunterladen. Sowohl in der Bibliothek als auch beim "tone"-Befehl besteht der Nachteil, dass keine Frequenzen unter 32 Hz erzeugt werden können und die anderen Frequenzen oft ungenau sind. Da man aber als Bastler beides gut gebrauchen kann, empfiehlt es sich eine kleine Änderung an der Tone-Bibliothek vorzunehmen: Dazu öffnet man die Datei "Tone.cpp" im "library"-Verzeichnis (bei mir unter "arduino-0019\libraries\Tone") mit einem Editor. In Zeile 100 steht folgender Eintrag:

const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2, 1, 0 };

dieser kann zu

const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 1, 2, 0 };

abgeändert werden. Das führt dazu, dass der 16-Bit-Timer des Arduinos bevorzugt gewählt wird (vor den 8-Bit-Timern) und somit höhere Auflösungen und niedrigere Frequenzen möglich sind. Niedriger deshalb, weil der Timer (ein "Zähler") dann zeitlich länger Zählen kann bevor er überläuft. Mit der Modifikation ist es möglich, Frequenzen bis hinunter zu 2 Hz zu erzeugen. Leider ist mir das gleiche Kunststück beim "tone"-Befehl bislang nicht gelungen. Aus diesem Grund ist hier die Variante, die auf der Bibliothek aufbaut:

// Patrick's Arduino :-)
// Frequenz-/Rechteckgenerator

#include <Tone.h>

#define INLENGTH 5 //maximale Größe der Zahl
#define INTERMINATOR 'H' //'H' von 'Hz'

char inString[INLENGTH+2];
int inCount;

#define MinFreq 2
#define MaxFreq 65535
#define Ausgangspin 13 //muss kein PWM-Pin sein

unsigned int Frequenz = 2; //Hz (Maximum: 65535 Hz)

Tone Generator;

void setup(){

Serial.begin(9600);
Serial.println("Bitte angeben wieviel Hz ausgegeben werden sollen (mit 'Hz')!");
Generator.begin(Ausgangspin);

Generator.play(Frequenz);
}

void loop(){
Eingabe(); //Eingabe-Funktion, die Eingabe-String entgegennimmt

//Zeichenkette -> Zahl
//Alternative: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1176289764
Frequenz=atol(inString);

//Bereich prüfen
Frequenz=constrain(Frequenz, MinFreq, MaxFreq);

Serial.print("Es wird gesetzt: ");
Serial.print(Frequenz,DEC);
Serial.println("Hz!");

Generator.play(Frequenz);
}

void Eingabe(){
inCount=0; //Ziffern-Zähler rücksetzen

do
{
while (Serial.available()==0);
inString[inCount] = Serial.read();
if(inString[inCount]==INTERMINATOR) break;
if((inString[inCount]<'0')||(inString[inCount]>'9')){
//continue; //geht nicht
inCount--; //-> Workaround
}
}
while(++inCount < (INLENGTH+1));
Serial.flush();
}
Download p_frequenzgen2.zip

Mit Hilfe eines OWON-Oszilloskops (mit eingebauter,genauer Frequenzerkennung), kam ich mit einem Arduino (Atmega328) mit der beschriebenen Software-Modifikation zu folgenden Messungen:

genau:
2Hz
10Hz
20Hz
100Hz
200Hz
1000Hz
10kHz
20kHz

leicht nach oben schwankend/abweichend (1 bis 2 Hz):
5Hz -> 5,001Hz
50Hz -> 50,01Hz
60Hz -> 60,01Hz
2000Hz
2500Hz
5000Hz
15kHz -> 15,01kHz
40kHz
50kHz -> 50,01kHz
stärker schwankend/abweichend:
1Hz -> 2,102Hz (! -> deaktiviert)
70Hz -> 70,04Hz
80Hz -> 80,04Hz
90Hz -> 90,07Hz
7500Hz
30kHz -> 30,08kHz
60kHz -> 60,16kHz
65,5kHz (und größer) -> 65,58kHz



Wer viel Strom von dem Signal-Pin braucht, sollte einen anderen Pin als Pin13 benutzen, da dieser auf dem Board eine LED mit Widerstand vorgeschaltet hat. Außerdem hatte ich den Eindruck, dass sich die LED bei hohen Frequenzen negativ auf die Signalflanken auswirkt. Diesen Fehler konnte ich jedoch nicht reproduzieren - möglicherweise lag es also an meinem unkonventionellen und ungeschirmten Versuchsaufbau.
Privat nutze ich übrigens einen solchen ATTiny2313-basierten Generator mit zwei Tastern und HD44780-Display:





zurück