PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Datenübertragung von pc zu zwei Motorsteuerungen über der Atmega644p



jiodatsinga
12.11.2012, 11:31
Guten Tag,

ich versuche gerade Zeile pro Zeile Positionskoordinaten (X,Y) einer Textdatei von PC zu zwei identischen Motorsteuerungen über ein Mikrocontroller zu senden. Die PositionKoordinaten(X,Y) der Textdatei sind in ASCii und werden in dieser Form zu den zwei Motorsteuerungen gesendet. Der Atmega 644p hat zwei USARTS(USART0 und USART1). USART0(RS232) dient zum Empfangen die Positionskoordinaten, die vom PC gesendet wurde. Dann wird über USART1(RS485) die empfangenen Positionskoordinaten zu den beiden Motorsteuerungen gesendet. Das Programm zum Senden der Positionskoordinaten von PC zum Atmega 644p wurde in c++ geschrieben und liegt ganz unten meinem Beitrag.
Die Positionskoordinaten, die von PC zu den beiden Motorsteuerungen über der Mikrocontroller gesendet werden, sind in folgender Form: "DX,YF".
D ---> Anfang des Befehls
X ---> Position auf die x-Achse in ASCii
',' ---> Trennzeichnen dient zur Unterscheidung von X und Y- Position
Y ---> Position auf die y-Achse in ASCii
F ---> Ende des Befehls.

Wenn ich die Positionskoordinaten(X,Y) der Textdatei Zeile pro Zeile zum Atmega644p sende, läuft alles wunderbar.
Aber wenn ich auf einmal alle Positionskoordinaten der Textdatei zum Atmega644p sende, wird nur ein, zwei oder drei Positionskoordinaten ausgeführt. Aber die Andere Positionskoordinaten(X,Y) werden nicht ausgeführt. Ich denke, etwas läuft bei meinem Atmega644p-Programm schief, vielleicht mein Empfangsinterrupt ISR(USART0_RX_vect). Ich komme einfach nicht klar. Mein Atmega644p-Programm liegt im Anhang.

Ich wäre sehr dankbar, wenn jemand mir hilft.

Danke im Voraus.

c++ Programm (PC Programm):


#include <fstream>
#include <string>
#include <iostream>
#include <sstream>

#include <Windows.h>

using namespace std;

// Senden eines Befehls Charakter pro Charakter und man test das Empfangen eines ACK
static bool SendungBefehl(HANDLE h, const char *s)
{
DWORD dummy;
char c;

// Wenn es seit dem letzten Befehl Antorten zu lesen gab,
// Zu spät, alles muss gelöscht werden.
PurgeComm(h, PURGE_RXCLEAR);
for (int i = 0; s[i] != 0; ++i)
if (!WriteFile(h, s + i, 1, &dummy, 0))
cout << "Error de WriteFile" << endl;
return false;
if (!ReadFile(h, &c, 1, &dummy, 0))
cout << "Erreur de ReadFile (time-out)" << endl;
return false; // Time-out

cout << "Réponse : " << (int)c << endl;
return c == '\x06'; // ACK
}

int main(void)
{
ifstream file("koordinaten.txt", ios::in | ios::binary);
string line;

if (!file)
{
cout << "Error: Die Öffnung der Textdatein in Lesen-Modus ist unmöglich" << endl;
return 1;
}
// Öffnung des seriellen Ports COM1
HANDLE h = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE)
{
cout << "Error: Öffnung der seriellen Port ist unmöglich" << endl;
return 1;
}
DCB dcb = { 0 };
BOOL dcbOk = GetCommState(h, &dcb);
dcb.BaudRate = CBR_115200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = TWOSTOPBITS;
dcbOk = SetCommState(h, &dcb);
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 100;
timeouts.ReadTotalTimeoutMultiplier = 100;
timeouts.ReadTotalTimeoutConstant = 100;
timeouts.WriteTotalTimeoutMultiplier = 100;
timeouts.WriteTotalTimeoutConstant = 100;
if (!SetCommTimeouts(h, &timeouts))
{
cout << "Erreur: SetCommTimeouts" << endl;
return 1;
}
// Lesen Zeile pro Zeile
while (getline(file, line))
{
int x; // x, y von der Textdatei
int y;
int x_steps; // x, y in Schrittmotor
int y_steps;
stringstream input; // Eingangsfluß (Eine Zeile der Textdatei)
stringstream output; // Ausgangsfluß (Ein Koordinatenpaar)

// Eine Zeile wird ein Eingangsfluß sein
input.str(line);
// Extraktion von X et du Y.
if (input.get() != 'X')
continue;
input >> x;
if (input.get() != 'Y')
continue;
input >> y;
// Konvertierung von Positionkoordinaten(X,Y) in Schrittmotor

x_steps = x * 127 / 500;
y_steps = y * 127 / 500;
// Sendung der PositionsKoordinaten Zeile pro Zeile über der serielle Port (COM1)
output << 'D';
output << x_steps;
output << ',';
output << y_steps;
output << 'F';
cout << "Sendung von : " << output.str() << endl;
if (SendungBefehl(h, output.str().c_str()))
cout << "OK" << endl;
else
cout << "ERROR" << endl;
}
CloseHandle(h);
return 0;
}

