Diskuze: Čtení stavu PINU RS232
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.

Člen

Zobrazeno 10 zpráv z 10.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.
Jsi si jist, že chceš C++ ? Protože to vypadá, že to děláš v C#...
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.).
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++.
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.
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(TEXT("\\\\.\\COM6"),
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // default security attributes
OPEN_EXISTING,
0,
NULL
);
private: System::Void timer1_Tick(System::Object^ sender,
System::EventArgs^ e) {
/*
if (hCom == INVALID_HANDLE_VALUE)
{
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";
}
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:
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ý:
Na event se čeká třeba skrz WaitForSingleObject.
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.
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(portname,
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // default security attributes
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if (hCom == INVALID_HANDLE_VALUE)
{
// 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;
}
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).
Zobrazeno 10 zpráv z 10.