Autor Beitrag
SchelmVomElm
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 154

W2K Pro
D5 Pro
BeitragVerfasst: Do 03.02.05 17:26 
Serielle Schnittstelle ansprechen und pollen

Da ich bisher eigentlich nur Fragen gestellt habe, wollte auch mal was für die Allgemeinheit tun…

Da ich viel Erfahrungen mit seriellen Schnittstellen gemacht habe, hier ein kleines, Crashkurs- artiges Tutorial. Gewisse Kenntnisse über die RS232 und Delphi bzw. API Programmierung setze ich voraus.

1. Benutzte GlobaleVariablen

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var
  PortTimeout : _COMMTIMEOUTS;
  PortHandle : Integer;
  PortDCB : TDCB;
  PortNr  : Integer;
  PortState : Cardinal;
  WriteOverlapped,ReadOverlapped,StatusOs: TOverlapped;


2. Die Schnittstelle öffnen / schließen / testen

Um die Schnittstelle zu öffnen und ein gültiges Schnittstellen- Handle zu bekommen, ruft man die Funktion CreateFile auf. Vereinfachtes Bsp:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
function OpenCOM(Port: byte): boolean; stdcall;
begin
  PortHandle :=
  CreateFile(PChar('\\.\COM'+IntToStr(Port)),GENERIC_READ or GENERIC_WRITE,0,
             nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,LongInt(0));
  
  //Overlapped = Asynchron auf Microsoftianisch
 
  {Da wir nun asynchron auf die Schnittstelle zugreifen (weiss der Teufel 
  warum – aber es sieht so aus als wäre diese Art des Zugriffs ab W2K
  praktisch ZWINGEND notwendig – selbst wenn man gar nicht asynchron übertragen will)  
  muss man auch die dafür notwendigen Structs initialisieren}
  
  if PortHandle > 0 then
  begin
    Result := true;
    InitOverlapped(WriteOverlapped);
    InitOverlapped(ReadOverlapped);
    InitOverlapped(StatusOs);
  end else Result := false;
end;


Die Ini Funktion für die Overlapped Strukturen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure InitOverlapped(var Overlapped : TOverlapped);
begin
  Overlapped.Offset := 0;
  Overlapped.OffsetHigh := 0;
  Overlapped.Internal := 0;
  Overlapped.InternalHigh := 0;
  Overlapped.hEvent := CreateEvent(nil,True,False,'');
end;


Um die Schnittstelle wieder zu schließen (und es gibt X mistige Programm die das vergessen, was zur Folge hat, dass danach andere Programme nicht mehr auf die Schnittstelle zugreifen können) geht man wie folgt vor:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure CloseCOM; stdcall;
begin
  PurgeComm(PortHandle, PURGE_RXABORT or PURGE_RXCLEAR or PURGE_TXABORT or PURGE_TXCLEAR);
  SetCommMask(PortHandle,0); //unterbricht WaitCommEvent im Polling thread
  CloseHandle(PortHandle);
  PortHandle := 0;
end;


Bevor man jedoch die Schnittstelle öffnet, sollte man vielleicht auch testen, ob Sie denn verfügbar ist (oder ob die tolle Com-Konsole von Pipi Lüdi- Soft vergessen hat die Schnittstelle zu schließen). Dies mach ich ziemlich billig (Verbesserungsvorschläge jederzeit willkommen):

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
function ComAvailable(ComNr: byte): boolean; stdcall;
var
  TestHandle : integer;
