Forum: Mikrocontroller und Digitale Elektronik Brauche Hilfe bei der Auswahl des Timers


von twizzler (Gast)


Lesenswert?

Hallo,

ich habe einen Atmega16 auf einem STK500 (ohne Quarz, daher Nutzung 1MHz 
Taktes des µCs) zur Verfügung und möchte 2 Timer verwenden, die in 
untersch. Intervallen je ihre Interrupt Routine (ISR) aufrufen.

1. Frage: Kann es in einem Programm mehr als zwei ISRs geben?

2. Frage: Ist ein PWM gesteuerter Timer in Kombination mit dem STK500 
genauer als einer ohne PWM, wenn wie oben gesagt nur der µC interne 1MHz 
Takt verwendet werden kann?

3. Frage: Jetzt interessiert mich aber noch, ob ich den "8-Bit Timer2 
mit PWM und asynch. Operation" genauso verwenden kann wie den "8-Bit 
Timer1 mit PWM".

Ich würde mich über jede Hilfe freuen, da ich sowohl zum ersten Mal 
einen Timer als auch einen Interrupt verwenden möchte.

twizzler


P.S.: Ja, das Datenblatt zum Atmega16 habe ich zur Hand. Ich würde aber 
nicht fragen, wenn ICH meine Probleme allein damit lösen könnte.

von twizzler (Gast)


Lesenswert?

OK, ich glaube mittlerweile verstanden zu haben, dass der PWM Betrieb 
für meine Anwendung am besten geeignet zu sein scheint. Der 16-Bit Timer 
erlaubt ebenfalls einen PWM Mode. Dann nehme ich nun diesen, oder? 
Schließlich benötige ich hier kein Prescaling Faktor und kann daher mein 
Signal µs genau bestimmen.

von Jan H. (linklon)


Lesenswert?

was willst du eigentlich genau machen?? du brauchst keine PWM um einen 
Timer zu nutzen, die PWM (Pulsweitenmodulation) ist lediglich eine 
Funktion, die der Timer zur verfügung stellt....Datenblatt...
Für das was du machen willst reicht ein timer der einen compare match 
interrupt auslöst.... unter umständen reicht ein timer, wenn er 2 
compare register besitzt. und nun zum prescaler (vorteiler) den kannst 
du einsetzen um längere zeiten verwirklichen zu können... ein Beispiel 
wenn du einen uC verwendest mit 1MHz Systemtakt 1/1MHz = 1us das heisst 
ohne prescaler kannst du mit einem 8Bit Timer (0-255) genau 256us 
messen.... der Prescaler macht also schon sinn.... erzähl mal was du 
genau machen willst...

von Jan H. (linklon)


Lesenswert?

PS such dir vieleicht mal n tutorial zum Thema Timer, und Interrupts....
Das hilft dir zu verstehen wie der uC denkt....

von twizzler (Gast)


Lesenswert?

@Jan Herzog

Den PWM halte ich für sinnvoll, da ich ein Servo ansteuern möchte. Und 
mit dem PWM könnte man ein Rechteck Signal generieren. Und ich denke, 
dass ich die Länge des Rechtecks in der main beeinflussen kann, oder?

Den Prescaler brauche ich beim 16 Bit Timer deshalb nicht, weil meine 
längste Zeitdauer 20ms - s. Servo - nicht überschreitet, oder?

von Jan H. (linklon)


Lesenswert?

ok, das macht sinn, wozu aber die interrupts??

von twizzler (Gast)


Lesenswert?

@Jan Herzog
Die Interrupts habe ich mir für die erste Variante mit den zwei Timern 
als scheinbar sinnvoll ausgedacht. Der erste Timer sollte das High Level 
Signal an einem beliebigen Portpin einschalten und der zweite Timer 
sollte für die verlbeibende Zeitdauer der insg. 20ms den Pin wieder auf 
Low setzen. Benötigt für solche Dinge keinen Interrupt?

Erübrigt sich die Interrupt Sache, wenn ich einen PWM verwende?

von twizzler (Gast)


Lesenswert?

welche Variante, würdet ihr mir empfehlen? Die zwei-Timer-Variante oder 
PWM-Variante?

von willi (Gast)


Lesenswert?

dafür brauchst du definitiv nicht 2 timer.

wenn du eine periodendauer von 20ms hast und dein high zwischen 0 und 
diesen 20ms variiren können soll, nimmst du einen timer den du so 
einstellst, dass die periodendauer eben genau 20ms ist, und benutzt im 
im compare match mode (oder so ähnlich). dann stellste die ganze 
geschichte noch so ein das der output compare pin passend getoggelt 
wird, und du musst in deiner main nur das compare register passend 
nachladen

