Forum: Mikrocontroller und Digitale Elektronik Interruptserviceroutine


von Dani (Gast)


Lesenswert?

Hallo,

ich hätte eine Frage zum folgenden Link:

http://rn-wissen.de/wiki/index.php/Servos#Siehe_auch

ISR(TIMER2_COMP_vect)
{
  static int count;
  if(count>servopos)SERVOPORT&=~(1<<SERVOPIN);
    else SERVOPORT|=(1<<SERVOPIN);
  if(count<2000)count++; // Die Impulse sollten alle 20ms gesendet 
werden! 6.2.11 mic
    else count=0;
};

Ich verstehe was ein Sevo ist und die wie die dieser funktioniert (f=50 
Hz, Periodenlänge 20ms, Impulsbreite zwischen 1ms und 2ms, usw). Ich 
komme nur nicht drauf wie die 2000 (20ms) berrechnet wurde.

if(count<2000)count++; ??????


Danke

: Verschoben durch User
von Nop (Gast)


Lesenswert?

in dem genannten Link steht auch noch:
1
void servo_init()
2
{
3
  TIMSK|=(1<<OCIE2);
4
  TCCR2 |= (1<<WGM21) | (1<<CS20);  //Prescale=1, CTC mode
5
  OCR2 = F_CPU/100000;      //alle 10µS ein IRQ
6
  DDRSERVO|=(1<<SERVOPIN);
7
};

Wenn alle 10µs ein Timer-Interrupt kommt, man in jedem Interrupt um eins 
hochzählt und das 2000 mal tut, dann sind das 2000*10µs = 20ms.

von Dani (Gast)


Lesenswert?

Danke.
Ich habe nun versucht ein PWM-Signal am Pin des Controllers zu erzeugen.
Wenn ich den Pin des Controller am Oszillokop anschließe, sehe ich nur 
in Strich und erkenne da keinen Impuls (Pulsbreite 10ms). Ich finde den 
Fehler im Code nicht? Danke

/*----Timer2-----CTC-Modus----
8-Bit Timer: 0...255
Prescaler: 64
F_CPU/Prescaler: 16MHz/64=250000 Takte/s
Alle 1ms soll ein Interrupt ausgelöst werden
Periodenlänge 30ms
-->OCR2A=250000*1ms=249
*/

#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>


//globale Variable
volatile uint8_t count;
void Timer2_init(void);


int main(void)
{
//PB1 als Ausgang setzen
DDRB|=(1<<PB1);
//Pin PB1 auf High setzen
PORTB|=(1<<PB1);

Timer2_init();
while(1)
{
} return 0;
}

void Timer2_init(void)
{
//Mode 4: CTC-Modus
TCCR2A|=(1<<WGM21);
//Prescaler 64
TCCR2B|=(1<<CS22);
//Der Vergleichswert beträgt 249
OCR2A=249;
//Interrupt aktivieren
TIMSK2|=(1<<OCIE2A);
sei();
}

ISR(Timer2_COMPA_vect)
{
    if(count<10)
    PORTB|=(1<<PB1);
    else
    PORTB&=~(1<<PB1);

    if(count<30)
    count++;
    else
    count=0;
}

von Nop (Gast)


Lesenswert?

Versuch erstmal, in der main in einer Endlosschleife ohne 
Timer-Interrupt den IO-Pin zu toggeln, mit Delay-Counterschleifen 
dazwischen (den counter als globales volatile deklarieren nicht 
vergessen).

Dann weißt Du schonmal, ob das Problem in der IO-Initialisierung oder im 
Aufsetzen des Timer-Interrupts liegt.

von Chilitester (Gast)


Lesenswert?

Dani kannst du dich bitte mal an die Regeln zum
Posten von C-Code halten?
(Formatierung)

von Wolfgang (Gast)


Lesenswert?

Nop schrieb:
> Wenn alle 10µs ein Timer-Interrupt kommt, man in jedem Interrupt um eins
> hochzählt und das 2000 mal tut, dann sind das 2000*10µs = 20ms.

Wenn man alle 10µs versucht, einen Timer-Interrupt zu feuern, würde ich 
erstmal ganz gründlich gucken, ob der Prozessor das vernünftig schafft 
und sich nicht die Interrupts auf die Füße treten. Mindestens wenn der 
µC auch noch andere Dinge erledigen soll, kann das sehr eng werden.

von Chilitester (Gast)


Lesenswert?

Wolfgang schrieb:
> würde ich erstmal ganz gründlich gucken, ob der Prozessor
> das vernünftig schafft

