Lieber Besucher, herzlich willkommen bei: RCLine Forum. Falls dies Ihr erster Besuch auf dieser Seite ist, lesen Sie sich bitte die Hilfe durch. Dort wird Ihnen die Bedienung dieser Seite näher erläutert. Darüber hinaus sollten Sie sich registrieren, um alle Funktionen dieser Seite nutzen zu können. Benutzen Sie das Registrierungsformular, um sich zu registrieren oder informieren Sie sich ausführlich über den Registrierungsvorgang. Falls Sie sich bereits zu einem früheren Zeitpunkt registriert haben, können Sie sich hier anmelden.

swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

1

Mittwoch, 25. Februar 2009, 14:21

Probleme bei Erzeugen eines servoimpulses

Hallo zusammen,

ich möchte mir einen Servoverzögerungsbaustein basteln. Nun habe ich aber schon Probleme beim Erzeugen eines einfachen Servoimpulses. Das Servo fährt stumpf in Endstellung. Angeschlossen ist die Impulsleitung des Servos an PB1
Da ich einen Fehler zwischen meinen Ohren vermute, möchte ich Euch bitten einmal über meinen Code zu schauen.

CPU: ATtiny 25
Takt: 8MHz, Prescaler 0 (Die Fuses stimmen).

Bei einem 8-Bit Timer sollte ich bei 8MHz Takt und einem prescaler von 64 auf 125 Ticks/ms kommen. Der Timer läuft im Mode 7, TOP ist OCR0A mit 249 entsprechen 2ms. Um den Frame von ca 20ms zu erzeugen kopple ich PB1 nur alle 9 Overflows an OC0B. OC0B ist die Länge des Impulses und kann Werte zwischen 124 und 249 annehmen.

Habe ich da schon einen Kinken in meinen Überlegungen?
Die Kopplung von OC0B an PB1 funktioniert. Zumindest habe ich je nach Wert in OC0B an einer probehalber angeklemmten LED unterschiedliche Helligkeiten.

Danke für Eure Hilfe......

Gruß,
Stefan

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
Servodelay -- Verzögerung eines Servosignals
CPU: ATtiny 25
Takt: 8MHz
Servo an OC0B (PB1)
Signal an PB0
*/

#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint8_t pulse;	//Impulsdauer
volatile uint8_t counts; //Durchlaufzähler
volatile uint8_t cnt;

int main(void) {

//PortB
DDRB |= (1 << PB1) | (1<<PB2);	//PB1 als Ausgang
DDRB &= ~(1 << PB0);	//PB0 als Eingang
PORTB |= (1 << PB0);	//PB0 internal pull up

pulse=200;
counts=0;

//Timer 0 Prescaler 64 >> 125 ticks / ms; Phase Correct Fast PWM Mode 7
OCR0A = 249;	//Obergrenze 2ms
OCR0B = pulse;
TCCR0A |= (1<<COM0B1) | (1<<WGM01) | (1<<WGM00);
TCCR0B |= (1<<WGM02) | (1<<CS01) | (1<<CS00);

//Timer 0..1
TIMSK |= (1 << TOIE0);

//Global interrupt ein
sei();

//mainloop
while(1) {
};

return(1);
}

ISR(TIMER0_OVF_vect) {
if(counts==8) {
        TCCR0A |= (1<<COM0B1);
        counts = 0;
        PORTB |= (1<<PB2);
        }
else {
        TCCR0A &= ~(1<<COM0B1);
        counts++;
        }
}

o.dippel

RCLine User

Wohnort: Büdingen / Hessen

Beruf: Software-Developer

  • Nachricht senden

2

Mittwoch, 25. Februar 2009, 16:53

RE: Probleme bei Erzeugen eines servoimpulses

Hi,

nur kurz :

Zitat

PORTB |= (1<<PB2);


Du musst PB2 irgendwann auch wieder auf LOW setzten
Nutz deine Sound-Karte als Oszilloskop ! (Spannungs-Teiler :5 an den Line-In / besser noch ein Poti dazu )


Mein Variabler PPM-Encoder (ist ALT/ Kann Fehler enthalten :nuts: ):

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#define SYSTEM_USED_TIMER_1

#define PPM_ENCODER_OUT_DDR  DDRB
#define PPM_ENCODER_OUT_PORT PORTB
#define PPM_ENCODER_OUT_PIN  PINB
#define PPM_ENCODER_OUT      PB1

volatile char max_channels = 8;
volatile int sync_pulse = 40035 / 2;
volatile int min_pulse = 20250 / 2;
volatile int shift_pulse = 4535 / 2;
volatile int ppm_range = 6750 / 2;
volatile char ppm_invert = 0;
volatile int pulscount = 0;
volatile char pulsflag = 0;
volatile int pulsmask[8];