von avr (Gast)


Lesenswert?

Du kannst nur mit Timer 1 arbeiten.

Timer ohne Vorteiler als PWM mit TOP-Wert in
ICR1 (hier 20000 -> 20 ms) und OCRA und B als
PWM-Wert (sinvoll sind beim Servo 1000-2000 -> 1-2 ms)
Pin wird gesetzt PD4 für OCRB PD5 für OCRA.

Mit der Vorlage sollte es gehen.

1
//ICC-AVR application builder : 17.05.2009 22:15:11
2
// Target : M16
3
// Crystal: 1.0000Mhz
4
5
#include <iom16v.h>
6
#include <macros.h>
7
8
//Signal bit definitions
9
#define  PWM_B  4  //PD4
10
#define  PWM_A  5  //PD5
11
12
void port_init(void)
13
{
14
 PORTA = 0x00;
15
 DDRA  = 0x00;
16
 PORTB = 0x00;
17
 DDRB  = 0x00;
18
 PORTC = 0x00; //m103 output only
19
 DDRC  = 0x00;
20
 PORTD = 0x00;
21
 DDRD  = 0x30;
22
}
23
24
//TIMER1 initialize - prescale:1
25
// WGM: 14) PWM fast, TOP=ICRn
26
// desired value: 20mSec
27
// actual value: 20,000mSec (0,0%)
28
void timer1_init(void)
29
{
30
 TCCR1B = 0x00; //stop
31
 TCNT1H = 0xB1; //setup
32
 TCNT1L = 0xE1;
33
 OCR1AH = 0x4E;
34
 OCR1AL = 0x1F;
35
 OCR1BH = 0x4E;
36
 OCR1BL = 0x1F;
37
 ICR1H  = 0x4E;
38
 ICR1L  = 0x1F;
39
 TCCR1A = 0xF2;
40
 TCCR1B = 0x19; //start Timer
41
}
42
43
//call this routine to initialize all peripherals
44
void init_devices(void)
45
{
46
 //stop errant interrupts until set up
47
 CLI(); //disable all interrupts
48
 port_init();
49
 timer1_init();
50
51
 MCUCR = 0x00;
52
 GICR  = 0x00;
53
 TIMSK = 0x00; //timer interrupt sources
54
 SEI(); //re-enable interrupts
55
 //all peripherals are now initialized
56
}
57
58
//
59
void main(void)
60
{
61
 init_devices();
62
 //insert your functional code here...
63
}

In der main brauchst du nur die PWM-Werte setzen.

Es gibt jedoch schönere Verwendungen für einen
16 Bit-Timer.

gruß avr

von Jan H. (linklon)


Lesenswert?

wie wärs mit prescaler und nem 8 bit timer?? reichen 8 bit Auflösung?

von spess53 (Gast)


Lesenswert?

Hi

>TCCR1B = 0x00; //stop
> TCNT1H = 0xB1; //setup
> TCNT1L = 0xE1;
> OCR1AH = 0x4E;
> OCR1AL = 0x1F;
> OCR1BH = 0x4E;
> OCR1BL = 0x1F;
> ICR1H  = 0x4E;
> ICR1L  = 0x1F;
> TCCR1A = 0xF2;
> TCCR1B = 0x19; //start Timer

Zumindest mal ein Beispiel, wie man es nicht macht.

MfG Spess

von avr (Gast)


Lesenswert?

Eigentlich ja, aber:

Signal 1 ms immer ein, 0-1 ms ein, 18-19 ms aus = 20 ms

Die Info ist die Dauer des Impulses (1-2 ms) bzw. die
Dauer (0-1 ms) nach dem Grundsignal (1 ms).
Die 18-19 ms danach sind uninteresant (aber wichtig).

Wenn ich die 20 ms mit 8 Bit auflöse erhalte ich 78 µs als
Einheit. Der Bereich 0-1 ms der die Info enthält hat dann
nur noch 13 Stufen.

Bei einem Servo mit 180° sollten es aber deutlich mehr sein.

Man muß also Aufteilen in Signal und Verzögerung.

Daher ist der Weg oben mit den 16 Bit eigentlich sehr
genau und einfach.

Für die anderen Wege gibt es hier im Forum viele Beispiele
(Suchfunktion!).

gruß hans

von twizzler (Gast)


Lesenswert?

Ich sehe den letzten Beitrag von avr als schlüssig an. Zudem reichen mir 
die 8-Bit tatsächlich nicht.

@Spess:
Was meinst du mit "So sollte man es NICHT machen"?

von spess53 (Gast)


