Link to home
Start Free TrialLog in
Avatar of galneweinhaw
galneweinhaw

asked on

Serial Port Communication

Hello,

I am building a program that is going to communicate with an actuator controller via "command strings" over the 9 pin serial port. I am using the CreateFile, ReadFile, and WriteFile functions. Here are the specifications of the controller

Electrical Specifications      EIA RS485
Synchronization Method      Asynchronous
Connection Method      Differential Line
Connector      6 pole modular
Strings Fromat      ASCII
Baud Rate      38.4kbps (Standard).  9.6kbps, 19.2kbps (Can be set as a factory default)
Data length      Eight bits
Stop bit      One bit
Parity check      None
Communication Method      Half-Duplex

Here is my implementation so far:

CString  m_sComPort;
      m_sComPort = "Com1";

      m_hCom = CreateFile (m_sComPort, // Port Name (Unicode compatible)
                                                GENERIC_READ | GENERIC_WRITE, // Open for Read-Write
                                                0, // COM port cannot be shared
                                                NULL, // Always NULL for Windows CE
                                                OPEN_EXISTING, // For communication resource
                                                0, // Non-overlapped operation only
                                                NULL); // Always NULL for Windows CE
      COMMTIMEOUTS ct;
      ct.ReadIntervalTimeout = 100;
      ct.ReadTotalTimeoutMultiplier = 10;
      ct.ReadTotalTimeoutConstant = 10;
      ct.WriteTotalTimeoutMultiplier = 10;
      ct.WriteTotalTimeoutConstant = 1000;
      if(!SetCommTimeouts(m_hCom, &ct))
      {
            MessageBox(NULL,(_T("Setting comm. timeouts.")), (_T("Error")), MB_OK);
            DWORD tmp = GetLastError();
            return false;
      }
      
      DCB dcb;
      dcb.DCBlength = sizeof(DCB);
      if(!GetCommState(m_hCom, &dcb))
      {
            MessageBox(NULL,(_T("Getting Comms. State.")), (_T("Error")), MB_OK);
            return false;
      }
      dcb.BaudRate = 9600; // set baud rate to what we want
      dcb.fOutxCtsFlow = TRUE;
      dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
      dcb.fDtrControl = DTR_CONTROL_ENABLE;
      dcb.fOutxDsrFlow = FALSE;
      dcb.fOutX = FALSE; // no XON/XOFF control
      dcb.fInX = FALSE;
      dcb.ByteSize = 8;
      dcb.Parity = NOPARITY;
      dcb.StopBits = ONESTOPBIT;

      if(!SetCommState(m_hCom, &dcb))
      {
            MessageBox(NULL,(_T("Setting Comms. State.")), (_T("Error")), MB_OK);
            return false;
      }
      return true;

My other functions are just the ReadFile and WriteFile using the 16 character commands.
example -> WriteFile(m_hCom, "02BaFFFF167A000603",16,&iBytesWritten,NULL);

Breakdown of Example According to Controller Manual:
STX                        02                             Start Transmission Character
Axis No.                   B                               (HEX) Axis 11(decimal)
Command                a                               Character for command
Position Data            FFFF167A                  Position in HEX as converted by algorithm
Zero's                     00                              String Filler (string must contain 16 characters)
BCC                        06                              Block Check Calculation - Value of String (HEX)
ETX                        03                              End Transmission Character

Nothing happens when I run this code, and in the debug window I notice that the BytesWritten data remains at '0', indicating to me that nothing is being written to the controller.

I have also tried using the ActiveX Controller "Microsoft Communications" and have had equal bad luck. I would prefer using the ReadFile and WriteFile functions though. But a solution is a solution.

-Cheers
Avatar of jeremyeadamich
jeremyeadamich

Hello,

I notice in your comments here that you state Windows CE...

m_hCom = CreateFile (m_sComPort, // Port Name (Unicode compatible)
                                        GENERIC_READ | GENERIC_WRITE, // Open for Read-Write
                                        0, // COM port cannot be shared
                                        NULL, // Always NULL for Windows CE
                                        OPEN_EXISTING, // For communication resource
                                        0, // Non-overlapped operation only
                                        NULL); // Always NULL for Windows CE

Is this a CE project or a Win32 project?

IF it is a CE project are you running your code on the emulator or on a device?

Jeremy
Avatar of jkr
>>Nothing happens when I run this code, and in the debug window I notice that the BytesWritten data remains at '0'

Check if 'WriteFile()' returns 'FALSE' and evaluate 'GetLastError()' in this case.
Avatar of galneweinhaw

ASKER

When I call GetLastError(),

