Forum: PC-Programmierung Serielle Schnittstelle


von Thomas H. (datatom)


Lesenswert?

Hallo zusammen,

ich habe ein Programm in C++ erstellt, welches Daten zum Mikrocontroller 
sendet und von dort empfängt. Leider funktioniert es nicht so wie es 
soll.
Auf dem Controller läuft ein Beispielprogramm von Atmel.

Ich habe ReadFile und die WriteFile in eine Schleife gesetzt.

Wie muss ich szBuff belegen(WriteFile), muss es ein ASCii-Wert sein?
Woher weiß ich, das ein Wert auf dem Controller ankommt?
Wieso funktioniert das Programm nicht?

Hier das Programm:


#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "windows.h"


int i = 1;
HANDLE hSerial;
COMMTIMEOUTS timeouts;
DCB dcbSerialParams;
char szBuff[4096];
DWORD dwBytesRead;
DWORD dwBytesWrite;
int n = 4096;


int _tmain(int argc, _TCHAR* argv[])
{

hSerial = CreateFile("COM3",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if(hSerial==INVALID_HANDLE_VALUE){
if(GetLastError()==ERROR_FILE_NOT_FOUND){
//serial port does not exist. Inform user.
  printf("Serial Port does not exist!\n");
}
//some other error occurred. Inform user.
printf("Some other error occurred!\n");
}

//////////////////////////////
if (!GetCommState(hSerial, &dcbSerialParams)) {
//error getting state
}
dcbSerialParams.BaudRate=CBR_9600;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
if(!SetCommState(hSerial, &dcbSerialParams)){
//error setting serial port state
}

///////////////////////////////
timeouts.ReadIntervalTimeout=50;
timeouts.ReadTotalTimeoutConstant=50;
timeouts.ReadTotalTimeoutMultiplier=10;
timeouts.WriteTotalTimeoutConstant=50;
timeouts.WriteTotalTimeoutMultiplier=10;
if(!SetCommTimeouts(hSerial, &timeouts)){
//error occureed. Inform user

  printf("Timeout!!\n");
}

//////////////////////////////////
while(i = 10000)
{
    if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
    //error occurred. Report to user.

       printf("Error by readfile!!\n");
    }
////////////////////////////////
    if(!WriteFile(hSerial, szBuff, n, &dwBytesWrite, NULL)){
    //error occurred. Report to user.

       printf("Error by writefile!!\n");
    }
}
///////////////////////////////
CloseHandle(hSerial);

////////////////////////////////
  system("pause");
  return 0;
}

Vielen Dank für eure Hilfe.

Grüße

datatom

von Reinhard Kern (Gast)


Lesenswert?

Hallo,

z.B. weil i = 1 ist und daher die Befehle nach while garnicht ausgeführt 
werden. Ohne Anspruch auf Vollständigkeit.

Gruss Reinhard

von Klaus W. (mfgkw)


Lesenswert?

wieso ist i 1? Es wird doch auf 1000 gesetzt...

von Klaus W. (mfgkw)


Lesenswert?

> Auf dem Controller läuft ein Beispielprogramm von Atmel.

Danke, für die Info. Soooo genau wollte ich es gar nicht wissen.

Ansonsten:
- Das Programm ist miserabel formatiert und nicht in [c]-Tags gesetzt
- Es steht nirgends, was es tun soll und woran du siehst, daß
  es sich falsch verhält.
  Aus einem offensichtlich falschen Programm das heraus zu lesen,
  was sich jemand dabei gedacht haben könnte, ist ziemlich
  sinnlos.
- Compilerwarnungen wurden offenbar ignoriert
- Fehlermeldungen werden mies ausgegeben (statt "Error by
  writefile!!\n" könnte man die Fehlerbeschreibung holen, dann
  müsste man hier nicht raten)

Soweit reicht es mir schon, nicht weiter lesen zu wollen.

