IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: Čtení stavu PINU RS232

V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Marek Švec
Člen
Avatar
Marek Švec:5.3.2018 19:52

Ahoj,
obracím se na vás s dotazem ohledně jednoho našeho projektu.
Jedná se o stopky pro PC (Windows) vytvořené ke stávajícímu HW.
Potřeboval bych nějakým způsobem detekovat stav jednotlivých pinů na konektoru RS232. Respektive by stačily piny (DSR a RI). Změna na RI (0 -> 5V) by měla stopky spustit a naopak změna na DSR (0 -> 5V) by měla stopky zastavit.
pro připojení používám System.IO.Ports. Připojení portu, odpojení, ... už mám potřebuji už pouze vyčítat stavy jednotlivých PINů.
Můžete mi prosím někdo poradit jak na to? Ideálně poslat nějaký krátký příklad?
Moc děkuju za odpovědi.

 
Odpovědět
5.3.2018 19:52
Avatar
Petr Čech
Tvůrce
Avatar
Odpovídá na Marek Švec
Petr Čech:5.3.2018 20:02

Jsi si jist, že chceš C++ ? Protože to vypadá, že to děláš v C#...

Nahoru Odpovědět
5.3.2018 20:02
the cake is a lie
Avatar
Marek Švec
Člen
Avatar
Marek Švec:5.3.2018 20:04

jojo jsem si jistý

 
Nahoru Odpovědět
5.3.2018 20:04
Avatar
Martin Dráb
Tvůrce
Avatar
Odpovídá na Marek Švec
Martin Dráb:5.3.2018 21:10

Spíš se přikláním k názoru, že to nepůjde. Ten sériový kabel zapojuješ zřejmě do nějakého čipu na desce, který pak ty signály (TTL?) bude interpretovat a komunikovat po sběrnici třeba s procesorem.

Z jakého důvodu potřebuješ reagovat jenom na změnu stavu jednoho pinů? Kvůli přesnosti, nebo chceš prostě do toho konektoru vrazit pouze jen ten jeden drát (nebo dva) a tím ušetřit na složitosti HW?

Pokud to první, tak to ti v obecnosti na Windows nepomůže, protože může trvat realtivně dlouho (milisekundy), než se aplikace, co ten port čte, dostane na procesor. Samozřejmě, dá se tomu hodně pomoci (vysoká priorita, zajistit té aplikaci nekonečný časová kvantum na procesoru...), ale garance nejsou, neb Windows nejsou realtime OS.

U druhého případu je to otázka. Komunikaci na sériové lince neznám do takových podrobností, takže nevím, zda se tam nedají najít piny, změna jejichž napětí způsobí nějakou událost, kterou ten čip na desce pošle pak OS (i třeba ve smyslu, že došlo k chybě přenosu atd.).

Nahoru Odpovědět
5.3.2018 21:10
2 + 2 = 5 for extremely large values of 2
Avatar
Marek Švec
Člen
Avatar
Marek Švec:5.3.2018 21:42

Hardware, pro který program píšeme byl vytvořen tak, aby byl schopen fungovat s programem staženým z uloz.to
Odkaz:
https://uloz.to/…pky-2-51-rar

Hardware hasičských stopek funguje tak, že při výstřelu z pistole sepne akustické čidlo a přes relátko sepne 5V na pinu RI. Potom když sepne čidlo v terči, pustí přes jiné relátko 5V na pin DSR. Sériový kabel je přes redukci přiveden do USB počítače.
V aplikaci stopky 2.51 se pak dá nastavit (soubor/nastavení sériového portu) co se vykoná po detekování napětí na jednotlivých PINech RS232.
My se snažíme napsat nový program ve Windows form, který by lépe vyhovoval pro naše potřeby, ale bohužel nemůžeme přijít na to jak rozchodit ten start a stop přes signál na pinech RS232. Nemám tušení v jakém jazyce je program stopky 2.51 napsán, ale předpokládám, že by to mělo jít i v C++.

 
Nahoru Odpovědět
5.3.2018 21:42
Avatar
Martin Dráb
Tvůrce
Avatar
Odpovídá na Marek Švec
Martin Dráb:6.3.2018 0:22

Nojo, ten uličník je v nějakém objektovém jazyce, takže HexRays decompiler má trošku problém, nicméně jsem objevil i něco bez jeho pomoci.

SetCommMask vypadá, že je to, co hledš. Jestli to dobře chápu, tak pro tebe budou zajímavé příznaky EV_DSR a EV_RING
https://msdn.microsoft.com/…=vs.85).aspx

Dole by měl být i odkaz na nějaký příklad, tak snad to pomůže.

Nahoru Odpovědět
6.3.2018 0:22
2 + 2 = 5 for extremely large values of 2
Avatar
Marek Švec
Člen
Avatar
Marek Švec:6.3.2018 21:51

Ahoj,
Děkuju moc za rady.
Dnes jsem zkusil udělat jednoduchý kód, ale bohužel mi to stále nefunguje.
K portu jsem připojen, ale SetCommMask stále vrací nonzero ať je na PINech 5V nebo 0V.
Níž posílám svou část kódu. Nevíte v čem by mohl být problém?

HANDLE hCom = CreateFile(TEX­T("\\\\.\\COM6"),
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // default security attributes
OPEN_EXISTING,
0,
NULL
);

