2016-06-12 41 views
0

我修改了Windows平臺下C(codeblocks/mingw)中其他人編寫的串行通信環回代碼。我能夠正確發送數據。我通過打開終端軟件來驗證這一點。但我無法收到數據。在下面的代碼中,我從ReadFile()的輸入緩衝區998中讀取錯誤消息錯誤。不知道錯誤是什麼。 我正在使用兩個CP210x USB串行模塊並將TxD連接到另一個的RxD。無法接收串行數據

#include <windows.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <commdlg.h> 
//#include <windef.h> 
#include <time.h> 

int nread,nwrite; 

void myDelay(unsigned int mseconds) 
{ 
    clock_t goal = mseconds + clock(); 
    while (goal > clock()); 
} 

int main(int argc, char* argv[]) 
{ 
    HANDLE hSerial; 
    COMMTIMEOUTS timeouts; 
    COMMCONFIG dcbSerialParams; 
    char *words, *buffRead, *buffWrite; 
    DWORD dwBytesWritten, dwBytesRead; 

    if(argc<3) 
    { 
     printf("Enter the com port as command line parameter and t for transmitter and r for receiver\n"); 
     printf("Example: Serial.exe com4 t\n"); 
     return(1); 
    } 
    hSerial = CreateFile(argv[1],GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); 

    if (hSerial == INVALID_HANDLE_VALUE) 
    { 
     if (GetLastError() == ERROR_FILE_NOT_FOUND) 
     { 
      printf(" serial port does not exist \n"); 
     } 
     else 
     { 
      printf(" some other error occured\n"); 
     } 

     return(1); 
    } 


    if (!GetCommState(hSerial, &dcbSerialParams.dcb)) 
    { 
     printf("error getting state \n"); 
     return(1); 
    } 

    dcbSerialParams.dcb.DCBlength = sizeof(dcbSerialParams.dcb); 

    // Set various serial port parameters. 

    dcbSerialParams.dcb.BaudRate = CBR_9600; 
    dcbSerialParams.dcb.ByteSize = 8; 
    dcbSerialParams.dcb.StopBits = ONESTOPBIT; 
    dcbSerialParams.dcb.Parity = NOPARITY; 

    dcbSerialParams.dcb.fBinary = TRUE; 
    dcbSerialParams.dcb.fDtrControl = DTR_CONTROL_DISABLE; 
    dcbSerialParams.dcb.fRtsControl = RTS_CONTROL_DISABLE; 
    dcbSerialParams.dcb.fOutxCtsFlow = FALSE; 
    dcbSerialParams.dcb.fOutxDsrFlow = FALSE; 
    dcbSerialParams.dcb.fDsrSensitivity= FALSE; 
    dcbSerialParams.dcb.fAbortOnError = TRUE; 

    if (!SetCommState(hSerial, &dcbSerialParams.dcb)) 
    { 
     printf(" error setting serial port state \n"); 
     return(1); 
    } 


    GetCommTimeouts(hSerial,&timeouts); 
    timeouts.ReadIntervalTimeout = 50; 
    timeouts.ReadTotalTimeoutConstant = 50; 
    timeouts.ReadTotalTimeoutMultiplier = 10; 
    timeouts.WriteTotalTimeoutConstant = 50; 
    timeouts.WriteTotalTimeoutMultiplier= 10; 

    if(!SetCommTimeouts(hSerial, &timeouts)) 
    { 
     printf("error setting port state \n"); 
     return(1); 
    } 

    while(1) 
    { 
     // Use a delay of 500 msec 
     myDelay(500); 
     if(!strcmp(argv[2],"t")) 
     { 

      printf("Write Mode\n"); 
      //****************Write Operation*********************// 
      words = "This is a string to be written to serial port COM1"; 
      nwrite = strlen(words); 

      buffWrite = words; 
      dwBytesWritten = 0; 

      if (!WriteFile(hSerial, buffWrite, nwrite, &dwBytesWritten, NULL)) 
      { 
       printf("error writing to output buffer \n"); 
       return(1); 
      } 

     } 


//***************Read Operation******************// 

     else 
     { 
      dwBytesRead = 0; 
      nread = strlen(words); 

      if (!ReadFile(hSerial, buffRead, nread, &dwBytesRead, NULL)) 
      { 
       printf("error reading from input buffer %d\n", GetLastError()); 
       continue; 
      } 
      printf("Data read from read buffer is \n %s \n",buffRead); 

     } 
    } 
    CloseHandle(hSerial); 
    return(0); 

} 
+1