von Reinhard Kern (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> wieso ist i 1? Es wird doch auf 1000 gesetzt...

Sorry, war in Pascal gedacht, aber richtig wird es dadurch auch nicht.

Gruss Reinhard

von Klaus W. (mfgkw)


Lesenswert?

Stimmt, besser wird es auch nicht.
Wäre i==10000 gemeint, würde das Programm auch keinen Sinn machen.
Mit i<10000 auch nicht, wenn das Inkrementieren fehlt.

von Martin V. (oldmax)


Lesenswert?

Hi Thomas
Meine Vorredner haben ja schon mal ein paar Hinweise betreffend der 
Struktur und Lesbarkeit gegeben. Auch ein Hinweis auf ein 
Beispielprogramm muß nicht mehr beackert werden. Daher mal etwas zur 
Sache:
Zuerst, damit ich weiß, die Kommunikation läuft, brauch ich eine 
Möglichkeit, dies zu testen. 2. PC und entsprechendes Programm oder 
wenn's bereits eine Kommunikation mit einem µC gibt, diese wieder 
hervorkramen oder die brutale Tour mit Brücke von TX nach RX.
Auf dem µC sendest du im Polling, Empfangen in einer ISR. Damit habe ich 
gute Erfahrungen gemacht. C ist nicht mein Ding, aber das 
Assemblertutorial hat mir hier sehr geholfen. Für C soll es ja auch 
eines geben.
Da speziell bei hohen Baudraten die Bytes nicht verloren gehen sollten, 
ist ein Ringpuffer angebracht. Mit einem Doppelregister holst du dir die 
Basisadresse des Buffers und addierst einen Schreibzeiger drauf. Dorthin 
speicherst du in der ISR den empfangenen Wert. Anschließend erhöhst du 
unter Berücksichtigung der Buffergrenze deinen Schreibzeiger oder setzt 
ihn auf 0. Im Polling, d.h. im laufenden Programm vergleichst du einfach 
einen Lesezeiger mit Schreibzeiger. Sind diese ungleich, bearbeitest du 
den Wert, der unter der Basisadresse + Lesezeiger steht, erhöhst den 
Lesezeiger in gleicher weise wie den Schreibzeiger und gut ist. Die 
Buffergröße lege ich ca. 2,5mal so hoch an, wie ich Daten hintereinander 
empfange. Bei knappen Speicher solltest du auch mit 1,5 fachem Wert 
auskommen.
Ach ja, innerhalb einer Programmschleife verzichte auf irgendwelche 
Warte oder Pausenzeiten......
vielleicht an der ein oder anderen Stelle ein NOP aber alles andere ist 
nicht nötig.
Grueß oldmax

von Thomas H. (datatom)


Angehängte Dateien:

Lesenswert?

So, ich habe das C++Programm nun geändert. Das mit der Variablen i war 
eine kleine Unachtsamkeit meinerseits:-) Es ist nun auch formatiert. Die 
Fehlerbehandlung bleibt erstmal in der einfachen Form, weil es zum 
Entwickeln so reicht und zum Glück auch keine Syntaxfehler und Warnungen 
vorhanden sind, siehe im Anhang die Datei Konsole.gif.