begin
  TestHandle :=
  CreateFile(PChar('\\.\COM'+IntToStr(ComNr)),GENERIC_READ or GENERIC_WRITE,0,
             nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,LongInt(0));
  if (TestHandle <= 0then
    Result := false
  else
  begin
    Result := true;
    CloseHandle(TestHandle);
  end;
end;



2. Die Schnittstelle konfigurieren:

Die Konfiguration der Schnittstelle erfolgt über den Device Control Block (PortDCB) siehe Windows.pas – TDCB. Mit dieser Struktur lassen sich Parameter wie Baudrate, Flusssteuerung, StopBits usw. setzen und zwar wie im folgenden Beispiel die Baudrate:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
function SetBaudRate(baud: cardinal): boolean; stdcall;
begin
  GetCommState(PortHandle,PortDCB);
  PortDCB.BaudRate := baud;
  Result := SetCommState(PortHandle,PortDCB);
end;


Die Hilfe des MS-SDK gibt auch bereitwillig Auskunft zu den verwendeten Funktionen.


3. Abfragen und Setzen der Status Leitungen

Um CTS, DCD, DSR und Ring abzufragen, eignet sich die Funktion GetCommModemStatus.

Bsp:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var PortState: cardinal;

begin
GetCommModemStatus(PortHandle,PortState); //PortHandle erhält man mit CreateFile – kommt später
//Nun die Abfrage – Hier auf Clear to send
if ((Portstate and MS_CTS_ON) <> 0then Result := true
    else Result := false;


Um RTS, DTR, XOFF, XON oder einen Break zu setzen oder zurückzusetzen benutzt man die Funktion EscapeCommFunction:

Bsp. Setzen und zurücksetzen der DTR Leitung

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure SetDTR; stdcall;
begin
  if (PortHandle <> 0then EscapeCommFunction(PortHandle,5);
end;

procedure ClearDTR; stdcall;
begin
  if (PortHandle <> 0then EscapeCommFunction(PortHandle,CLRDTR);
end;


In diesem Zusammenhang bedeutet XON/XOFF, dass ein Empfangen der entsprechenden XON/XOFF Chars simuliert wird. Ein Break ist, wenn ich die TX – Leitung dauerhaft auf 1 setze. ACHTUNG, ist ein Break gesetzt und ich versuche zu senden (mit WriteFile), wird das Programm eine sauberen Abgang hinlegen. Am Besten man lässt den Quatsch – braucht eh keiner.


4. Lesen und Schreiben

Jetzt wird’s endlich interessant. Zum Lesen und Schreiben verwendet man die Funktionen ReadFile und wie sollte es auch sonst sein, WriteFile. Eigentlich ist die Benutzung dieser Funktionen im Zusammenhang mit der seriellen Schnittstelle ganz einfach – wenn man ein Programmierbeispiel hat:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
function SendString(Str: PChar): boolean; stdcall;
var
  written  : cardinal;
  tmpStr : string;
  i: LongBool;
begin
  if (PortHandle <> 0then
  begin
    tmpStr := string(Str);
    Result := not WriteFile(PortHandle,tmpStr[1],Length(tmpStr),written,@WriteOverlapped);
  end;
end;

function ReadString(var Buf: PChar): Cardinal; stdcall;
var
  StrBuf: string;
  Error,BytesRead: DWORD;
  Status: TComStat;
  RdSuccess: boolean;
begin
  BytesRead := 0;
  if (PortHandle <> -1then
  begin
    ClearCommError(PortHandle,Error,@Status);
    case Error of
      CE_BREAK,CE_DNS,CE_FRAME,CE_IOE,CE_MODE,CE_OOP,CE_OVERRUN,CE_PTO,CE_RXOVER,
      CE_RXPARITY,CE_TXFULL:
      begin
        BytesRead := 0;
      end
    else
      begin
        SetLength(StrBuf,Status.cbInQue);
        RdSuccess := ReadFile(PortHandle,StrBuf[1],Status.cbInQue,BytesRead,@ReadOverlapped);
        if not RdSuccess then BytesRead := 0;
      end;
    end;
  end;
  if (BytesRead > 0then
  begin
    Result := BytesRead;
    try
      StrPCopy(Buf,StrBuf);
    except
      Result := 0;
    end;
  end else Result := 0;
end;



An dieser Stelle eine Anmerkung:
Ich habe mir für den Schnittstellen Zugriff zunächst eine Delphi Unit und dann eine DLL geschrieben. Aus der stammen die ganzen Funktionen. Daher übergebe ich auch PChars. Ich bitte etwaige Unelegantheiten im Bezug auf PChar – string zu entschuldigen – die kommen durch das Hin- und Her. Um das ganze als Delphi Unit zu verwenden, sollte überall die Direktive stdcall entfernt werden.

Und nun *Trommelwirbel* das interessanteste:

5. Schnittstellen Polling

Möchte man benachrichtigt werden, wenn auf die Schnittstelle (von aussen) zugegriffen wird (Daten gesendet oder Statusleitungen gesetzt werden), so musste man in grauer Vorzeit die Schnittstelle manuell zyklisch abfragen (Polling). Dies kann man heute sehr elegant mit einem Thread erledigen. Das ganze funktioniert im Groben so:
Man erstelle einen Thread, man halte in an mit der Funktion WaitCommEvent. Der Thread ist nun angehalten und zwar bis eines der Ereignisse eingetreten ist, die man vorher mit SetCommMask spezifiziert hat. Wird der Thread fortgesetzt ist eines der Ereignisse eingetreten. Will man den Thread von „aussen“ aus dem Wartezustand befreien macht man das so:

ausblenden Delphi-Quelltext
1:
SetCommMask(PortHandle,0);					


Hier nun ein Bsp. Für einen Polling- Thread. In diesem Beispiel wird, wenn ein Ereignis eintritt, die Funktion ReleaseEvent aufgerufen, die ich hier weglasse, da sie zu speziell wäre.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
type
  TSerialThread = class(TThread)
  protected
    fComEvent: cardinal;
    procedure Execute; override;
  public
    constructor Create;
    property ComEvent: cardinal read fComEvent;
  end;

constructor TSerialThread.Create;
begin
  FreeOnTerminate:= True;
  inherited Create(False);
end;

procedure TSerialThread.Execute;
var
  SerialEvent, WaitResult, BytesRead: Cardinal;
begin
  SetCommMask(PortHandle,EV_CTS or EV_BREAK or EV_DSR or
  EV_ERR or EV_RING or EV_RLSD or EV_RXCHAR or EV_RXFLAG or EV_TXEMPTY);
  if not WaitCommEvent(PortHandle,SerialEvent,@StatusOs) then
  begin
    if (GetLastError = ERROR_IO_PENDING) then
    begin
      WaitResult := WaitForSingleObject(StatusOs.hEvent,INFINITE);
      case WaitResult of
        WAIT_OBJECT_0:
        begin
          if GetOverlappedResult(PortHandle,StatusOs,BytesRead,false) then
            ReleaseEvent(SerialEvent);
        end;
      end;
    end;
  end else ReleaseEvent(SerialEvent);
end;


Dieser Thread stellt lediglich die Mindestanforderung an einen Polling thread dar. Für den Hausgebrauch (und mehr) sollte das reichen.

So, bevor ich mich noch mehr zu dem Thema auslasse, will ich erst mal sehen ob das irgendein Schwein interessiert.

MfG SchelmVomElm

_________________
for(;P("\n"),R--;P("|"))for(e=C;e--;P("_"+(*u++/8)%2))P("|"+(*u/4)%2);


Zuletzt bearbeitet von SchelmVomElm am Fr 04.03.05 10:42, insgesamt 2-mal bearbeitet
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6330
Erhaltene Danke: 134

Windows 7 + Windows 10
Tokyo Prof + CE
BeitragVerfasst: Do 03.02.05 17:31 
Vor 6 Jahren hätte ich das gebrauchen können :wink:
digi_c
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1905

W98, XP
D7 PE, Lazarus, WinAVR
BeitragVerfasst: Mo 07.02.05 21:12 
Danke füt den Artikel, was mich noch interessieren würde, wäre das Timing unter Windows. Der normale Timer ist ja sehr ungenau, reicht es da für periodische Messungen z.B. TcTimer(Multimediatimer) zu benutzen oder gibt es da andere Wege?

Achso und Elektor hat auch ne sehr nützliche DLL dazu geschrieben, die das alles Kapselt, Link such ich nochmal;)
SchelmVomElm Threadstarter
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 154

W2K Pro
D5 Pro
BeitragVerfasst: Di 08.02.05 10:28 
Kenn ich schon 8) Läuft nicht unter W2K :?
Du kannst ja Die Funktionen der Elektor DLL mal mit
meinen vergleichen da wirst Du einige Unterschiede
feststellen....
Wieso Timing? Solange Du nur über RX/TX Zeichen austauscht
braucht Du eigentlich kein Timing - das ist der Sinn des
Polling threads. Anders sieht es aus wenn Du die Leitungen
selbst (bitweise) manipulierst um Daten zu übertragen.
Dann findest Du im Forum glaub ich jede Menge zum Thema Timer.

PS Du hast mit diesen Methoden keine Kontrolle darüber, wann
genau ein Zeichen physikalisch über die Schnittstelle
gesendet oder empfangen wurde.

_________________
for(;P("\n"),R--;P("|"))for(e=C;e--;P("_"+(*u++/8)%2))P("|"+(*u/4)%2);
digi_c
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1905

W98, XP
D7 PE, Lazarus, WinAVR
BeitragVerfasst: Di 08.02.05 20:13 
Doch die haben eine neue wo in 2 Heften der WinAPI COMM Zugriff erklärt wird, ich fin den Link schon noch ...;)
Pkan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 18



BeitragVerfasst: So 27.03.05 14:28 
Hi
:wink: super turial
aber ich hab ein riesen Problem.
Ich will meine Rs232 schnittstelle ganz einfach steuern.
die 3 sendeleitungen gaanz einfach an oder aus sachalten (zur Pumpensterung)
und die 4 empfamsleitungen einfach nur auslesen, spannung oder keine ( an oder aus)
ich habs versucht aber ich komm einfach nicht dahinter wie ich das richtig mache.
Wenn mir einer helfen könnte oder einen Vorschlag machen könnte.....
Danke :D
hedie
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 249

WIN XP WIN 2000 WIN Longhorn
D7 Pers D2005 Architect Vollversion
BeitragVerfasst: So 27.03.05 18:02 
Klar Doch

wen du Den LPT Port benutzen würdest, dann wäre gleich alles viel einfacher (für mich :D )
fals du dich deshalb entschliesst den LPT Zu benutzen , dann kann ich dir helfen (wirklich ganz einfach gesteuert 8) )

_________________
Grüsse hedie
hört auf traurig zusein hört lieber radio Basilisk
Pkan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 18



BeitragVerfasst: So 27.03.05 18:09 
für dich einfacher?? :D
neija...hast du schon ein programm??
wenns wirklich viel einfacher ist nehm ich den und bau den stecker um
Danke :)
hedie
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 249

WIN XP WIN 2000 WIN Longhorn
D7 Pers D2005 Architect Vollversion
BeitragVerfasst: So 27.03.05 18:12 
Klar war heute Fleissig am Proggen 8)
wenn du willst, kann ich dir eines meiner programme geben.

dazu musst du mir nur sagen, welche der leitungen du verwenden willst und welcher LPT (LPT1, LPT2 ....)

_________________
Grüsse hedie
hört auf traurig zusein hört lieber radio Basilisk
Pkan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 18



BeitragVerfasst: So 27.03.05 18:19 
loooooooooooool mein HIGH END PC besitz nur eine Druckerschnittstelle
^^du bist elktroniler?? is ja der hammer ich auch....und das kann ich wesentlcih besser als delphi... :) hast du icq??
:)
hedie
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 249

