Hallo,
beschäftige mich gerade wegen meiner Bachelorarbeit mit dem Arduino UNO,
momentan benötige ich nur ein Rechtecksignalburst von 6-8 Impulsen das sich immer wider wiederholt.
diese werden verstärkt und auf einen Ultraschalwandler mit 40kHz gegeben.
Problem ist das das Rechtecksignal jittert, auf dem Oszi sieht man wie das Rechtecksignal manchmal richtig ist und ab und zu aber auch verschoben und falsch ausgegeben wird. habe 2 verschiedene Arduino Uno Bords versucht.
Habe das Jittern als Video mal hochgeladen
An was liegt das ? und kann ich das irgendwie beheben ?
Unten sieht man den einfachen Quellcode !
int outPin = 13; // digitaler Pin 13
void setup()
{
pinMode(outPin, OUTPUT); // setzt den digitalen Pin als Ausgang
}
void loop()
{
for(int i=0;i<7;i++){
digitalWrite(outPin, HIGH); // schaltet den Pin an
delayMicroseconds(7); // hält für 7 Mikrosekunden an
digitalWrite(outPin, LOW); // schaltet den Pin aus
delayMicroseconds(10); // hält für 10 Mikrosekunden an
}
delay(20); // ms
}
Microseconds kriegst du so nur in 4er Schritten. Und digitalWrite() selbst dauert auch schon ein bisschen.
Mit Timern sollte man 40 kHz genauer hinkriegen, und irgendwie auch 8 Pulse davon alle 20 ms.
Ich würde Richtung "IR - Fernbedienungscode senden" suchen, die 38 kHz in 40 ändern und dann rauskriegen wie das mit der Codierung zu vereinfachen ist. Da ist deine Anforderung ja deutlich einfacher.
Wie gesagt Timer1 oder Timer2 verwenden. Der 8 Bit Timer2 reicht bei diesen kurzen Taktzeiten.
Wenn symmetrische Impulse reichen, kann man den CTC Modus verwenden. Dann kann man das Schalten des Pins per Hand im Compare Match Interrupt machen und gleichzeitig dort die Anzahl der Impulse zählen. Und nach x Impulsen den Timer wieder deaktivieren.
Achtung: es gibt beim Atmega328 ein, zwei kleinere Unterschiede zu dem da. Vor allem hat jeder Timer ein eigenes Interrupt Masken Register TIMSKn, anstatt ein gemeinsames Register für alle Timer. Im Zweifelsfall ins Datenblatt schauen.
Aber der Rest ist glaube ich identisch.
Das schalten von Pin 13 selbst geht so in zwei Taktzyklen, statt den 3-4µs die digitalWrite() braucht:
PINB |= _BV(5);
Das toggelt bei jedem Aufruf den Pin.
Oder jeweils eine 0 oder 1 auf das Ausgangsregister PORTB schreiben:
PORTB |= _BV(5); //Pin auf 1 setzen
PORTB &= ~_BV(5); //Pin auf 0 setzen
HDR_Michel:
Problem ist das das Rechtecksignal jittert, auf dem Oszi sieht man wie das Rechtecksignal manchmal richtig ist und ab und zu aber auch verschoben und falsch ausgegeben wird. habe 2 verschiedene Arduino Uno Bords versucht.
An was liegt das ? und kann ich das irgendwie beheben ?
Das liegt im wesentlichen an ausgeführten "Interrupts" im System, die den laufenden Code an jeder Stelle zwecks Behandlungs des Interrupts unterbrechen können. Wenn Du in Deinem Code (oder verwendeten Libraries) keine Interrupts aktivierst, kämen beispielsweise auch der Timer-Interrupts in Frage, mit dem die Arduino-Software standardmäßig die Zeit zählt, oder bei aktivierter serieller Schnittstelle die Interrupts zum Senden und Empfangen von seriellen Zeichen. Die Laufzeit Deines Codes (auch delay-Zeiten) verlängert sich dann jeweils um die Dauer der Interrupt-Serviceroutine, die zwischendurch läuft.
Ein exakteres Timing von zeitkritischem Code erreichst Du zum Beispiel, indem Du die Interrupts während der Zeit blockierst, die so genau bestimmt werden soll. Beispiel:
void loop()
{
noInterrupts();
// zeitkritischer Code hier
interrupts();
// sonstiger Code hier
}
Ansonsten hast Du hier ja schon Hinweise zur Programmierung von Timern bekommen.
Die Bit Makros enthalten die Bit-Nummern der Bits und das BV Makro macht (1 << Nummer), also schiebt das entsprechende Bit n mal nach links. Durch das Oder werden dann die entsprechenden Bits gesetzt.
40kHz sollte OCR2A = 199 sein
Das COM2A0 Bit hat den Vorteil, dass Pin 11 (auf dem UNO) automatisch getoggelt wird. Man könnte das mit dem Compare Match Interrupt verbinden um die Anzahl der Impulse zu zählen. So wird der Pin in Hardware geschaltet und nicht von anderen Interrupts verzögert, aber man bekommt das Schalten trotzdem mit und kann es zählen. Wenn man das Schalten per Hand in der ISR macht, könnte das eventuell immer noch nicht passen, da sich Interrupts nicht gegenseitig unterbrechen. Aber beim Zählen macht es nichts wenn das später geschieht.
@Serenifly
Danke für den Code, echt super !
Funktioniert wunderbar !
Habe den Code ein bisschen abgeändert um ein PWM Signal zu bekommen, da meine nachfolgende Transistorschaltung nicht so sauber schaltet wie der Ausgang des Arduino. Deshalb schreibe ich abwechselnd 2 verschiedene Comparewerte in das Compareregister
Wie gesagt, wenn du PWM willst gibt es auch richtige PWM Modi, die diese Umschaltung automatisch für dich machen. Dafür gibt es bei MaxEmbedded auch Code in Part II (für Timer0, aber das kann man anpassen). Mit PWM per Hand kenne ich mich aber nicht aus.
Aber wenn es so geht, kannst du es auch lassen
Wobei compareSwitch nicht global sein muss, da das nur in der ISR verwenden wird. Das kannst du genau wie counter lokal und static machen