Ich weiß allerdings auch nicht, wie ich in C++ die Fehlercodes abfragen 
kann :-(

Im Anhang befindet das C-Programm, die Headerdatei und zwei dazugehörige 
readme-Dateien, was auf dem Controller abläuft. Es ist ein 
Beispielprogramm von Atmel: AVR®32 AT32UC3 Series Software Framework: 
USART Driver.
http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4192

Der Controller ist ein UC3B (AT32UC3B0256).

Zwischen dem Mikrocontroller und dem PC ist ein USB/RS232-Adapter (ATEN 
UC-232A) und zwei Kabel RxD und TxD, überkreuzt.

Ich habe nun folgende Probleme:

ReadFile und WriteFile dauern ca. jeweils 30 Sekunden. Warum ist die 
Verbindung so langsam?

Woher weiß ich, dass die Verbindung zwischen PC und Controller 
funktioniert? Was oldmax im Beitrag vorher geschrieben hat, verstehe ich 
nicht:-(

Wie kann ich, wenn die Verbindung klappt, Daten senden, z.B. die Zahl 
64000? Das Controllerprogramm sendet die Daten die kommen, wieder zum PC 
zurück.

Vielen Dank für die Hilfe:-)

Grüße

Datatom

Hier noch einmal das C++Programm

// SerielleSchnittstelle.cpp : Definiert den Einstiegspunkt für die 
Konsolenanwendung.
//

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "windows.h"



int i = 1;
HANDLE hSerial;
COMMTIMEOUTS timeouts;
DCB dcbSerialParams;
char szBuff[4096];
DWORD dwBytesRead;
DWORD dwBytesWrite;
int n = 4096;

int _tmain(int argc, _TCHAR* argv[])
{
  hSerial = CreateFile("COM3",
  GENERIC_READ | GENERIC_WRITE,
  0,
  0,
  OPEN_EXISTING,
  FILE_ATTRIBUTE_NORMAL,
  0);
  if(hSerial==INVALID_HANDLE_VALUE)
  {
    if(GetLastError()==ERROR_FILE_NOT_FOUND)
    {
      //serial port does not exist. Inform user.
      printf("Fehler bei CreateFile. Serial Port existiert nicht!\n");
    }
    //some other error occurred. Inform user.
    printf("Fehler bei CreateFile. Sonstiger Fehler!\n");
  }
  else
  {
    printf("Kein Fehler bei CreateFile!\n");
  }
//////////////////////////////
  if (!GetCommState(hSerial, &dcbSerialParams))
  {
    //error getting state
    printf("Fehler bei GetCommState!\n");
  }
  else
  {
    printf("Kein Fehler bei GetCommState!\n");
  }
  dcbSerialParams.BaudRate=CBR_9600;
  dcbSerialParams.ByteSize=8;
  dcbSerialParams.StopBits=ONESTOPBIT;
  dcbSerialParams.Parity=NOPARITY;
  if(!SetCommState(hSerial, &dcbSerialParams))
  {
    //error setting serial port state
    printf("Fehler bei GetCommState beim Parameter belegen!\n");
  }
  else
  {
    printf("Kein Fehler bei GetCommState beim Parameter belegen!\n");
  }
///////////////////////////////
  timeouts.ReadIntervalTimeout=50;
  timeouts.ReadTotalTimeoutConstant=50;
  timeouts.ReadTotalTimeoutMultiplier=10;
  timeouts.WriteTotalTimeoutConstant=50;
  timeouts.WriteTotalTimeoutMultiplier=10;

  if(!SetCommTimeouts(hSerial, &timeouts))
  {
    //error occureed. Inform user
    printf("Fehler bei Timeout!\n");
  }
  else
  {
    printf("Kein Fehler bei Timeout!\n");
  }
//////////////////////////////////
  while(i < 10000)
  {
    if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL))
    {
      //error occurred. Report to user.
      printf("Fehler bei ReadFile!\n");
    }
    else
    {
      printf ("Kein Fehler bei ReadFile!\n");
    }
////////////////////////////////
    szBuff[0] = 0x02;
    szBuff[1] = 0x01;
    szBuff[2] = 0x05;

    if(!WriteFile(hSerial, szBuff, n, &dwBytesWrite, NULL))
    {
      //error occurred. Report to user.
      printf("Fehler bei WriteFile!\n");
    }
    else
    {
      printf ("Kein Fehler bei WriteFile!\n");
    }
    i++;
  }
///////////////////////////////
  CloseHandle(hSerial);
////////////////////////////////
  system("pause");
  return 0;
}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Anmerkung zum Screenshot:

Der stellt Text dar. Windows kann den Text in die Zwischenablage 
kopieren, und den Text kann man dann aus der Zwischenablage hier in das 
Fenster einfügen. Ein Graphikscreenshot ist hier völlig nutzlos.

