30. november 2004 - 12:15
Der er
9 kommentarer og
1 løsning
Seriel kommunikation i Win32
Hej Eksperter!
Jeg ønsker at skrive og læse fra COM porten fra min Win32 applikation, skrevet i C (og bruger WinAPI). Dette går også fint så længe det er non-overlapped fil-operationer. Problemet er nu, at jeg ikke ved hvornår der modtages noget på COM porten. Er det muligt at lave det interruptstyret (eller lign.) således at når der modtages data på porten kaldes en funktion, som læser på porten og lægger det læste data over i en buffer (evt. en fil).
Vil dette kunne lade sig gøre eller er det nødvendig at starte en separat proces op, som hele tiden overvåger porten?
Jeg har haft kig på det sidste løsning (separat proces), som nok kan laves ved at læse porten som Overlapped, men jeg syntes dokumentationen på MSDN er forvirrende (Har læst
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/msdn_serial.asp), og ville derfor gerne lave det lidt mere "lige til" :)
Håber nogen kan hjælpe! Alt kan bruges, men det ville være perfekt med noget konkret kode.
Hilsen Jesper
NB. Det skal lige tilføjes at jeg har læst andre spm på eksperten angående seriel kommunikation, men syntes ikke at der var noget jeg kunne bruge..
01. december 2004 - 20:34
#7
Det blev til et meget simelt terminal program. Det kan bruges til at sende AT-kommandoer til et modem. Du skriver blot kommandoen (F.ex. AT) og trykker enter, svaret fra modemet vil blive vist øverst.
#include <stdio.h>
#include <windows.h>
typedef struct
{
HANDLE Port;
DWORD MainThreadId;
}ThreadParamType;
void GotoXY(int x, int y);
BOOL KeyHit(void);
WORD GetChar(void);
HANDLE StdInHandle;
HANDLE StdOutHandle;
void SetTimeOut(HANDLE Port)
{
COMMTIMEOUTS commtimeouts;
GetCommTimeouts(Port, &commtimeouts);
commtimeouts.ReadIntervalTimeout = MAXDWORD;
commtimeouts.ReadTotalTimeoutMultiplier = 0;
commtimeouts.ReadTotalTimeoutConstant = 0;
SetCommTimeouts(Port, &commtimeouts);
}
void Tx(HANDLE Port, const char *data)
{
DWORD Dummy;
WriteFile(Port, data, strlen(data), &Dummy, 0);
WriteFile(Port, "\r\n", 2, &Dummy, 0);
}
DWORD Rx(HANDLE Port, void *Buffer, int MaxSize)
{
DWORD Length;
ReadFile(Port, Buffer, MaxSize, &Length, 0);
return Length;
}
DWORD WINAPI RxThreadProc(LPVOID Parameter)
{
ThreadParamType *ThreadParam = (ThreadParamType *)Parameter;
while(1)
{
char Buffer[256], *p;
int len;
len = Rx(ThreadParam->Port, Buffer, sizeof(Buffer));
if(len)
{
p = malloc(len);
memcpy(p, Buffer, len);
PostThreadMessage(ThreadParam->MainThreadId, 1001, len, (LPARAM )p);
}
Sleep(100);
}
}
DWORD WINAPI TxThreadProc(LPVOID Parameter)
{
ThreadParamType *ThreadParam = (ThreadParamType *)Parameter;
while(1)
{
MSG msg;
GetMessage(&msg, NULL, 0, 0xFFFF);
Tx(ThreadParam->Port, (char *)msg.wParam);
free((char *)msg.wParam);
Tx(ThreadParam->Port, "\r\n");
}
}
int main(void)
{
DWORD RxThreadId, TxThreadId;
ThreadParamType ThreadParam;
MSG msg;
char InBuffer[60];
int idx, i;
DCB dcb;
HANDLE ComPort = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if(ComPort == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "Failed to open port\n");
return 0;
}
StdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
StdInHandle = GetStdHandle(STD_INPUT_HANDLE);
ThreadParam.Port = ComPort;
ThreadParam.MainThreadId = GetCurrentThreadId();
GetCommState(ComPort, &dcb);
dcb.BaudRate = 9600;
dcb.ByteSize = 8;
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
dcb.fOutxCtsFlow = 1;
SetCommState(ComPort, &dcb);
SetTimeOut(ComPort);
CreateThread(0, 0, RxThreadProc, (LPVOID )&ThreadParam, 0, &RxThreadId);
CreateThread(0, 0, TxThreadProc, (LPVOID )&ThreadParam, 0, &TxThreadId);
Sleep(1000); /* Let the threads start */
GotoXY(0, 0);
for(i = 0; i < 22; i++)
printf(" \n");
idx = 0;
GotoXY(idx, 20);
while(1)
{
if(PeekMessage(&msg, NULL, 0, 0xFFFF, PM_REMOVE))
{
char *p;
GotoXY(0, 0);
for(i = 0; i < 20; i++)
printf(" \n");
p = (char *)msg.lParam;
GotoXY(0, 0);
for(i = 0; i < (int )msg.wParam; i++)
if(p[i] != '\r')
putc(p[i], stdout);
free(p);
GotoXY(idx, 20);
}
else if(KeyHit())
{
WORD Key = GetChar();
GotoXY(idx, 20);
if(Key == VK_RETURN)
{
char *p = malloc(idx + 1);
InBuffer[idx] = 0;
strcpy(p, InBuffer);
PostThreadMessage(TxThreadId, 1002, (WPARAM )p, 0);
idx = 0;
}
else if(idx < sizeof(InBuffer) - 2)
{
InBuffer[idx] = (char )Key;
GotoXY(idx, 20);
fputc((char )Key, stdout);
idx++;
}
}
else
Sleep(50);
}
return 0;
}
void GotoXY(int x, int y)
{
COORD c;
c.X = (short )x;
c.Y = (short )y;
SetConsoleCursorPosition(StdOutHandle, c);
}
BOOL KeyHit()
{
DWORD NumEvents, NumEventsRead;
INPUT_RECORD *InputRecord;
DWORD i;
GetNumberOfConsoleInputEvents(StdInHandle, &NumEvents);
InputRecord = (INPUT_RECORD *)malloc(sizeof(INPUT_RECORD)*NumEvents);
PeekConsoleInput(StdInHandle, InputRecord, NumEvents, &NumEventsRead);
for(i = 0; i < NumEventsRead; i++)
{
if(InputRecord[i].EventType & KEY_EVENT && InputRecord[i].Event.KeyEvent.bKeyDown)
{
if(InputRecord[i].Event.KeyEvent.wVirtualKeyCode != VK_CONTROL &&
InputRecord[i].Event.KeyEvent.wVirtualKeyCode != VK_MENU &&
InputRecord[i].Event.KeyEvent.wVirtualKeyCode != VK_SHIFT)
{
free(InputRecord);
return TRUE;
}
}
}
free(InputRecord);
return FALSE;
}
WORD GetChar()
{
DWORD NumEventsRead;
INPUT_RECORD InputRecord;
while(1)
{
if(!ReadConsoleInput(StdInHandle, &InputRecord, 1, &NumEventsRead))
return 0;
if(InputRecord.EventType & KEY_EVENT && InputRecord.Event.KeyEvent.bKeyDown)
{
if(InputRecord.Event.KeyEvent.wVirtualKeyCode != VK_CONTROL &&
InputRecord.Event.KeyEvent.wVirtualKeyCode != VK_MENU &&
InputRecord.Event.KeyEvent.wVirtualKeyCode != VK_SHIFT)
{
return InputRecord.Event.KeyEvent.wVirtualKeyCode;
}
}
}
}