COM-port ansprechen



  • Hallo

    Mein Ziel ist es über den Com1 -port abzufragen ob ein Schalter geschlossen oder offen ist. Meine Überlegung: Über RTS sende ich ständig ein TRUE. RTS mit CTS über den Schalter kurzschließen und wenn CTS TRUE ist weiß ich das der Schalter geschlossen wurde.

    Ich habe es geschafft den RTS zu setzen kann aber nicht den CTS abfragen. Bzw CTS ist immer 0.
    Findet irgendwer einen Fehler in meinen Code, oder weiß was ich falsch mache ?

    Das ist mein (zusammengesuchter) 🙂 Code:

    cport.h

    #define WRONG_PORT 100
    #define ON true
    #define OFF false
    
    class ComPort
    {
    public:
    int SetOPEN (int PORT);
    int SetCLOSE (void);
    int SetDTR (bool mode);
    int SetRTS (bool mode);
    int SetTXD (bool mode);
    bool GetCTS ();
    bool GetDSR ();
    void SetAll (bool mode);
    };
    

    main.cpp

    #include "CPORT.H"
    #include <stdio.h>
    #include <conio.h>
    #include <windows.h>
    #include <atlbase.h>
    
    HANDLE hCom;
    DWORD COMStatus;
    
    LPWSTR foo(const char* s) {
    	USES_CONVERSION;
    	LPWSTR p = A2W(s); // ANSI to WIDE
    	return p;
    }
    
    int ComPort::SetOPEN(int PORT)
    {
    if(PORT<=0 || PORT>4)
    {
    return WRONG_PORT;
    }
    
    LPCSTR ansistr = "COM1"; 
    LPWSTR neuerStr = foo(ansistr);
    
    hCom = CreateFile(neuerStr,
    GENERIC_READ | GENERIC_WRITE,
    0,
    NULL,
    OPEN_EXISTING,
    0,
    NULL);
    
    return 0;
    }
    
    int ComPort::SetCLOSE()
    {
    CloseHandle(hCom);
    return 0;
    }
    
    int ComPort::SetDTR(bool mode)
    {
    if(mode==ON)
    {
    EscapeCommFunction(hCom, SETDTR); // setzen
    }
    else
    {
    EscapeCommFunction(hCom, CLRDTR); // Loeschen
    }
    return 0;
    }
    
    int ComPort::SetRTS(bool mode)
    {
    if(mode==ON)
    {
    EscapeCommFunction(hCom, SETRTS); // setzen
    }
    else
    {
    EscapeCommFunction(hCom, CLRRTS); // Loeschen
    }
    return 0;
    }
    
    int ComPort::SetTXD(bool mode)
    {
    if(mode==ON)
    {
    EscapeCommFunction(hCom, SETBREAK); // setzen
    }
    else
    {
    EscapeCommFunction(hCom, CLRBREAK); // Loeschen
    }
    return 0;
    }
    
    bool ComPort::GetCTS()
    {
    GetCommModemStatus(hCom, &COMStatus);
    if(COMStatus & MS_CTS_ON)
    {
    return ON;
    }
    return OFF;
    }
    
    bool ComPort::GetDSR()
    {
    GetCommModemStatus(hCom, &COMStatus);
    if(COMStatus & MS_DSR_ON)
    {
    return ON;
    }
    return OFF;
    }
    void ComPort::SetAll (bool mode)
    {
    SetRTS(mode);
    SetTXD(mode);
    SetDTR(mode);
    }
    
    void main(void){
    	BOOL Loop = TRUE;
    	ComPort comp;
    
    	while(Loop){
    
    		if( _kbhit() ){
    			Loop = FALSE;
    		}
    			if (comp.SetOPEN(1)!=100){			
    				comp.SetRTS(true);	
    				if (comp.GetCTS()== true){
    					printf ("schalter geschlossen\n");
    				}
    			}else{
    				printf("Wrong comport\n");
    		}
    	}	
    	comp.SetCLOSE();
    }
    

    Gruß Eisenschlumpf



  • Ich hatte auch mal so etwas vor...
    Ich habe dann auch eine entsprechende Klasse geschrieben, welche ich schlussendlich aber nie so richtig getestet habe, weil ich dann doch den LPT benutzte. Kurz: Da du scheinbar so oder so einfach Codeschnipsel aneinander gereiht hast, kannst du vielleicht einfach einmal ausprobieren ob's mit meinem Code evtl. tatsächlich funktioniert.

    //main.cpp
    #include <iostream>
    #include <conio.h>
    #include "mjserial.h"
    
    int main(void)
    {
    	MasterJimmy::Serial com1;
    	bool loop=true;
    
    	com1.open();
    	com1.setrts();
    	while(loop){
    		if(kbhit()) loop=false;
    		bool cts_state=false;
    		com1.getcts(&cts_state);
    		if(cts_state==true)
    			std::cout<<"\rSchalter geschlossen      ";
    		else
    			std::cout<<"\rSchalter nicht geschlossen";
    	}
    	std::cin.get();
    }
    
    //////////////////////////////////////////////////////////////
    // Documentname:	mjserial.h
    // Version:			1.0
    // Author:			Master-Jimmy (transistornet.de)
    
    #ifndef ___MJSERIAL___
    #define ___MJSERIAL___
    
    #include <windows.h>
    
    namespace MasterJimmy{
    	class Serialparameters{
    	public:
    		std::string	portname;
    		unsigned short	baudrate;
    		unsigned short	charlength;
    		unsigned short	stopbits;
    		unsigned short	parity;
    
    		Serialparameters(void){
    			this->portname="COM1";
    			this->baudrate=9600;
    			this->charlength=8;
    			this->stopbits=1;
    			this->parity=0;
    		}
    		Serialparameters(std::string _portname){
    			this->portname=_portname;
    			this->baudrate=9600;
    			this->charlength=8;
    			this->stopbits=1;
    			this->parity=0;
    		}
    	};
    
    	class Serial{
    	private:
    		HANDLE			handle;
    		Serialparameters	params;
    
    	public:
    		Serial(void);
    		Serial(Serialparameters _params);
    		~Serial(void);
    		HANDLE gethandle(void);
    		bool open(void);
    		bool close(void);
    		bool write(std::string _buffer);
    		bool read(std::string *_buffer,long _numberofchars);
    		bool setdtr(void);
    		bool cleardtr(void);
    		bool setrts(void);
    		bool clearrts(void);
    		bool setbreak(void);
    		bool clearbreak(void);
    		bool getcts(bool *_state);
    		bool getdsr(bool *_state);
    	};
    
    	Serial::Serial(void){
    		this->handle=INVALID_HANDLE_VALUE;
    	}
    
    	Serial::Serial(Serialparameters _params){
    		this->handle=INVALID_HANDLE_VALUE;
    		this->params.portname=_params.portname;
    		this->params.baudrate=_params.baudrate;
    		this->params.charlength=_params.charlength;
    		this->params.stopbits=_params.stopbits;
    		this->params.parity=_params.parity;
    	}
    
    	Serial::~Serial(void){
    		this->close();
    	}
    
    	HANDLE Serial::gethandle(void){
    		return this->handle;
    	}
    
    	bool Serial::open(void){
    		if(this->handle==INVALID_HANDLE_VALUE){
    			this->handle=CreateFileA(
    				this->params.portname.c_str(),
    				GENERIC_READ|GENERIC_WRITE,
    				0,
    				NULL,
    				OPEN_EXISTING,
    				0,
    				NULL);
    			if(this->handle!=INVALID_HANDLE_VALUE){
    				DCB	paramstruct;
    				GetCommState(this->handle,&paramstruct);
    				paramstruct.DCBlength=sizeof(paramstruct);
    				paramstruct.BaudRate=this->params.baudrate;
    				paramstruct.ByteSize=(BYTE)this->params.charlength;
    				paramstruct.StopBits=(BYTE)this->params.stopbits;
    				paramstruct.Parity=(BYTE)this->params.parity;
    				SetCommState(this->handle,&paramstruct);
    				COMMTIMEOUTS timeoutstruct;
    				timeoutstruct.ReadIntervalTimeout=100;
    				timeoutstruct.ReadTotalTimeoutMultiplier=100;
    				timeoutstruct.ReadTotalTimeoutConstant=100;
    				timeoutstruct.WriteTotalTimeoutMultiplier=100;
    				timeoutstruct.WriteTotalTimeoutConstant=100;
    				SetCommTimeouts(this->handle,&timeoutstruct);
    				return true;
    			}
    			else{
    				return false;
    			}
    		}
    		else{
    			return false;
    		}
    	}
    
    	bool Serial::close(void){
    		if(this->handle!=INVALID_HANDLE_VALUE){
    			CloseHandle(this->handle);
    			this->handle=INVALID_HANDLE_VALUE;
    			return true;
    		}
    		else{
    			return false;
    		}
    	}
    
    	bool Serial::write(std::string _buffer){
    		if(this->handle!=INVALID_HANDLE_VALUE){
    			for(unsigned long pos=0;pos<_buffer.length();pos++){
    				DWORD writtenchars;
    				WriteFile(
    					this->handle,
    					&_buffer[pos],
    					1,
    					&writtenchars,
    					NULL);
    			}
    			return true;
    		}
    		else{
    			return false;
    		}
    	}
    
    	bool Serial::read(std::string *_buffer,long _numberofchars){
    		if(this->handle!=INVALID_HANDLE_VALUE&&_numberofchars>0){
    			_buffer->clear();
    			while(_buffer->length()!=_numberofchars){
    				DWORD	readchars;
    				char	buffer[]={"0"};
    				ReadFile(
    					this->handle,
    					&buffer[0],
    					1,
    					&readchars,
    					NULL);
    				if(readchars==1){
    					*_buffer=_buffer->append(buffer);
    				}
    			}
    			return true;
    		}
    		else{
    			return false;
    		}
    	}
    
    	bool Serial::setdtr(void){
    		if(this->handle!=INVALID_HANDLE_VALUE){
    			EscapeCommFunction(this->handle,SETDTR);
    			return true;
    		}
    		else{
    			return false;
    		}
    	}
    
    	bool Serial::cleardtr(void){
    		if(this->handle!=INVALID_HANDLE_VALUE){
    			EscapeCommFunction(this->handle,CLRDTR);
    			return true;
    		}
    		else{
    			return false;
    		}
    	}
    
    	bool Serial::setrts(void){
    		if(this->handle!=INVALID_HANDLE_VALUE){
    			EscapeCommFunction(this->handle,SETRTS);
    			return true;
    		}
    		else{
    			return false;
    		}
    	}
    
    	bool Serial::clearrts(void){
    		if(this->handle!=INVALID_HANDLE_VALUE){
    			EscapeCommFunction(this->handle,CLRRTS);
    			return true;
    		}
    		else{
    			return false;
    		}
    	}
    
    	bool Serial::setbreak(void){
    		if(this->handle!=INVALID_HANDLE_VALUE){
    			EscapeCommFunction(this->handle,SETBREAK);
    			return true;
    		}
    		else{
    			return false;
    		}
    	}
    
    	bool Serial::clearbreak(void){
    		if(this->handle!=INVALID_HANDLE_VALUE){
    			EscapeCommFunction(this->handle,CLRBREAK);
    			return true;
    		}
    		else{
    			return false;
    		}
    	}
    
    	bool Serial::getcts(bool *_state){
    		DWORD state;
    		if(!GetCommModemStatus(this->handle,&state))
    			return false;
    		if(state&MS_CTS_ON)
    			*_state=true;
    		else
    			*_state=false;
    		return true;
    	}
    
    	bool Serial::getdsr(bool *_state){
    		DWORD state;
    		if(!GetCommModemStatus(this->handle,&state))
    			return false;
    		if(state&MS_DSR_ON)
    			*_state=true;
    		else
    			*_state=false;
    		return true;
    	}
    }
    
    #endif
    


  • Vielen Dank für deinen Code.

    Hab den auch gleich mal hergenommen und getestet. Jedoch sagt er mir auch "schalter nicht geschlossen". -->Selber Fehler.

    Das setzen vom RTS funktioniert einwandfrei ( die spannung hüpft von -V auf +V).

    Nach ein bischen herumgooglen habe ich hier: http://www.eiit.de/v2/index.php?showtopic=3499
    ein tolles kleines Tool gefunden das mir den derzeitigen Status alles Pins grafisch darstellt. und wenn ich da RTS auf CTS kurzschließe funktionierts einwandfrei. warum also ned auch in dem Programm....?



  • Keiner mehr eine Idee ?



  • Code von eisenschlumpf:

    void main(void){
    	BOOL Loop = TRUE;
    	ComPort comp;
    
    	while(Loop){
    
    		if( _kbhit() ){
    			Loop = FALSE;
    		}
    			if (comp.SetOPEN(1)!=100){			
    				comp.SetRTS(true);	
    				if (comp.GetCTS()== true){
    					printf ("schalter geschlossen\n");
    				}
    			}else{
    				printf("Wrong comport\n");
    		}
    	}	
    	comp.SetCLOSE();
    }
    

    Schon mal genau angeguckt, was Deine (Haupt-)Schleife macht?
    Du versuchst mit jedem Schleifendurchlauf jedesmal den COM-Port zu öffnen. Das ist Schmarrn.

    Martin



  • VIELEN DANK.
    Hab das jetzt umgeändert, dass ich nur einmal den Port öffne und den RTS setze und es funktioniert!!

    Weiß vielleicht jemand in welchen intervallen der CTS-pin jetzt pro Sekunde abgefragt wird?
    Erkenne ich mit der methode auch, wenn der Schalter nur ein paar µs geschlossen ist?

    gruß Eschlumpf



  • Die Häufigkeit der Intervalle liegt an Dir bzw. Deiner Schleife.
    Ich würde z.B. mit einem Timer alle 300ms..500ms den Portpin abfragen. Das ist für heutige PC-Systeme nicht zu schnell.

    eisenschlumpf schrieb:

    Erkenne ich mit der methode auch, wenn der Schalter nur ein paar µs geschlossen ist?

    Nein, Du fragst mit Deiner Funktion GetCTS() nur den momentan gerade vorherrschenden Signalzustand ab.
    Windows (oder die Treiber für serielle Schnittstelle) merkt sich nicht, daß ein doppelter Signalwechsel (also Schalter ein und wieder aus) vorlag.

    Also mußt Du mit dem Schalter dafür sorgen, daß der Kontakt, sagen wir mal, mindestens 2 Sekunden lang ansteht (natürlich muß Deine Applikation oder diese eine Schleife in dieser Zeit bereit sein).
    Alternativ könntest Du (wenn Du des Hardware-Bastelns mächtig bist) mit einem Monoflop oder mit einem NE555-Timerbaustein die Schalterkontakt-Zeit künstlich verlängern oder je nach Situation für immer speichern.

    Martin


Anmelden zum Antworten