ich suche eine Möglichkeit um bei einem Druck auf entsprechende Taster folgende Pulsformen an einem Ausgang eines Leonardos zu erzeugen:
Taster 1: 2us off, 198us on, 2us off usw..
Taster 2: 40us off, 160us on, 40us off usw..
Taster 3: 1ms off, 99ms on, 1ms off usw..
Taster 4: dauerhaft off
Kein Taster gedrückt: dauerhaft on
Ich habe mich nun schon ein bisschen zu fast PWM eingelesen und hatte irgendwo einen Verweis auf das TOP-Register der Timer zum Erreichen spezieller PWM-Frequenzen gefunden. Allerdings war das soweit ich weiß auf den Arduino Uno mit dem Atmega328 statt dem Leonardo mit dem 32u4 bezogen und der Link ist leider unauffindbar..
Naja, wenn ich mich richtig entsinne, müsste ich für
Taster 1 das PWM Signal invertieren, die 16MHz durch 8 teilen, 4 Takte "on" und das TOP-Register auf 400 stellen
Taster 2 das PWM Signal invertieren, die 16MHz durch 8 teilen, 80 Takte "on" und das TOP-Register auf 400 stellen
Taster 3 das PWM Signal invertieren, die 16MHz durch 64 teilen, 250 Takte "on" und das TOP-Register auf 25000 stellen
Taster 4 den Ausgang dauer-LOW setzen
und ansonsten den Ausgang dauer-HIGH setzen
Für Taster 1 und 2 bräuchte ich dann mindestens einen 9bit-Timer, für Taster 3 einen mit mindestens 15 Bit. Zum Glück enthält der 32u4 zwei 16bit-Timer, von dem einer aber wohl auch von der Arduino-Library genutzt wird, was dank Timer-Interrupts zu Problemen führen könnte?
Da ich leider absolut keine Ahnung von den entsprechenden Registern habe, könnte mir jemand einen passenden Code in Arduino schreiben oder mir entsprechende Hilfestellung leisten? Der Leonardo muss nichts anderes tun, aber die Timings müssen so präzise wie nur irgend möglich sein.
Zum Glück enthält der 32u4 zwei 16bit-Timer, von dem einer aber wohl
auch von der Arduino-Library genutzt wird, was dank Timer-Interrupts zu
Problemen führen könnte?
Es gibt nicht "die Arduibo-Library".
Welche Timer benutzt werden, hängt von den von dir in deinem Programm verwendeten Libraries ab.
Wie genau müssen die angegebenen Zeiten eingehalten werden?
Solche Geschichten bedingen ein gnadenloses Einarbeiten in die Register, denn mit einer library hat schon jemand vorgedacht, was der Benutzer denn allenfalls moechten koennte. Du wuerdes dann alls diese Modi durchprobieren, und allenfalls feststellen, dass ein Mode knapp so waere wie gewuenscht, und mit zwei Tagen Verzoegerung das Kapitel zu den Registern durchlesen.
Und vergiss mal Pulse aufgrund von Tasten... die koennen Prellen, und was soll dann geschehen, resp funktioniert das Konzept dann immer noch ?
Wenn die Taster nur zum Einschalten der Impulsfolge
dienen, ists kein Problem.
Soll aber der Impuls direkt vom Taster ausgelöst werden,
würde ich durch den Taster ein externes Flipflop triggern, was dann
quasi vom 1. Prellschlag des Tasters gesetzt wird und vom Prozzi dann zurückgesetzt wird.
Du mußt aber die entsprechenden Interruptroutinen selbst
schreiben und optimieren.
ich sehe da stumpf 2 Möglichkeiten, wenn die Tasten nicht parallel genutzt werden sollen.
Entweder den CTC Timer Mode nutzen und die Pulslängen aufaddieren lassen und entsprechend den Pin umschalten. Wobei das Pin schalten direkt im zugehörigen Register erfolgen muss, digitalWrite ist mit 4µs Verzögerung zu langsam bei deinen Anforderungen.
Oder wenn es blockieren darf, dann jeweils eine Sequence schreiben mit for Schleifen und NOPs. Entsprechend geduldig anpassen bis die Zeiten stimmen.
Ist das immer derselbe Ausgang? Was passiert, wenn zwei Knöpfe gedrückt werden?
Billige, schnelle Lösung: Timer mit 1 uS-Interrupt zählt Variable hoch, Interruptroutine setzt je nach Wert Pin hoch oder niedrig oder den Wert zurück.
Georg hast recht, mit PWM geht das, mittels Timer Hardwarepin ist das absolut präzise. Hatte nicht gleich geschnallt das die Pulszeiten gleich bleiben.
Habe das einmal ungetestet für die erste Pulsfolge geschrieben.
2µs + 198µs = 200µs Periodendauer = 5000Hz
Die Formel für Phase Correct Mode stellt man nach TOP um und erhält für Prescaler 1 die Einstellung 1600.
200µs = 1600 TOP
Demzufolge entsprechen 2µs = 16 für Compare
Jetzt kannst du dir für den Timer verschiedene Settings anlegen und entsprechend je Taster aufrufen usw.. Den Rest kannste bestimmt selbst.
1
constbytepulsPin{10};// OC1B bzw. PB6 nicht invertiert, IRFxxxx Mosfet
2
3
voidsetup(void)
4
{
5
initTimer1();
6
digitalWrite(pulsPin,HIGH);// OC1B bzw. PB6 nicht invertiert
Die Taster sollen nur zur Auswahl des Ausgangssignals dienen. Die entprelle ich mit mehrfachem Auslesen mit kurzem Delay und priorisiere sie sodass sie sich nicht gegenseitig überschreiben.
Kapitel 14 - Timer 1. Table 14-3.
Es muss das Bit COM1B0 zusätzlich gesetzt werden.
Die erste '1' steht für Timer 1 >> 'n'
'B' für genutzten Kanal, es soll ja Pin OC1B schalten, deswegen auch OCR1B als Compare-Match-Register.
'0/1' am Ende für das Bit
Dann sollte das invertiert laufen.
Für 100ms Periodendauer wirst du den Prescaler auf 64 ändern müssen.
Baue die Funktion "changeTimer1" auf einen 3. Parameter um und übergebe den passenden Prescaler gleich mit. Dann ist jede Änderung weiterhin nur mittels Parameterübergabe lösbar. Ansonsten erstmal rumspielen, kräftig ausprobieren, auch mal im Manual lesen und mit allen warm werden.
Leider waren die Tests heute nicht erfolgreich. Die einzige Zeile, die einen Einfluss auf den Ausgangszustand hat, ist
digitalWrite(pulsPin, HIGH);
Da millis und andere Arduino- Bibliotheken wohl die ersten Timer nutzen, habe ich den Code dann auf Ausgang 6 (PC6) und Timer 3 umgeschrieben. Auch das war leider erfolglos.
Leider finde ich auch keinen Beispielcode online. Wie kann ich weiter vorgehen?
bin den Sketch nochmal durchgegangen, ich kann erstmal kein Problem feststellen. Teste mal wie gesagt den IDE Blinksketch, da müßte die Board Led 13 blinken. Danach kannste Pin 10 testen ob der Pin blinkt.
Wird fehlerfrei kompiliert?
Wird das Programm übertragen?
Irgendwelche Fehlermeldungen?
In der IDE > Datei > Voreinstellungen:
Ausführliche Ausgabe während: beide Haken rein
alle Compiler Warnungen einschalten
ich habe das jetzt auf meinem Mega2560 getestet, da ist PB6 Pin 12. Man muss tatsächlich das initTimer1() nach pinMode ausführen. Da überschreibt die DDRx Einstellung die vorherige Timer-Pin Änderung. Hatte ich auch nicht mehr dran gedacht.
Allerdings ist das Konstrukt mit den while-Schleifen nicht wirklich elegant. Wie würde man so etwas lösen wenn der MC während dem Warten auf ein Loslassen etwas anderes tun soll?
Zur Frage. Lässt sich mit Blockadefreier Programmierung lösen. Schau dir das IDE Bsp. BlinkWithoutDelay an. Man verwendet den Arduino typischen Millisekundenzähler den man mit millis() jederzeit abfragen kann. Vergleiche das mit Differenzzeitenbildung mit der Armbanduhr. Damit kann man 24h bzw. nur das Ziffernblatt betrachtet max. 12h an Zeitdifferenzen bilden. Also wieviel Zeit vom letzten draufgucken vergangen ist. millis() zählt 32Bit und das reicht für Differenzen von 48 Tagen. Man muss nur für alle Variablen die mit Zeiten und millis zu tun haben unsigned long bzw. uint32_t verwenden. Dann gibt es keine Probleme.
Und wegen deinem Spaghetti Code, so nennt man das mit deinen 4 Einzeltaster, man hat Code Dopplungen die alle gepflegt werden müssen, kannst du dich mit Arrays und for Schleifen befassen. Ggf. schon mit struct. Motto: Gleiche Dinge zusammenfassen.
Übrigens wird Arduino in C++ programmiert. Falls du in Büchern nachschlagen möchtest. Da reicht erstmal ein C++11 Buch.
jetzt sind die Funktionen verstümmelt. Nur wegen den Änderungen muss man nicht den kompletten Timer jedesmal neu initialisieren. Die Funktionsnamen machen auch nicht mehr das für was sie gedacht waren. Mir gefällt das ehrlich gesagt nicht.
Heute habe ich mir den Code mit dem Oszilloskop angesehen. Dabei viel als erstes auf, das der Puls immer mit einer Periodendauer Verzögerung ausgelöst wurde. Das konnte ich über Umschalten in den Fast PWM Mode 15 lösen.
Danach habe ich noch ziemlich viel rumgefummelt, weil ich sporadische Pulse im Bereich von 250ns während initTimer und diverse andere Problemchen hatte und bin nun beim Code im Anhang angelangt.
Wie man sieht, werden in initTimer1 während D0 am Oszilloskop high ist diverse Variablen gesetzt, während D1 die Compare Output (OC1B) Options gesetzt und während D2 der Timer gestartet.
Bei einem geringen Duty Cycle wie in Case 1 geht das zu 99% problemlos und der Ausgang geht nach dem Starten des Timers mit der richtigen Pulsdauer auf low (Anhang O1.png).
Wenn der Duty Cycle aber deutlich höher wird (Case 2), geht der Ausgang bei rund 50% der Tasterbetätigungen bereits während dem Setzen der Compare Output (OC1B) Options auf low und der erste Puls ist zu lang (Anhang O2.png).
Verschiebe ich das Setzen der Compare Output (OC1B) Options hinter das Starten des Timers, wird der erste Puls komplett weggelassen (Anhang O3.png) oder der Ausgang geht noch während dem Setzen los und ist etwas zu kurz (Anhang O4.png).
Woher kommt das? Wie überrede ich den Timer dazu, diese beiden Fehlerfälle nicht zu zeigen?
Ich habe es schon mit
[C]
PORTF = 2; //D1 high
TCNT1 = periode - 10 ;
TCCR1A |= _BV(COM1B0) | _BV(COM1B1);
[/C]
nach dem Starten des Timers versucht um immer die Startbedingung zu treffen, was das Verschlucken des ersten Pulses zwar beseitigt, aber dann ist bei etwa 50% der Betätigungen der erste Puls etwas Verzögert, was zu erwarten und verschmerzen ist (Anhang O5.png) und bei den anderen 50% zu lang (Anhang O6.png), was vermieden werden muss.
@ Falk:
Ich habe gestern nicht gesehen das die Änderungen der Funktionen schon vom TO kamen. Entschuldigung.
@ TO:
Dieses Zusammengewürfel von unterschiedlichen Funktionen macht man nicht. Der Code wird unwartbar. Außerdem erwartet man das die Funktion das macht was ihr Name aussagt. Nicht weniger aber auch nicht mehr. Jetzt haste den Salat mit den ewigen Inits. Bevor du die Funktionen verbiegst solltest du den Timer verstehen. Ich habe bewusst den Mode 11 ausgewählt. Hat Doppel Bufferung der Register und macht keinen Mist wie Fast-PWM. Fast-PWM erzeugt mit Compare 0 immer Spikes. Außerdem macht es gerade Sinn Doppel Bufferung zu verwenden, damit er zum richtigen Zeitpunkt seine Updates macht. Warum das jetzt im Tasterbetrieb stören sollte wenn es noch eine Periode dauert weiß ich nicht. Da gibt es anderes Verbesserungspotential.
Bspw.
Wenn es dauerhaft High sein soll einfach Compare auf 0.
Wenn es dauerhaft Low sein soll einfach Compare = Periode.
Allein damit ist sichergestellt das der letzte Puls Dank Doppel Bufferung sauber ausgeführt wird.
Andere Idee. Damit das umschalten der Pulsfolgen harmonisch erfolgt, setzt man Compare auf 0, vergleicht den Counter mit dem alten Compare, wenn >= stoppt man den Timer. Oder man wartet eine komplette Periode. Bis hierher ist sichergestellt das der letzte Puls immer sauber ausgeführt wird und das Signal danach auf High wechselt und bleibt. Im Schatten dessen Compare und Top ändern, Counter nullen und Prescaler setzen.
Dafür kann man sich eine schöne State Maschine bauen.
Du solltest das Timer Kapitel lesen und beim rumspielen verstehen lernen.
Hat Doppel Bufferung der Register und macht keinen Mist wie
Fast-PWM. Fast-PWM erzeugt mit Compare 0 immer Spikes.
Compare (ich vermute du meinst damit OCR1B) ist wenn der Spike auftritt nie 0 und wird erst nach OCR1A gesetzt. Macht man es andersrum, kriegt man massive Probleme.
In Timer Mode 11 kommen ebenfalls während dem Setzen von COM1B0 und COM1B1 sporadische Pulse aus dem Ausgang, siehe Anhang O7.png.
Wenn ich einen Duty Cycle von 25% auswähle, kommt der zusätzliche Puls in Mode 11 wie auch der zu lange Puls in Timer Moder 15 mit einer Wahrscheinlichkeit von ~25%. Das liegt wohl am Zustand von OC1B beim Reseten des Timers. Das habe ich über ein force match mit ausgeschaltetem Ausgang in resetTimer1 lösen können. Den Code gibt's im Anhang.
Nun tut die Kiste was sie soll, siehe Anhang O8.png.
Die -1 schreibt man in die Funktion, dort gehört sie hin!
1
PORTF=32;// D3 high
Das schreibt man auch nicht so, vor allem da man es noch kommentieren muss. Zumal dein Kommentar und die C-Anweisung NICHT übereinstimmen! D3 wäre 8!
Eine selbsterklärende Schreibweise ist das Mittel der Wahl. Außerdem setzt du damit ALLE Bits in dem Port, was in den meisten Fällen nicht gewünscht ist. Siehe Bitmanipulation.
1
PORTF|=(1<<PF5);
1
DDRB&=0<<6;// Disable OUTPUT B6
Falsch! Das macht nicht das, was der Kommentar sagt! Siehe Bitmanipulation. Eher so.
1
DDRB&=~(1<<PB6);// Disable OUTPUT B6
1
TCCR1A|=_BV(COM1B0)|_BV(COM1B1);// Set at match
2
TCCR1C=_BV(FOC1B);// Force match
Set a match ist irreführend. Es muss set on match heißen. Und hier ist die Zuweisung |= zwar möglich, aber nicht nötig und auch eher ungünstig. Das passt nur, weil vorher das Register komplett auf 0 gesetzt wurde. Hier wäre eine einfache, komplette Zuweisung mit = sinnvoll.
Allerdings ist dein Konzept nicht korrekt. Wenn du TCC1A auf 0 setzt, wird das IO-Pin vom Timer entkoppelt und das Bit aus PORTB auf das IO-Pin geschaltet. Das wird in deinem Programm aber nie beschrieben, ist also ab Reset 0. Damit geht dein Ausgang auf LOW. Ist das gewollt? Eher nicht. Deine Signale sollen doch meist HIGH sein. Wenn man es richtig machen will und sicher ohne Glitch, sprich Störpulse umschalten will, muss man den Zähler synchronisiert anhalten. D.h. man darf ihn nur anhalten, wenn man weiß daß sich der Zählerstand in einem unkritischen Bereich befindet, wo sich der Ausgang nicht ändert. Bei deinen Einstellungen wäre das immer im oberen Bereich des Zählers, aber nicht ganz oben. Sagen wir zwischen 75 und 95%. Etwa so. Die Konstanten mit Endung L sind nötig, damit die Rechnung in 32 Bit gemacht wird, wegen des Überlaufs.
1
uint16_tmin=(OCR1A*96L)>>7;// 75%
2
uint16_tmax=(OCR1A*115L)>>7;// 90%
3
while((TCNT1<min)||(TCNT1>max);// warte auf Fenster
4
TCCR1B=0;// Timer stop, output HIGH
Dann kann man auch mittels des richtigen IO-Modes
1
TCCR1A=_BV(COM1B1);
2
TCCR1C=_BV(FOC1B);
den Pin ohne Glitch auf LOW setzen und dort lassen, bis die neue Konfiguration erfolgt.
Überlege doch einmal. Der Timer befindet sich in irgendeinem Zustand den man nicht kennt. Jetzt muss man ihn zum nächstmöglichen Zeitpunkt sicher anhalten. Mit willkürlichen sofortigen Stopp wird das nichts. Nutze die Möglichkeiten die der Timer mitbringt.
Ich hatte es schon beschrieben was du machen kannst/musst. Das erfordert das Verständnis vom Timer und dessen Arbeitsweise. Force Match usw. braucht man nicht. Pin IO extra schalten muss man auch nicht.
Wofür ist das überhaupt? Was machst du mit den Pulsen?
Wegen Fast-PWM und Spikes. Haste falsch verstanden. Vergiss einmal alles mit deinem Programm. Konfiguriere Fast-PWM, irgendeine Periodendauer und Compare auf 0. Schau dir das Signal an.
Wegen dem Umschalten. Ich bin das jetzt Hundert mal gedanklich durchgegangen. Wenn man das umschalten zwischen den Pulsformen mit dem Zwischenschritt Compare auf 0 macht und zusätzlich danach TCNT auf noch aktuelle Pulslänge abwartet kann nichts schief gehen. Dabei spielt es auch keine Rolle ob TCNT hoch oder runter zählt. Danach ist das Signal ohne Faxen sicher auf Dauer-High und man kann den Timer gefahrlos stoppen, Compare + Top + Prescaler umkonfigurieren, starten. Die Automatik mit dem Update mittels gepuffertem Register nimmt einem alle Probleme ab.
Die -1 schreibt man in die Funktion, dort gehört sie hin!
Da hast du Recht mit, habe ich korrigiert.
PORTF = 32; // D3 high
Das schreibt man auch nicht so, vor allem da man es noch kommentieren
muss. Zumal dein Kommentar und die C-Anweisung NICHT übereinstimmen! D3
wäre 8!
Eine selbsterklärende Schreibweise ist das Mittel der Wahl. Außerdem
setzt du damit ALLE Bits in dem Port, was in den meisten Fällen nicht
gewünscht ist. Siehe Bitmanipulation.
Das bezieht sich auf D3 am Oszilloskop und war nur für die Veranschaulichung im Code. Da der PORTF im Moment für nichts anderes genutzt wird, war das die einfachste und schnellste Möglichkeit um an den entsprechenden Stellen die Ausgänge zu setzen und wieder zurück zu setzen.
Es muss set on match heißen. Und hier ist die Zuweisung |= zwar möglich, aber nicht nötig und auch eher ungünstig. Das passt nur, weil vorher das Register komplett auf 0 gesetzt wurde. Hier wäre eine einfache, komplette Zuweisung mit = sinnvoll.
Ist angepasst, danke für den Hinweis.
Allerdings ist dein Konzept nicht korrekt. Wenn du TCC1A auf 0 setzt,
wird das IO-Pin vom Timer entkoppelt und das Bit aus PORTB auf das
IO-Pin geschaltet. Das wird in deinem Programm aber nie beschrieben, ist
also ab Reset 0. Damit geht dein Ausgang auf LOW. Ist das gewollt?
Auch damit hast du Recht, das Bit wird im setup auf High gesetzt, aber ob es im weiteren Programmverlauf auch High bleibt, ist dem Zufall überlassen. Das habe ich dementsprechend geändert indem ich den Ausgang während jedem Reset auf High setze.
Dass der Puls unterbrochen wird wenn der Taster losgelassen wird, ist gewollt. Wenn man mal wirklich lange Pulse einstellt, aber der Taster früher losgelassen wird, ist das in der Anwendung ein ziemlich praktisches Feature.
Einen Match zu forcen während der Timer gestoppt aber Compare Output noch an ist, führt auch dazu, dass der Ausgang sauber auf HIGH geht. Dementsprechend muss ich nicht mehr PB6 kurzzeitig auf Input umschalten.
Ich wollte nun noch eine Begrenzung der Pulsanzahl pro Knopfdruck einbauen. Dank Timerinterrupt sollte das ja eigentlich nicht so schwer sein. Leider braucht es wiederholbare 2,6µs vom Erreichen von OCR1B bis zum Auslösen von ISR(TIMER1_COMPB_vect) [D0 Oszilloskop high], was in Case 1 (5µs LOW, 10µs Periode, 2 Pulse) noch einen kleinen dritten Puls bis der Match geforced wird [D2 Oszilloskop high] ergibt. Kann man das noch schneller hinbiegen?
Einen Match zu forcen während der Timer gestoppt aber Compare Output
noch an ist, führt auch dazu, dass der Ausgang sauber auf HIGH geht.
Dementsprechend muss ich nicht mehr PB6 kurzzeitig auf Input umschalten.
Sagte ich das nicht bereits?
Ich wollte nun noch eine Begrenzung der Pulsanzahl pro Knopfdruck
einbauen. Dank Timerinterrupt sollte das ja eigentlich nicht so schwer
sein. Leider braucht es wiederholbare 2,6µs vom Erreichen von OCR1B bis
zum Auslösen von ISR(TIMER1_COMPB_vect) [D0 Oszilloskop high],
Dann schreib das auch so in deinen Kommentar!
was in
Case 1 (5µs LOW, 10µs Periode, 2 Pulse) noch einen kleinen dritten Puls
Wo kommt plötzlich die 10us Periode her?
bis der Match geforced wird [D2 Oszilloskop high] ergibt. Kann man das
noch schneller hinbiegen?
Ja, mit einer ISR in Assembler. Frag mal unseren Spezi Bernd Stein, der kennt sich damit gut aus ;-)
Dein counter muss volatile sein, sonst funktioniert das nicht so, oder nur durch Zufall. Siehe Interrupt. Muss der 16 Bit sein? Oder reichen 8 Bit?
Man kann das auch mit einer ISR in C versuchen, dann muss man aber wissen was man tut! Vor allem darf man in der ISR keine Funktionen aufrufen, denn die kosten in der ISR am Anfang viel Zeit, weil viele Register gesichert werden müssen. Weiterhin muss man das Abschalten möglichst an den Anfang der ISR schreiben, logisch. Etwa so.
1
volatileuint8_ttccr1b_setup=0;
2
3
....
4
counter=5;// Pulse -1
5
tccr1b_setup=(1<<CS11)|(1<<CS10);// prescaler for timer 1
Vor allem darf man in der ISR keine Funktionen
aufrufen, denn die kosten in der ISR am Anfang viel Zeit, weil viele
Register gesichert werden müssen.
Der Hinweis war Gold wert, nun dauert es nurnoch 1,5µs vom Erreichen von OCR1B bis zum Auslösen von ISR(TIMER1_COMPB_vect) und ohne die Bewegungen an Port F geht sogar 4µs/8µs problemlos.
Gehe ich richtig in der Annahme, dass dein Vorschlag nur für zwei oder mehr Pulse funktioniert? Dann würde ich mich nämlich mit meinem Code im Anhang zufrieden geben, außer jemand will sich wirklich noch an Assembler versuchen, das übersteigt meine Kenntnisse bei weitem.
Vielen Dank für eure Unterstützung, ich habe in den letzten Tagen sehr viel dazu gelernt :)
ich verstehe eure Herangehensweise nicht mehr. Buffer-Register werden ignoriert. Keine State Maschine geschrieben um die sich hier eigentlich alles dreht. Dafür wird mit brutalsten Mitteln der Timer umgebogen. Ihr baut euch Sackgassen. Ich sehe nur noch Stückwerk was einst saubere Funktionen waren.
Ich habe getestet, bis zu welchen Werten das noch funktioniert, bei 5µs
LOW und 10µs Periode war reproduzierbar jedes mal ein dritter Puls
dabei.
Das wundert mich nicht. Leider liegt der Fokus auf die Probleme falsch.
Da mir das Herz dabei blutet bin ich komplett raus.
Na dann zeig doch mal, wie du das umsetzen würdest.
Ich hätte gerne low-Pulse auf Knopfdruck mit einstellbarer Länge, Periode und optional auch Anzahl pro Knopfdruck. Wird der Taster losgelassen, soll der Ausgang wieder high werden, selbst wenn ein langer Puls oder die bestellte Pulsanzahl noch nicht vorbei sind.
Diese Aufgaben bewältigt der Code ziemlich gut.
Entschuldige meine forsche Antwort - vorallem da dein Beispielcode bei meinen Startschwierigkeiten sehr hilfreich war - aber die letzten Kommentare waren absolut nicht konstruktiv.
Naja, BTT: Bevor man OCR1A und OCR1B auf 16bit-Werte setzen kann, muss man den entsprechenden Modus auch in TCCR1B wählen. Ich habe also unter Zeile 65 noch ein TCCR1B = tccr1b_setup; eingefügt und die Zeile 85 in TCCR1B |= tccr1b_tmp; geändert.
ich verstehe eure Herangehensweise nicht mehr. Buffer-Register werden
ignoriert. Keine State Maschine geschrieben um die sich hier eigentlich
alles dreht. Dafür wird mit brutalsten Mitteln der Timer umgebogen. Ihr
baut euch Sackgassen. Ich sehe nur noch Stückwerk was einst saubere
Funktionen waren.
Was ist denn mit dir los? Nur weil nicht alles oberlehrbuchhaft nach deiner Vorstellung läuft verlierst du die Nerven?
Naja. pulselimit muss auch volatile sein. Das gilt für ALLE Variablen, welche sowohl in einer ISR als auch im Hauptprogramm benutzt werden, egal ob lesen oder schreiben.
ich renne nicht den sich laufend veränderten Anforderungen hinterher. Mit sofortigen Pulsstopp und Pulszähler und vielleicht noch Pulsstopp nach Vorgabe müßte ich mein Gesamtkonzept überdenken. Logisch das nun einige Aussagen von mir nicht mehr passen. Ich ändere dafür aber nicht wild drauflos. Wie meine Lösung aussah bis zu den neuen Anforderungen kann ich dir zeigen.
Ich weiß das sich Falk mit Programmierung und Timern auskennt. Aber wir haben unterschiedliche Herangehensweisen. Grundlegend er C und ich C++. Von daher macht es keinen Sinn wenn wir uns ins Gehege kommen und du dann zwischen den Stühlen stehst. Da ziehe ich mich lieber zurück. Außerdem möchte ich mit Falk u.a. diesen Sommer noch ein Bier trinken gehen. :-)
naja, da müßte ja wohl eher Brüno an mich ...
Ich kann dir aber gern ein Bier ausgeben, daran soll es nun nicht scheitern. Selbst wenn ich vorher Flaschen sammeln gehen muss. :-)
Diese Kommentare sind ein Papagei, der alles nachplappert. Sinnlos!
1
sei();// allow interrupts
Das brauchst du nicht bei Arduino, denn die Interrupts laufen beim
Aufruf von Setup schon.
Ich hab deinenm Programm mal den letzten Schliff verpaßt. Damit wird es
kompakter und doch besser lesbar und schneller! Das IO-Pin wird NIE vom Timer getrennt! Siehe Anhang.