Das Kopieren in die Zwischenablage geht so:

Text mit der Maus markieren (lässt er sich nicht markieren, Rechtsklick 
und im Kontextmenü "markieren" auswählen). Um den markierten Text in die 
Zwischenablage zu befördern, die Eingabetaste drücken.

Desweiteren sollte Dir aufgefallen sein, daß das von Dir hochgeladene 
Bild sehr viel weißen Rand enthält - ist das Raum für persönliche 
Anmerkungen?

Wenn man Screenshots mit MSPAINT in eine Datei speichern will, vor dem 
Einfügen aus der Zwischenablage die Bildgröße ("Bildattribute") auf 
einen sehr kleinen Wert (1x1 reicht) stellen. Beim Einfügen erscheint 
dann die Frage, ob das auf die Größe der eingefügten Daten vergrößert 
werden soll.

Zur eigentlichen Frage:

Den Fehlercode einer fehlgeschlagenen Operation gibt die 
Win32-API-Funktion GetLastError zurück.

von Arc N. (arc)


Lesenswert?

Rufus t. Firefly schrieb:
> Zur eigentlichen Frage:
>
> Den Fehlercode einer fehlgeschlagenen Operation gibt die
> Win32-API-Funktion GetLastError zurück.

Kleine Ergänzung

GetLastError
http://msdn.microsoft.com/en-us/library/ms679360(VS.85).aspx
und wie man daraus einen mehr oder weniger aussagekräftigen Text 
erzeugt:
http://msdn.microsoft.com/en-us/library/ms680582(v=VS.85).aspx

> ReadFile und WriteFile dauern ca. jeweils 30 Sekunden. Warum ist die
> Verbindung so langsam?

Welchen Wert hat n beim Empfangen und Senden?
http://msdn.microsoft.com/en-us/library/aa363437(VS.85).aspx
bzw.
http://msdn.microsoft.com/en-us/library/aa363190(v=VS.85).aspx
ReadIntervalTimeout gibt an wie viele Millisekunden zw. zwei Bytes 
vergehen dürfen hier 50
ReadTotalTimeoutMultiplier wird mit der Anzahl der Bytes multipliziert 
die empfangen werden sollen hier 4096 * 10 dazu wird 
ReadTotalTimeoutConstant addiert...

von Thomas H. (datatom)


Lesenswert?

Hallo,

vielen Dank für die Antworten.

Ich habe wegen der Fehlerbehandlung das Beispiel

 http://msdn.microsoft.com/en-us/library/ms680582%28v=VS.85%29.aspx

angewandt. Leider kommt es bei der Zeile

 MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

zu folgenden Fehler:

GetProcessId failed with Error 6: Das Handle ist ungültig.

Was bedeutet diese Fehlermeldung?

Dann habe ich den Wert n von 4096 auf  gesetzt. ReadFile und WriteFile 
laufen nun wesentlich schneller. Die Frage ist nun, wie niedrig darf der 
Wert sein, so dass trotzdem alle Bytes gesendet und empfangen werden 
können?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das Beispiel erzeugt diesen Fehler, um zu demonstrieren, wie so ein 
Fehlercode ausgewertet ist. Hast Du überhaupt verstanden, was Du da tun 
willst?

von Thomas H. (datatom)


Lesenswert?

Ja habe ich. Den Fehler habe ich selber ausgelöst. Ich habe den 
Controller vom P abgezogen und dann kam der Fehler beim CreateFile. Die 
Frage hätte ich nicht stellen sollen:-(

Jetzt bleibt nur noch die zweite Frage aus dem vorletzten Beitrag:

> Dann habe ich den Wert n von 4096 auf 8 gesetzt. ReadFile und WriteFile
> laufen nun wesentlich schneller. Die Frage ist nun, wie niedrig darf der
> Wert sein, so dass trotzdem alle Bytes gesendet und empfangen werden
> können?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.