WIN XP WIN 2000 WIN Longhorn
D7 Pers D2005 Architect Vollversion
BeitragVerfasst: So 27.03.05 18:21 
nein :( aber MSN :D
Elektroniker mit Leidenschaft :D

dein Progg ist gleich fertig 8)

_________________
Grüsse hedie
hört auf traurig zusein hört lieber radio Basilisk
Pkan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 18



BeitragVerfasst: So 27.03.05 18:26 
goil....
^^bin gerade auf deiner homepage.
Ich hab auch son ritig goile Projekte gemacht...
neija ich müsste auch mal homepage machen..aber die zeit
vlt. erkennst du die extrmen vorteile von icq..dann können wir ja mal chatten :wink:
mit welchen delphi schreibst du das programm(vers??)
ich werde später noch timer und so dazu machen
hedie
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 249

WIN XP WIN 2000 WIN Longhorn
D7 Pers D2005 Architect Vollversion
BeitragVerfasst: So 27.03.05 18:31 
Weshalb lädst du dir nicht msn (hat ton und sogar webcam übertragung :D )

also ich schreibe es in Delphi7
fals du nicht draus kommst, einfach fragen (im forum oder hedie2@tiscali.ch)

deine programm habe ich angehängt 8)

(freue mich über mails)
Einloggen, um Attachments anzusehen!
_________________
Grüsse hedie
hört auf traurig zusein hört lieber radio Basilisk
Pkan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 18