Hubert.G
12.11.2012, 14:48
Ich habe mir dein Programm nicht durchgeschaut, nach deiner Beschreibung gibt es zwei Möglichkeiten.
Du hast einen Buffer-Überlauf oder eher das die 8MHz Takt nicht zu deinen 115200 Baud passen, das sind laut Tabelle 8,5% Fehler.
7,3728MHz oder 11,0592 wären da die bessere Wahl.

jiodatsinga
12.11.2012, 15:24
Hallo Hubert.G

Danke schön für deine Rückmeldung.
ich habe gerade die Übertragungsrate und Fosc geändert. Jetzt habe ich laut der Tabelle des Datenblatts als Takt 7,3728MHz und 9600baud als baudrate ausgewählt. Das sind laut Tabelle des Datenblatts 0,0% Fehler. Trotzdem läuft mein Programm nicht.

Wie du vorher vermutet hast, habe ich wahrscheinlich ein Pufferüberlauf !! Kannst du mir helfen den Pufferüberlauf zu lösen ?

Danke im Voraus.

Hubert.G
12.11.2012, 15:42
Ich nehme an du hast auch den Quarz getauscht.
#define usart_buffer_max_size 256u
Schreib das 256 anstelle des 64 hinein.

jiodatsinga
12.11.2012, 16:04
Ich habe den Quarz getauscht und habe im Programm 256 anstelle 64hinein geschrieben.
Aber das Programm läuft immer nicht gut.

Hubert.G
12.11.2012, 17:10
Ist es besser geworden oder gleich geblieben. Sonst probiere mal 512, mehr wird dann schon kritisch wenn das Programm sonst noch was machen soll.

jiodatsinga
12.11.2012, 17:18
Das Problem ist gleich geblieben und nicht besser geworden. Ich probiere mit 512 und melde mich später.

Hubert.G
12.11.2012, 18:03
Ich habe mir das Programm mal kurz angeschaut, da ist kein RX-Buffer vorhanden. Da musst du dein Programm anpassen oder die Geschwindigkeit noch mal verringern, wobei anpassen das bessere wäre.

oberallgeier
12.11.2012, 18:07
... Übertragungsrate und Fosc geändert ... als Takt 7,3728MHz ... ausgewählt ...Ich weiß nicht, ob ich Dich richtig verstehe - dann wärest Du reichlich falsch. Denn in Deinem code steht


... #define FOSC 8000000 // Clock Speed ...Die Taktangabe ist kein irgendwie wählbarer Wert, wählbar ist nur der Quarz mit der entsprechenden Taktrate - und GENAU DER Wert, der auf dem Quarz steht, wird (bis auf hier nicht zu beachtende Ausnahmen) in den Code geschrieben. Andernfalls gibts Fehler, weil der Compiler damit Setzwerte für die Datenübertragung ausrechnet, die für Deine Hardwareausrüstung garnicht zutreffen.

Fazit: was am Quarz steht muss im Code auch reingeschrieben werden - sprich: der auf dem Quarz angegebene Taktwert muss in der Quelle genau wieder zu finden sein. Der Quarz ist aber wählbar . . .


Ich habe den Quarz getauscht und ... Programm läuft immer nicht gut.Was steht den AKTUELL auf Deinem Quarz der in der Platine steckt und was hast Du als FOSC im Quelltext genannt?

jiodatsinga
12.11.2012, 19:01
Ich bedanke mich bei oberallgeier und Hubert.G für die Feedback

