PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Verbindung zwischen zwei uC



nec-rot
05.11.2011, 13:12
Hallo Leute,

ich möchte gerne Daten von einem Mikrocontroller zu einem anderen Mikrocontroller senden.
Mikrocontroller2 wertet einen Ultraschallsensor SRF02 aus, und sendet die gemessene Entfernung zu Mikrocontroller1.

Probiert habe ich das ganze über die Serielle Schnittstelle der beiden Mikrocontroller.
Leider scheitert es immer wieder daran, dass die Zykluszeit des Mikrocontrollers der empfängt extrem in die Höhe schnellt.
Dazu muss man noch sagen, dass auf dem Mikrocontroller der empfangen soll, die Mulwii-Software läuft welche einen Quadrocopter steuert.

Sobald ich meinen Codeschnipsel in das Programm einfüge, geht die Zykluszeit in die höhe und der Quadrocopter reagiert nicht mehr.

Mikrocontroller1: ArduinoProMini Atmega 328p (empfängt)
Mikrocontroller2: Arduino Uno Atmega 328p (sendet)
Ultraschallsensor: SRF02


Diesen Code verwende ich auf dem zu empfangenden Mikrocontroller1:


void srf02_serial()
{

char inString[21];
int inCount;

inCount = 0;

do
{
while (Serial.available()==0);
inString[inCount] = Serial.read();
if(inString[inCount]==13) break;
}

while(++inCount < 20);

inString[inCount] = 0;


}

die Übertragung funktioniert zwar, aber wie gesagt, die Zykluszeit geht extrem in die Höhe.

kann ich an diesem Code etwas abändern damit er die Zykluszeit nicht so krass beeinflusst?

lg tobias

-schumi-
05.11.2011, 14:16
Herzlich willkommen im RN :-D

Ich schätze, das dauert so lange, weil der andere µC so langsam sendet, bzw. UART nicht unbedingt sehr schnell ist, wenn man Übertragungsfehler vermeiden möchte.

Ich würds z.B. so machen:


#define StringStatus_bereit 0
#define StringStatus_empfange 1
#define StringStatus_bitteabholen 2



// Die drei Variablen global deklarieren
char inString[21];
int inCount;
char StringStatus = StringStatus_bereit; // Sagt dir, ob im Moment noch der String empfangen wird, oder ob er schon fertig ist




void srf02_serial()
{
if ((StringStatus = StringStatus_bereit) && (Serial.available()==0)) // Falls bereit und Daten anliegen...
{
StringStatus = StringStatus_empfange; // ...wird der Status auf "empfange" gesetzt
inCount = 0; // Und der Zähler zurückgesetzt
}


while((StringStatus == StringStatus_empfange) && (Serial.available()==0)) // Falls mit Empfangen beschäftigt und Daten anliegen
{
inString[inCount] = Serial.read(); // Werden die Daten in den String geschrieben
if((inString[inCount]==13) || (inCount >= 18)) // Falls dein Enter(?)-Zeichen kommt oder der String schon voll ist...
{
inString[19] = 0; // ...am Ende ein Stringende-Zeichen setzten...
StringStatus = StringStatus_bitteabholen; // ...und sagen dass die Übertragung fertig ist und die Daten abgeholt werden können
}
inCount++;
}
}

(Aber ungetestet - sprich Tippfehler garantiert vorhanden^^)

Allerdings muss dann die Sub bei jedem durchlauf der Hauptschleife aufgerufen werden. Sobald in StringStatus StringStatus_bitteabholen drinsteht, kannst du die Daten des Strings verarbeiten. Sobald du fertig bist musst du den StringStatus aber wieder auf StringStatus_bereit setzten, sonst wartet die Sub nur bis du endlich fertig bist.

Viele Grüße
-schumi-

radbruch
05.11.2011, 14:45
Oder eine ISR-Lösung:


volatile uint8_t usart_puffer[25], usart_write=0, usart_read=0, eingabe=0;

#define BAUD_LOW 38400 //Low speed - 38.4 kBaud
#define UBRR_BAUD_LOW ((F_CPU/(16*BAUD_LOW))-1)

