PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] CTC Modus



volpi
13.08.2014, 11:43
Hallo zusammen,

ich habe eine Funktion erstellt welche ein PPM Signal für den Trainerport meiner Futaba Funke erzeugt. Das Startsignal ist ein 0,4ms LOW gefolgt von dem ersten HIGH Signal für Kanal 1 (0,7ms - 1,54ms). Das ganze Wiederholt sich bis wir an Kanal 8 angekommen sind. Nach Kanal 8 kommt nochmal ein 0,4ms LOW Signal welches in einem 11ms langen HIGH Signal endet. Das ganze fängt dann wieder von vorne an.

Es wird also mit sehr kurzen Timings gearbeitet. Sodass der Interrupt nur 210x im Bereich von 0,7ms bis 1,54ms getriggt wird. Ich benutze Timer0 im CTC Modus, ohne Prescale. Den gewünschten Endwert von 64 habe ich das Register OCR0 geladen. Soweit funktioniert auch alles. Wenn ich nun eine 32 als gewünschten Endwert wähle sollte der Interrupt ja nun 2x 210x also 410x durchlaufen werden. Irgendwie funktioniert das Programm dann aber nicht mehr.

Ich benutze einen ATmega32 mit 16MHz Quarz. Fuses sind gesetzt. Das Signal prüfe ich mit einem Logic Analysator. Der Code schaut folgendermaßen aus:



#define F_CPU 16000000L


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


void g_ppm(int Kanal[]);
void init();


int Werte[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
volatile int counter = 0;


int main(void)
{
init();

while(1)
{
g_ppm(Werte);
}
}


void init(void)
{
DDRD = 0xFF;
PORTD = (1<<PD0);
sei();

TCCR0 = (1<<WGM01); // CTC Modus
TCCR0 |= (1<<CS00); // Kein Prescale - CPU Takt
OCR0 = 64; // Endwert
TIMSK |= (1<<OCIE0); // Compare Interrupt erlauben
}


void g_ppm(int Kanal[])
{
counter = 0;

do // Startsignal
{
PORTD = (0<<PD0);
} while (counter != 100); // 100 = 0,4ms

for (int i = 0; i <= 7; i++)
{
counter = 0;

do // Signal
{
PORTD = (1<<PD0);
} while (counter != Kanal[i]+175 );

counter = 0;

do // Pause
{
PORTD = (0<<PD0);
} while (counter != 100); // 100 = 0,4ms

}

do // Endsignal
{
PORTD = (1<<PD0);
} while (counter != 2800); // 2750 = 11ms


}


ISR (TIMER0_COMP_vect)
{
counter++;
}


Meine Frage lautet nun:

Wieso funktioniert das Programm nicht, wenn ich den Endwert auf 32 neheme?

Liebe Grüße
volpi

wkrug
13.08.2014, 15:54
Überleg mal, was Du da tust.
Der Controller hat gerade mal 32 Taktzyklen, bevor wieder eine neuer Interrupt ausgelöst wird.
Das reicht noch nicht mal zum sichern aller Register!
Ich würd die Telegrammaufbereitung anders machen.
Nimm den Timer 1 mit einem Prescaler von 8.
Somit ist ein Takt 0,5µs lang.
Dann trägst Du in das OCR Register die gewünschte Puls bzw. Pausenlänge + den aktuellen OCR Register Inhalt ein.
Dann musst Du nur noch ein Flag setzen, ob ein Impuls oder ne Pause dran ist und den entsprechenden Port Ein- bzw. Ausschalten.
Dadurch ist ein Impulsauflösung von 0,5µs gegeben, das entspricht etwa 2000 sinnvollen Werten für 1ms, das schafft so gut wie keine Anlage.

Auch für einen kurzen Impuls von 1ms hat dein Controller 2000*8 also 16000 Taktzyklen Zeit, bevor er wieder einen Interrupt abarbeiten muss.

Solche Fehler wie Deinen kann man wunderbar mit dem Simulator vom AVR Studio 4.xx nachvollziehen.
Dann wirst Du merken, das der Controller ständig nur den Interrupt ausführt und auch welche verpasst ( Der Comparematch Interrupt hat nur ein Flag ).

volpi
13.08.2014, 19:22
Vielen Dank für diese Antwort.

Da ich noch blutiger Anfänger im Bereich Mikrocontroller und C Programmierung bin, hab ich mich schon sehr über meine "funktionierende" Lösung gefreut. Nach deinem Beitrag und sehr elegantem Lösungsvorschlag muss ich wohl nochmal neu ran und die Anwendungsbereiche für Interrups nochmal neu überdenken.