BeitragVerfasst: So 27.03.05 18:40 
Danke
jo ich hab auch delphi 7
^^ja webcam ist auch auch gut aber ich lass mich nit gern von msn ausspioniern..und bei meinen system ist das auch besser wenn onkel bil gates nicht alles weis :)
ich probier gleich mal es programm aus
Pkan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 18



BeitragVerfasst: So 27.03.05 18:59 
is ja alles ganz fein :D aber du steuerst ja die LPT an...
welchen pin schaltest du jetzt( hast du manchmal en plan con LPT port mit leitungsnamen(und welchen du ansteuerst))
muss mir erstmal en neuen stecker anlöten
hedie
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 249

WIN XP WIN 2000 WIN Longhorn
D7 Pers D2005 Architect Vollversion
BeitragVerfasst: So 27.03.05 19:03 
besch du schwizer wen ja dan können wir ja so schreiben (einfacher)

und ich steuere den pin 4 an also D2 weil es auch noch d 0 gibt

_________________
Grüsse hedie
hört auf traurig zusein hört lieber radio Basilisk
Karlson
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 2077

MacOSX 10.5, Ubuntu, OpenSuse 11
C, Java, PHP
BeitragVerfasst: So 27.03.05 19:08 
user profile iconhedie hat folgendes geschrieben:
besch du schwizer wen ja dan können wir ja so schreiben (einfacher)