SIGNAL(SIG_OVERFLOW1) {
	if (pulsflag == 0) {
		// Pulse-Pause ~0,4ms
		if (ppm_invert == 0) {
			PPM_ENCODER_OUT_PORT &= ~(1<<PPM_ENCODER_OUT);
		} else {
			PPM_ENCODER_OUT_PORT |= (1<<PPM_ENCODER_OUT);
		}
		TCNT1 = 65535 - shift_pulse;
		pulsflag = 1;
	} else if (pulsflag == 1) {
		// Pulse 1ms
		if (ppm_invert == 0) {
			PPM_ENCODER_OUT_PORT |= (1<<PPM_ENCODER_OUT);
		} else {
			PPM_ENCODER_OUT_PORT &= ~(1<<PPM_ENCODER_OUT);
		}
		TCNT1 = 65535 - min_pulse + ppm_range;
		pulsflag = 2;
	} else {
		if (pulscount < (int)(max_channels)) {
			// Pulse 0-1ms
			TCNT1 = (65535 - ppm_range) - pulsmask[pulscount];
			pulscount++;
			pulsflag = 0;
		} else if (pulscount < (int)(max_channels + 1)) {
			// Sync1. - Pulse 2.5ms
			TCNT1 = 65535 - (int)sync_pulse;
			pulscount++;
		} else {
			// Sync2. - Pulse 2.5ms
 			TCNT1 = 65535 - (int)sync_pulse;
			pulscount = 0;
			pulsflag = 0;
		}
	}
}

void PPM_Encoder_Set(char port, int value) {
	pulsmask[(int)port] = value;
}

void PPM_Encoder_Init(void) {
	PPM_ENCODER_OUT_DDR |= (1<<PPM_ENCODER_OUT);
	PPM_ENCODER_OUT_PORT &= ~(1<<PPM_ENCODER_OUT);
	pulsmask[0] = 0;
	pulsmask[1] = 0;
	pulsmask[2] = 0;
	pulsmask[3] = 0;
	pulsmask[4] = 0;
	pulsmask[5] = 0;
	pulsmask[6] = 0;
	pulsmask[7] = 0;
	// Timer 1
	TIMSK = (1<<TOIE1);
	TCNT1 = 0;
	TCCR1B = (1<<CS10);
	sei();                   /* enable timers */
}



:w

3

Mittwoch, 25. Februar 2009, 20:14

RE: Probleme bei Erzeugen eines servoimpulses

Um es vorweg zu nehmen, ich hab euere beiden Quellcodes nicht durchgearbeitet.

Ich möchte aber eine andere Methode der Servoimpulserzeugung vorschlagen, die mit den beiden Output Comparematch Interrupts des Timers 1 arbeitet.

1. Der Prescaler für den Timer 1 wird auf /8 eingestellt.
Das bedeutet bei einer Quarzfrequenz von 8MHz wird das TCNT Register alle µs um 1 erhöht.
2. Der Comparematch Interrupt B schaltet den Ausgang - Indeinem Fall PB2 ein und zählt zum aktuellen Stand von TCNT1 die gewünschte Servoimpulslänge dazu und stellt diese in das Comparematch Register von COM1A ( Comparematch A ).
3. Nun liegt der Servoimpuls an, bis der Comparematch Interrupt A zuschlägt.
Dieser schaltet nun den Port PB2 wieder ab und beendet somit den Servoimpuls.
Gleichzeitig wird zum Stand des Zählers TCNT1 die gewünschte Pausenlänge dazuaddiert und in das COM1B eingetragen.

Vorteile:
Durch die Teilung von /8 bekommt man die benötigten Comparematch Werte direkt in µs, was einfach nachvollziehbar ist.
Das System ist auf mehrere Servoausgänge problemlos erweiterbar.
Da das TCNT1 Register ja nicht beeinflusst wird, kann man den Timer 1 mittels ICP auch noch zur Servoimpulsauswertung ( Eingang ! ) heranziehen, die dann auch noch im Interrupt laufen kann.
Änderungen für die Impulslänge werden erst für den neuen Servoimpuls übernommen. ( Vermeidung von Überholeffekten ).
Da die Interrupt Routinen sehr einfach sind ( Additionen und Registeroperationen ) kann man sie auch noch in inline Assembler schreiben und somit die maximale Geschwindigkeit rauskitzeln.

Nachteile:
Die Servoimpulsgenerierung findet nicht vollständig in Hardware statt.
TCNT1 darf nicht manipuliert werden.

swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

4

Mittwoch, 25. Februar 2009, 20:21