錯誤998 ERROR_NOACCESS「對內存位置的無效訪問」。用100%的自信告訴你,你正在向ReadFile()傳遞一個錯誤的指針。你是,你從來沒有初始化* buffRead *。一個更好的聲明是'BYTE buffRead [4096];'並且爲緩衝區大小傳遞一個正確的值,即4096. printf()語句也是錯誤的,你不會得到一個正確的以零結尾的字符串。 –

+0

工作。沒有注意到內存沒有分配。如果你寫這個答案,我可以將其標記爲答案。現在它適用於我。接收部分也做了一些改動,以避免垃圾顯示。一些更多的變化我會做作爲清理代碼' 其他{ 一部分,如果(dwBytesRead) { 爲(計數= 0;計數 Rajesh

回答

0

讀取和寫入COM端口會互相阻塞,使得您的讀取在FIFO耗盡時幾乎總是超時。也可能有一些數據在FIFO中已經如此...如果您發送和接收的數據量過大,數據丟失更有可能以這種方式進行。非螺紋COM端口訪問

這裏小古例如

//--------------------------------------------------------------------------- 
//--- port class ver: 1.0 ------------------------------------------------ 
//--------------------------------------------------------------------------- 
#ifndef _port_h 
#define _port_h 
//--------------------------------------------------------------------------- 
class port 
     { 
public: HANDLE  hnd; 
     AnsiString error; 
     DWORD  rlen,wlen,err; 
     DCB   rs232_state; 
     COMMPROP  properties; 
     COMMTIMEOUTS timeouts; 
     COMSTAT  stat; 
     port(); 
     ~port(); 
     int open(AnsiString name); 
     void close(); 
     int get_stat();  // err,stat 
     int get_timeouts(); // timeouts 
     int set_timeouts(); 
     int get_properties(); // properties 
     int get_rs232_state(); // rs232_state 
     int set_rs232_state(); 
     void rst_rs232_state(); 
     void out(BYTE data) { WriteFile(hnd,&data,1,&wlen,NULL); } 
     void in (BYTE *data) { ReadFile (hnd, data,1,&rlen,NULL); } 
     void in (char *data) { ReadFile (hnd, data,1,&rlen,NULL); } 
     void out(BYTE *data,DWORD len) { WriteFile(hnd,data,len,&wlen,NULL); } 
     void in (BYTE *data,DWORD len) { ReadFile (hnd,data,len,&rlen,NULL); } 
     }; 
//--------------------------------------------------------------------------- 
port::port() 
     { 
     rlen=0; 
     wlen=0; 
     err =0; 
     error=""; 
     hnd=NULL; 
     rst_rs232_state(); 
     } 
//--------------------------------------------------------------------------- 
port::~port() 
     { 
     close(); 
     } 
//--------------------------------------------------------------------------- 
int port::open(AnsiString name) 
     { 
     close(); 
     rlen=0; 
     wlen=0; 
     hnd=CreateFile(name.c_str(),GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_ALWAYS,0,NULL); 
     if (hnd==NULL) return 0; 
     get_timeouts(); 
     get_properties(); 
     get_rs232_state(); 

     timeouts.ReadIntervalTimeout; 
     timeouts.ReadTotalTimeoutMultiplier; 
     timeouts.ReadTotalTimeoutConstant; 
     timeouts.WriteTotalTimeoutMultiplier; 
     timeouts.WriteTotalTimeoutConstant; 

     properties.wPacketLength; 
     properties.wPacketVersion; 
     properties.dwServiceMask; 
     properties.dwReserved1; 
     properties.dwMaxTxQueue; 
     properties.dwMaxRxQueue; 
     properties.dwMaxBaud; 
     properties.dwProvSubType; 
     properties.dwProvCapabilities; 
     properties.dwSettableParams; 
     properties.dwSettableBaud; 
     properties.wSettableData; 
     properties.wSettableStopParity; 
     properties.dwCurrentTxQueue; 
     properties.dwCurrentRxQueue; 
     properties.dwProvSpec1; 
     properties.dwProvSpec2; 
     properties.wcProvChar[1]; 

     return 1; 
     } 
