Nur mit den 16Bit des Hardware-Timers:
Dein PPS-Signal löst automatisch das Capture-Event des Timers aus, der Zählerstand wird ins ICR kopiert. Etwa einmal jede Sekunde. Außerdem nutzt Du den IRQ des Capture-Events. Du lädst den letzten Capture-Wert in zwei Register, den neuen in zwei andere und speicherst sie fürs nächste mal. Anschließend bildest Du die Differenz (SUB + SBC). Das Ergebnis ist der Betrag der Differenz, das Carry stellt das Vorzeichen. Wie das dann weiterbehandelt werden soll, weiß ich nicht - Du wolltest ja später 'n String draus machen, also ist der Betrag schon mal nicht schlecht. Den Betrag selbst kannst Du testweise auch erstmal ohne Vorzeicheninfo rausjagen, einfach nacheinander die zwei Bytes ins UDR schreiben. Da der Transmitter seit dem letzten Transmit ja eine Sekunde Zeit hatte, ist er definitiv frei, das erste Byte landet also im Shift-Register, das zweite im Transmit Buffer, wo es wartet, und automatisch übertragen wird, sobald das erste raus ist.
Ein Byte besteht aus zehn Bit, wenn man Start und Stop-Bit mitzählt - selbst bei 2400Baud könntest Du in der Sekunde also 240 Bytes (Zeichen) übertragen lassen.
Wie gesagt sind uns sechzehn Bit aber nun nicht genug Auflösung - der Timer soll im weitere Bits erweitert werden.
Also die zwei Bytes in Hardware, und ein weiteres in Software. 24Bit, rein rechnerisch also 16,777216 MHz, die erfaßt werden könnten. Wenn das nicht reicht, könnte man entweder die Auflösung über den Prescaler halbieren, oder mit einem weiteren Byte gegehalten (was dann aber sicher reichen sollte.
Mit 24Bit:
Grundsätzlich so wie oben, zusätzlich muß aber das dritte Byte in Form eines Registers in Software an den Timer gekoppelt werden. Im TOV-IRQ inkrementierst Du diese Register. Statt des Carry muß dann das Zero genutzt werden, wegen INC (falls nötig).
Bei der Differenzbildung in der Capture-ISR müssen entsprechend drei Bytes betrachtet werden. Insbesondere wird das dritte Byte ja nicht automatisch "abgelichtet".
Folgende Sonderfälle sind zu untersuchen:
- der Timer läuft vor dem Capture Event über: dann wird auch sein IRQ vorher behandelt, OK
- der Timer läuft nach dem Capture-Event, aber während der ISR über: Die ermittelte Differenz stimmt, der TOV-IRQ wartet im Hintergrund auf das Ende der Capture-ISR. Etwa 16Bit-Takte Zeit für die ISR. OK
- das Capture-Event tritt während der TOV-ISR ein: der Timer ist also bereits inkrementiert, das dritte Byte wird gerade inkrementiert, die Capture-ISR wartet, Du hast höchstens eine Sekunde Zeit für die Behandlung. OK
- TOV und Capture schlagen echt(!) gleichzeitig zu: Dann hat das Capture den Vorrang (wegen der IVT). Es wird also wie (2) behandelt - ABER der Timer ist bereits übergelaufen, das dritte Byte wurde aber noch nicht inkrementiert (der IRQ wartet ja noch). NICHT OK
Um (4) mußt Du Dich also kümmern.
Der Timer ist also übergelaufen, aber der IRQ konnte noch nicht behandelt werden. Insbesondere wurde also 0x0000 ge-capture-t. Ist die 0x0000 im ICR ein hinreichendes Kriterium? Nicht im allgemeinen - der Timer steht bei Prescalern größer eins ja mehrere Takte. Die TOV-ISR kann also vor dem Capture-Event ausgelöst worden sein, der Timer aber während des Captures noch nicht inkrementiert worden sein. Im ICR wäre dann folglich noch die 0x0000, das dritte Byte wäre in der Capture-ISR bereits (korrekt) inkrementiert. Das entspräche (1).
Also nochmal: der Timer ist gerade eben übergelaufen (ICR=0x0000) UND der Überlauf IRQ wurde noch nicht behandelt. Das läßt sich natürlich am noch gesetzten TOV-Flag erkennen. wenn beide Bedingungen erfüllt sind, mußt Du das eingelesene Soft-Byte inkrementieren (also nicht den Zähler selbst, sondern die Kopie, klar?)
Ok, die TOV-ISR sollte sich recht kurz halten lassen. In der Capture-ISR müssen die "geblitzten" Werte zumindest festgehalten werden (also auch das Soft-Byte) unter Beachtung von Fall (4). Die Differenzbildung ist auch recht simpel, zwei Bytes in den UART zu knallen auch, aber wenn mehr gesendet werden sollen (Baudrate!), und/oder ggf noch BCDs/Strings/... generiert werden sollen, muß an das gesamte Timing gedacht werden.
Die Capture-ISR muß der TOV-ISR genug Luft lassen, und die triggert alle 16Bit-Takte (wobei sich in 65 Kilotakten schon das ein oder andere erledigen läßt (Prescaler=1 angenommen)).
Ansonsten werden eben nur die vollständigen Captures oder die Differenzen abgelegt (und ein Statusflag), und dann außerhalb der ISRs (durch das Flag getriggert) weitere Umwandlungen und der Transfer behandelt, wofür dann etwa 'ne Sekunde (sechzehn Millionen Takte abzüglich vieler TOVs und eines Captures) verfügbar sind.
Und da
@TommyB sich ja immer für ... eher unkonventionelle Vorschläge meinerseits begeistert: Der Tiny4313 besitzt 'n USI, und dieses 'n vier-Bit-Flankenzähler (um die sechzehn Flanken der Clock für acht Bit zu zählen). Diesen vier-Bit-Counter kann man in Hardware(!) an einen Timer koppeln.
Intern leider nur an das "Timer/Counter
0 Compare Match" (äh... welcher von den beiden??). Aber man kann Timer1 ja auch bei jedem Überlauf automatisch ein Bein toggeln lassen (über einen der Output Compare-Channel), und dieses
extern auf den Clock-Eingang des USI-Counters legen. Dann hätte man einen 20Bit-Timer, wobei der 20Bit-TOV dann durch den USI Overflow Interrupt behandelt werden müßte. Das Input-Capture erwischt in Hardware natürlich auch nur die untersten 16Bit, der Rest wäre wie oben zu behandeln. Nur das Fall-4-Problem hast Du hier nicht, stattdessen kann der Timer jetzt aber während der ISR überlaufend den 4-Bit-Anteil inkrementieren (dann ist ICR sehr groß und TCNT nach dem auslesen des USI-Counters sehr klein. Vielleicht könnte man hier auch mit einer leeren tricksen … wahrscheinlich nicht).
Cave!: Das USIOIF scheint durch die ISR nicht automatisch gelöscht zu werden. Muß dann also selbst mit "1" beschrieben werden.
Den gekoppelten 20Bit-Hardware-Timer kannst Du natürlich trotzdem mit mehreren zusätzlichen Soft-Bytes erweitern.
Uuuund wo ich gerade am rumspinnen bin: Man kann natürlich auch erstmal Timer0 als Counter an Timer1 koppeln (externe Verbindung), und dann intern den USI-Counter dranschalten. Wäre dann mal eben ein 28-Bit-Timer.
(jaja, Capture dann mit soft-Unterstützung)