PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : RP6 und RC



blenderkid
30.12.2007, 18:46
Hi,
ich habe auf meinen Robby einen RCEmpfänger draufgebaut und die PWM Stecker an die ADCs gesteckt.
Ich habe ein Programm geschrieben ,dass 200ms lang zählt wie oft der Strom an geht.
Hmm,jetzt habe ich beim Steuern des RP6 immer eine Verzögerung bis er reagiert.

Gibt es eine bessere Methode die Frequenz des PWM zu ermitteln?

DIV

Dirk
30.12.2007, 19:19
Hi,

wenn du so ein Programm schreiben kannst, könntest du sicher auch darauf kommen, dass man so ohne alle weiteren Infos (Hardware: Was ist wo dran? Was soll das bewirken? Software: Stell dein Prog ein!) eine Glaskugel brauchen würde, um deine Frage zu beantworten.

Gruß Dirk

blenderkid
31.12.2007, 12:02
Hi, okay kann ich verstehen.

Ich finde keine Datenblätter zu dem Empfänder und der Fernsteuerung ( acoms AP-202/40 und AR-2/40 ), war auch keine Anleitung dabei :( .
Der Empfänder hat zwei Kanäle. Ich habe die PWM-Stecker, der beiden Kanäle, an ADC2 und ADC3 auf dem M32 gesteckt und die GNDs an die GNDs.

Wenn ich die ADCs auslese erhalte ich entweder 0 oder 655.
Jetzt möchte ich herausfinden wie die Frequenz der PWMs ist, um den RP6 mit der Fernsteuerung steuern zu können

roboterheld
31.12.2007, 13:29
....Jetzt möchte ich herausfinden wie die Frequenz der PWMs .......


kannste doch selber festlegen.

http://www.mikrocontroller.net/topic/87282#new

radbruch
31.12.2007, 13:51
Hallo blenderkid

Mit einfachen Bordmitteln des RP6:

// Auswerten eines 2-Kanal RC-Empfängers an PortC0 und PortC1 31.12.2007 mic

// Mit der RP6-Library, blockierend ähnlich wie sleep(), noch ohne timeout!!!
// Durch die Verwendung von SCL/SDA kann das Programm nicht angehalten werden,
// Nach einem Reset startet der ATMega32 sofort erneut.
// Besser ist ein Anschluß an ADC0/ADC1 (PortA0 und PortA1)

#include "RP6RobotBaseLib.h" // Library einbinden
#include "RP6uart.h" // Zum Debuggen, wir wollen ja was sehen,
#include "RP6uart.c" // auch wenn wir kein LCD besitzen

uint8_t read_rc(uint8_t kanal)
{
extern uint8_t delay_timer; // der sleep()-Timer aus RP6RobotBaseLib.c

if (kanal == 1) // Eingang Kanal 1 der RC-Fernbedienung (SCL xBus Pin10)
{
while (!(PINC & 1)); // Warten auf aufsteigende Flanke
sleep(1); // setzt den delay_timer auf 0
while (PINC & 1); // Warten auf absteigende Flanke
return (delay_timer); // Fertig, Rückgabewert in 0.1ms
}
if (kanal == 2) // Eingang Kanal 2 der RC-Fernbedienung (SDA xBus Pin12)
{
while (!(PINC & 2)); // Warten auf aufsteigende Flanke
sleep(1); // setzt den delay_timer auf 0
while (PINC & 2); // Warten auf absteigende Flanke
return (delay_timer); // Fertig, Rückgabewert in 0.1ms
}
return(0); // ungültiger Parameter übergeben
}


int main(void)
{
initRobotBase();
DDRC &= ~3; // Ports auf Eingang
PORTC &= ~3; // und PullUps aus
setLEDs(1); // Anzeige Programm gestartet

writeString_P("\n\n\r2-Kanal RC-Empfänger einlesen 31.12.07 mic\n\r");

while(1)
{
writeString_P("\n\r");
writeString_P("Kanal 1: ");
writeInteger(read_rc(1), 10);
writeString_P(" Kanal 2: ");
writeInteger(read_rc(2), 10);
mSleep(300);
}
return 0;
}

Die Ausgabe dazu:

[RP6BOOT]

[READY]



2-Kanal RC-Empfãnger einlesen 31.12.07 mic


Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 13 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 13 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 15 Kanal 2: 13

Kanal 1: 15 Kanal 2: 13

Kanal 1: 15 Kanal 2: 13

Kanal 1: 16 Kanal 2: 13

Kanal 1: 16 Kanal 2: 14

Kanal 1: 17 Kanal 2: 14

Kanal 1: 18 Kanal 2: 14

Kanal 1: 18 Kanal 2: 14

Kanal 1: 18 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 12 Kanal 2: 14

Kanal 1: 9 Kanal 2: 14

Kanal 1: 10 Kanal 2: 14

Kanal 1: 10 Kanal 2: 14

Kanal 1: 10 Kanal 2: 13

Kanal 1: 10 Kanal 2: 13

Kanal 1: 12 Kanal 2: 13

Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 11

Kanal 1: 14 Kanal 2: 10

Kanal 1: 14 Kanal 2: 10

Kanal 1: 14 Kanal 2: 10

Kanal 1: 14 Kanal 2: 10

Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 15

Kanal 1: 14 Kanal 2: 18

Kanal 1: 14 Kanal 2: 18

Kanal 1: 14 Kanal 2: 18

Kanal 1: 14 Kanal 2: 18

Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14

Kanal 1: 14 Kanal 2: 14


Da das Signal nur 0 oder 1 ist, benötigt man natürlich keinen ADC. Der Empfänger wird an Vcc und GND angeschlossen. Die Kanäle in dieser Version an SDA und SCL (PortC0/PortC1). Alle Anschlüsse sind am xBUS verfügbar.

Gruß

mic

[Edit]
Ich Depp, ich weiß doch, welche Ports verwendet werden sollten. Hier die Version für ADC2/3 (ungeprüft):

// Auswerten eines 2-Kanal RC-Empfängers an PortA2 und PortA3 31.12.2007 mic

// Version für blenderkid (nicht geprüft)

#include "RP6RobotBaseLib.h" // Library einbinden
#include "RP6uart.h" // Zum Debuggen, wir wollen ja was sehen,
#include "RP6uart.c" // auch wenn wir kein LCD besitzen

uint8_t read_rc(uint8_t kanal)
{
extern uint8_t delay_timer; // der sleep()-Timer aus RP6RobotBaseLib.c

if (kanal == 1) // Eingang Kanal 1 der RC-Fernbedienung (ADC2 PortA2)
{
while (!(PINA & 4)); // Warten auf aufsteigende Flanke
sleep(1); // setzt den delay_timer auf 0
while (PINA & 4); // Warten auf absteigende Flanke
return (delay_timer); // Fertig, Rückgabewert in 0.1ms
}
if (kanal == 2) // Eingang Kanal 2 der RC-Fernbedienung (ADC3 PortA3)
{
while (!(PINA & 8)); // Warten auf aufsteigende Flanke
sleep(1); // setzt den delay_timer auf 0
while (PINA & 8); // Warten auf absteigende Flanke
return (delay_timer); // Fertig, Rückgabewert in 0.1ms
}
return(0); // ungültiger Parameter übergeben
}


int main(void)
{
initRobotBase();
DDRA &= ~12; // Ports auf Eingang ADC2+3
PORTA &= ~12; // und PullUps aus
setLEDs(1); // Anzeige Programm gestartet

writeString_P("\n\n\r2-Kanal RC-Empfänger einlesen 31.12.07 mic\n\r");

while(1)
{
writeString_P("\n\r");
writeString_P("Kanal 1: ");
writeInteger(read_rc(1), 10);
writeString_P(" Kanal 2: ");
writeInteger(read_rc(2), 10);
mSleep(300);
}
return 0;
}

Noch ein [Edit]: Hab' doch glatt überlesen, dass es für ein M32 sein soll. Damit kann ich leider nicht dienen, weil mir das keiner schenken mag. *traurigkuck*

SlyD
31.12.2007, 14:53
Hallo,

@mic:
Kleiner Hinweis dazu:
Seit Version 1.3 der RP6Lib vom 25.9 gibt es auch die 16Bit Variable "timer" die alle 100µs hochgezählt wird. Sowohl für die RP6BaseLib als auch die RP6ControlLib.

Damit könnte man es so schreiben:


// Hier wird der E_INT1 Pin an PORTA als Eingang verwendet...
while (!(PINA & E_INT1)); // Warten auf aufsteigende Flanke
timer=0;
while (PINA & E_INT1); // Warten auf absteigende Flanke
return (timer); // Fertig, Rückgabewert in 0.1ms


Auf delay_timer sollte man eigentlich gar keinen Zugriff haben (der Compiler sollte meckern ;) ) - hast Du an den Headern was verändert?


