Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I am receiving junk on the serial port

I have an Atmel mirocontroller sending data which I want to receive on my PC over COM1.

When I attach a terminal program, the data is received correctly (it is all ascii, all printable except for \n).

However, my code appears to be receiving junk (non-ascii chars). Can anyone see what I am doing wrong? Thanks

Sending code, just for info

// USART options.
static const usart_options_t USART_CONSOLE_OPTIONS =
{
    .baudrate     = 115200,
    .charlength   = 8,
    .paritytype   = USART_NO_PARITY,
    .stopbits     = USART_1_STOPBIT,
    .channelmode  = USART_NORMAL_CHMODE
};

Receiving code

E_boolean OpenCom1(void)
{
   COMMTIMEOUTS timeouts;

   comPortHandle = CreateFile("COM1",  // Specify port device: default "COM1"
   GENERIC_READ | GENERIC_WRITE,       // Specify mode that open device.
   0,                                  // the device isn't shared.
   NULL,                               // the object gets a default security.
   OPEN_EXISTING,                      // Specify which action to take on file.
   0,                                  // default (not overlapped i/o).
   NULL);                              // default (hTemplate must be NULL for COM devices).

   if (comPortHandle == INVALID_HANDLE_VALUE)
      return False;

   deviceControlBlock.DCBlength = sizeof(deviceControlBlock);

    if((GetCommState(comPortHandle, &deviceControlBlock) == 0))
    {
      // CodeMe: do what?
      return False;
    }

    deviceControlBlock.BaudRate = CBR_115200;
    deviceControlBlock.StopBits = ONESTOPBIT;
    deviceControlBlock.Parity   = NOPARITY;
    deviceControlBlock.ByteSize = DATABITS_8;
    deviceControlBlock.fRtsControl = 0;

    if (!SetCommState(comPortHandle, &deviceControlBlock))
    {
      // CodeMe: do what?
      return False;
    }

    // set short timeouts on the comm port.
    timeouts.ReadIntervalTimeout = MAXDWORD;
    timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
    timeouts.ReadTotalTimeoutConstant = 1000;   // oen second
    timeouts.WriteTotalTimeoutMultiplier = 1;
    timeouts.WriteTotalTimeoutConstant = 1;
    if (!SetCommTimeouts(comPortHandle, &timeouts))
    {
      // CodeMe: do what?
      return False;
    }

   FlushFileBuffers(comPortHandle);

   PurgeComm (comPortHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);

   return True;
}//OpenCom1()

// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
void      ReadCharacterFromCom1(INPUT char *theCharacter)
{
   DWORD numBytesRead;

   numBytesRead = 0;

   while (numBytesRead == 0)
   {
      ReadFile(comPortHandle,           // handle of file to read
               theCharacter,            // store read data here
               sizeof(char),            // number of bytes to read
               &numBytesRead,           // pointer to number of bytes actually read
               NULL);
   }

   return;
}//ReadCharacterFromCom1()
like image 769
Mawg says reinstate Monica Avatar asked Mar 04 '13 03:03

Mawg says reinstate Monica


2 Answers

The function "ReadFile" is called with a "sizeof(char)" for number of bytes to read. This will alway be evaluated to be 1, probably not the value that you intended. The result is every call to the ReadCharacterFromCom1 will only read 1 valid character from the port and return, the rest that you saw are the junks left in the buffer because the buffer is not (manually) terminated with a null.

Suggest that you change it to:

 /* ============================================================ */
DWORD ReadCharacterFromCom1(char *pszBuffer, int nMaxCharToRead)
{
    DWORD dwBytesRead = 0;
    while (dwBytesRead == 0)
    {   ReadFile(comPortHandle, // handle of file to read
            pszBuffer,  // store read data here
            nMaxCharToRead, // number of bytes to read
            &dwBytesRead,   // pointer to number of bytes actually read
            NULL);
    }
    // terminate string with null
    pszBuffer[dwBytesRead] = 0;
    return dwBytesRead;
}

// test code ------------------------
char szBuffer[512];
DWORD dwCount = ReadCharacterFromCom1(szBuffer, sizeof(szBuffer)-1);
printf(_T("Receive %d chars: <%s>"), nCount, szBuffer);
like image 99
mfc Avatar answered Oct 20 '22 22:10

mfc


Assuming baud rate, number of data bits, parity and the number of stop bits are set up correctly you most likley are missing to set up any kind of flow control. You do not show us (fully) how you initialise the DCB.

Flow control inhibits buffer overflows in the sender/receiver.

Depending on what kind of serial cabeling you use and what kind of data shall be transferred soft- or hardware flow control can be used.

Hardware flow control is the preferred kind of flow control as it works for plain ASCII and binary data to be transferred. Its requiers a fully wired serial connection. It is also referred to as RTS and/or DTR flow control.

If you only have the mininal three-wire RS232/V.24 cabeling you might like to use software flow control (also referrred to as Xon/Xoff handshake). Xon/Xoff-handshake flow control works for ASCII data to be transfered only. To send binary data via such a connection it needs to be encode to pure ASCII. Use base64 encoding for example to do so.

How to set up flow control under windows you might like to read here: http://www.cplusplus.com/forum/windows/89698/

This http://msdn.microsoft.com/en-us/library/ff802693.aspx might serve as a reference.

like image 31
alk Avatar answered Oct 20 '22 22:10

alk