Auf meinem Quarz, der in der Platine gesteckt wurde, steht Momentan 7,3728MHz und ich habe auch schon 7,3728MHz als Fosc im Quelltext geschrieben.

Jetzt versuche ich gerade mein Programm anzupassen und werde auch die baudrate vom PC, Motorsteuerungen und der Mikrocontroller reduzieren.

Soll Unbedingt der PC, Mikrocontroller und Motorsteuerungen das gleiche Baudrate haben? In der Grundeinstellung haben die Motorsteuerungen den Wert 115200 als Baudrate. Darum habe ich auch für den Mikrocontroller und PC 115200 als Baudrate ausgewählt. Soll Unbedingt der PC, Mikrocontroller und Motorsteuerungen das gleiche Baudrate haben? Ich werde den Wert 9600 als Baudrate für den PC, MiKrocontroller und Motorsteuerungen auswählen. Ich melde mich nachher.

Danke nochmal

Hubert.G
12.11.2012, 19:23
Ich sehe keinen Grund warum die beiden USART nicht unterschiedliche Baudraten haben könnten.

oberallgeier
12.11.2012, 21:15
... Quarz ... 7,3728MHz und ich habe auch schon 7,3728MHz ...Dieser Quarz passt ja bestens zu allen Baudraten unter 200kBd, siehe hier (klick). (http://www.gjlay.de/helferlein/avr-uart-rechner.html)

jiodatsinga
13.11.2012, 12:02
Moin,


Ich habe mir das Programm mal kurz angeschaut, da ist kein RX-Buffer vorhanden.

Wozu brauche ich RX-Buffer ? laut meinem Code die Byte die von UDR0 empfangen wurden, werden nachher in der Variable "data" geschrieben. Später werden die Byte, die vom "data" empfangen wurden, nacheinander in usart_command[usart_command_size] geschrieben. Meiner Meinung nach brauche ich kein RX-Buffer.

Aber es kann sein, dass mein Gedanke falsch ist. Wenn es der Fall ist, kannst du mir durch ein Beispiel illustrieren, wie ich RX-Buffer in meinem Code einsetzen soll.

Ich habe folgende Änderung in meinem Code gemacht:
- Neues Baudrate : 9600bps
- Die Taktangabe, die auf meinem Quarz steht, ist 7,372MHz. Ich habe genau diese Taktangabe im Quelltext hineingeschrieben.
- Änderung von Stoptbit in PC und Mikrocontroller-Programm: Jetzt 1 Stopbit anstelle 2 Stopbits
- Der PC, die beiden Motorsteuerungen und der Mikrocontroller haben das gleiche Baudrate und zwar 9600bps.
- Ich habe sogar jeweils der Buffer usart_buffer_max_size, sowie usart_command_max_size auf 512u und 20 erweitern

Leider ist das Problem gleich geblieben. Ich vermute, der PC bekommt nicht rechtzeitig eine Rückmeldung vom Mikrocontroller, bevor er die nächsten Positionskoordinaten sendet. Laut meinem Gedanke soll der PC für jede gesendete Positionskoordinaten ein Signal vom Mikrocontroller bekommen, bevor er die nächste Positionskoordinaten sendet. Aber das funktioniert für höchstens zwei oder drei Positionskoordinaten. Aber die restlichen Positionskoordinaten werden vom Pc nicht nicht übertragen.

Ich habe delay-Funktion benutzt, um die Kommunikation zu verbessert. Aber es klappt immer nicht!!

Ich wäre sehr dankbar für weitere Hilfe.

Danke im Voraus..

Mikrocontroller-Code:


#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
# define F_CPU 3686400UL
#include <util/delay.h>


#define FOSC 7372000 // Clock Speed
#define BAUD 9600UL

#define UBRR_VAL ((FOSC+BAUD*8)/(BAUD*16)-1) // clever runden
///////////////////////////////////////////////////////////////////
#define usart_buffer_max_size 512u
#define usart_command_max_size 20

char usart_command[usart_command_max_size + 1] = {0};
char usart0_tx_buffer[usart_buffer_max_size];
char usart1_tx_buffer[usart_buffer_max_size];
volatile uint8_t usart_command_size = 0;
volatile uint8_t usart0_tx_buffer_size = 0;
volatile uint8_t usart0_tx_buffer_start = 0;
volatile uint8_t usart1_tx_buffer_size = 0;
volatile uint8_t usart1_tx_buffer_start = 0;
/////////////////////////////////////////////////////////////////////
volatile uint8_t command_ready = 0;

/////////////////////////////////////////////////////////////////////
// Configuration USART0, USART1 and setting Baudrate

void USART_Init(unsigned int ubrr)
{
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char) ubrr;
UBRR1H = (unsigned char)(ubrr>>8);
UBRR1L = (unsigned char) ubrr;
UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0) | (0<<TXCIE0) | (0<<UDRIE0);
UCSR0C = (0<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00); // 1 Stopbit, data = 8 Bits
UCSR1B = (1<<RXEN1) | (1<<TXEN1) | (0<<RXCIE1) | (0<<TXCIE1) | (0<<UDRIE1);
UCSR1C = (0<<USBS1) | (1<<UCSZ11) | (1<<UCSZ10); // 1 Stopbit, data = 8 Bits
}

