Hallo,
also ich denke jetzt, dass der Tiny13 wohl kein ICP beherrscht. Daher
würde ich gerne einen Timer möglichst schnell laufen lassen, um Zeit zu
messen (der Tiny läuft auf 1MHz).
Hier ist mein Code:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<util/delay.h>
4
5
longruntime=0;
6
inton=0;
7
8
ISR(TIM0_OVF_vect)
9
{
10
runtime++;
11
if(runtime>1024)
12
{
13
runtime=0;
14
if(on==0)
15
{
16
PORTB&=~(1<<PB3);
17
on=1;
18
}
19
else
20
{
21
PORTB|=(1<<PB3);
22
on=0;
23
}
24
}
25
TCNT0=255;
26
}
27
28
intmain()
29
{
30
TCCR0B=(1<<CS00);
31
TIMSK0=(1<<TOIE0);
32
33
DDRB=(1<<PB3);
34
PORTB&=~(1<<PB3);
35
36
sei();
37
38
while(1){}
39
}
Leider zeigt mir das Oszi, dass im Moment der PB3 nur mit etwa 65ms
getogglet wird. Wenn ich diesen Wert durch 1024 Teile beudetet das, dass
ich die Runtime nur auf etwa 60µs genau messen kann. Ich würde die
Genauigkeit gerne steigern. Wie kann ich das machen?
> also ich denke jetzt, dass der Tiny13 wohl kein ICP beherrscht.
Das ist korrekt, ein Blick ins Datenblatt hätte diese Vermutung
bestätigt.
> Daher würde ich gerne einen Timer möglichst schnell laufen lassen,
Das geht mit Vorteiler 1:1. Da der Tiny13 nur einen 8-Bit-Timer (mit
Zählumfang von 256) hat, ist schnell aber nicht immer gut, denn damit
kann man dann längere Impulse nicht mehr so ohne weiteres messen.
> um Zeit zu messen (der Tiny läuft auf 1MHz).
Das (1MHz) halte ich für ein Gerücht. Der Tiny13 läuft üblicherweise mit
9,6MHz und Systemtaktvorteiler 1:8, was einen Takt von 1,2MHz ergibt.
Der Systemvorteiler kann vom Programm verändert werden, wie das geht,
steht im Datenblatt.
Wenn Du Zeiten mit dem Tiny13 messen willst, dann kläre estmal ab,
welchen Bereich die Zeiten haben können. Daraus ermittels Du den
benötigten Timer-Vorteiler und notfalls auch noch den benötigten
Systemvorteiler. Nun kannst Du den externen Interrupt oder einen
Pinchange-Interrupt benutzen, um die Flanke zu dedektieren. Der Timer
läuft dabei frei durch. In der ISR des ext. Interrupts prüfst Du, ob es
Impulsbeginn oder Impulsende ist. Bei Impulsbeginn merkst Du Dir den
aktuellen Timerstand (Zeitstempel), bei Impulsende liesr Du den
Timerstand ein und subtrahierst davon den gemerkten Stand des
Impulsbeginns. Wenn Du dieses Grundprinzip ausbaust, kannst Du
Impulsdauer, Impulspause und Periodendauer in (fast) einem Rutsch
ermitteln. In ASM ist das kein Akt, C ist allerdings nicht mein Ding, da
kann ich Dir kein Beispiel geben.
...
Ich würde gerne auf 1µs genau messen. Dazu muss ich wohl auf 9,6MHz
takten. Aber obwohl ich TCNT0 immer auf 255 setze bekomme ich nur alle
10µs einen Interrupt?
> Ich würde gerne auf 1µs genau messen. Dazu muss ich wohl auf 9,6MHz> takten.
Es interessiert nicht nur die Auflösung, sondern vor allem die der
Wertebereich der Dauer der zu erwartenden Impulse. Die Impulszeit muss
ja in den Zählbereich des Timers passen, und der ist nur 256, denn der
Tiny13 hat nur einen 8-Bit-Timer. Mit einem AVR, der über einen
16-Bit-Timer verfügt, geht ICP besser, einerseits wegen des größeren
Wertebereiches von 65536, andererseits wegen der verfügbaren
Hardware-ICP-Einheit.
> Aber obwohl ich TCNT0 immer auf 255 setze bekomme ich nur alle> 10µs einen Interrupt?
Das verstehe ich jetzt nicht...
Wiso setzt Du TCNT0 auf 255? Wenn Du Impulsdauer messen willst, dann
brauchst Du den Timer überhaupt nicht auf irgendeinen Wert zu setzen. Du
brauchst den Timer doch nur im externen Interrupt zu lesen.
Den Timer lässt man frei durchlaufen, das hat den angenehmen
Nebeneffekt, dass man nebenher noch einen (oder auch beide)
Compare-Interrupts benutzen kann, um Zeiten zu erzeugen, z.B. für
serielle Ausgabe.
Ich glaube fast, Du hast eine völlig falsche Vorstellung von der
Funktionsweise des ICP (egal ob in Hardware oder Software) und
versuchst, die Impulsdauer durch Pollen des Portpins und Zählen im
Timer-Interrupt zu realisieren. Das ist für langsamere Impulse zwar auch
ein praktikabler Weg, ist aber kein ICP.
Unter dem Aspekt, dass Du vielleicht im Timer-Interrupt pollen und
zählen willst, bekommt Deine Aussage:
> Ich würde gerne auf 1µs genau messen. Dazu muss ich wohl auf 9,6MHz> takten.
eine andere Bedeutung. Ein Interrupt-Intervall von 1ms bekommst Du mit
9,6MHz Controllertakt nicht hin, da alleine der Aufruf des Interrupts
und dessen Rücksprung etwa 10 Takte braucht. Dazu kommt noch
SREG-Sicherung und die eigentliche Arbeit. Unter 20-30 Takte wirst Du
(in ASM) nicht auskommen, in einer Hochsprache vermutlich mehr.
...
Hallo,
also ich dachte eher daran eine Variable "runtime" in der ISR hochzählen
zu lassen und somit die Zeit zu messen. Aber du hast recht: Einfach den
Timer Zählen lassen und den Timerstand auszulesen ist natürlich deutlich
schneller -- wenn auch weniger genau. Ich probiere es... Ich möchte
Zeitspannen im Bereich 10µs bis 250µs messen.
> also ich dachte eher daran eine Variable "runtime" in der ISR hochzählen> zu lassen und somit die Zeit zu messen.
Das ist auch eine akzeptable Methode, ist aber kein ICP. 8-(
Software-ICP mit externem Interrupt als Flankentrigger und einem
Timer-Vorteiler von 1:8 (bei 9,6MHz Controllertakt) erlaubt einen
Messbereich bis 213µs. Vielleicht kannst Du ja Deine Ansprüche
korregieren.
Ergänzend kannst Du ja auch eine Compare-Einheit auf den ICP-Zeitstempel
des Impulsbeginns setzen und mit dem Compare-Interrupt den Übertrag
zählen. Dann macht es vielleicht auch Sinn, mit Timer-Vorteiler 1:1 zu
arbeiten. Die ermittelten Zahlen sind dann allerdings nicht im
1ms-Raster, das Ergebnis müsste also noch skaliert werden.
Besser fährst Du mit einem AVR, der mit 1MHz bzw. 8MHz intern läuft
(z.B. Tiny2313). Der hat dann (meist) auch Hardware-ICP am 16-Bit-Timer.
Mit 8MHz Controllertakt und Timer-Vorteiler 1:8 erhält man das Ergebnis
im Raster von 1µs. Dann sind auch noch genug Pins vorhanden, das
Ergebnis auf einem LCD oder einer mehrstelligen gemultiplexten
Siebensegmentanzeige anzuzeigen.
...
Hallo,
danke für die vielen Tipps! :-)
Ich habe mich jetzt für die Methode mit dem Analog-Comparator-Interrupt
(interne Referenzspannung) mit Timer entschieden. Da ich aber noch nie
mit dem Analog-Comparator gearbeitet habe wollte ich nun erst einmal den
Interrupt betrieb zu laufen bringen. Einstellen möchte ich: Interrupt
bei fallender Flanke auf ADC1. Der Interrupt soll dann eine LED blitzen
lassen. Leider funktioniert es nicht. Hier mein Code:
>Ich habe mich jetzt für die Methode mit dem Analog-Comparator-Interrupt>(interne Referenzspannung) mit Timer entschieden.
Wo ist der Timer? "Delay" zählt nicht!
In der ANA_COMP-ISR musst du je nach eingestellter Flankenrichtung den
Timer starten oder stoppen (bei steigender Flanke starten, bei fallender
stoppen).
Wenn der Timer gestoppt ist, liest man den Timer-Wert aus, speichert ihn
in einer Varibalen und setzt ein Flag, damit das Hauptprogramm weiß,
dass es eine neue Pulslänge gibt., die verarbeitet werden kann.
Die Flankenrichtung kann man anhand der ACIS-Bits im ACSR feststellen
und ein (Abfrage und Änderung von ACIS0 sollte reichen).
Den Code mußt du dir jetzt aber selber ausdenken...
Das Problem ist nicht das Timing... im ersten Schritt möchte ich
eigentlich nur die den Interrupt auslösen und die LED aufblitzen lassen
(bei fallender Flanke an PB0). Leider wird der Interrupt nicht ausgelöst
oder zumindest die ISR nicht aufgerufen.