Den Bootloader interessiert zum Starten des Programms übrigens nur SDA.

ACHTUNG: Auf jeden Fall zur Sicherheit 1K Widerstände in Serie dazwischen schalten wenn man SDA oder SCL als Sensoreingänge verwenden möchte! Der Bootloader generiert beim Starten nämlich einen General Call auf dem I2C Bus, schaltet SDA und SCL also als Ausgänge und ganz kurz nach GND!

--> Für E_INT1 und die beiden freien ADC Anschlüsse braucht man natürlich keinen Widerstand.
An den freien I/Os vom RP6-M32 Modul sowieso nicht wenn man die Portrichtung auf Eingang schaltet.


--------------------------------------------------------------------

@blenderkid:
Für das RP6-M32 Erweiterungsmodul funktioniert es prinzipiell natürlich ganz ähnlich. Hier hast Du auch jede Menge freie I/O Pins.

Um nochmal auf die Ausgangsfrage einzugehen:


Gibt es eine bessere Methode die Frequenz des PWM zu ermitteln?


Ja - man misst statt der Anzahl der Pulse einfach die Dauer eines einzelnen Pulses! Wie in dem Programmbeispiel von mic.

MfG,
SlyD

radbruch
31.12.2007, 16:34
Hallo SlyD

Ich verwende die orginale Version 1.3 vom 25.9.07 Die Variable delay_timer habe so eingebunden:

