Hallo, ich soll für eine Veranstaltung ein C/C++ Programm schreiben das eine Zeitmessung vornimmt: Ausgelöst wird die Zeitmessung von Hand am PC und stoppen soll die Zeitmessung bei der Durchbrechung einer Lichtschranke. Die Lichtschranke ist über die RS232 Schnittstelle mit dem PC verbunden und schickt eine Spannung von 1 Volt, wird die Schranke durchbrochen fällt die Spannung auf 0 Volt ab und die Zeitmessung soll stoppen. Darum benötige ich bitte einen Code der mir dieses Problem lösen kann. Ich freue mich über jede Antwort und hoffe das mir bitte jemand helfen kann.
Hi Hans, also mit 0-1 Volt wirst du an der RS232 nicht wirklich viel machen können. Die arbeitet mit +-12 V. Grundsätzlich kann ich dir helfen, gehen wir mal das Problem an. 0-1 V wird schwer, möchtest du einen µC verwenden oder "nur eine schaltung aufbauen". Wenn du einen MC verwendest, könntest du das Signal wandel und aufnehmen. Wenn nun die lichtschranke durchbrochen wird, wird ein Pin am µC wie ein Taster "gedrückt" du sendest über die RS232 ein paar daten an den PC. Wenn du keinen MC verwenden möchst musst du die Spannung modifizieren. Wenn du diese auf +- 12 V ändern kannst, könntest du den CTS (so heist das ding glaube ich) abfragen. Wenn du nicht mit -+ 12 Volt arbeiten möchtest musst du dass ganze auf 5 V trimmen und du könntest an die LPT schnittstelle( Drucker schnittstelle) gehen. Grundsätzlich, solltest du dir weniger gedanken um die Software machen als um die Schaltung. Bei fragen stehe ich dir gerne zur verfügung. gruß marek
Danke schon mal im Voraus marek Die 0-1 Volt habe ich nur als Beispiel genommen weil ich nicht genau wusste mit welcher Spannung RS232 arbeitet aber danke das du mich aufgeklärt hast. Das heißt also die Schaltung wird dann so aufgebaut das grundsätzlich 12 Volt fließen und bei einer Durchbrechung der Schranke auf -12 Volt umgeschalten wird und ich dann diese Veränderung an der RS232 Schnittstelle ablesen kann? Hoffe ich habe das richtig verstanden. Kennst du dich mit solchen Schaltungen aus? Wenn ja, könntest du mir bitte eine Zusammenkritzeln? Wäre dir sehr dankbar. PS: Wäre es mit einem µC leichter und wieviel kostet so ein Ding? mfg Walti
Hi Walter, das mit dem uC wäre leichter, da man da ein Protokoll definieren kann. Ehmmmmm.... ich kann morgen aber mal testen wie schnell die Schaltung mit den 24 V zu realisieren wäre.... wofür brauchst du diese Anwendung? P.S. ja du hast es richtig verstanden. Gruß Marek
Ich soll für eine Veranstaltung in meiner Gemeinde eine Zeitmessung machen und deshalb ist auch das Budget für das Ganze extrem knapp. Deshalb ist auch wichtig das die Schaltung nicht zu komplex und präzise wird da das ja teuer werden kann. Mit "wie schnell die Schaltung zu realisieren wäre", meinst du damit wie lange es dauern würde diese Schaltung zu bauen dann kann ich dich beruhigen, es sind noch mehrere Wochen bis zur Veranstaltung. mfg Walti
Ok... ich verstehe.... ich schaue mir dass ganze morgen mal an, wenn ich die Schaltung hinbekomme, entwickel ich dir das Programm..... wenn das ganze läuft schicke ich dir die Pläne via email o. die Platine via Post. Das ganze kostet dich dann ein paar nette fotos... dann nehme ich dass ganze als projekt auf für meine Homepage ( welche ich noch gestallten muss :) ) gru0 marek
Eh.... mom.... wie sind nun die Daten der Lichtschranke ? Ich muss schon wissen was für ein verhalten vorliegt . gruß marek
Weche Daten brauchst du denn genau von der Lichtschranke? Auch muss ich die Schranke leider erst noch kaufen und mich vorher noch mit einem Kollegen über die ganze Sache absprechen, weil ich den Auftrag erst vor 3 Stunden bekommen hab. Tut mir wirklich leid aber das Ganze könnte noch ein paar Tage dauern. Kann ich denoch bitte auf dein Angebot zurückkommen? PS: kannst du mir eine Lichtschranke empfehlen? mfg Walti
Eine Lichtschranke kann ich dir nicht empfehlen, da ich mit der Thematik,so noch nicht gearbeitet habe. Such dir mal eine Lichtschranke aus, welche eine digitales interface hat. Schick mir die informationen und wir gehen dass ganze durch. Sobald dein Projekt steht, schickst du mir eine email und wir nehmen kontakt auf. Gruß Marek
Okay geht klar werd ich machen. Und nochmal vielen Dank für deine Hilfe. mfg Walti
Warum so kompliziert? An CTS (Pin8), DSR (Pin6), RI (Pin9) und DCD (Pin1), jeweils gegen Masse (Pin5) kann je ein Lichtschrankenausgang oder ein anderer Ausgang, der mindestens +5V gegen Masse oder -5V gegen Masse anlegt, angeschlossen werden. Die Software registriert alle Pegelwechsel an den 4 Eingängen mit Zeitangabe in µS. Die Eigenverzögerung ist aber von PC zu PC verschieden, so das man davon ausgehen kann, das die Zeiten auf die Millisekunde genau ist. Um der Diskussion wegen "Echtzeit" und dergleichen vorzubeugen: Ja, ich weiß, was das ist! /************************************************************ ** CommThread : Öffnet, schließt und liest den Port, ** sendet die Zeiten per PostThreadMessage ** an den MonitorThread ************************************************************/ #include <windows.h> #include <process.h> #include <stdio.h> // Prototypes: DWORD WINAPI ComThread (LPVOID lpParam); DWORD WINAPI MonitorThread (LPVOID lpParam); HANDLE StartComThread (DWORD iPortNum, HWND hEdit); long queryPrecisionTime (void); long queryPrecisionTimeStamp (void); // Globals: HANDLE hCom = INVALID_HANDLE_VALUE; // global struc contains parameter for threads typedef struct { volatile BOOL ThreadStoppen; volatile int iComPortNum; volatile DWORD dwMonitorThreadId; } PARAMS, *PPARAMS; static HANDLE hEvent; // Message types #define MSG_MIN_RANGE 0 // Der Message-Type für PostThreadMessage setzt sich aus // QS_ALLPOSTMESSAGE (=256) und dem eigenem Message-Type // (siehe MSG_xxxxxxx) zusammen. // Mit MSG_MIN_RANGE können verschiedene Gruppen bei // Bedarf gebildet werden. #define MSG_TIME MSG_MIN_RANGE + 1000 // vom ComThread #define MSG_TRIG MSG_MIN_RANGE + 2000 // reserviert #define MSG_COMOPEN MSG_TRIG + 4 #define MSG_COMCLOSE MSG_TRIG + 5 #define QEVENT "QueueEvent" //-------------------------------------------------------------------- // COMThread // // erstellt eine Queue, setzt danach den Event ("Queue ist ready"). // Schließt eine geöffneten COM-Port und öffnet den neuen (Nummer ist // in der Strukur, auf die lpParam zeigt). // liest die queue aus. // // Thread Funktion // Liest eventgesteuert den Status von CTS, DSR, ... ein und // sendet in dwEvtMask alle zum Event gehörenden Ereignisse // zum Monitor-Thread. // //-------------------------------------------------------------------- DWORD WINAPI ComThread (LPVOID lpParam) { long lTime; volatile PPARAMS pparams; // struct-Instanz pparams = (PPARAMS) lpParam; // Zuweisung zu lpParam int iPortNum = pparams->iComPortNum; // ... DWORD dwMonitorThreadId = pparams->dwMonitorThreadId; // ... char szPort[15]; static OVERLAPPED o; // Maske für SetCommMask, die bestimmt, welche Ereignisse auftreten können DWORD dwEvtMaskIn = EV_CTS | EV_DSR | EV_BREAK | EV_RING | EV_RXCHAR | EV_RLSD | EV_ERR | EV_RXFLAG | EV_TXEMPTY; DWORD dwEvtMask = 0; // Maske, in die WaitCommEvent aktuelle Werte schreibt BOOL bRet; CloseHandle (hCom); // "alten" COM-Port schließen // Com Port öffnen wsprintf (szPort, "COM%d", iPortNum); hCom = CreateFile (szPort, GENERIC_READ | GENERIC_WRITE, 0, // exclusive access NULL, // no security attributes OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (hCom == INVALID_HANDLE_VALUE) { LPVOID lpMsgBuf; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); MessageBox (NULL, (LPCTSTR)lpMsgBuf, TEXT("ComThread: error: CreateFile()"), MB_OK | MB_ICONINFORMATION); LocalFree (lpMsgBuf); pparams->ThreadStoppen = TRUE; } else { if (!SetCommMask (hCom, dwEvtMaskIn)) MessageBox (NULL, "SetCommMask fehlgeschlagen", "COM Port:", MB_OK | MB_ICONSTOP); // Create an event object for use in WaitCommEvent. o.hEvent = CreateEvent (NULL, // no security attributes FALSE, // auto reset event FALSE, // not signaled NULL); // no name } // Setzt die Priorität "High" für das Programm // Achtung: nicht "RealTime" verwenden - System wird instabil! DWORD dwProcessId; // own process identifier HANDLE hProcess; // handle to the own process DWORD dwDesiredAccess = PROCESS_SET_INFORMATION; // access flag BOOL bInheritHandle = TRUE; // handle inheritance flag BOOL bReturn; // If the SetPriorityClass succeeds, then nonzero DWORD dwPriorityClass = HIGH_PRIORITY_CLASS; dwProcessId = GetCurrentProcessId (); hProcess = OpenProcess (dwDesiredAccess, bInheritHandle, dwProcessId); bReturn = SetPriorityClass (hProcess, dwPriorityClass); printf ("\r\nComThread: %s geöffnet, warte auf Events ...", szPort); // eine message zum Monitor-Thread senden: bRet = PostThreadMessage (dwMonitorThreadId, (QS_ALLPOSTMESSAGE + MSG_COMOPEN), (WPARAM)iPortNum , (LPARAM)0); // Auf Events warten: while (!pparams->ThreadStoppen) // solange weitermachen bis TRUE { WaitCommEvent (hCom, &dwEvtMask, &o); // EventMask "scharf machen" // kommt der Event, ist auch die dwEvtMask geladen und es kann weitergehen if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) // warten bis Event { lTime = queryPrecisionTimeStamp (); // Zeit holen // Message senden. In dwEvtMask können mehrere Ereignisse gesetzt sein // Ereignisse und Daten in eine Message-Queue schreiben und dann // gleich weitermachen. Die Daten NICHT hier weiterverarbeiten! bRet = PostThreadMessage (dwMonitorThreadId, (QS_ALLPOSTMESSAGE + MSG_TIME), (WPARAM)dwEvtMask , (LPARAM)lTime); } // end of: if (WAIT_OBJECT_0 == ... } // end of: while (... CloseHandle (o.hEvent); CloseHandle (hCom); // COM-Port schließen printf ("\r\nComThread: %s geschlossen", szPort); bRet = PostThreadMessage (dwMonitorThreadId, (QS_ALLPOSTMESSAGE + MSG_COMCLOSE), (WPARAM)iPortNum , (LPARAM)0); return (0); } //---------------------------------------------------------------------- ------ // MonitorThread // // erstellt eine Queue, setzt danach den Event und liest // die queue aus //---------------------------------------------------------------------- ------ DWORD WINAPI MonitorThread (LPVOID lpParam) { static char szMsg[255] = ""; static char szMsgTmp[30] = ""; int i = 0; BOOL bRet; MSG msg; volatile PPARAMS pparams; // struct-Instanz pparams = (PPARAMS) lpParam; // Zuweisung zu lpParam DWORD COMStatus; // create a queue for the thread PeekMessage ((LPMSG)&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); // sent event after queue creation back to the threads creator bRet = SetEvent (hEvent); printf ("\r\nMonitorThread: warte auf Events ..."); // get messages by message from threads local queue while ((bRet = GetMessage (&msg, NULL, 0, 0)) != 0) { if (bRet == -1) { // handle the error and possibly exit MessageBox (NULL, "MonitorThread: GetMessage error", "COM Port:", MB_OK | MB_ICONSTOP); return NULL; // error! } else { // a valid message is received switch (msg.message) { case (QS_ALLPOSTMESSAGE + MSG_COMOPEN): printf ("\r\nMonitorThread: MSG_COMOPEN: lParam=0x%08x wParam=0x%08x", msg.lParam, msg.wParam); break; case (QS_ALLPOSTMESSAGE + MSG_COMCLOSE): printf ("\r\nMonitorThread: MSG_COMCLOSE: lParam=0x%08x wParam=0x%08x", msg.lParam, msg.wParam); break; case (QS_ALLPOSTMESSAGE + MSG_TIME): // Time stamp message: lParam=time, wParam=dwEvtMask szMsg[0] = '\0'; if (DWORD(msg.wParam) & EV_CTS) { GetCommModemStatus (hCom, &COMStatus); if (COMStatus & MS_CTS_ON) { // CTS (Pin8) activated wsprintf (szMsgTmp, "\r\nCTS_ON : %lu µs", msg.lParam); } else { // CTS (Pin8) deactivated wsprintf (szMsgTmp, "\r\nCTS_OFF: %lu µs", msg.lParam); } strcat (szMsg, szMsgTmp); } if (DWORD(msg.wParam) & EV_DSR) { GetCommModemStatus (hCom, &COMStatus); if (COMStatus & MS_DSR_ON) { // DSR (Pin6) activated wsprintf (szMsgTmp, "\r\nDSR_ON : %lu µs", msg.lParam); } else { // DSR (Pin6) deactivated wsprintf (szMsgTmp, "\r\nDSR_OFF: %lu µs", msg.lParam); } strcat (szMsg, szMsgTmp); } if (DWORD(msg.wParam) & EV_RLSD) { GetCommModemStatus (hCom, &COMStatus); if (COMStatus & MS_RLSD_ON) { // DCD (Pin1) activated wsprintf (szMsgTmp, "\r\nRLSD_ON: %lu µs", msg.lParam); } else { // DCD (Pin1) deactivated wsprintf (szMsgTmp, "\r\nRLSD_OFF: %lu µs ", msg.lParam); } strcat (szMsg, szMsgTmp); } if (DWORD(msg.wParam) & EV_RING) { GetCommModemStatus (hCom, &COMStatus); if ((COMStatus & MS_RING_ON)) { // RI (Pin9) activated wsprintf (szMsgTmp, "\r\nRING_ON: %lu µs", msg.lParam); } else { // RI (Pin9) deactivated wsprintf (szMsgTmp, "\r\nRING_OFF: %lu µs", msg.lParam); } strcat (szMsg, szMsgTmp); } printf (szMsg); break; default: wsprintf (szMsg, "\r\nMonitorThread: default: lParam=0x%08x wParam=0x%08x message=0x%08x", msg.lParam, msg.wParam, msg.message); MessageBox (NULL, (LPCTSTR)szMsg, "COM Port:", MB_OK | MB_ICONSTOP); break; } // end of: switch (msg.message) } // end of: if (bRet == -1) else ... } // end of: while((bRet = GetMessage(... printf ("\r\nMonitorThread: beendet"); return 0; } // Globale Variablen // struct für Zeitmessung union ut_LargeInteger { LARGE_INTEGER o_WinPart; ULONGLONG l_MyPart; }; int i_ResetPrecisionTime = 0; ULONGLONG l_PerfFrequ; ut_LargeInteger uo_PerfCount; /*********************************************************************** * Die Funktion queryPrecisionTimeStamp () liefert die seit dem Start des PC verstrichene Zeit in Mikrosekunden. ************************************************************************ / long queryPrecisionTimeStamp (void) { if (i_ResetPrecisionTime == 0) { i_ResetPrecisionTime = 1; QueryPerformanceFrequency (&uo_PerfCount.o_WinPart); l_PerfFrequ = uo_PerfCount.l_MyPart; } ut_LargeInteger uo_perfCount; QueryPerformanceCounter (&uo_perfCount.o_WinPart); return (long) (uo_perfCount.l_MyPart * 1000000 / l_PerfFrequ); } // ********************************************************************* int main (void) { DWORD dwMonThreadId; DWORD dwComThreadId; HANDLE hMonThread; HANDLE hComThread; DWORD dwState; PARAMS p; // MonitorThread erstellen: // Erstellt den Event für die Thread Queue hEvent = CreateEvent (NULL, false, true, QEVENT); // Thread starten und uMonThreadID für ComThread merken hMonThread = CreateThread ( // Handle des Threads NULL, // no security attributes 0, // use default stack size MonitorThread, // thread function &p, // argument to thread function 0, // use default creation flags &dwMonThreadId); // returns the thread identifier if (hMonThread == NULL) printf ("\r\nCreateThread (MonitorThread) fehlgeschlagen"); p.dwMonitorThreadId = dwMonThreadId; // merken, für ComThread // wait for queue completition dwState = WaitForSingleObject (hEvent, 100); CloseHandle (hEvent); // "alten" Thread stoppen p.ThreadStoppen = TRUE; CloseHandle (hComThread); // "alten" Thread stoppen p.iComPortNum = 1; // ComThread: Starten und Parameterstruct übergeben p.ThreadStoppen = FALSE; hComThread = CreateThread ( // Handle des Threads NULL, // no security attributes 0, // use default stack size ComThread, // thread function &p, // argument to thread function 0, // use default creation flags &dwComThreadId); // returns the thread identifier if (hComThread == NULL) printf ("\r\nCreateThread (ComThread) fehlgeschlagen"); Sleep (30000); // nur so zum Test CloseHandle (hMonThread); // MonitorThread beenden CloseHandle (hComThread); // ComThread beenden return (0); } Die main-funktion sollte noch angepaßt werden, z.B. mit einer Schleife. Jetzt ist sie nach 30 Sekunden zu Ende. Blackbird
Also ich würde dazu ja VB empfehlen, da ist sowas in 10 - 20 Zeilen erledigt...
Hallo Blackbird, vielen Dank erstmal für den Source-Code Wieviel mA darf ich maximal am RS232 anschließen ohne das ich das Motherboard völlig brate? Und bei diesem Programm muss ich also eine Spannung von 5 Volt an beispielsweise Pin8 anlegen und Pin5 auf Masse legen. Falls die Lichtschranke dann durchbrochen wird, fällt die Spannung auf 0 und das Programm reagiert darauf und stoppt? Ich hoffe mal das ich das richtig verstanden habe. mfg Walti PS: sorry Phillipp aber leider beherrsche ich kein VB deshalb werde ich auch die Version von Blackbird verwenden, nicht böse sein ;)
War ein paar Tagen nicht anwesend, kann also erst jetzt antworten: "Wieviel mA darf ich maximal am RS232 anschließen ohne das ich das Motherboard völlig brate?" Die PC-Hardware begrenzt den Strom, dem Motherboard geschieht nichts. 5mA an einem Ausgang sind so die Grenze, ist jedoch von PC zu Pc verschieden. Die Spannung beträgt dabei noch ca. max. 8V. Einen Ausgang (z.B. RTS Pin7) kann man so auf -10V (gegen Masse Pin5) setzen: EscapeCommFunction (hPort, SETRTS); // RTS setzten Pin7 Auf +10V kann man in so setzen: EscapeCommFunction (hPort, CLRRTS); // RTS rücksetzten Pin7 "Und bei diesem Programm muss ich also eine Spannung von 5 Volt an beispielsweise Pin8 anlegen und Pin5 auf Masse legen." Ja "Falls die Lichtschranke dann durchbrochen wird, fällt die Spannung auf 0 und das Programm reagiert darauf und stoppt? Ich hoffe mal das ich das richtig verstanden habe." Ja Ja "PS: sorry Phillipp aber leider beherrsche ich kein VB deshalb werde ich auch die Version von Blackbird verwenden, nicht böse sein ;)" Das VB-Programm würde ich auch gerne sehen. Muß nicht kommentiert sein, ich programmiere auch VB und denke, dass ich es "pur" verstehe. Blackbird
Kleiner Nachtrag: Nicht das Programm stoppt, sondern die Zeit für das Auftreten dieses Ereignisses (Pegelwechsel an Pin8) wird "gestoppt". Blackbird
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.