第一次用串口通信做一个小软件,该软件的用途就是给卡里面写一些数据。我现在所用的到设备是一个读卡器和一张卡。软件在和卡进行交互时,需要得到卡的一些返回数据,表明这次是否通信成功。例如:软件通过串口给读卡器发送:FF A1 20 04,经过延时之后(由于读卡器给卡写数据相对来讲比较慢),软件收到FF A1时表明通信成功,否则通信失败。根据对读卡器的描述,写一个字节需要25ms。那么如果我发送4个字节,需要延时25*4ms就够了。所以在程序中,我用Sleep(100)进行延时。但问题是:
在写数据的时候,我做了这样的延时,为什么还是收不到数据呢?在发数据之前加上一个较大的延时才能收到。可在发送数据之前我什么都没有做啊?并且根据说明仅需要在写数据之后做延时就行。例子代码:
1、现在情况BOOL CProcess::mf_CheckOutCardPsw(unsigned char *t_key)
{
unsigned char key[5] = {0};
unsigned char t_recv[2] = {0};
key[0] = 0xFF;
key[1] = 0xA3;
memcpy(key+2,t_key,3);
Sleep(1000);
g_serialcomm.SendData(key,5);
Sleep(200);
g_serialcomm.ReciveData(t_recv,2);
Sleep(200);
if ((t_recv[0] != 0xff) || (t_recv[1] != 0xa3))
{
return FALSE;
}
return TRUE;
}2、正常情况:BOOL CProcess::mf_CheckOutCardPsw(unsigned char *t_key)
{
unsigned char key[5] = {0};
unsigned char t_recv[2] = {0};
key[0] = 0xFF;
key[1] = 0xA3;
memcpy(key+2,t_key,3);
g_serialcomm.SendData(key,5);
Sleep(200);
g_serialcomm.ReciveData(t_recv,2);
if ((t_recv[0] != 0xff) || (t_recv[1] != 0xa3))
{
return FALSE;
}
return TRUE;
}PS:有关串口的三个函数,打开、发送、接收,大家看看有什么问题吗?
//打开串口
BOOL CSerialComm::Open()
{
if(m_bOpened)
{
return TRUE;
}

DCB dcb;
//创建端口句柄
m_hComDev = CreateFile((LPCTSTR)serialport, GENERIC_READ | GENERIC_WRITE,
0, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL ); if( m_hComDev == INVALID_HANDLE_VALUE )
{
return FALSE;
}

memset(&m_OverlappedRead, 0, sizeof( OVERLAPPED));
memset(&m_OverlappedWrite, 0, sizeof( OVERLAPPED));
COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0; CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 5000;
SetCommTimeouts(m_hComDev,&CommTimeOuts); m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); dcb.DCBlength = sizeof( DCB );
GetCommState(m_hComDev, &dcb );
dcb.BaudRate = atoi(byterate); //波特率
dcb.ByteSize = atoi(datebit);  //数据位
dcb.Parity = atoi(checkbit);   //校验位
dcb.StopBits = atoi(stopbit);  //停止位
SetupComm(m_hComDev, atoi(buffersize), atoi(buffersize));//设置输入输出缓冲区大小 if( !SetCommState( m_hComDev, &dcb ) ||
!SetupComm( m_hComDev, 10000, 10000 ) ||
m_OverlappedRead.hEvent == NULL ||
m_OverlappedWrite.hEvent == NULL )
{
DWORD dwError = GetLastError();
if( m_OverlappedRead.hEvent != NULL ) 
{
CloseHandle( m_OverlappedRead.hEvent );
}
if( m_OverlappedWrite.hEvent != NULL )
{
CloseHandle( m_OverlappedWrite.hEvent );
}
CloseHandle( m_hComDev );
return FALSE;
}
m_bOpened = TRUE;
return m_bOpened;
}//接受串口信息
DWORD CSerialComm::ReciveData(void *buffer, DWORD dwBytesRead)
{
if( !m_bOpened || m_hComDev == NULL ) 
{
return 0;
} BOOL bReadStatus;
DWORD dwErrorFlags;
COMSTAT ComStat;

ClearCommError( m_hComDev, &dwErrorFlags, &ComStat );
if(!ComStat.cbInQue)
{
return 0;
}
dwBytesRead = min(dwBytesRead,(DWORD) ComStat.cbInQue);
bReadStatus = ReadFile(m_hComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead);
if(!bReadStatus)
{
if( GetLastError() == ERROR_IO_PENDING )
{
WaitForSingleObject( m_OverlappedRead.hEvent, 2000 );
return dwBytesRead;
}
return 0;
}
return dwBytesRead;
}//发送串口信息
DWORD CSerialComm::SendData(const unsigned char *buffer, DWORD dwBytesWritten)
{
if( !m_bOpened || m_hComDev == NULL )
{
return 0;
}

BOOL bWriteStat;

bWriteStat = WriteFile(m_hComDev, buffer, dwBytesWritten, &dwBytesWritten, &m_OverlappedWrite);
if(!bWriteStat)
{
if ( GetLastError() == ERROR_IO_PENDING ) 
{
WaitForSingleObject( m_OverlappedWrite.hEvent, 1000 );
return dwBytesWritten;
}
return 0;
}
return dwBytesWritten;
}
还有疑问就是:
1、关于串口通信同步异步有什么区别?对于我现在这个软件的需求有什么不同吗?
2、Sleep函数是将该函数挂起,对读写串口有什么影响?
3、串口读写一定要分开吗?即做成两个线程。
4、串口通信编程需要注意什么?
5、COMMTIMEOUTS结构在串口通讯有什么作用或者说影响?串口通信软件C通信