Lesenswert?

Hi

>Was meinst du mit "So sollte man es NICHT machen"?

Es gibt Bitdefinitionen, die man benutzen sollte:

TCCR1B = 1<<CS12|1<<CS11 ist wesentlich aussagekräftiger als
TCCR1B= 0x6

Hat nichts mit falsch oder richtig zu tun.

MfG Spess

von twizzler (Gast)


Lesenswert?

@avr

ich habe gerade deinen Code kompilieren wollen und festgestellt, dass 
ich die macros.h nicht habe. Ich habe CLI() durch cli() und SEI durhc 
sei() ersetzt und die macros.h durch die interrupt.h ersetzt. Ist das 
auch OK? Kompilieren ist so jedenfalls möglich.

Wofür sind die defines?

#define  PWM_B  4  //PD4
#define  PWM_A  5  //PD5

Muss ich den Servo wirklich an PD4 und PD5 anschließen?

Ich vermute der PWM_B Wert ist für das variable 0...1ms Signal gedacht. 
Wie setze ich PWM_B beispielsweise auf 0,5ms; etwa so? PWM_B = 500;

LG twizzler

von Karl H. (kbuchegg)


Lesenswert?

twizzler schrieb:

> Wofür sind die defines?
>
> #define  PWM_B  4  //PD4
> #define  PWM_A  5  //PD5
>
> Muss ich den Servo wirklich an PD4 und PD5 anschließen?
>
> Ich vermute der PWM_B Wert ist für das variable 0...1ms Signal gedacht.
> Wie setze ich PWM_B beispielsweise auf 0,5ms; etwa so? PWM_B = 500;

Nein.
Du weist einen Wert an das OCR1A oder OCR1B Register zu.
Für weitere Details verweise ich auf das Datenblatt zu deinem Prozessor. 
Im Kapitel über den Timer 1 findest du auch eine ausführliche 
Beschreibung zur PWM, welche Register beteiligt sind und wo die Signale 
am µC herausgeführt sind.

> void timer1_init(void)
> {
>  TCCR1B = 0x00; //stop
>  TCNT1H = 0xB1; //setup
>  TCNT1L = 0xE1;
>  OCR1AH = 0x4E;
>  OCR1AL = 0x1F;
>  OCR1BH = 0x4E;
>  OCR1BL = 0x1F;
>  ICR1H  = 0x4E;
>  ICR1L  = 0x1F;
>  TCCR1A = 0xF2;
>  TCCR1B = 0x19; //start Timer
> }

Na denn, viel Spass beim Aufdröseln in die einzelnen Bits und 
identifizieren mit dem Datenblatt, was da eigentlich alles eingestellt 
und freigeschaltet ist.

Man kann das ganze auch so schreiben

void timer1_init(void)
{
   TCCR1B = 0x00; //stop

   TCNT1  = 0xB1E1; //setup
   OCR1A  = 0x4E1F;
   OCR1B  = 0x4E1F;
   ICR1   = 0x4E1F;

   TCCR1A = 0xF2;
   TCCR1B = 0x19; //start Timer
}

Das hat dann den Vorteil, dass sich der Programmierer nicht um die 
korrekte Beschreibung eines 16 Bit Registers kümmern muss, sonder der 
Compiler sich um die richtige Reihenfolge kümmert (erst High, dann Low).

Das Aufdröseln der Bits in TCCR1A und TCCR1B hingegen überlass ich dem 
Leser :-)


> Die 18-19 ms danach sind uninteresant (aber wichtig).

Nicht wirklich. Den meisten Servos ist das völlig egal, ob da eine 18 ms 
Pause hinten nach kommt oder nicht. Servos interessieren sich sowieso 
nur für die Länge des Pulses. Die Wiederholzeit von 20ms kommt ja nicht 
aus einem Servoproblem an sich, sondern ist entstanden, weil man einige 
Servopositionen hintereinander über die Funkstrecke schicken muss und 
trotzdem noch erkennen können muss, welcher Puls zu Servo 1 gehört. Am 
Funkweg sind einfach nur alle Puls hintereinander angeordnet. Jeder Puls 
kann maximal 2 ms lang sein, so dass man bei 8 Servos dafür maximal 16 
ms (plus ein paar Zerquetschte) für die 8 Pulse brauchte. Dann noch eine 
etwas längere Pause (für den Frameanfang) und fertig war der 
Übertragungsframe. Der Empfänger pfriemelt da gar nicht lange rum, 
sondern lässt einfach einen Zähler mitlaufen. Mit jedem Pulsende wird 
der nächste Puls auf den nächsten Ausgang durchgeschaltet, bei einer 
längeren Pause wird der Zähler wieder auf 0 gesetzt. Und so kommt es, 
dass an einem Servoausgang am Empfänger nur alle 20ms ein Puls 
auftaucht.
Aber wie gesagt: Analogservos ist diese Zeitdauer ziemlich egal. 
Lediglich Digitalservos werten diese Wiederholrate manchmal aus um zu 
erkennen, ob sie vielleicht einem Störsignal nachlaufen, oder ob die 
Pulslänge tatsächlich von einem Sender stammen kann.