extern uint8_t delay_timer;

Eine Fehlermeldung erhalte ich nicht beim Compilieren, ich lese die Variable auch nur aus.

Ich verwende delay_timer mit Absicht, weil weiterhin timer für eigene Anwendungen frei bleiben sollte. Weil meine Funktion blockierend ist, kann delay_timer von sleep() in dieser Zeit nicht verwendet/verändert werden. Ein weiterer Vorteil ist, dass ich mit sleep(0) (war noch ein Bug in der ersten Version) bequem schreibend auf delay_timer zugreifen kann, auch wenn der Aufruf theoretisch einen kleinen Messfehler verursacht.

Der Tipp mit dem SDA-Reset funktioniert wunderbar, ich habe nun den zweiten Kanal auf E-INT1 gelegt und kann das Programm deshalb auch wieder stoppen.

Das aktuelle Programm sieht nun so aus:

// Auswerten eines 2-Kanal RC-Empfängers an PortC0 und PortA4 31.12.2007 mic

// Mit der RP6-Library, blockierend wie sleep(), ohne timeout!!!
// Besser ist ein Anschluß an ADC0/ADC1 (PortA0 und PortA1)

#include "RP6RobotBaseLib.h" // Library einbinden
#include "RP6uart.h" // Zum Debuggen, wir wollen ja was sehen,
#include "RP6uart.c" // auch wenn wir kein LCD besitzen

uint8_t read_rc(uint8_t kanal)
{
extern uint8_t delay_timer; // der sleep()-Timer aus RP6RobotBaseLib.c

if (kanal == 1) // Eingang Kanal 1 der RC-Fernbedienung (SCL xBus Pin10)
{
while (!(PINC & 1)); // Warten auf aufsteigende Flanke
sleep(0); // setzt den delay_timer auf 0
while (PINC & 1); // Warten auf absteigende Flanke
return (delay_timer); // Fertig, Rückgabewert in 0.1ms
}
if (kanal == 2) // Eingang Kanal 2 der RC-Fernbedienung (E_INT1 xBus Pin8)
{
while (!(PINA & E_INT1)); // Warten auf aufsteigende Flanke
sleep(0); // setzt den delay_timer auf 0
while (PINA & E_INT1); // Warten auf absteigende Flanke
return (delay_timer); // Fertig, Rückgabewert in 0.1ms
}
return(0); // ungültiger Parameter übergeben
}


int main(void)
{
initRobotBase();
DDRC &= ~1; // Ports auf Eingang (SCL)
PORTC &= ~1; // und PullUps aus
extIntOFF(); // E_INT1 auf Eingang
setLEDs(1); // Anzeige Programm gestartet

writeString_P("\n\n\r2-Kanal RC-Empfänger einlesen 31.12.07 mic\n\r");

while(1)
{
writeString_P("\n\r");
writeString_P("Kanal 1: ");
writeInteger(read_rc(1), 10);
writeString_P(" Kanal 2: ");
writeInteger(read_rc(2), 10);
mSleep(300);
}
return 0;
}

