Forum: Mikrocontroller und Digitale Elektronik AT90S8535 <-- Daten --> PC


von jan_ (Gast)


Lesenswert?

Hallo,

habe mir einen Parallel-Programmer für den AT90S8535 gebaut, an dem eine 
Erweiterungsplatine für die serielle Kommunikation über RS-232 
angeschlossen ist. Die Erweiterungsplatine habe ich, wie im 
"AVR-Tutorial-6. Das UART"
http://www.mikrocontroller.net/tutorial6.htm
beschrieben, aufgebaut.

Für den Funktionstest Zwischen Controller und PC verwende ich das 
Controller-Programm

http://people.freenet.de/atavr/ser.asm

Dieses Programm empfängt über RS-232 eine Textdatei vom PC und sendet 
sie wieder zurück.
Auf dem PC läuft HyperTerminal. Auf dem Bildschirm im Fenster des 
HyperTerminal erscheint der Inhalt dieser Textdatei. Soweit funktioniert 
alles gut.

Nun meine Frage:
Ich möchte statt HyperTerminal ein C-Programm
für den PC schreiben, das genau das oben beschriebene ermöglicht. Das 
Programm sollte es möglich machen, eine Datei (oder über die Tastatur 
eingegebene Zeichen)an den Controller senden und empfangen zu 
können(Anzeige auf dem Bildschirm oder auf die Festplatte speichern).
Kann mir da jemand helfen?

jan_

von Andreas (Gast)


Lesenswert?

Wenn Du das unter Windwos machen willst, musst Du die Funktionen 
ReadFile und WriteFile benutzen.

Als Compiler bietet sich der gcc an.
Die IDE von dev-c++ ist sehr gut und kostenlos.
Beides kannst Du unter www.bloodshed.net runterladen.
Hiermit habe ich schon Software geschrieben, die vom PC zu externen 
MC-gesteuerten Geräten Datensätze sendet und empfängt.

Hoffe hiermit ist Dir erstmal weiter geholfen.

Grüße
Andreas

von jan_ (Gast)


Lesenswert?

Hallo Andreas,

Danke dir für die Antwort. Am liebsten würde ich das unter Linux mit gcc 
bzw. gtk+ schreiben, kann aber auch für Windows sein.
Vielleicht hat jemand ein paar Code-Beispiele zu dem speziellen Problem.

Schöne Grüße
jan_

von Andreas (Gast)


Lesenswert?

Habe das wie ich es unter windows mit dem gcc gemacht habe nicht mehr 
gefunden, da ich das Programm mittlerweile geändert habe.

Ich habe es für den Borland Builder erweitert. Insofern mußt Du Dir die 
entsprechenden Sachen hier rauskopieren. Fehlerabfrage beim 
Empfang/Senden muss auch noch ergänzt werden.

Hier die Routinen um den Com-Port zu öffnen:

  #ifdef  _BORLANDC_
    COMMTIMEOUTS CommTimeouts;
  #else
    LPCOMMTIMEOUTS CommTimeouts;
  #endif
  char sComNo[20];

  sprintf(&sComNo[0],"Com%d",ComPort);
  iCommId = CreateFile(sComNo,              /* lpFileName */
                         GENERIC_READ | GENERIC_WRITE,  /* 
dwDesiredAccess */
                         0,                             /* dwShareMode 
*/
                         NULL,                           /* 
lpSecurityAtributes */
                         OPEN_EXISTING,                 /* 
dwCreationDistribution */
                         0,                             /* 
dwFlagsAndAttributes */                   /* dwFlagsAndAttributes */
                         0);                            /* hTemplateFile 
*/

  if (iCommId < 0)
    return false;
  else
    {
      GetCommState(iCommId, &fDCB);
//      fDCB.Flags=0;

      /* Setze die Flags im DCB */
      fDCB.fBinary  = ON;

      if (fHWFlowOptions == chwfUseRTS)
         fDCB.fRtsControl == ON;
      if (fHWFlowOptions == chwfUseDTR)
         fDCB.fDtrControl == ON;
      if (fHWFlowOptions == chwfRequireCTS)
      {
          fDCB.fOutX      = ON;
        fDCB.fInX      = ON;
      }
//      if (fHWFlowOptions == chwfRequireDSR)
//      SetDCBFlag(dcbfOutxDsrFlow);

      fDCB.XoffChar=cXOffChar;
      fDCB.XonChar=cXOnChar;

      fDCB.XonLim=iXonLimit;
      fDCB.XoffLim=iXoffLimit;

//      if (set::of(cswfBoth,cswfReceive, eos).has(SWFlowOption)) 
SetDCBFlag(dcbfInX);
//      if (set::of(cswfBoth,cswfTransmit, eos).has(SWFlowOption)) 
SetDCBFlag(dcbfOutX);

      fDCB.BaudRate=iBaudrate;
      fDCB.ByteSize=iDatabits;

      switch (fStopbits) {
        case csb1   : fDCB.StopBits=ONESTOPBIT; break;
        case csb1_5 : fDCB.StopBits=ONE5STOPBITS; break;
        case csb2   : fDCB.StopBits=TWOSTOPBITS; break;
      }

      fDCB.Parity=fParity;
//      if (fParity>cpNone)  SetDCBFlag(dcbfParity);

      /* Setze DCB */

      if(!SetCommState(iCommId,&fDCB))
        throw("COMM - Error : SetCommState");

      SetupComm(iCommId,iInSize,iOutSize);
      GetCommTimeouts(iCommId,&CommTimeouts);
  #ifdef  _BORLANDC_
      CommTimeouts.WriteTotalTimeoutMultiplier=1;
      CommTimeouts.WriteTotalTimeoutConstant=iSendTimeoutLength;
      CommTimeouts.ReadIntervalTimeout=10;
      CommTimeouts.ReadTotalTimeoutMultiplier=1;
      CommTimeouts.ReadTotalTimeoutConstant=iReceiveTimeoutLength;
  #else
      CommTimeouts->WriteTotalTimeoutMultiplier=1;
      CommTimeouts->WriteTotalTimeoutConstant=iSendTimeoutLength;
      CommTimeouts->ReadIntervalTimeout=10;
      CommTimeouts->ReadTotalTimeoutMultiplier=1;
      CommTimeouts->ReadTotalTimeoutConstant=iReceiveTimeoutLength;
  #endif
  SetCommTimeouts(iCommId,&CommTimeouts);
  return true;
  }