//--------------------------------------------------------------------------- 
void port::close() 
     { 
     if (hnd==NULL) return; 
     CloseHandle(hnd); 
     hnd=NULL; 
     } 
//--------------------------------------------------------------------------- 
int port::get_stat() 
     { 
     if (ClearCommError(hnd,&err,&stat)) return 1; 
     error=GetLastError(); 
     return 0; 
     } 
//--------------------------------------------------------------------------- 
int port::get_timeouts() 
     { 
     if (GetCommTimeouts(hnd,&timeouts)) return 1; 
     error=GetLastError(); 
     get_stat(); 
     return 0; 
     } 
//--------------------------------------------------------------------------- 
int port::set_timeouts() 
     { 
     if (SetCommTimeouts(hnd,&timeouts)) return 1; 
     error=GetLastError(); 
     get_stat(); 
     return 0; 
     } 
//--------------------------------------------------------------------------- 
int port::get_properties() 
     { 
     if (GetCommProperties(hnd,&properties)) return 1; 
     error=GetLastError(); 
     get_stat(); 
     return 0; 
     } 
//--------------------------------------------------------------------------- 
int port::get_rs232_state() 
     { 
     if (GetCommState(hnd,&rs232_state)) return 1; 
     error=GetLastError(); 
     get_stat(); 
     return 0; 
     } 
//--------------------------------------------------------------------------- 
int port::set_rs232_state() 
     { 
     if (SetCommState(hnd,&rs232_state)) return 1; 
     error=GetLastError(); 
     get_stat(); 
     return 0; 
     } 
//--------------------------------------------------------------------------- 
void port::rst_rs232_state() 
     { 
     rs232_state.BaudRate = CBR_9600; 
     rs232_state.ByteSize = 8; 
     rs232_state.Parity  = NOPARITY; 
     rs232_state.StopBits = ONESTOPBIT; 
     rs232_state.fOutxCtsFlow= FALSE; 
     rs232_state.fOutxDsrFlow= FALSE; 
     rs232_state.fOutX  = FALSE; 
     rs232_state.fInX  = FALSE; 
     rs232_state.fBinary  = FALSE; 
     rs232_state.fRtsControl = RTS_CONTROL_DISABLE; 
     } 
//---------------------------------------------------------------------------//--------------------------------------------------------------------------- 
//---------------------------------------------------------------------------//--------------------------------------------------------------------------- 
//--------------------------------------------------------------------------- 
#endif 
//--------------------------------------------------------------------------- 

正是在C++/VCL所以才改寫AnsiStringchar*或你有,改變它的文件程序到你的任何字符串類型。如果您無法訪問課程,請重寫爲C。用法很簡單:

// globals and init 
port com; 
com.open("COM2"); 
com.timeouts.ReadIntervalTimeout  =10; 
com.timeouts.ReadTotalTimeoutMultiplier =10; 
com.timeouts.ReadTotalTimeoutConstant =10; 
com.timeouts.WriteTotalTimeoutMultiplier=10; 
com.timeouts.WriteTotalTimeoutConstant =10; 
com.set_timeouts(); 

// send/recv 
char q; 
com.out(`x`); // send x 
com.in (&q); // recv ... 

您應該使用線程來解決這個問題,因爲沒有線程阻塞通信。反正不爲環回你應該線程:

  1. 組中的兩個COM端口相同的協議
  2. 總是先發送,然後接收
  3. 設置足夠小超時(不阻塞太長)
  4. 出現數據丟失和超時(和處理這樣...不阻斷其發送)
  5. 僅發送BYTES不是所有的COM端口有沿途大的FIFO ...

更安全做閱讀內螺紋......像:

volatile bool _stop=false; // set this to true when you want to exit 
unsigned long __stdcall thread_com(LPVOID p) 
     { 
     char q; 
     for (;!_stop;) 
     { 
     com.in (&q); // recv ... 
     if (q<32) q=`.`; // data loss due to timeout if not sending `0..31` of coarse 
     Sleep(1); // just not to burn CPU ... 
     } 
     } 

HANDLE thread_com_hnd=CreateThread(0,0,thread_com,NULL,0,0); // do this only after COM port is initialized 
+0

我一直在尋找非常簡單的接收/發送C代碼,我不熟悉線程等。此代碼主要是爲了理解目的。無論如何,我會記住這一點,以防我進一步改變。 – Rajesh