UBRRH = UBRR_BAUD_LOW >> 8; // Baudrate is Low Speed
UBRRL = (uint8_t) UBRR_BAUD_LOW;
UCSRA = 0x00;
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
UCSRB = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE); // Senden, Empfangen und Empfang-ISR einschalten

while(1)
{
if(eingabe)
{
// empfangene Zeichen stehen jetzt in usart_puffer[]
// ...verarbeiten...

usart_read=0;
usart_write=0;
eingabe=0;
}
// Ab hier Hauptprogramm:
}


SIGNAL (SIG_UART_RECV)
{
usart_puffer[usart_write]=UDR;
if(usart_puffer[usart_write++] == 13) eingabe=1; // CR empfangen
if(usart_write > 24) {usart_write=24; eingabe=2;} // Pufferüberlauf!
}

nec-rot
05.11.2011, 14:52
@schumi
seltsam, nachdem ich grade den Code hochgeladen habe, sind direkt die Motoren angelaufen!! das kapier ich jetzt mal überhaupt nicht!

Im Prinzip gehts mir darum die Entfernung die der Ultraschallsensor ermittelt irgendwie in den Mikrocontroller rein zu bekommen.
Ob es nun über einen zweiten uC geht oder direkt über den ersten per I2C ist mir egal.

Ich möchte einfach nur die Entfernung einlesen, und mit diesem Wert weiter arbeiten, um den Copter auf einer höhe zu regeln,

Vielleicht kannst du dir mal den Code hier anschauen und mir sagen wie ich den Sensor am besten in das Projekt implementieren kann. Ich steh irgendwie aufm Schlauch.
http://multiwii.googlecode.com/files/MultiWiiV1_8.zip

Grüße Tobias

nec-rot
05.11.2011, 14:58
Oder eine ISR-Lösung:


volatile uint8_t usart_puffer[25], usart_write=0, usart_read=0, eingabe=0;

#define BAUD_LOW 38400 //Low speed - 38.4 kBaud
#define UBRR_BAUD_LOW ((F_CPU/(16*BAUD_LOW))-1)

UBRRH = UBRR_BAUD_LOW >> 8; // Baudrate is Low Speed
UBRRL = (uint8_t) UBRR_BAUD_LOW;
UCSRA = 0x00;
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
UCSRB = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE); // Senden, Empfangen und Empfang-ISR einschalten

while(1)
{
if(eingabe)
{
// empfangene Zeichen stehen jetzt in usart_puffer[]
// ...verarbeiten...

usart_read=0;
usart_write=0;
eingabe=0;
}
// Ab hier Hauptprogramm:
}


SIGNAL (SIG_UART_RECV)
{
usart_puffer[usart_write]=UDR;
if(usart_puffer[usart_write++] == 13) eingabe=1; // CR empfangen
if(usart_write > 24) {usart_write=24; eingabe=2;} // Pufferüberlauf!
}


also hier versteh ich mal garnix ;)

-schumi-
05.11.2011, 15:51
Die Interruptlösung ist natürlich eleganter, wenn auch komplizierter^^

Allerdings glaub ich, wird das in diesen Fall nicht gehen, weil der Interrupt schon von der Mulwii-Software selbst benutzt wird (um dann weitere Unterfunktionen ala
Serial.read() usw. bereitzustellen, denke ich)


nachdem ich grade den Code hochgeladen habe, sind direkt die Motoren angelaufen!! das kapier ich jetzt mal überhaupt nicht!
Ich noch weniger, hab die Software noch nie in den Finger gehabt und kann dementsprechend wenig damit anfangen...
Könntest du mal kurz erläutern, wo überhaupt dein UART-Zeug steht? Wie das ganze gegliedert ist?

Ich konnts nämlich nicht finden...

Gruß
-schumi-

PS: Warum enden die Sourcen eigentlich auf .pde? Also wenn das ne IDE ist, dann ne doofe^^ Und was hat Java damit zu tun?

radbruch
05.11.2011, 15:58
Unabhängig vom Kompiler/IDE sind while-Schleifen tötlich, egal wie harmlos sie aussehen:

while (Serial.available()==0);
while((StringStatus = StringStatus_empfange) && (Serial.available()==0))