解决方案 »

  1.   

    是   你接收是采用事件触发,就不需要延时,直接等返回数据再发送下一帧数据。如果是查询还真得延时(这时程序就会什么都不能干,只能等待)。
        所以既然你采用事件方式,只需来数据接收就接收就行了。你也完全可以建立一个接收程,也不用等什么事件了,直接就是读数据,
        COMMTIMEOUTS是影响发送和接收数据的,就是超时设置,如果在规定时间没有发送成功/接收成功或在规定时间没有发完所有数据/接收完所有数据,就会中止发送/接收数据
        发送不需要建立线程,接收最好建立一个线程,因为不知道数据何时到,这样就不需延时影响其它操作
      

  2.   

    “FILE_FLAG_OVERLAPPED”
    重叠 I/O 还要用 Sleep ?
      

  3.   

    请 使用 “EV_RXCHAR”异步 接受 要等 EV_RXCHAR 事件!
    不是 靠 Sleep 的
      

  4.   

    用线程也关系,收到数据后就发命令,主线程收到命令后就接着干。你可以用MSCOMM这个控件,这个简单些,在接收函数里发送命令就可以接着下一步的操作了
      

  5.   

    嗯,我一直怀疑是Sleep的问题,可是我不是很懂,你说的那个代码是什么样的?能给出参考吗?谢谢你!
      

  6.   

    在接受和发送的时候,添加SetCommMask(m_hComDev,EV_RXCHAR),然后在程序中一下代码即可,示例代码: DWORD Event = 0;
    if (WaitCommEvent(g_serialcomm.m_hComDev,&Event,NULL))
    {
    g_serialcomm.ReciveData(reseivedata,sizeof(reseivedata));
    }这样对吗?
    难道还是 : while(1)
    {
    if (WaitCommEvent(g_serialcomm.m_hComDev,&Event,NULL))
    {
    g_serialcomm.ReciveData(reseivedata,sizeof(reseivedata));
    break;
    }
    }
      

  7.   

    首先串口什么时候有确认数据应该是由你的设备决定的:就是说设备200ms才返回数据,你sleep(100)肯定得不到数据。
    关于读写需要注意你的设备是不是一读一写的也就是写了后才能给你反馈;假如这样的话就没有必要多线程,一个线程搞定
    建议楼主可以做一个循环 获取完成以后推出循环;