Thread: Serial Comms

  1. #1
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907

    Serial Comms

    Hey all,

    The intention of the program is to be able to send and receive data between a PIC16F648A and a C program hosted on Windows 8 using Code::blocks.

    Because I am very inexperienced using the Windows API, I have read the following:
    Serial Communications
    http://146.83.206.1/~jhuircan/Protoc...serial-win.pdf

    The code for the PIC16F648A can send and receive data successfully - This is varified by using PuTTY.

    The PIC's program can also receive data from the C program running in Code::Blocks (This is varified by incrementing a number on a display which the PIC is controlling when certain input is detected).

    The one thing that has not been successfully demonstrated is the hosted program receiving data from the PIC.

    The C program is as follows:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <windows.h>
    
    int main(int argc, char *argv[])
    {
        HANDLE hComm;
        DCB dcbSerialParams;
        char initstr[20];
    
        hComm = CreateFile( "COM3",
                            GENERIC_READ | GENERIC_WRITE,
                            0,
                            0,
                            OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL,
                            0);
    
        if (hComm == INVALID_HANDLE_VALUE)
        {
            if (GetLastError() == ERROR_FILE_NOT_FOUND)
            {
                fputs("Error: Serial port does not exist\n", stderr);
            }
    
            return EXIT_FAILURE;
        }
    
        fputs ("Port opened successfully\n", stdout);
    
        ZeroMemory(&dcbSerialParams, sizeof(dcbSerialParams));
        dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    
    /*
     * See
     * http://forums.codeguru.com/showthread.php?43432-I-finally-found-it!-BuildCommDCB-bug!
     */
        strcpy(initstr, "9600,n,8,1,x");
    
        if (BuildCommDCB(initstr, &dcbSerialParams))
        {
    
            COMMTIMEOUTS timeouts;
    
            timeouts.ReadIntervalTimeout = 20;
            timeouts.ReadTotalTimeoutMultiplier = 10;
            timeouts.ReadTotalTimeoutConstant = 100;
            timeouts.WriteTotalTimeoutMultiplier = 10;
            timeouts.WriteTotalTimeoutConstant = 100;
    
            if (SetCommTimeouts(hComm, &timeouts))
            {
                char szRXBuff[100] = {0};
                char szTXBuff[100] = "Test";
                DWORD dwBytesRead = 0;
    
    
                if (!WriteFile(hComm, szTXBuff, strlen(szTXBuff), &dwBytesRead, NULL))
                {
                    char lastError[1024];
                    FormatMessage(
                                  FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                  NULL,
                                  GetLastError(),
                                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                  lastError,
                                  1024,
                                  NULL);
    
                    fprintf(stderr, "Error: Could not send TX buffer\n%s", lastError);
    
                }
    
                fprintf(stdout, "\nBytes Written: %d\n", (int)dwBytesRead);
    
                if (!ReadFile(hComm, szRXBuff, (DWORD)(sizeof(szRXBuff)-1), &dwBytesRead, NULL))
                {
                    char lastError[1024];
                    FormatMessage(
                                  FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                  NULL,
                                  GetLastError(),
                                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                  lastError,
                                  1024,
                                  NULL);
    
                    fprintf(stderr, "Error: Could not receive RX buffer\n%s", lastError);
    
                }
    
                printf("%d:%x%x%x%x%x", (int)dwBytesRead, szRXBuff[0],szRXBuff[1],szRXBuff[2],
                                        szRXBuff[3],szRXBuff[4]);
            }
            else
            {
                // Couldn't build the DCB. Usually a problem
                // with the communications specification string.
                fputs("Error: Could not set serial port timeouts\n", stderr);
            }
    
        }
        else
        {
            // Couldn't build the DCB. Usually a problem
            // with the communications specification string.
            fputs("Error: Could not set DCB settings (such as baud rate, parity, ect...)\n", stderr);
        }
    
        if (!CloseHandle(hComm))
        {
            fputs("Error: Could not close handle\n", stderr);
        }
    
        return EXIT_SUCCESS;
    }
    The relevent PIC code is as follows:
    Code:
    void handle_rx(void)
    {
        switch (handle_rx_state)
        {
            case wait_for_rx_input:
    
               /* change state when input found */
                if (rx_in_pointer != rx_out_pointer)
                {
                    handle_rx_state = echo_input;
                }
                break;
    
            case echo_input:
    
                //printf("%X", rx_buffer[rx_out_pointer]);
                if (rx_buffer[rx_out_pointer] == 't')
                {
                    increment_display();
                    putch('*');
                }
    
                handle_rx_state = wait_for_rx_input;
                rx_out_pointer = (rx_out_pointer + 1) % RX_BUFSIZE;
    
                break;
        }
    }
    The output for the program:
    PIC:
    Output is incremented only when 't' is included in the sent string
    - Varified behavour using Putty -

    Hosted C program:
    [output]
    Port opened successfully

    Bytes written: 4
    0:00000
    [/output]
    No bytes are successfully written back.


    Is there a setting I am missing to be able to read the COM port?
    Is the input buffered? (i.e. Is the program missing the '*'?)
    Fact - Beethoven wrote his first symphony in C

  2. #2
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    I believe that a file opened for read/write access needs a positioning command between reads and writes. I don't know if that's the case here (doesn't make much sense, really), but you could try putting this before your read:
    Code:
    if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
        // error
    }
    You could also try a fflush(stdout) after the putch in the PIC code.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  3. #3
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    I've tried rewinding the File Pointer, but it didn't seem to change the problem.
    Code:
                if (SetFilePointer(hComm, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
                {
                    char lastError[1024];
    
                    FormatMessage(
                                  FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                  NULL,
                                  GetLastError(),
                                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                  lastError,
                                  1024,
                                  NULL);
    
                    fprintf(stderr, "Error: Could not rewind handle\n%s", lastError);
                }
    The signal is getting to the PIC and being sent back to the computer fine

    Serial Comms-20131108_152710_10p-jpg

    I think that there is something with the ReadFile that I am missing.
    Fact - Beethoven wrote his first symphony in C

  4. #4
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Well, it was a long shot.

    As a test, try putting a Sleep(1000) before the read.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  5. #5
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    The program had no change in its behaviour - Just out of curiousity, what where you looking for?
    Fact - Beethoven wrote his first symphony in C

  6. #6
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    I though maybe the read was happening too quickly and so was missing the data. I guess that would indicate that your timeouts are not set properly. You might try longer timeouts anyway, or setting them to 0 (which I think means no timeout).

    Here's some links (if you haven't found these already) :


    COMMTIMEOUTS


    BuildCommDCB


    Communications Functions
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  7. #7
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    I would suggest to add the following

    Code:
    DWORD dwCommEvent;
    SetCommMask(hComm, EV_RXCHAR);
    WaitCommEvent(hComm, &dwCommEvent, NULL);
    before you are trying to read from port. It could be you are trying to read from it when nothing is present in the buffer and timeout till the first byte arrives occured.


    The following Ms article Serial Communications suggests such approach to reading on non-overlapped ports
    Code:
    DWORD dwCommEvent;
    DWORD dwRead;
    char  chRead;
    
    if (!SetCommMask(hComm, EV_RXCHAR))
       // Error setting communications event mask
    
    for ( ; ; ) {
       if (WaitCommEvent(hComm, &dwCommEvent, NULL)) {
          do {
             if (ReadFile(hComm, &chRead, 1, &dwRead, NULL))
                // A byte has been read; process it.
             else
                // An error occurred in the ReadFile call.
                break;
          } while (dwRead);
       }
       else
          // Error in WaitCommEvent
          break;
    }
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  8. #8
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    After including the extra code the program is hanging, which is suggesting (to me) that the program is not registering the event of a character being received.
    Fact - Beethoven wrote his first symphony in C

  9. #9
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    It looks like you're missing the following after BuildCommDCB (which only fills in the structure but does not apply it):
    Code:
    SetCommState(hComm, dcbSerialParams);
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  10. #10
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Looking at the code in the serial settings of MSDN, the function SetCommState is only used when changing the parameters manually, not when using BuildCommDCB.

    Serial Communications

    Also, correct me if I am wrong, but I would assume that if the DCB was not being set up properly, more than just the receive would not be working.
    Fact - Beethoven wrote his first symphony in C

  11. #11
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    I have found documentation which supports the need to use SetCommState
    BuildCommDCB function (Windows)

    I'll need to wait until tomorrow before I can try it.
    Fact - Beethoven wrote his first symphony in C

  12. #12
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Hey all,

    The basic program is now working fine

    For all those playing at home, here is the final code:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <windows.h>
    
    int main(int argc, char *argv[])
    {
        HANDLE hComm;
        DCB dcbSerialParams;
        char initstr[20];
    
        hComm = CreateFile( "COM3",
                            GENERIC_READ | GENERIC_WRITE,
                            0,
                            0,
                            OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL,
                            0);
    
        if (hComm == INVALID_HANDLE_VALUE)
        {
            if (GetLastError() == ERROR_FILE_NOT_FOUND)
            {
                fputs("Error: Serial port does not exist\n", stderr);
            }
    
            return EXIT_FAILURE;
        }
    
        fputs ("Port opened successfully\n", stdout);
    
        ZeroMemory(&dcbSerialParams, sizeof(dcbSerialParams));
        dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    
    /*
     * See
     * http://forums.codeguru.com/showthread.php?43432-I-finally-found-it!-BuildCommDCB-bug!
     */
        strcpy(initstr, "9600,n,8,1,x");
    
        if (BuildCommDCB(initstr, &dcbSerialParams))
        {
            if (SetCommState(hComm, &dcbSerialParams))
            {
    
                COMMTIMEOUTS timeouts;
    
                timeouts.ReadIntervalTimeout = 20;
                timeouts.ReadTotalTimeoutMultiplier = 10;
                timeouts.ReadTotalTimeoutConstant = 100;
                timeouts.WriteTotalTimeoutMultiplier = 10;
                timeouts.WriteTotalTimeoutConstant = 100;
    
                if (SetCommTimeouts(hComm, &timeouts))
                {
                    char szRXBuff[100] = {0};
                    char szTXBuff[100] = "Test";
                    DWORD dwBytesRead = 0;
                    DWORD dwCommEvent;
                    DWORD dwRead;
                    char  chRead;
    
    
                    if (!WriteFile(hComm, szTXBuff, strlen(szTXBuff), &dwBytesRead, NULL))
                    {
                        char lastError[1024];
                        FormatMessage(
                                      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                      NULL,
                                      GetLastError(),
                                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                      lastError,
                                      1024,
                                      NULL);
    
                        fprintf(stderr, "Error: Could not send TX buffer\n%s", lastError);
    
                    }
    
                    fprintf(stdout, "\nBytes Written: %d\n", (int)dwBytesRead);
    
                    /* Recommended way
                    if (SetCommMask(hComm, EV_RXCHAR))
                    {
                        if (WaitCommEvent(hComm, &dwCommEvent, NULL))
                            {
                              do {
                                 if (ReadFile(hComm, &chRead, 1, &dwRead, NULL))
                                    putc(chRead,stdout);
                                    // A byte has been read; process it.
                                 else
                                    // An error occurred in the ReadFile call.
                                    break;
                              } while (dwRead);
                           }
                           else
                           {
                                char lastError[1024];
                                FormatMessage(
                                              FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                              NULL,
                                              GetLastError(),
                                              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                              lastError,
                                              1024,
                                              NULL);
    
                                fprintf(stderr, "Error: Problem with WaitCommEvent\n%s", lastError);
                           }
    
                    }
                    else
                    {
                        char lastError[1024];
                        FormatMessage(
                                      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                      NULL,
                                      GetLastError(),
                                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                      lastError,
                                      1024,
                                      NULL);
    
                        fprintf(stderr, "Error: Could not set up Comm Mask\n%s", lastError);
                    }*/
    
                    FlushFileBuffers(hComm);
    
                    /* Not recommeded way, but will do for this test */
                    if (!ReadFile(hComm, szRXBuff, (DWORD)(sizeof(szRXBuff)-1), &dwBytesRead, NULL))
                    {
                        char lastError[1024];
                        FormatMessage(
                                      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                      NULL,
                                      GetLastError(),
                                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                      lastError,
                                      1024,
                                      NULL);
    
                        fprintf(stderr, "Error: Could not receive RX buffer\n%s", lastError);
    
                    }
    
                    printf("\n%d:%x%x%x%x%x", (int)dwBytesRead, szRXBuff[0],szRXBuff[1],szRXBuff[2],
                                            szRXBuff[3],szRXBuff[4]);
                }
                else
                {
                    // Couldn't build the DCB. Usually a problem
                    // with the communications specification string.
                    fputs("Error: Could not set serial port timeouts\n", stderr);
                }
    
            }
            else
            {
                fputs("Error: Could not set DCB settings (such as baud rate, parity, ect...)\n", stderr);
            }
        }
        else
        {
            // Couldn't build the DCB. Usually a problem
            // with the communications specification string.
            fputs("Error: Could not build DCB settings (such as baud rate, parity, ect...)\n", stderr);
        }
    
        if (!CloseHandle(hComm))
        {
            fputs("Error: Could not close handle\n", stderr);
        }
    
        return EXIT_SUCCESS;
    }
    Here is the output when Rx and Tx of the RS-232 are short circuited (output looped straight back into the input):
    [output]
    Port opened successfully

    Bytes Written: 4

    4:546573740
    [/output]

    One thing that I forgot to mention is that all this is done through a USB to RS232 converter.

    Also, there are a lot of warnings that need to be sorted through - If you want to use this code, you need to sort through them as well.
    Fact - Beethoven wrote his first symphony in C

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Comms
    By r_james14 in forum C Programming
    Replies: 7
    Last Post: 11-22-2011, 08:17 AM
  2. Serial RS232 + OpenGL (multithread+Serial Comm)
    By manatttta in forum C Programming
    Replies: 3
    Last Post: 10-15-2011, 01:33 AM
  3. PIC16F88 wireless serial comms with USART
    By c.fry in forum C Programming
    Replies: 1
    Last Post: 05-16-2011, 09:50 AM
  4. Parent/Child comms homework
    By csgirl in forum C Programming
    Replies: 7
    Last Post: 05-15-2010, 02:40 PM
  5. HELP... LabVIEW Fluke 45 Serial Comms VI
    By studentsaj in forum Windows Programming
    Replies: 0
    Last Post: 03-08-2002, 11:17 AM