RE: Probleme bei Erzeugen eines servoimpulses

Hallo Olli,

danke für Deine schnelle Antwort.

Zitat

Du musst PB2 irgendwann auch wieder auf LOW setzten


An PB2 hängt nur eine LED, um zu testen ob der Zähler überhaupt mal bei 8 ankommt.
Das Servo ist an PB1 / OC0B. Der Port wird vom Timer getriggert. Ich vermute mal, dass da beim ankoppeln bzw. trennen des Ports alle 9 Overflows etwas schief läuft. Das kann ich im AVR SImmulator leider nicht sehen.

Danke auch für deinen Code. Du verwendest aber einen 16-Bit Timer. Mein Tiny hat aber nur 8 Bit. Um den Servoimpuls ca. alle 20ms zu wiederholen will ich nur bei jedem 10ten Durchlauf den Port an den Timer ankoppeln. Ich probiers jetzt mal mit manuellem setzen eines Ports.

Gruß,
Stefan

EDIT:

ich habe jetzt alles an PB2 gehängt, nun klappt es: ???

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
....
ISR(TIMER0_COMPB_vect) {
     PORTB &= ~(1<<PB2);
}

ISR(TIMER0_OVF_vect) {
if(counts==8) {
     //TCCR0A |= (1<<COM0B1);
     PORTB |= (1<<PB2);
     counts = 0;
     }
else {
     //TCCR0A &= ~(1<<COM0B1);
     counts++;
     }
}


Was mich nur wundert, denn wenn ich mangels Oszi (Die Soundkartenlösung finde ich gut, habe die Woche über in HH nur beschränkte Möglichkeiten. Und eine Fahrt zum großeb C kostet das Selbe wie die Versandkosten von Reichelt) den prescaler auf 1024 setze, sind zumindest Optisch beide Lösungen gleich.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »swessels« (25. Februar 2009, 20:49)


swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

5

Mittwoch, 25. Februar 2009, 21:04

RE: Probleme bei Erzeugen eines servoimpulses

Hallo Wilhelm,

danke auch für Deine Antwort.

Aber wenn ich das richtig sejhe, beziehst Du Dich auf den Timer1 eines Mega8. Der Tiny hat aber nur 2 8-Bit Timer. Ich muss also entweder weit genug vorteilen oder Overflows zählen. Bei ( Bit Auflösung, 8MHz Takt und einem Vorteiler von 64 passen die 2ms gerade so in einen Timerdurchlauf.

Gruß,
Stefan

6

Freitag, 27. Februar 2009, 15:24

RE: Probleme bei Erzeugen eines servoimpulses

Mein Vorschlag bezieht sich auf einen Controller mit einem 16Bit Timer, wie dem ATMEGA 8.
Ich hab Servoroutinen auch schon bei einem AT90S2313 ausprobiert.
Sobald man dabei Timer Überläufe, zur Bestimmung der Impulslänge, braucht wirds schwierig.

swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

7

Montag, 2. März 2009, 07:10

RE: Probleme bei Erzeugen eines servoimpulses

Hallo Wilhelm,

ich habe es jetzt hinbekommen. Die Variante "alle X Overflows den OCRX-Pin an- bzw. abkoppeln" funktioniert nicht.
Manuell nur alle X Overflows einen Pin high- bzw. low- setzen klappt. Siehe Codeschnipsel 3 Posts weiter oben.

Gruß,
Stefan

8

Montag, 2. März 2009, 17:26

RE: Probleme bei Erzeugen eines servoimpulses

Mit einem Preload in das TCNTx Register kann man dann auch noch die Zwischenschritte zu den Überläufen einstellen.

if(X>12)
{
TCNT0=256-(Sollwert%256);
};

Nur mal so als Pseudocode.
TCNT wir dabei mit einem Wert vorgeladen und es brauchen somit nicht mehr so viele Takte kommen, als wenn der Zähler bei 0 beginnen würde.

swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

9

Dienstag, 3. März 2009, 09:05

RE: Probleme bei Erzeugen eines servoimpulses

Hallo Wilhelm,

Zitat

Mit einem Preload in das TCNTx Register kann man dann auch noch die Zwischenschritte zu den Überläufen einstellen.


Meinst Du zum erhöhen der Auflösung?
Mit meiner Variante oben habe ich zwar nur nutzbare 125 Schritte, das sollte aber für Landeklappen oder Fahrwerke reichen.

Gruß,
Stefan

10

Dienstag, 3. März 2009, 13:57

RE: Probleme bei Erzeugen eines servoimpulses

Zitat

Meinst Du zum erhöhen der Auflösung?

Ja - so war's gedacht.