PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PWM Signal von RC-Empfänger auswerten



MartinFunk
17.01.2007, 14:37
Hi,
ich möchte das PWM signal eines RC-Empfängers auswerten.
Hat das schon jemand gemacht ? Hätte mir jemand einen beispielcode?
In Google und in der Forum suche hab ich nur was in Bascom und ASM gefunden.

Mfg Martin

Hanni
17.01.2007, 18:07
Jo, das hab ich schon mal gemacht ... nur halt in ASM ...

MartinFunk
17.01.2007, 19:16
Hat das auch schonmal jemand in C gemacht?

MfG Martin

wkrug
18.01.2007, 07:54
Ich hab erst kürzlich so ein Programmteil in ASM für C gemacht.
Wenn ich heute nach Hause komme kann ich dir den Quellcode mal zuschicken wenn Du das möchtest. Der ist aber für CodeVision AVR!

Im Prinzip läuft dabei der Timer1 frei.
Die Servoimpulse werden auf einen Interrupteingang des AVR gelegt.
Am Anfang steht die Interruptauslösung auf "steigende Flanke".
Im Interrupt 0 wird dann der aktuelle Zählerwert in eine Variable eingelesen und die Interrupteinstellung auf fallende Flanke geändert (MCUCR).
Bei der fallenden Flanke wird der Zählerwert des Timers 1 erneut ausgelesen und der Startwert davon abgezogen und die Interrupteinstellung wieder auf steigende Flanke für den nächsten Impuls gesetzt. Du kannst nach einer fertigen Messung noch ein Flag setzen (Bit Variable) das ein neuer Servoimpuls erkannt wurde (Zur Weiterverarbeitung im Hauptprogramm).
Dadurch das der Timer 1 frei läuft können alle Interrupteingänge + der ICP Pin für die Servoimpulsauswertung verwendet werden. Du kannst somit bis zu 4 Servokanäle überwachen (ATMEGA 16) ohne dabei den Prozessor übermäßig zu belasten.

Als Teilerfaktor für den Timer 1 würd ich 8 verwenden bei einem 8MHz Quarz, dann werden deine Servoimpulse im 1uS Bereich aufgelöst. Ein durchschnittlicher Servoimpuls (1,5ms) wird somit als 1500 dargestellt.
Der gesamte Servoweg 1ms bis 2ms hat somit 1000 Schritte und sollte somit auch für anspruchsvollere Aufgaben geeignet sein.

Wenns nicht reicht - Taktfrequenz erhöhen (16 MHz) oder Teilerfaktor des Timers 1 auf 1 setzen (würd ich bei 4MHz Taktfrequenz machen).

Henry
18.04.2007, 13:45
Hallo Martin,

ich weiß nicht ob Du das Problem schon gelöst hast. Ich habe aufgrund dieses Beitrags hier mal einen Code zusammengebastelt (da ich das auch gesucht habe). Mit Hilfe des Forums habe ich dann auch noch kleine Probleme darin behoben.

Hie mal die Codeteile die Relevant sind um erst einmal ein Grundgerüst zu haben. Ich habe das in einzelnen Funktionen gelöst, kann man sicher noch besser machen (bin aber selber noch nicht so fit in C).
Das Beispiel läuft bei mir auf einem Mega16 mit 8MHz, es basiert auf der vorhergehenden Antwort.

Interrupt auf INT0 initialisieren:


void init_interrupt(void)
{
MCUCR |= (1<<ISC00) | (1<<ISC01); //INT0 auf Steigende Flanke stellen (Löst Interrupt bei steigendet Flanke an INT0 aus
GICR |= (1<<INT0); //Interrupt von INT0 auf Enable
}

Timer initialisieren:


void init_timer(void)
{
//Timer 1 (16Bit)
TCCR1B |= (1<<CS11); //Vorteiler auf CPU Takt/8
}

PortB initialisieren (als Ausgang schalten):


void init_digital(void)
/*Diese Funktion initialisiert die verwendeten Ports*/
{
DDRB |= (1<<DDB1) | (1<<DDB2) | (1<<DDB3) | (1<<DDB4) | (1<<DDB5); //Bit 1 bis Bit 5 an Port B als Ausgang belegen
}


Interrupt an INT0 auswerten:


ISR(INT0_vect)
{
if (flanke == 1)
{
start = TCNT1;
MCUCR |= (1<<ISC01); //INT0 auf fallende Flanke stellen
MCUCR &= ~(1<<ISC00);
flanke = 0;
}
else
{
stop = TCNT1;
impuls = stop - start;
MCUCR |= (1<<ISC00) | (1<<ISC01); //INT0 auf Steigende Flanke stellen (Löst Interrupt bei steigendet Flanke an INT0 aus)
flanke = 1;
}
}


Testprogramm zur Visualisierung der Auswertung:


#include <avr/io.h>
#include <avr/iom16.h>
#include <avr/interrupt.h>
#include "inttypes.h"

init_digital(); // Ports initialisieren (eigene Funktion)
init_timer(); // Timer initialisieren (eigene Funktion)
init_interrupt(); // Interrupt initialisieren


int main(void)
{

int start;
int stop;
int32_t impuls;
int flanke;

sei(); //Interrupts aktivieren

while(1)
{

//************************************************** **************************
if (impuls < 1100)
{
PORTB |= (1<<PB3); //Bit3 auf High setzen
}

if (impuls > 1800)
{
PORTB |= (1<<PB4); //Bit4 auf High setzen
}

if ((impuls > 1490) & (impuls < 1550))
{
PORTB &= ~(1<<PB4); //Bit4 auf Low setzen
PORTB &= ~(1<<PB3); //Bit3 auf Low setzen
}

//************************************************** **************************

}

}


In meinem Beispiel wird bei einem vollen Knüppelausschlag in eine Richtung PB3 gesetzt in nullstellung wieder zurückgesetzt und in die andere Richtung PB4 auf High und in Nullstellung ebenfalls wieder auf Low

Ich hoffe das Hilft Dir weiter, falls Du noch keine Lösung hast.

MartinFunk
18.04.2007, 15:23
Hi,
nein ich habe das problem noch nicht gelöst.
Danke für den code ich werds gleich mal ausprobieren.

MfG Martin

Henry
18.04.2007, 15:29
Dann konnte ich Dir ja evt. sogar damit helfen ;)
Viel weiter bin ich auch noch nicht, da ich jetzt erst einmal schauen muss wie ich meine Idee umsetzen kann.
Da scheitert es zur Zeit noch an der Programmtechnischen Umsetzung ;)