Leider sind meine ADC0/1-Anschlüsse vorerst dauerhaft belegt, weil ich sie zur Servoansteuerung verwende um meinen RP6 mit einem 4-Radantrieb zu betreiben. Ich habe immer noch keine Alternative zu den orginalen Antriebseinheiten gefunden, deshalb muss ich wohl abwarten, bis mir die passenden Teile eines Schrott-RP6 in die Hände fallen oder arexx ein Getriebekit zum Nachrüsten anbietet.

Gruß

mic

blenderkid
01.01.2008, 18:11
Hi, muss man irgendetwas besonderes machen um den timer zu verwenden?
Bei mir sagt der immer 0.
ich habe mal probiert:
writeInteger(timer,10);
mSpleep(200);
writeInteger(timer,10);

und auch da sagt er zwei mal 0.

SlyD
01.01.2008, 18:47
Die timer Variable gibt es wie gesagt erst seit der Version vom 25.9.2007 bzw. 28.9 der RP6Lib.
Hier die aktuelle Version:
http://www.arexx.com/rp6/downloads/RP6Examples_20071016.zip

Da muss man eigentlich nichts machen und kann die Variable direkt in allen eigenen Programmen verwenden.

Beispiel:


uint16_t t_end = 0;
uint16_t t_start = timer;

mSleep(100);
t_end = timer;

// Es ist besser die Ausgaben getrennt von den Messungen zu machen
// da die Ausgaben selbst auch Zeit benötigen.

writeString_P("# Start: ");
writeInteger(t_start,DEC);
writeString_P(" -> End: ");
writeInteger(t_end,DEC);
writeString_P(" -> Diff: ");
writeInteger(t_end - t_start,DEC);
writeChar('\n');


MfG,
SlyD

blenderkid
01.01.2008, 20:06
ich habe das hier geschrieben:

uint8_t RC(uint8_t kanal)
{
if (kanal == 1)
{
while((PINA&8));

timer=0;


while(!(PINA&8));

return (timer);
}
if (kanal == 2)
{
while(!(PINA&4));

timer=0;

while(PINA&4);

return (timer);
}
return(0);
}

und da sagt er immer 0.

blenderkid
01.01.2008, 20:11
uups, die Smilies sollen Achten sein.

radbruch
01.01.2008, 21:05
Hallo blenderkid

Poste doch mal dein komplettes Programm (möglichst aufs nötigste reduziert, möglichst kopiert und nicht nachgeschrieben wie "mSpleep(200); und in code-Tags), so dass man es im Umfeld betrachten kann. Erster Tipp: falsche (oder keine) Kanal-Nr. an RC() übergeben.

Man kann einen Eintrag hier im Forum auch editieren. Um die lästigen ;)-Smilies zu unterdrücken, kann man unten das Häckchen bei "Smilies in diesem Beitrag deaktivieren" reinmachen.

Gruß

mic

blenderkid
02.01.2008, 12:44
Ok hier also der Code aufs nötigste reduziert


uint8_t RC(uint8_t kanal)
{
if (kanal == 1)
{
while(!(PINA&8));

timer=0;


while(PINA&8);

return (timer);
}
if (kanal == 2)
{
while(!(PINA&4));

timer=0;

while(PINA&4);

return (timer);
}
return(0);
}

void moveCommand(behaviour_command_t * cmd)
{
RCcount=RC(1);
RCcount2=RC(2);
writeInteger(RCcount,10);
writeChar('\n');
}

int16_t main(void)
{
initRP6Control();

DDRA &= ~ADC3;
DDRA &= ~ADC2;
PORTA &= ~12;
startStopwatch6();
startStopwatch7();

writeInteger(timer,10);
mSleep(200);
writeInteger(timer,10);
while(true)
{
moveCommand(0);
}
return 0;
}