von twizzler (Gast)


Lesenswert?

@Karl Heinz Buchegger

Jetzt bin ich wohl der entdröselmeister! ;-)

void timer1_init(void)
{
 TCCR1B = 0x00;   //stop

 TCNT1  = 0xB1E1; //setup, 45537 (?)
 OCR1A  = 0x4E1F; //19999
 OCR1B  = 0x4E1F; //19999
 ICR1   = 0x4E1F; //19999
 TCCR1A = 
1<<COM1A1|1<<COM1A0|0<<COM1B1|0<<COM1B0|0<<FOC1A|0<<FOC1B|1<<WGM11|0<<WG 
M10;
 TCCR1B = 0<<ICNC1|0<<ICES1|1<<WGM13|1<<WGM12|0<<CS12|0<<CS11|1<<CS10; 
//start Timer
}

Kompilieren funktioniert schon mal. Danke übrigens für deine Antwort 
bezüglich der PWM-Wert Änderung. Weißt du zufällig auch warum die o. 
angefragten #defines dann noch wichtig sind, obwohl sie nun im Code 
nicht mehr vorkommen.

Auch die Antwort auf die Frage, ob die Servos wirklich an beide Pins PD4 
u. 5 anzuschließen sind, würde mich noch sehr interessieren.

Das war es erstmal an weiteren Fragen.

von twizzler (Gast)


Lesenswert?

Scheinbar habe ich da irgendwelche Verständnisschwierigkeiten. Nach dem 
Datenblatt sieht es so als entspräche PD4 oder PD5 dem OCR1A oder OCR1B 
Signal. Wobei sich letztere scheinbar nur dadurch unterscheiden, dass 
sie invers zueinander sind. So entschied ich mich zunächst für PD4 als 
Steuerleitung für mein Servo. Allerdings tat sich da nichts. Wenn ich 
eine LED über PD4 ansteuere leuchtet diese aber permanent bzw. mit einem 
20ms Takt. Habe leider kein Oszilloskop zur Hand.

Warum zappelt mein Servo nicht? Und wieso beträgt der TCNT Wert 45537 
anstatt 20000?

Müssen die Datenblätter so verteufelt undurchsichtig sein?

Bitte gebt mir einen weiteren Hinweis!

von Karl H. (kbuchegg)


Lesenswert?

twizzler schrieb:
> Scheinbar habe ich da irgendwelche Verständnisschwierigkeiten. Nach dem
> Datenblatt sieht es so als entspräche PD4 oder PD5 dem OCR1A oder OCR1B
> Signal.

Bingo

> Wobei sich letztere scheinbar nur dadurch unterscheiden, dass
> sie invers zueinander sind.

Das sind 2 voneinander unabhängige PWM Einheiten (ok, sie teilen sich 
den TOP Wert, da sie beide am gleichen Timer beheimatet sind).

Ich habe jetzt die Konfigurationsbits nicht studiert. Kann natürlich 
sein, dass die so eingestellt sind, dass an der einen das inverse der 
anderen raus kommt.

> Warum zappelt mein Servo nicht? Und wieso beträgt der TCNT Wert 45537
> anstatt 20000?

Als erstes musst du mal ergründen, welcher PWM Modus eingestellt ist.
Was ist der TOP Wert (wie weit zählt der Timer).

Wie schnell taktet dein µC?
Davon ausgehend musst du zurückrechnen, welcher Wertebereich in OCR1A 
(bzw. OCR1B) dem Bereich 1 bis 2 ms entspricht.

von Karl H. (kbuchegg)


Lesenswert?

OK.
WGM13 ist gesetzt, WGM12 und WGM11.

Das ist MOdus 14. In diesem Modus zählt der Timer von 0 bis ICR1. Ist 
ICR1 erreicht, wird der Timer auf 0 gesetzt und es geht wieder von vorne 
los.

Das vorladen des TCNT1 kannst du ignorieren. Das ist nur beim ersten 
Durchlauf interessant und man hätte TCNT1 in diesem konkreten Fall 
genausogut einfach auf 0 setzen können. Wird dann der Overflow erreicht 
zählt der Timer immer von 0 bis 19999. (65536 - 19999 = 45537)