////////////////////////////////////////////////////////////////////////////////

// function receive USART0

unsigned char USART0_Receive (void)
{
while(!(UCSR0A & (1<<RXC0)) ); // Wait for data to be received

return UDR0; // Get and return received data from buffer
}


// function transmit USART0

void USART0_Transmit (unsigned char data0)
{
while ( !(UCSR0A & (1<<UDRE0)) ); // Wait for empty transmit buffer

UDR0 = data0; // Put data into buffer, sends the data
}

// function receive USART1

unsigned char USART1_Receive (void)
{
while(!(UCSR1A & (1<<RXC1)) ); // Wait for data to be received

return UDR1; // Get and return received data from buffer
}

// function transmit USART1

void USART1_Transmit (unsigned char data1)
{
while ( !(UCSR1A & (1<<UDRE1)) ); // Wait for empty transmit buffer

UDR1 = data1; // Put data into buffer, sends the data
}

/////////////////////////////////////////////////////////////////////

// Eingang vom Ringpuffer
void USART0_QueueIn(char c)
{
int i;

if (usart0_tx_buffer_size < usart_buffer_max_size)
{
i = (usart0_tx_buffer_size + usart0_tx_buffer_start) % usart_buffer_max_size;
usart0_tx_buffer[i] = c;
++usart0_tx_buffer_size;
}
else
{
usart0_tx_buffer_size = 0;
}
}

// Ausgang vom Ringpuffer
char USART0_QueueOut(void)
{
char c;

if (usart0_tx_buffer_size == 0)
return 0;
c = usart0_tx_buffer[usart0_tx_buffer_start];
--usart0_tx_buffer_size;
usart0_tx_buffer_start = (usart0_tx_buffer_start + 1) % usart_buffer_max_size;
return c;
}

// Eingang vom Ringpuffer
void USART1_QueueIn(char c)
{
int i;

if (usart1_tx_buffer_size < usart_buffer_max_size)
{
i = (usart1_tx_buffer_size + usart1_tx_buffer_start) % usart_buffer_max_size;
usart1_tx_buffer[i] = c;
++usart1_tx_buffer_size;
}
else
{
usart1_tx_buffer_size = 0;
}
}

// Ausgang vom Ringpuffer
char USART1_QueueOut(void)
{
char c;

if (usart1_tx_buffer_size == 0)
return 0;
c = usart1_tx_buffer[usart1_tx_buffer_start];
--usart1_tx_buffer_size;
usart1_tx_buffer_start = (usart1_tx_buffer_start + 1) % usart_buffer_max_size;
return c;
}

// Sendung einer Antwort über der Ringpuffer zum USART0
static void USART0_Send(const char *s)
{
int i;

for (i = 0; s[i] != 0; ++i)
USART0_QueueIn(s[i]);
if (usart0_tx_buffer_size > 0)
UCSR0B |= 1 << UDRIE0;
}

// Sendung eines Befehls über der Ringpuffer zum USART1
static void USART1_Send(const char *s)
{
int i;

for (i = 0; s[i] != 0; ++i)
USART1_QueueIn(s[i]);
if (usart1_tx_buffer_size > 0)
UCSR1B |= 1 << UDRIE1;
}