Hier kommt immer 0 heraus. :-(

mfg blenderkid

blenderkid
02.01.2008, 12:58
vielleicht wegen dem return(0); ?

radbruch
02.01.2008, 15:00
Hallo blenderkid

Was ich nun halt immer noch nicht weiß: Wie ist bei deinem Programm die Variable "timer" deklariert.

Egal, für einen schnellen Test kannst du folgendes ändern:

erstes timer=0; in timer=11;
zweites timer=0; in timer=22;
und das return(0); in return(33);

Bei 11 oder 22 stimmt etwas nicht mit dem timer, dann mal timer durch delay_timer ersetzen(beide sind gleichschnell 0,1ms!). 33 wird wohl nicht auftreten.

Gruß

mic

SlyD
02.01.2008, 15:12
Wie ist bei deinem Programm die Variable "timer" deklariert.


Braucht er nicht zu deklarieren - ist im RP6Lib drin als
volatile uint16_t timer;


@Blenderkid: Du hast aber auch an ADC0 oder ADC1 was angeschlossen? Eventuell mal den anderen Kanal verwenden falls Du da was verwechselt hast beim anschließen?

Poste mal nach den Modifikationen die mic vorgeschlagen hat die komplette Ausgabe des Programms!

Und zusätzlich würde ich einfach an vielen Stellen (z.B. Beginn/Ende einer Funktion, in den If Bedingungen etc. ) mal probeweise
writeString_P("#1#\n");
...
writeString_P("#2#\n");
...
usw. hinschreiben immer mit anderen Nummern natürlich. Dann weisst Du genau an welche Stellen Dein Programm hinspringt und wo es hakt.

Evtl. noch ein mSleep(100) in die Hauptschleife reinmachen damit die Ausgaben nicht zu schnell erfolgen.

Sobald das Programm dann funktioniert, kannst Du die ganzen Ausgaben wieder entfernen.

MfG,
SlyD

EDIT:
PINA & 8 ist natürlich E_INT1.
PINA & 4 ist allerdings nicht ADC1...

Schreib das am besten immer so: PINA & ADC0, PINA & E_INT1, PINC & SCL etc. dann weiss man auch direkt welcher Pin gemeint ist.
Diese ganzen Definitionen findest Du in der Datei RP6RobotBase.h

blenderkid
02.01.2008, 15:16
diese includes benutze ich.



#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"

sonst deklariere ich timer nicht.


Bei dem Test kommt immer 11 heraus.
Als ich delay_timer benutzt hab, sagte mir der Compiler: RP6Control_10_Move2.c:467: error: 'delay_timer' undeclared (first use in this function)

MfG

blenderkid

blenderkid
02.01.2008, 15:32
>>Diese ganzen Definitionen findest Du in der Datei RP6RobotBase.h<<

ich benutze aber den M32.
also RP6ControlLib.h

SlyD
02.01.2008, 15:36
Ach - sorry - hab ich nicht mehr dran gedacht.

Natürlich ist es auch dafür sinnvoll die entsprechenden Definitionen aus "RP6Control.h" zu verwenden, also z.B. PINA & ADC2 usw. - dann weiss man direkt wo was angeschlossen ist.

blenderkid
02.01.2008, 15:37
Es wird oben von Verion 1.3 erzählt. In der Dateien aus dem Link oben:
http://www.arexx.com/rp6/downloads/RP6Examples_20071016.zip

Steht immer version 1.1

radbruch
02.01.2008, 15:40
Hallo

Die Pins sollten eigentlich richtig sein, sonst würde die Funktion RC() nie beendet werden (oder es sind zufällig irgendwelche Eingänge die wechseln).

Wenn 11 zurückgemeldet wird, läuft irgendwas mit dem Timer schief. Ich würde mal delay_timer einbinden (das hat bei mir funktioniert) und dann weiter entscheiden:

extern uint8_t delay_timer;

und timer=0; durch Sleep(0); ersetzen.

Gruß

mic

SlyD
02.01.2008, 15:45
@blenderkid:
Ja - oben dachte ich auch noch Du sprichst von der Lib für das Mainboard - die hat Version 1.3 - die Lib für das RP6Control Modul ist 1.1 - da ist der Timer natürlich auch schon mit drin.
Die Versionsnummern laufen getrennt, damit man sehen kann in welchen Teilen der Lib sich was verändert hat.

Die sind nur in einem Archiv, weil einige Dateien gemeinsam verwendet werden (I2C und UART Funktionen)

MfG,
SlyD

PS:
Was ist denn die Ausgabe mit dem Code den ich oben gepostet habe:
https://www.roboternetz.de/phpBB2/viewtopic.php?p=339987#339987
?

blenderkid
02.01.2008, 15:49
Ahh, klasse der delay_timer funktioniert sehr gut.

Danke an Alle.

MfG

blenderkid