locked
Serial communication issue RRS feed

  • Question

  • Hello to all,

     

    I'm puzzling over a problem about the serial ports. I'm quite new to Visual C++ (2010 Express) but I'm not new to programming.
    The first step I did is to read this document:

    http://msdn.microsoft.com/en-us/library/ms810467.aspx#serial_topic4

    Then I tried to implement a simple test program to check the serial communication routine.
    At the end of the post I attach a working code, ready to compile.

     

    Well, in my main program I need to manage multiple serial ports as well as multiple timers. So I'm going to use WaitForMultipleObjectsEx and friends.
    The small code below is very similar to the examples provided in the MSDN page I wrote before.

    When you start the program you will see a '.' every timeouts, just to know the application is alive.
    If you send some data to COM1 (9600 8N1) you will get the char written out.

    First question: the first time it will read the same char *two* times. Why?

    Now if you send bytes "slowly" such as from hyperterminal the program works like a charm. But if you send data quickly (like every serial connection) it will receive garbage data. However it seems to receive the right number of chars but duplicates the last ones... Something like this:

    sent -> QUIT
    received -> ITTT

     

    Please, may you help me to fix this small piece of code?

    Thank you in advance,
    Marco

     

    complete code (I'm sorry I don't know why it loses the layout):

    #include "stdafx.h"
    



    #include <iostream>
    #include <stdio.h>
    #include <Windows.h>

    using
    namespace
    std;

    int
    _tmain(int
    argc, _TCHAR* argv[]) {
    HANDLE hSerial;

    hSerial = CreateFile("COM1"
    , GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
    DCB dcb;
    FillMemory(&dcb, sizeof
    (dcb), 0);
    GetCommState(hSerial, &dcb);
    dcb.BaudRate = 9600;
    dcb.ByteSize = 8;
    dcb.fParity = FALSE;
    dcb.StopBits = ONESTOPBIT;
    dcb.fInX = FALSE;
    dcb.fOutX = FALSE;
    dcb.fDtrControl = DTR_CONTROL_DISABLE;
    dcb.fRtsControl = RTS_CONTROL_DISABLE;
    SetCommState(hSerial, &dcb);

    DWORD dwRes;
    DWORD dwCommEvent;
    DWORD dwStoredFlags;
    DWORD dwOvRes;
    BOOL fWaitingOnStat = FALSE;
    OVERLAPPED osStatus = {0};
    char
    chRead;
    DWORD dwRead;

    dwStoredFlags = EV_RXCHAR;
    SetCommMask(hSerial, dwStoredFlags);
    osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    for
    (;;) {
    if
    (!fWaitingOnStat) {
    WaitCommEvent(hSerial, &dwCommEvent, &osStatus);
    fWaitingOnStat = TRUE;
    }

    if
    (fWaitingOnStat) {
    dwRes = WaitForSingleObject(osStatus.hEvent, 500);
    switch
    (dwRes) {
    case
    WAIT_OBJECT_0:
    if
    (GetOverlappedResult(hSerial, &osStatus, &dwOvRes, FALSE))
    do
    {
    ReadFile(hSerial, &chRead, 1, &dwRead, &osStatus);
    cout << chRead;
    } while
    (dwRead);
    fWaitingOnStat = FALSE;
    break
    ;

    case
    WAIT_TIMEOUT:
    cout << "."
    ;
    break
    ;

    default
    :
    cout << "Error WaitForSingleObject\n"
    ;
    CloseHandle(osStatus.hEvent);
    return
    0;
    }
    }
    }
    return
    0;
    }


     

    Sunday, April 25, 2010 7:09 PM

Answers

  • Hello Marco,

    To post code use the code block (icon looks like </>) and insert your code into it.

    do
    { ReadFile(hSerial, &chRead, 1, &dwRead, &osStatus);
     cout << chRead;
    } while (dwRead);
    

    This loop does the output whether the ReadFile succeeds or not.  Test the result returned by ReadFile before deciding to output. 

    For a practical application you will need to use a buffer and accept whatever number of characters ReadFile can give you for each call. Reading only one char at a time is too inefficient.

     

    Sunday, April 25, 2010 8:59 PM

All replies

  • Hello Marco,

    To post code use the code block (icon looks like </>) and insert your code into it.

    do
    { ReadFile(hSerial, &chRead, 1, &dwRead, &osStatus);
     cout << chRead;
    } while (dwRead);
    

    This loop does the output whether the ReadFile succeeds or not.  Test the result returned by ReadFile before deciding to output. 

    For a practical application you will need to use a buffer and accept whatever number of characters ReadFile can give you for each call. Reading only one char at a time is too inefficient.

     

    Sunday, April 25, 2010 8:59 PM
  • Scott,

     

    by the way I used the "Insert code block" button in the toolbar, but for some reasons it didn't work.

    Thank you for your hints, I will try them.

    Marco

     

    Sunday, April 25, 2010 9:17 PM