habe folgendes Verständnis Problem: Ich möchte gerne die 16 bit Auflösung des Nano verwenden, um genaure Taktsignale mit höherer Freq. zu erzeugen. Habe das so realisiert: 16bit Auflösung an Pin9 mit 16Mhz und einem prescaler von 256. Aktuell lasse ich 1 Hz ausgeben mit 50% duty cycle.
Wie kann ich denn Timer/Taktgeber nun wieder korrekt "ausschalten" bzw. nach gegebener Zeit wieder aktivieren?
Aktuell habe ich das so realisiert, dass ich den duty cycle, also OCR1A auf 0% setzte, aber tatsächlich lauft der timer ja weiter und bin auch nicht ganz zufrieden mit dieser Lösung.
Hier der Code:
void setup() {
// Set-up fast PWM on the Arduino UNO at 1Hz on Digital pin D9
pinMode(9, OUTPUT); // Set digital pin 9 (D9) to an output
//pinMode(10, OUTPUT); // Set digital pin 10 (D10) to an output, and include _BV(COM1B1)
TCCR1A = 0; // Reset TCCR1A Register
TCCR1B = 0; // Reset TCCR1B Register
TIMSK1 = 0; // Reset TIMSK1 Register (disable Timer Compare Interrupts)
TCNT1 = 0; // Start 0
TCCR1A = _BV(COM1A1) | _BV(WGM11); // Enable the PWM output OC1A on digital pins 9 (Include _BV(COM1B1) for dp 10)
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12); // Set fast PWM and prescaler of 256 on timer 1 (if CS12 and CS10 active: presc.: 1024 etc. datasheet)
ICR1 = 62499; // Set the PWM frequency to 1Hz: 16MHz/(256 * 1Hz) - 1 = 62499
OCR1A = ((ICR1 + 1) / 2) - 1; //50% duty cycle
}
void loop() {
}
Ich versuche Kameras mit dem Takt zu triggern, das heißt die laufen mit z.B. 30Hz für 2min. Danach dürfen diese nicht mehr weiterlaufen und kein Takt mehr anliegen.
Das mit 0% duty cycle funktioniert auch diesbezüglich, aber nur bei niedrigen Frequenzen, bin ich bei 1kHz und gehe auf 0% duty cycle habe ich trotzdem bei jeder Taktflanke spikes im Oszi, und die Kameras reagieren schon auf die Taktflanke und zweitens scheint mir das nicht die korrekte vorgehensweise zum Beenden des Taktgebers bzw. bei beispielsweise der Funktion analogwrite(Pinxy, value), schreibe ich ja eine 0 um das Signal zu beenden und eine z.B. 100 für 100Hz etc.
analogWrite(pin, value) -> Value steht ebenso für den duty cycle von 0-255 und leider gibt es in Kombination mit dieser Funktion immer wieder Probleme...
Suche einfach einen elegante Weg, die Taktgeber auszuschalten ohne die Register zu reseten und neu zu "kalibrieren" oder den duty cycle auf 0 zu variieren^^
Die Arduino Software schaltet jedesmal wenn man digitalWrite() auf PWM Pins macht erst mal PWM aus. Über die COMn Pins. Damit kannst du über ein einzelnes Bit den Timer von den externen Pins trennen
Und bei den Extremwerten in analogWrite() wird wiederum digitalWrite() gemacht. Nicht PWM
Die Spikes die du auf dem Oszi siehst entstehen im leicht fehlerhaften Fast PWM Mode. Wenn eigentlich 0 sein soll, also aus, produziert der Modi Nadelimpulse. Wenn es die Frequenz zulässt, nimm einen höheren Modi. Die machen solchen Mist nicht.
vielen Dank für deine Antwort, genau das was ich gesucht habe!
Habe auch mal analogWrite(pin, val) probiert und funktioniert auch. Mich würde nur interessieren, ob das ok ist die Funktion analogWrite zu verwenden, wenn ich schon extra FastPWM aktiviert habe, um eigentlich solche Funktionen zu vermeiden^^
wenn du die Timereinstellungen änderst, dann stimmt von analogWrite das DutyCycle nicht mehr. Die Timer sind von Arduino.cc so eingestellt das die 8 Bit Auflösung mittels analogWrite passt. Das ist aufeinander abgestimmt. Fummelt man dran rum, muss man alles selbst einstellen. Du musst dich entscheiden, bleibst bei Standard oder nicht ...
Nur zum besseren Verständnis, da mir die Erfahrung fehlt. Ist das die korrekte Einstellung für die Fast PWM 16bit Auflösung? Bzw. Ich benötige: 1Hz bis ca 15kHz mit höherer Auflösung (hier 16bit)
pinMode(9, OUTPUT); // Set digital pin 9 (D9) to an output
//pinMode(10, OUTPUT); // Set digital pin 10 (D10) to an output, and include _BV(COM1B1)
TCCR1A = 0; // Reset TCCR1A Register
TCCR1B = 0; // Reset TCCR1B Register
TIMSK1 = 0; // Reset TIMSK1 Register (disable Timer Compare Interrupts)
TCNT1 = 0; // Start 0
TCCR1A = _BV(COM1A1) | _BV(WGM11); // Enable the PWM output OC1A on digital pins 9 (Include _BV(COM1B1) for dp 10)
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12); // Set fast PWM and prescaler of 256 on timer 1 (if CS12 and CS10 active: presc.: 1024 etc. datasheet)
ICR1 = 62499; // Set the PWM frequency to 1Hz: 16MHz/(256 * 1Hz) - 1 = 62499
OCR1A = ((ICR1 + 1) / 2) - 1; // 50% duty cycle
Und ist es korrekt, dass ich über folgende Formel 16MHz/(256 * Frequenz) - 1 = ICR1 die Frequenz berechnen kann.
deine Timereinstellung für Mode 14 stimmen soweit.
Deine Formel für TOP (ICR1) stimmt auch.
Jeder Modi hat seine eigene Formel.
Womit ich nicht klar komme ist die Berechnung von OCR1A.
Du musst sicherstellen das der Comparewert nie größer wie TOP ist, sonst wird der Compare nie ausgelöst.
TOP = 62499 >> 1Hz
TOP = 3 >> 15kHz
Was heißt das für dich?
Mit konstanten Prescaler hast du ...
für 1Hz eine Auflösung von 62500 Schritten,
für 15kHz eine Auflösung von nur 4 Schritten
16 Bit Timer bedeutet nicht das man immer 16Bit zur Verfügung hat. Es stellt das mögliche Maximum dar des Umfangs aller Einstellmöglichkeiten.
Meine Empfehlung wenn du in die Timer tiefer einsteigen möchtest. Programmiere dir einen Frequenzgenerator inkl. Duty Cycle Einstellung. Daran kannste dich austoben. Für deine max. 15kHz nimm den Timer Mode 9 oder 11. Damit sind TOP und Compare Register gebuffert, kannste jederzeit ohne Gefahr ändern und die Modi produzieren keine Spikes.
Ich empfehle dir auch bei allen Timereinstellung den Timer erst zu starten wenn alle Einstellungen gemacht sind.
Also heißt das, dass ich für eine Frequenz von 15kHz für eine Einstellung mit prescaler 256 eigentlich folgenden Wert in das Register ICR1 schreiben müsste:
16MHz/(256 * 15kHz) - 1 = 3.167
ICR1 = 3.167;
Wenn ich das mache, und mir das Register dann ausgebe:
Serial.println(ICR1);
Erhalte ich ICR1 = 3 und nicht meinen eingegebenen Wert von 3.167 und demnach nicht 15kHz sondern wie im angehängten Bild (rechts unten zu sehen) ~15.65kHz.
Wenn ich das richtig verstehe rundet das Register, weil es nur integer Werte aufnehmen kann?
Gibt es eine Möglichkeit oder eine andere Option, dass ich exakt 15kHz erhalte, ohne dass im Register gerundet wird?
(Oder wäre es sinnvoll, da ich die Frequenzen ziemlich genau benötige, den prescaler zu erhöhen, da ich dann 16bit für 16Mhz/1024 = max 15525 Hz habe oder einen anderen Arduino zu verwenden, wie den Due, welcher 32bit timer realisiert?)
natürlich können die Register nur Ganzzahlen aufnehmen. Das hatte ich vorausgesetzt das du das weißt.
Und ja du musst den Prescaler ändern um die Genauigkeit der Zielfrequenz zu erhöhen. TOP sollte immer im oberen Bereich des Möglichen liegen für maximale Genauigkeit.
Erstelle dir eine Exceltabelle worin du deine Zielfrequenz eingibts und die Tabelle gibt dir zu allen Prescalern den TOP Wert aus inkl. Abweichung. Dann sieht man schnell was wie möglich ist. Das ganze noch umgekehrt mit TOP Wert Eingabe und Frequenzausgabe und das alles für alle Timermodi.
Prescaler 1024? Du musst den Prescaler verkleinern, nicht erhöhen. Prescaler ist die Grobeinstellung, TOP die Feineinstellung. Alles hängt miteinander zusammen.