it returns a 6
which means there is an INVALID HANDLE,

More to this, when I try to shut down the program, there is a first chance exception talking about an Invalid handle
So, have you verified that your handle is valid? E.g.

m_hCom = CreateFile (...);

if (!m_hCom) {

  dwError = GetLastError();
}

What port name are you using with 'CreateFile()'?
BTW, according to the docs, there's a suble little difference for CE, such as the name has to be 'COM1:' instead of 'COM1' - NOTE the trailing colon:

http://msdn.microsoft.com/library/en-us/fileio/fs/createfile.asp states "The CreateFile function can create a handle to a communications resource, such as the serial port COM1"

http://msdn.microsoft.com/library/en-us/wceobjst/html/cerefCreateFile.asp says "When lpFileName points to a COM port to open, you must include a colon after the name. For example, specify COM1: to open that port. When using IrCOMM, specify COM3:. "

Okay just to clarify, I am working on with Visual Studios 6.0, on an Windows XP computer. I pulled that code from a website (they are not my comments) sorry for the miscommunication.

I have fixed (at least for testing purposes) the invalid handle. It know does not create any errors, but still the string format does not seem to be valid, for the controller still does nothing
Are you sure about the DCB settings? I'd suggest to

     DCB dcb;
    dcb.DCBlength = sizeof(DCB);
    if(!GetCommState(m_hCom, &dcb))
    {
         MessageBox(NULL,(_T("Getting Comms. State.")), (_T("Error")), MB_OK);
         return false;
    }

    // set that according to your specs
    BuildCommDCB("baud=9600 parity=N data=8 stop=1", &dcb);

     if(!SetCommState(m_hCom, &dcb))
    {
         MessageBox(NULL,(_T("Setting Comms. State.")), (_T("Error")), MB_OK);
         return false;
    }

Apart from that, according to your specs, you'll need to set ETX at the end of the string, e.g.

"02BaFFFF167A000006X\003"

The '\003' is the escape sequnce for ETX, the 'X' represents the BCC value that *you* have to calculate.
    return true;
Could it possibly be that I'm setting the incorrect amount of memory (currently 16 bytes) in the WriteFile function? I tried the above and there is no progress.

Could it be an improper format? Should I send you the "serial protocol manual."
>>Could it be an improper format?

That's what I tried to point out - according to the table you posted above, the last char has to be 0x03 (and not the character '3') which I corrected above. But, I don't know how to calculate the BCC byte...
Here is information provided in the manual regarding the BCC byte, let me know if any more info will be of use

BCC:      
Two characters ’00-FF’ showing hexadecimal number digits for block check characters. It is calculated by using the 12 data characters (excluding STX, ETX and BCC).  It’s calculated by taking last 2 characters of the one's complement of the sum of the ASCII codes of those 12 characters.

Example of calculating BCC

[STX]1a1234567800[BCC][ETX]

First, add all ASCII codes for the 12 data characters:
      sum = 31H+61H+31H+32H+33H+34H+35H+36H+37H+38H+30H+30H = 296H
Second, take the last 2 characters of the 1’s complement:
       [BCC] = "6A"
Hello,

   Insted of Read/Write to file.... directly send data to com port....
http://sourceforge.net/projects/comport/  (this is in pascal.....)

Rgds
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you for the help on the BCC bit, I haven't gotten there yet because I still can't communicate with the controller. But thank you for the assistance.

I don't know if it means anything, but the manual seems to want the command strings in hexadecimal ASCII values. And when I look at the
char acCmd[] = "\002BaFFFF167A0006X\003" value in Debug mode. It does not seem to match up, for instance

the manual says '0' should have a value of '30', whereas the actual value for '0' in the program is '48'

could this be a problem
>>the manual says '0' should have a value of '30'

Um which '0' are you referring to?
0 (Zero the number)
Ah, now I got you - that's OK, '48' is the ASCII code for '0'. BTW, have to correct myself, the command string should be

"\002BaFFFF167A0006\003"
Its over, the actuator is going back to the company, after grinding the tech support for 3 days, I got talking to their communications "expert" and they told me I would be crazy to program it in VC++ 6.0, saying that it would take over a 1000 lines of code (don't ask why, cause he didn't know). Apparently it is easier to program it in VB, but I would still have to know the "handshake procedure," which they were unsure of. After downloading a trail version of a com spy and turning on their software, there was a ton going on that was way out of the scope of the documentation they gave me.

Thus, this horse is dead, and there is no sense flogging it. If they are not going to tell me the command procedure then its all for nothing.

jkr, thanks for sticking with this train wreck, all points and props go to you........