// Verarbeitung eines Befehls
static void ProcessCommand(void)
{
int i;
int x;
int y;
char x_moteur[12];
char y_moteur[12];


for (i = 0; i < usart_command_size; ++i)
if (usart_command[i] == ',')
break;

if (i <= 0 || i >= usart_command_size - 1)
{
// Man hat kein Kommazeichen in Mitte des Strings gefunden -> Fehler
USART0_Send("\x15"); // NAK, Sendung hat nicht geklappt.
usart_command_size = 0;
return;
}
// Ich wandle x und y in Integer um, um Berechnung durchzuführen, wenn es nötig ist
// Extraktion von X und Y
usart_command[i] = 0;
usart_command[usart_command_size] = 0;
x = atoi(usart_command);
y = atoi(usart_command + i + 1);
usart_command_size = 0;
itoa(x, x_moteur, 10);
itoa(y, y_moteur, 10);

// Sendung position x_moteur
USART1_Send("#1s");
USART1_Send(x_moteur);
USART1_Send("\r");
USART1_Send("#1A\r"); // Losfahren der Platine auf die x-Achse


// _delay_ms(30000); // Warten 15000ms --> 15s

// Sendung position y_moteur
USART1_Send("#2s");
USART1_Send(y_moteur);
USART1_Send("\r");
USART1_Send("#2A\r"); // Losfahren der Platine auf die y-Achse


_delay_ms(30000); // Warten 30000ms --> 30s

USART0_Send("\x06"); // ACK --> Freigage: PC kann nächste Data senden.

}

// Interruptsfunktion für das Empfangen von Byte
// Diese Funktion ist High, wenn RXCIE0 = 1
ISR(USART0_RX_vect)
{
char data;
data = UDR0;

// Verarbeitung des Befehls -->("D X,Y F")
// X = x_moteur und Y = y_moteur
if (data == 'F')
{
command_ready = 1;
}

else if (data == 'D')
{
// Erzeugung eines neuen Befehls
usart_command_size = 0;
}

else
{
// Als man weder F, noch D empfängt, speichert man
//die Koordinatenposition(X,Y) in einem Befehl
if (usart_command_size < usart_command_max_size)
{
usart_command[usart_command_size] = data;
++usart_command_size;
}
else
{
usart_command_size = 0;
}
}
}



// Interruptsfunktion für Byte-Übertragung
// Diese Funktion ist an, wenn UDRIE1 = 1
ISR(USART0_UDRE_vect)
{
UDR0 = USART0_QueueOut();
// Sendung stoppen, wenn es keine Daten mehr gibt zu senden
if (usart0_tx_buffer_size == 0)
UCSR0B &= ~(1 << UDRIE0);
}

// Interruptsfunktion für Byte-Übertragung
// Diese Funktion ist an, wenn UDRIE1 = 1
ISR(USART1_UDRE_vect)
{
UDR1 = USART1_QueueOut();
// Sendung stoppen, wenn es keine Daten mehr gibt zu senden
if (usart1_tx_buffer_size == 0)
UCSR1B &= ~(1 << UDRIE1);
}

void VorEinstellungMotor(void)
{
//USART1_Send("#1|0\r"); // Deaktivierung von Antwort der Motorsteuerung Nr 1
//USART1_Send("#2|0\r"); // Deaktivierung von Antwort der Motorsteuerung Nr 2
//USART1_Send("#1:baud=7"); // Baudrate = 9600
//USART1_Send("#2:baud=7"); // Baudrate = 9600
USART1_Send("#1D0\r"); // Festlegen der Position der Platine als Ursprung auf die x-Achse
USART1_Send("#2D0\r"); // Festlegen der Position der Platine als Ursprung auf die y-Achse
USART1_Send("#1p2\r"); // Modus: Absolut Positionierung --> p=2
USART1_Send("#2p2\r"); // Modus: Absolut Positionierung --> p=2

}


int main (void)
{
USART_Init(UBRR_VAL); // Initialisierung von USART0 and USART1
VorEinstellungMotor(); // Initialisierung Motorsteuerung
sei(); // Aktierung Interruptsfunktion


while (1) // Endlosschleife
{
if(command_ready)
{
ProcessCommand();
command_ready = 0;

}
}

}

jiodatsinga
13.11.2012, 15:41
Weißt zufällig jemand wie ich der Hardware Handshake RTS/CTS in meinemm Mikrocontroller-Code einsetzen, um die Datenfluss zwischen dem Mikrocontroller und dem PC zu kontrollieren .

Danke im Voraus !!