von Karl H. (kbuchegg)


Lesenswert?

Mit dieser Belegung:

TCCR1A =
1<<COM1A1|1<<COM1A0|0<<COM1B1|0<<COM1B0|0<<FOC1A|0<<FOC1B|1<<WGM11|0<<WG 
M10;

sollte sich eigentlich am B-Kanal gar nichts tun.
COM1A1 und COM1A0 sind so geschaltet, dass
"Set OC1A on compare match, clear OC1A at BOTTOM"

d.h
Der Timer zählt fröhlich vor sich hin. Immer von 0 bis 19999 (weil in 
ICR1 19999 drinnen steht).
Wenn der Timerwert (in TCNT1) gleich OCR1A ist, dann wird der Ausgang 
OC1A auf high geschaltet. Erreicht dre Timer die 19999, wird er im 
nächsten Takt zu 0 und gleichzeitig wird der Ausgang OC1A wieder zu 0.

Wenn du also einen 1 ms Puls haben willst, musst du den OCR1A Wert so 
einstellen, dass der Timer noch 1 ms braucht, ehe er 19999 erreicht. 
Wenn 19999 tatsächlich 20 ms entsprechen, dann sind 1ms ein Wert von 
1000. Du musst OCR1A also auf 18999 stellen. Denn dann braucht der Timer 
noch genau 1ms bis der TOP Wert 19999 erreicht wird.

Alternativ kannst du die ganze Schose natürlich umstellen, sodass der 
OC1A Pin bei einem Timerwert von 0 auf 1 geht und bei erreichen des 
Comparewertes wieder auf 0 fällt.

Das wär dann COM1A1 auf 1, COM1A0 auf 0
OCR1A auf 1500 ergibt dann einen 1.5 ms Puls, der sich alle 20 ms 
wiederholt.

Alles bei 1 Mhz gerechnet (ich hab jetzt die Zahlen von avr nicht 
nchgerechnet)

von twizzler (Gast)


Lesenswert?

@Karl Heinz Buchegger

Vielen Dank für deine sehr ausführlichen Hinweise. Hat mir sehr 
weitergeholfen. Ich habe deinen letzten Tip befolgt und die Schose 
umgedreht, d. h. COM1A1 auf 1, COM1A0 auf 0

Für's erste komme ich soweit zurecht. Vielen Dank für jede Hilfe von 
Euch allen!!!

von twizzler (Gast)


Lesenswert?

Ich habe zunächst eine ganz einfache Routine geschrieben:

Servo ganz links, dann 5 Sek. später ganz rechts, dann 5 Sek. später 
wieder ganz links usw.

Häufig brummt oder vibriert der Servo beim Verharren an einer Position 
oder beim Rüberfahren zur nächsten Position. Manchmal erfolgt das 
Verharren oder Rüberfahren auch ohne brummen. Ich kann da keine 
Regelmäßigkeit feststellen. Ich habe bisher zwei verschiedenen Servos 
unterschiedlicher Bauart getestet. Das Verhalten ist bei beiden 
identisch.

Kennt das jemand von Euch?

von Karl H. (kbuchegg)


Lesenswert?

twizzler schrieb:

> Kennt das jemand von Euch?

Ja.
Das kommt auch bei 'normaler' Benutzung von Servos mit einer 
Fernsteuerung vor. Im Servo können billige Potis verbaut sein, bei denen 
der Schleifer ein klein wenig hakt und das Poti auf kleine Stellversuche 
nicht gleich reagiert und sich der Widerstandswert in kleinen Sprüngen 
ändert. Die Folge ist, dass die Servoelektronik ständig am Nachregeln 
ist. Es ist nicht unüblich, dass ein Servo an einer Position knurrt und 
an einer Position gleich daneben völlig ruhig ist. Auch ein 
schwergängiger Kraftabtrieb vom Servo (Bowdenzüge die schwergängig 
verlegt sind) kann dieses Phänomen verursachen. Oder ein Servo welches 
über die Endstellung gefahren ist sodass die interne Überdrehsicherung 
im Getriebe (ein Zapfen) an den Endpositionen in seiner Nut ansteht.

von twizzler (Gast)


Lesenswert?

Das ist ja blöd. Dann habe ich für 35 € einen "Billigservo" 
(Segelwindenservo) erstanden! Ich werde mal größere Schrittweiten 
testen. Wenn aber alles nichts hilft, kann ich nur hoffen, dass er trotz 
der großen Regelanstrengung 48 Stunden am Stück durchhält.

Danke für die Antwort!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.