PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer1 versteh Problem



DeltaEx
28.12.2006, 16:36
Hallo Leute,

irgendwie stehe ich auf der Leitung und kann den Code nicht ganz kapieren . Und zwar ist das die Servosteuerung von der Seite: http://www.schoeppl.info/de/elektronik/servotester/servotester.aspx

Und zwar muss ja für ein Servo nach 20ms ein Signal folgen das zwischen 1ms und 2ms liegt.

Wie wird hier im Quellcode sichergestellt das SIGNAL (SIG_OVERFLOW1) nach 20ms erst aufgerufen wird?

Irgendwie verstehe ich nicht wie das timming gesetzt ist.



#define F_CPU 8000000

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


void initadc(void);
void inittimer1(void);

unsigned char volatile liADC = 0;
unsigned char volatile liPause = 0;
unsigned int volatile liPreload = 0;

int main()
{

initadc();
inittimer1();
sei();
DDRB = 255;


while (1==1)
{
// Timer Preload berechnen, bei 8 Mhz entspricht 8000 ca. 1ms, +max 1ms des ADC - Da Servosignal zw. 1 und 2ms spezifiziert ist
liPreload = 65536 - 8000 - ((8000 / 256) * liADC); // Entspricht 1 ms

}

}

SIGNAL (SIG_OVERFLOW1)
{
// 1 Volldurchlauf dauert ca. 8ms, 2 x 8 = 16 ms Pause, dann port einschalten, dauer einstellen, dann port abschalten
liPause++;
if (liPause==2)
{
PORTB=255;
TCNT1=liPreload;
}
if (liPause==3)
{
PORTB=0;
liPause=0;
}

}


SIGNAL (SIG_ADC)
{
liADC = ADCH;
}

void initadc(void)
{

//interne Referenzspannung und AD-Wandlerkanal 0, ADLAR setzen, 8 Bit des High Registers reichen
ADMUX = (1<<REFS1) | (1<<REFS0) | (1<<ADLAR);



// AD Wandler einschalten, Freerunning einschalten, Conversion starten, Interrupt einschalten, Prescaler auf 64
ADCSRA = (1<<ADEN)|(1<<ADFR)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1);

}

void inittimer1(void)
{
TCCR1B = (1<<CS10); // Direkter Takt, kein Prescaling
TIMSK |= (1<<TOIE1); // Overflowinterrupt aktivieren

}
[/url]

uwegw
28.12.2006, 17:13
Der Timer wird angeschmissen und läuft zwei Mal durch, was bei diesem Vorteiler 16ms dauern soll. Dann wird der Servoausgang eingeschaltet und der Timer mit einem Wert geladen, der ihn diesmal schon nach den 1 bis 2ms (je nach ADC-Wert) überlaufen lässt. Dann wird der Servoausgang wieder abgeschaltet. Somit ergibt sich eine Folge von Impulse, zwischen denen jeweils 16ms liegen. Nicht ganz normgemäß, aber dei meisten Servos dürften damit noch klarkommen.

DeltaEx
28.12.2006, 17:45
aber liPreload wird nicht mehr zurück gesetzt. das heißt das wird das Signal (SIG_OVERFLOW1) ab den ersten durchlauf zwischen 1ms und 2ms aufgerufen oder?

DeltaEx
29.12.2006, 14:07
Eine Frage habe ich noch ...
Was ist der Unterschied wenn ich

TCNT1 = 8000

ein bestimmten Wert gebe oder es so mache:

TCNT1L = 0xe0
TCNT1H = 0xb1

??
was ist richtig was ist besser?

linux_80
29.12.2006, 14:37
Hallo,

besser ist die obere Version, denn dann baut der Compiler die richtige Version aus H- und L-Register zusammen, und später schauts auch noch verständlicher aus, als mit zwei Werten für zwei Register.

Für den AVR ist das Später egal wie man es gemacht hat, solange die Reihenfolge eingehalten wurde.

Bei 16-Bit Registern muss man ja immer ein bestimmtes Ritual einhalten, und das überlasse ich lieber dem Compiler, als selber nachzudenken wierum das jetzt gleich wieder war. ;-)