.... würde ich erst mal gucken ob das jemand überhaupt
braucht. Zum Servo-Steuern sicherlich nicht.

von Dani (Gast)


Lesenswert?

Wolfgang schrieb:
> Wenn man alle 10µs versucht, einen Timer-Interrupt zu feuern, würde ich


In meinem Fall wird alle 1ms ein Interrupt ausgelöst

von Dani (Gast)


Lesenswert?

Chilitester schrieb:
> Dani kannst du dich bitte mal an die Regeln zum
> Posten von C-Code halten?
> (Formatierung)

Wenn ich wüsste wie..

von Chilitester (Gast)


Lesenswert?

Dani schrieb:
> Wenn ich wüsste wie..

Steht doch genau unten (--> Formatierung)

von Wolfgang (Gast)


Lesenswert?

Chilitester schrieb:
> .... würde ich erst mal gucken ob das jemand überhaupt
> braucht. Zum Servo-Steuern sicherlich nicht.

Zum Steuern eines Servos würde es sicher reichen, wenn man z.B. einen 
1ms System-Interrupt laufen hat, der dann für die 20ms Periodendauer 
gezählt wird und einen 8-Bit Timer, quasi als Monoflop, zur Erzeugung 
des Steuerimpulses.
Dann müßte man sich nur noch eine Beschäftigung für den Prozessor 
überlegen, damit der sich nicht zu Tode langweilt ;-)

von Dani (Gast)


Lesenswert?

Ich habe zuvor mithilfe der Phasen- und Frequenkorrekte PWM (Timer1, 
Hardware PWM) ein Signal erzeugt, welches am Oszilloskop zusehen ist. 
Jetzt wollte ich Soft-PWM (Timer2 Interrupt) anwenden.

von Georg (Gast)


Lesenswert?

Dani schrieb:
> Jetzt wollte ich Soft-PWM (Timer2 Interrupt) anwenden

Du hast es aber mit 2 Zeiten zu tun: 20 ms Basis, davon x ms PWM-Impuls. 
Dazu brauchst du 2 Timer, einen für 20 ms und einen zweiten, der vom 
ersten gestartet wird und die variablen 0..20 ms für die Impulslänge 
ausgibt. Es sei denn es gibt zusätzliche Hardware wie Caption-Register.

Oder du programmierst einen Timer abwechselnd mit x ms (PWM ein) und 20 
- x ms (PWM aus), das ist aber weniger genau. Man kann aber die 
Verzögerung zum Wiederstarten des Timers einrechnen.

Heutige Controller verfügen ja über ganze Timer-Rudel.

Georg

von Dani (Gast)


Lesenswert?

Georg schrieb:
> Dani schrieb:
>> Jetzt wollte ich Soft-PWM (Timer2 Interrupt) anwenden
>
> Du hast es aber mit 2 Zeiten zu tun: 20 ms Basis, davon x ms PWM-Impuls.
> Dazu brauchst du 2 Timer, einen für 20 ms und einen zweiten, der vom
> ersten gestartet wird und die variablen 0..20 ms für die Impulslänge
> ausgibt. Es sei denn es gibt zusätzliche Hardware wie Caption-Register.
>
> Oder du programmierst einen Timer abwechselnd mit x ms (PWM ein) und 20
> - x ms (PWM aus), das ist aber weniger genau. Man kann aber die
> Verzögerung zum Wiederstarten des Timers einrechnen.
>
> Heutige Controller verfügen ja über ganze Timer-Rudel.
>
> Georg

Ich dachte in der ISR Routine habe ich  bereits shon die Zeit definiert, 
in denen ein Pin auf High bzw. Low gesetzt wird.

ISR(Timer2_COMPA_vect)
{
    if(count<10)
    PORTB|=(1<<PB1);
    else
    PORTB&=~(1<<PB1);

    if(count<30)
    count++;
    else
    count=0;
}

von guest (Gast)


Lesenswert?

Wenn man schon fremde Sourcen zitiert sollte man wenigstens auf die 
Quelle verweisen:
https://www.proggen.org/doku.php?id=electronics:projects:legorobot

Wolfgang schrieb:
> Wenn man alle 10µs versucht, einen Timer-Interrupt zu feuern, würde ich
> erstmal ganz gründlich gucken, ob der Prozessor das vernünftig schafft
> und sich nicht die Interrupts auf die Füße treten.

Bei 4MHz geht es nicht (hat Karl Heinz vor Jahren schon rausgefunden). 
Bei 8MHz geht es wohl. Beim Lego Roboter sind es 16MHz.

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.