Mag sein, aber das Forum hier ist Deutsch, folglich werdet ihr auch bitte Deutsch schreiben, schließlich sollen nicht-schweizer auch was verstehen.
Pkan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 18



BeitragVerfasst: So 27.03.05 19:10 
gut...Nee bin ich net auch wenn meine rechtschreibung/schrift manchmal wie "hinter chinesisch aussieht...ich komm ausn :!: OSTEN :!:
auch sachsen..
neija müssen uns unbedingt mal über unsere elkto projekte unterhalten :D
hedie
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 249

WIN XP WIN 2000 WIN Longhorn
D7 Pers D2005 Architect Vollversion
BeitragVerfasst: So 27.03.05 19:11 
Klar machen wir freu mich schon :D

_________________
Grüsse hedie
hört auf traurig zusein hört lieber radio Basilisk
SchelmVomElm Threadstarter
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 154

W2K Pro
D5 Pro
BeitragVerfasst: Mi 30.03.05 10:12 
@Hedie: Ich habe mir mal deine Seite angeschaut. Bin auch leidenschaftlicher Elektroniker - und Elektor Leser. Ich wollte dich nur warnen :!: - ich glaube nicht dass es Elektor toll findet dass Du Artikel von denen veröffentlichst. Die Dinger sind kostenpflichtig - Download 1,50 €. Da kannst Du 'nen mords Ärger kriegen...

_________________
for(;P("\n"),R--;P("|"))for(e=C;e--;P("_"+(*u++/8)%2))P("|"+(*u/4)%2);