Hiermit wird ein Zeichen gesendet:

void  SendChar(char Ch)
{
  DWORD dWrCount;

  WriteFile(iCommId,&Ch,1,&dWrCount,NULL);
}

Hiermit ein ganzer String:

void  SendData(string& Str)
{
  WriteFile(iCommId,&Str[1],Str.length(),&dWrCount,NULL);
}

einzelnes Zeichen einlesen:
( beim mehreren Zeichen cCharacter ändern und 
"iCommId,&cCharacter,X,...")

char GetChar()
{
  char cCharacter;
  DWORD iReadCount;
  bool bResult;


  bResult=ReadFile(iCommId,&cCharacter,1,&iReadCount,NULL);
  if (bResult)
    if (iReadCount==0)
      iLastError = CE_TIMEOUT;
    else
      iLastError = CE_OK;
  else
    iLastError = GetCommError();

  if (iReadCount>0)  return cCharacter; else return '\0';
}

Ganz zum Schluss wieder Schliessen:

  if(CloseHandle(iCommId))
    return true;
  else
    return false;

von Linux-Hero (Gast)


Lesenswert?

Hier findest Du die nötigen Informationen:
http://www.fokus.gmd.de/linux/HOWTO/Serial-Programming-HOWTO/

Als Beispiel (zwar alt, aber immer noch gültig):
http://www.linux-magazin.de/Artikel/ausgabe/1999/08/Messen/messen.html

Ansonsten, wenn es simpel sein soll und Du keine Extrafunktionen 
brauchst, kannst Du ja mal ein man fopen/fclose/fgets/fwrite machen.

von jan_ (Gast)


Lesenswert?

Danke!

Viele Grüße
jan_

von jan_ (Gast)


Lesenswert?

Hallo,

habe mir das Linux Serial-Programming-HOWTO angeschaut und zum Testen in 
dort vorgestelltes Programm für meinen Zweck modifiziert:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#define MODEMDEVICE "/dev/ttyS0"

main()
{
  int fd, c, res, k;
  struct termios oldtio, newtio;
  char buf[255];
  char buf1[]="123456789test1_test2_test3";

  fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY);
  if (fd < 0){perror (MODEMDEVICE); exit(-1)}

  tcgetattr(fd, &oldtio);
  bzero(&newtio, sizeof(newtio));

  newtio.c_cflag = CS8 | CLOCAL | CREAD;
  newtio.c_iflag = IGNPAR;
  newtio.c_lflag = 0;
  newtio.c_cc[VTIME] = 1;  // 1/10 s auf Zeichen warten
  newtio.c_cc[VMIN] = 0;

  cfsetospeed(&newtio, B9600);
  cfsetispeed(&newtio, B50); // Fehlerfreier Empfang mit 50 Baud

  tcsetattr(fd, TCSANOW, &newtio);
  write(fd, buf1, sizeof(buf1));

   for (k=0; k<30 k++)
   {
    res = read(fd, buf, sizeof(buf1));
    buf[res] = 0;
    printf ("%s\n, buf");
   }
  tcsetattr(fd, TCSANOW, &oldtio);
  close(fd);
}
//-----------------------------------------

Es ergeben sich neue Fragen:

1. Vom PC wird über die serielle Schnittstelle zum Controller ein String 
buf1="123456789test1_test2_test3" geschickt. Das Controllerprogramm 
schickt ihn wieder zum PC zurück. Die 'Controller-Baudrate' ist , wie 
aus dem Controller-Assembler-Programm ersichtlich, auf 9600 Baud 
eingestellt.
Wähle ich aber die gleiche Übertragungsrate im C-Programm (PC) mit Hilfe 
von cfsetospeed(&newtio, 9600) bzw. cfsetispeed(&newtio, 9600) aus, dann 
funktoniert der Empfang nicht fehlerfrei. Es treten folgende Fehler auf:

PC-Baudrate, Senden/Empfangen 9600 Baud
Die gesendeten und empfangenen Zeichen stimmen nicht überein.

PC-Baudrate, Senden 9600 Baud/Empfangen 4800 Baud
Erste 4 Bytes werden überhaupt nicht empfangen, völlig andere Zeichen 
bei ca. jedem dritten Empfangsversuch.

PC-Baudrate, Senden 9600 Baud/Empfangen 1200 Baud
erste 2 Bytes werden überhaupt nicht empfangen. Die restlichen Zeichen 
werden korrekt empfangen.

PC-Baudrate, Senden 9600 Baud/Empfangen 50 Baud
Alle Zeichen werden korrekt empfangen

Wie kann ich das Programm(C unter Linux) ändern (oder neu schreiben?), 
um bei einer höheren Übertragungsrate(Empfang),
a l l e Zeichen korrekt zu empfangen?

Viele Grüße
jan_

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.