Forum: Mikrocontroller und Digitale Elektronik Servo mit 8bit Timer


von Thomas (Gast)


Lesenswert?

Hallo,

da ich den Timer 1 meines Atmega für die input capture Funktion brauche, 
möchte ich nun mit dem 8bit Timer mein Servo ansteuern.
Meine grundlegenden Überlegungen dazu waren, dass ich alle 0,004ms einen 
Interrupt auslöse und dabei eine Zählvariable hochzähle mit der ich den 
1-2ms Impuls erzeuge und nach 20ms erneut starte.
Leider bewegt sich das Servo nicht, habe testweise auch schon den Wert 
des Winkels in main geändert, bewegt sich trotzdem nicht.
Wäre toll wenn mir hier jemand meinen Fehler aufzeigen könnte.
Hier mal der Code:
1
#define outputPin PIND7
2
#define outputPort PORTD
3
#define outputDDR DDRD
4
5
#define F_CPU 16000000UL
6
7
#include <avr/io.h>
8
#include <avr/interrupt.h>
9
#include <util/delay.h>
10
11
volatile uint16_t angle=90;      //Winkel in Grad
12
13
void output_init(void){
14
  outputDDR |= (1<<outputPin);
15
  outputPort &= ~(1<<outputPin);
16
}
17
18
void timer_init(void){
19
  
20
  TCCR0B |= (1<<CS01) | (1<<CS00);  //Normal mode F_CPU/64
21
  TIMSK0 |= (1<<TOIE0);
22
}
23
24
ISR(TIMER0_OVF_vect){          //Interrupt alle 0,004ms
25
  static uint16_t ms_counter=0;
26
  
27
  if (ms_counter==5000) ms_counter=0;  // 20ms Interval erzeugen 5000*0,004=20ms
28
  else ms_counter++;
29
    
30
  if (ms_counter<((1+(angle/180))/0.004))  //Winkel in Interval umrechnen
31
  { outputPort |= (1<<outputPin);      //Pin so lange einschalten bis gewünschte Dauer erreicht
32
  }
33
  
34
  else {outputPort &= ~(1<<outputPin);
35
    }
36
}
37
38
int main(void)
39
{
40
  output_init();
41
  timer_init();
42
  
43
  sei();
44
  
45
    while(1)
46
    {
47
    
48
49
    }
50
}

von foo (Gast)


Lesenswert?

C, Integer-Arithmetik, angle/180 ist 0 für angle<180, 1 für 180 <= angle 
< 360.

von Thomas (Gast)


Lesenswert?

Ach sche**e ist klar das da nichts rauskommt.
Aber in Excel sieht die Formel doch so schön aus ....

Dickes Danke!

von Stefan E. (sternst)


Lesenswert?

Außerdem:
1) Die aktuelle Konfiguration produziert einen Interrupt ungefähr jede 
ms, nicht alle 0.004ms.
2) Und wären es tatsächlich 0.004ms, würde die ISR nie und nimmer in 
dieses Intervall "reinpassen".

von foo (Gast)


Lesenswert?

Wobei ich mich da gerade frage warum der sich nicht einfach auf 0 Grad 
dreht, egal was du einstellst. Dass er dreht, solltest du merken/hören 
und fühlen wenn du ihn von Hand verstellst (ggf auch vorher).

Ich würde die Float-Arithmetik aber komplett rauswerfen. Dürfte hier 
auch mit Integer zu machen sein. Weniger Zeit in der ISR und so.

von STK500-Besitzer (Gast)


Lesenswert?

((1+(angle/180))/0.004)

= 250 * (1+(angle/180)))
= 250+250*angle/180

von Karl H. (kbuchegg)


Lesenswert?

Thomas schrieb:
> Hallo,
>
> da ich den Timer 1 meines Atmega für die input capture Funktion brauche,

Das ist aber kein wirkliches Hinderniss.
Man kann auch mit einem frei durchlaufendem Timer und Compare Interrupt 
Servo-Pulse erzeugen.

So ähnlich wie hier
https://www.mikrocontroller.net/articles/Modellbauservo_Ansteuerung#Signalerzeugung_f.C3.BCr_mehrere_Servos_mittels_Timer_.28C.29
nur dass man keinen CTC Modus nimmt, sondern statt dessen den neuen 
'Zeitwert' ins OCR Register addiert.

(Komisch: ich dachte, ich hätte das so im Artikel gemacht. Statt dessen 
ist da ein CTC Modus mit OCR neu setzen)

von Thomas (Gast)


Lesenswert?

Stefan E. schrieb:
> Außerdem:
> 1) Die aktuelle Konfiguration produziert einen Interrupt ungefähr jede
> ms, nicht alle 0.004ms.
> 2) Und wären es tatsächlich 0.004ms, würde die ISR nie und nimmer in
> dieses Intervall "reinpassen".

Richtig..ich habe natürlich vergessen das der Timer erst überlaufen muss 
bevor ein Interrupt auftreten kann..

Karl H. schrieb:
> Thomas schrieb:
>> Hallo,
>>
>> da ich den Timer 1 meines Atmega für die input capture Funktion brauche,
>
> Das ist aber kein wirkliches Hinderniss.
> Man kann auch mit einem frei durchlaufendem Timer und Compare Interrupt
> Servo-Pulse erzeugen.
>
> So ähnlich wie hier
> https://www.mikrocontroller.net/articles/Modellbau...
> nur dass man keinen CTC Modus nimmt, sondern statt dessen den neuen
> 'Zeitwert' ins OCR Register addiert.
>
> (Komisch: ich dachte, ich hätte das so im Artikel gemacht. Statt dessen
> ist da ein CTC Modus mit OCR neu setzen)

Ich bin nicht sicher ob ich dir da ganz folgen kann.

Also bei jedem Compare Interrupt entweder die restliche Zeit bis zum 
Verstreichen des 20ms Intervalls oder bei Beginn eines neuen Intervalls 
den Wert für den 1-2ms Impuls als neuen Compare Wert einstellen. Dazu, 
wegend es frei laufenden Timers den gewünschten Wert zum aktuellen 
Counter Wert addieren? Richtig?
Davon lässt sich dann die Input Capture Messung auch nicht stören?

Vielen Dank für eure Hilfe. Wahnsinnig informatives Forum!!

von Rahul D. (rahul)


Lesenswert?

Die 20ms sind ziemlich unerheblich. Die Pause kann kürzer, aber auch 
länger sein.

von Stefan E. (sternst)


Lesenswert?

Thomas schrieb:
> Dazu,
> wegend es frei laufenden Timers den gewünschten Wert zum aktuellen
> Counter Wert addieren?

Nein, nicht zum Counter-Wert addieren, sondern zum alten Compare-Wert. 
In der Zeit zwischen Compare-Match und dem Punkt wo du den neuen 
Compare-Wert ermittelst, ist der Counter ja schon wieder etwas weiter 
gelaufen.

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.