private: System::Void timer1_Tick(Sys­tem::Object^ sender, System::EventArgs^ e) {
/*
if (hCom == INVALID_HANDLE_VA­LUE)
{
this->label5->Text = "ERROR";
}
else
{
this->label5->Text = "V pohodě";
}
*/
bool RI1 = SetCommMask(hCom, EV_RING);
if (RI1)
{
this->label7->Text = "RI1";
}
else
{
this->label7->Text = "NIC";
}
bool DSR1 = SetCommMask(hCom, EV_DSR);
if (DSR1)
{
this->label5->Text = "DSR1";
}
else
{
this->label5->Text = "NIC";
}

 
Nahoru Odpovědět
6.3.2018 21:51
Avatar
Martin Dráb
Tvůrce
Avatar
Odpovídá na Marek Švec
Martin Dráb:6.3.2018 23:52

SetCommMask ti nevrací, zda daná událost nastala či ne, ale jen instruuje ovladač sériového portu, aby ty události monitoroval a informoval tě o nich, až si to budeš přát. A přát si to budeš tak, že zavoláš WaitCommEvent. Mrkni tady na tento příklad:
https://msdn.microsoft.com/…=vs.85).aspx

Postup je asi takovýto:

  1. získat přístup k portu (CreateFile),
  2. nastavit monitorovanou sadu událostí (SetCommMask),
  3. začít čekat na událost (WaitCommEvent).

Pokud WaitCommEvent skončí úspěchem, v druhém parametru ti nastaví bity podle toho, k jakým událostem došlo (jsou to stejné bity jako v případě SetCommMask).

Ten příklad je podle mě dost nešťastný, protože tam čekají na tu událost portu asynchronně, nicméně pomíjejí pár věcí, které se při takkovém použití hodí vědět. Výhoda asynchronního čekání je taková, že dané vlákno není zablokováno v WaitCommEvent, ale může dělat jiné věci.

Postup pro asynchronní řešení je asi takový:

  1. při otevírání portu musíš specifikovat příznak FILE_FLAG_OVER­LAPPED,
  2. musíš inicializovat OVERLAPPED strukturu, a to tak, že ji celou vynuluješ a vytvoříš manual reset event (CreateEvent), který přiřadíš do položky hEvent (to je v tom příkladu vidět),
  3. zavoláš WaitCommEvent.

Na event se čeká třeba skrz WaitForSingle­Object.

Pokud volání vrátí nulovou hodnotu (chyba), je potřeba zkontrolovat, zda chyba není ERROR_IO_PENDING, což není chyba, ale informace "vše se podařilo, ale požadovaná událost zatím nenastala".

Jakmile se objeví událost, na kterou čekáš, tak se onen manual reset event přepne do signálního stavu a zřejmě do druhého parametru funkce dostaneš bitovou masku udávající, k jakým událostem došlo. Aby monitorování pokračovalo, budeš muset znovu zavolat WaitCommEvent.

Pro asynchronní řešení je asi nejlepší, aby jak ta OVERLAPPED struktura, tak druhý parametr volání WaitCommEvent vedly do míst, která neztrácí platnost při konci metody.

A nebo můžeš čekat na událost synchronně (ne overlapped) v separátním vlákně a případně prostě informovat hlavní vlákno, které obsluhuje GUI.

Nahoru Odpovědět
6.3.2018 23:52
2 + 2 = 5 for extremely large values of 2
Avatar
Marek Švec
Člen
Avatar
Odpovídá na Martin Dráb
Marek Švec:7.3.2018 22:49

Moc děkujeme za rady.
Už se nám to povedlo rozchodit :)
Udělali jsme si knihovnu dle příkladu na MSDN třeba se to bude někdy někomu jako příklad hodit

#include "COM_PORTY.h"
HANDLE PripojPort(char port[])
{
HANDLE hCom;

char portname[100] = "\\\\.\\";
strcat_s(portname, port);

hCom = CreateFileA(por­tname,
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // default security attributes
OPEN_EXISTING,
FILE_FLAG_OVER­LAPPED,
NULL
);
if (hCom == INVALID_HANDLE_VA­LUE)
{
// Handle the error.
//return 5;
}
return hCom;
}
int StavPortu(HANDLE hCom)
{
// Set the event mask.
OVERLAPPED o;
BOOL fSuccess;
DWORD dwEvtMask;

fSuccess = SetCommMask(hCom, EV_RING | EV_DSR);

if (!fSuccess)
{
// Handle the error.
return 6;
}

// Create an event object for use by WaitCommEvent.

o.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);

// Initialize the rest of the OVERLAPPED structure to zero.
o.Internal = 0;
o.InternalHigh = 0;
o.Offset = 0;
o.OffsetHigh = 0;

assert(o.hEvent);
WaitCommEvent(hCom, &dwEvtMask, &o);

if (dwEvtMask)
{
if (dwEvtMask & (EV_DSR))
{
return 1;
}
else if (dwEvtMask & (EV_RING))
{
return 2;
}
}
DWORD dwRet = GetLastError();
if (!(ERROR_IO_PENDING == dwRet))
{
return 0;
}

return 0;
}

 
Nahoru Odpovědět
7.3.2018 22:49
Avatar
Martin Dráb
Tvůrce
Avatar
Odpovídá na Marek Švec
Martin Dráb:8.3.2018 1:44

Masku (dwEvtMask **) byste měli testovat až v případě, že víte, že **WaitCommEvent uspěla.

Event, který tam vytváříte, byste měli na konci funkce zrušit (CloseHandle), jinak každé volání způsobů leak jednoho handle. To není nic vážného, ale po určité (pravda, hooodně dlouhé) době se začnou dít divné věci.

Podobně by měla existovat párová funkce k PripojPort, která daný sériový port zavře (CloseHandle). Tady je to vážnější, protože dokud ten port nezavřete, nikdo jiný se k němu nedostane (což ale může být záměr).

Nevím, zda mohou obě události nastat současně. Pokud ano, ta funkce to neřeší (vždy reportuje jen jednu z nich – pouze přítomnost jednoho bitu v masce).

Nahoru Odpovědět
8.3.2018 1:44
2 + 2 = 5 for extremely large values of 2
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 10.