(und 'ne Zuweisung statt des Vergleichs ist besonders fies ;)

nec-rot
05.11.2011, 16:36
Die Dateien kannst du mit dem Arduino Tool hier: http://arduino.googlecode.com/files/arduino-0022.zip öffnen.
Das ganze untergliedert sich in verschiedene Bereiche:

ich hab mal meinen Schaltplan + den Code als Bild angehängt


204722047320474

-schumi-
05.11.2011, 16:39
while((StringStatus = StringStatus_empfange) && (Serial.available()==0))
(und 'ne Zuweisung statt des Vergleichs ist besonders fies ;)
Desshalb sagte ich ja, mit Sicherheit Tippfehler enthalten^^
(Habs oben mal ausgebessert)

Aber weist du was besseres? (Wenn man keine ISR benutzen darf)

Das Problem ist ja, dass wenn man ein IF anstatt WHILE verwendet, der Controller pro 1x Hauptschleife durchlaufen auch nur 1 Zeichen entgegennehmen kann. Und da sowohl Geschwindigkeit des UART als auch die Zeit die die Hauptschleife um einmal durchzulaufen benötigt unbekannt sind, ist es nicht möglich abzuschätzen, ober der Buffer überläuft oder nicht.

Mal abgesehen davon, dass ich damit warscheinlich sowiso überfordert währe, das auszurechnen^^

Mit der While-Schleife entleert er bei jedem Durchlauf der Hauptschleife den Buffer, so dass ein Überlauf wohl recht unwarscheinlich ist...

Hättest du ne bessere Lösung?

Gruß

[EDIT]: @nec-rot:
Ich werds mal versuchen^^

nec-rot
05.11.2011, 16:50
danke Schumi;)

mit dem I2c Bus hab ich das teil ja auch schon zum laufen bekommen, und zwar direkt über den Mikrocontroller 1.
Vielleicht kann man den Code effizienter einsetzen um die Zykluszeit kaum zu beeinflussen.



//Einlesen der Entferung über I2C mit SRF02 Ultraschallsensor.

#include <Wire.h>

#define srf02Address (0xE0 >> 1)
#define cmdByte 0x00 //Startbefehl zum messen
#define rangeByte 0x02
#define startMessung 0x51

byte MSB = 0x00;
byte LSB = 0x00;


void setup()
{
Serial.begin(115200);
Wire.begin();
}

void loop()
{
int rangeData = getRange();

Serial.println(rangeData); // Ausgabe der Entfernung

delay(200);

}

int getRange()

{
int range = 0;

Wire.beginTransmission(srf02Address); //Ultraschallmesser wird über seine Adresse angesprochen
Wire.send(cmdByte); //Startbefehl zum messen
Wire.send(startMessung); //Startet Messvorgang in cm
Wire.endTransmission();

delay(100);

Wire.beginTransmission(srf02Address);
Wire.send(rangeByte);
Wire.endTransmission();

Wire.requestFrom(srf02Address, 2);
while(Wire.available() < 2);
MSB = Wire.receive();
LSB = Wire.receive();

range = (MSB << 8) + LSB;

return(range);
}

-schumi-
05.11.2011, 17:13
Also...
Ich hab nen Tippfehler, einmal Stringstatus anstatt StringStatus geschrieben....
Ich kanns nicht erfolgreich kompilieren, weil der AVR-GCC meine math.h anmault (warum weis ich nicht... mal gucken)
#2 würde mir sowiso nichts bringen, weil mein Gehirn nicht 2 AVRs, inclusive Pheripherie simulieren kann^^ Und um den Code von Hand durchzugehen ist es zu viel und zu komplex....

mit dem I2c Bus hab ich das teil ja auch schon zum laufen bekommen, und zwar direkt über den Mikrocontroller 1. Eindeutig die bessere Lösung - aber ich bin ein I2C-Noob und kann dir da leider nicht weiterhelfen ;)
Du kannst es aber auch nochmal mit der Seriellen versuchen, ich hab die Fehler oben ausgebessert..

Gruß
-schumi-

PS: Für Code gibt es Codeblöcke, dann bekommt der auch keine Smileys :) Die findest du im Editor in der Zweiten Symoblleiste, der 3. Button von rechts (Das Schweinegatter)