VC++串口WriteFile()的问题

wyymay 2009-09-20 03:53:59
一个折磨我很久的问题,希望能得到大家的帮助。谢谢!
我用vc写了个串口发送数据的程序,但是程序运行到WriteFile()后就停止了,也没有返回值,后面的程序不再执行。但是当我把应用程序(调试生成的.exe)关闭后,另一台电脑的串口调试助手上会显示要发送的数据。这是什么原因引起的呢?为什么一定要关闭后数据才能发送出去呢?
WriteFile (hComm, //串口句柄
buf, //被写数据缓冲区
bufLen, //被写数据缓冲区大小
&dwNumBytesWritten, //函数执行成功后,返回实际向串口写的个数
NULL) ;
...全文
1947 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
Wang471981125 2010-11-27
  • 打赏
  • 举报
回复
summersdw1 2010-09-08
  • 打赏
  • 举报
回复

//Myserial.h
class CMySerial
{
public:
void Port_Close();
bool Port_Init();
CMySerial();
virtual ~CMySerial();

HANDLE CommHandle;
COMMPROP CommProps;
COMMTIMEOUTS commTimeOuts;
DCB CommDcb;
int m_nBaudRate;
int m_nPort;
bool m_bOpen;
char m_sLastError[128];
}




//Myserial.cpp
CMySerial::CMySerial()
{
this->m_bOpen = false;

}

CMySerial::~CMySerial()
{

}


bool CMySerial::Port_Init()
{

if (this->m_bOpen)
{
Port_Close();
}
CString port;
port.Format(_T("\\\\.\\COM%d"),this->m_nPort);
CommHandle = CreateFile(port,
GENERIC_READ | GENERIC_WRITE,
NULL, // don't share port
NULL, // SecurityAttributes - none in Win95
OPEN_EXISTING, // how to create
0, // file attributes
NULL // handle of file with attributes to copy
);
if (CommHandle != INVALID_HANDLE_VALUE)
{

CommProps.wPacketLength = sizeof(COMMPROP);
SetupComm (CommHandle,4096, 4096);
GetCommProperties (CommHandle, &CommProps);
GetCommState (CommHandle, &CommDcb);
this->CommDcb.DCBlength = sizeof(DCB);
CommDcb.BaudRate =this->m_nBaudRate;
CommDcb.ByteSize = 8;
CommDcb.fParity = FALSE;
CommDcb.StopBits = ONESTOPBIT;
CommDcb.fBinary = TRUE;
CommDcb.fOutxCtsFlow = FALSE;
CommDcb.fOutxDsrFlow = FALSE;
CommDcb.fDtrControl = DTR_CONTROL_ENABLE;
EscapeCommFunction(CommHandle, SETDTR);
CommDcb.fRtsControl = RTS_CONTROL_ENABLE;
EscapeCommFunction(CommHandle, SETRTS);
CommDcb.fDsrSensitivity = FALSE;
CommDcb.fTXContinueOnXoff = FALSE;
CommDcb.fOutX = FALSE;
CommDcb.fInX = FALSE;
CommDcb.fErrorChar = FALSE;
CommDcb.fNull = FALSE;
CommDcb.fAbortOnError = FALSE;
if (SetCommState (CommHandle, &CommDcb) == FALSE)
{
CloseHandle(CommHandle);
strcpy(this->m_sLastError,"Could not setup COMM port");
return false;
}
commTimeOuts.ReadIntervalTimeout = 0;
commTimeOuts.ReadTotalTimeoutMultiplier = 0;
commTimeOuts.ReadTotalTimeoutConstant = 500;//
commTimeOuts.WriteTotalTimeoutMultiplier = 0;
commTimeOuts.WriteTotalTimeoutConstant = 0;
if (SetCommTimeouts (CommHandle, &commTimeOuts) == FALSE)
{

strcpy(this->m_sLastError,"Could not set COMM timeouts");
return false;

}
PurgeComm (CommHandle, PURGE_TXCLEAR | PURGE_RXCLEAR);
}
else
{
strcpy(this->m_sLastError,"Open Comm Fail!");
return false;
}
m_bOpen = true;
return true;
}



void CMySerial::Port_Close()
{
if (this->m_bOpen==false)
return;
if (CommHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(this->CommHandle);
CommHandle = INVALID_HANDLE_VALUE;
this->m_bOpen = false;
}
}



paerxiushi 2010-09-07
  • 打赏
  • 举报
回复
你这个问题是因为在调用CreateFile时指定了同步模式的来收发数据,而那个串口调试助手程序是采用了异步模式的。同步通讯时,调用WriteFile的那个函数会处于等待状态,直到接受方接受完数据为止。建议你要么两个程序都采用同步,要么都采用异步。

当你用同步方式发数据给异步的程序来接受时,由于异步接受数据时,文件不会发出同步信号,因此发送端一直接受不到这个信号,等到异步的那一方退出程序,那么文件句柄关闭。同步发送的这一方才得到了信号。
当你用异步方式发数据给同步接受的程序时,永远不会成功。
xscansou 2010-09-06
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 vc1000 的回复:]
LZ应该以可重叠方式打开串口:
m_hCom=CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL); // 重叠方式
在读写串口时指定可重叠读写,否则就会像你说的WriteFile()没有执行完成之……
[/Quote]

为什么WriteFile最后一个不能指定为NULL?
wmswxpmyl 2010-09-05
  • 打赏
  • 举报
回复
可能你创建的串口是异步形式:
这样的话writefile函数回立刻返回,此时可能你的数据还没有发完!所以会返回0值!
liweisdut 2010-08-28
  • 打赏
  • 举报
回复
异步收发,重叠IO
hscbd 2010-08-27
  • 打赏
  • 举报
回复
发送部分所使用内存一直增加
GoldWood 2010-05-14
  • 打赏
  • 举报
回复
http://download.csdn.net/source/2352400
下载看看,也许有帮助
liutzh_2008 2010-04-16
  • 打赏
  • 举报
回复
不要用同步方式,同步时在等待你的响应断的回执呢。
vc1000 2010-04-13
  • 打赏
  • 举报
回复
LZ应该以可重叠方式打开串口:
m_hCom=CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL); // 重叠方式
在读写串口时指定可重叠读写,否则就会像你说的WriteFile()没有执行完成之前是不会返回的,即阻塞了。
BOOL WriteFile(
HANDLE hFile, // handle to file
LPCVOID lpBuffer, // data buffer
DWORD nNumberOfBytesToWrite, // number of bytes to write
LPDWORD lpNumberOfBytesWritten, // number of bytes written
LPOVERLAPPED lpOverlapped // overlapped buffer
);
lpOverlapped-----不要指定为NULL
draenors 2010-04-13
  • 打赏
  • 举报
回复
和你们一样的问题 - -!
怎么没答案呢?
wyymay 2009-09-21
  • 打赏
  • 举报
回复
先谢谢各位,下面是我的部分代码,贴出来
这是打开串口部分:
BOOL CCESeries::OpenPort(CWnd* pPortOwner, UINT portNo ,UINT baud, UINT parity ,UINT databits , UINT stopbits )
{
DCB commParam;
TCHAR szPort[15];
// 已经打开的话,直接返回
if (m_hComm != INVALID_HANDLE_VALUE)
{
return TRUE;
}
ASSERT(pPortOwner != NULL);
ASSERT(portNo > 0 && portNo < 5);
//设置串口名
wsprintf(szPort, L"COM%d:", portNo);
//打开串口
m_hComm = CreateFile(
szPort,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
NULL
);
if (m_hComm == INVALID_HANDLE_VALUE)
{
TRACE(_T("CreateFile 返回无效句柄"));
return FALSE;
}
if (!GetCommState(m_hComm,&commParam))
{
return FALSE;
}

commParam.BaudRate = baud;
commParam.fBinary = TRUE;
commParam.fParity = TRUE;
commParam.ByteSize = databits;
commParam.Parity = NOPARITY;
commParam.StopBits = stopbits;
commParam.fOutxCtsFlow = FALSE; commParam.fOutxDsrFlow = FALSE; commParam.fDtrControl = DTR_CONTROL_ENABLE;
commParam.fDsrSensitivity = FALSE;
commParam.fTXContinueOnXoff = TRUE;
commParam.fOutX = FALSE; commParam.fInX = FALSE; commParam.fErrorChar = FALSE; commParam.fNull = FALSE; commParam.fRtsControl = RTS_CONTROL_ENABLE;
commParam.fAbortOnError = FALSE; // 当串口发生错误,并不终止串口读写

if (!SetCommState(m_hComm, &commParam))
{
TRACE(_T("SetCommState error"));
return FALSE;
}


//设置串口读写时间
COMMTIMEOUTS CommTimeOuts;
GetCommTimeouts (m_hComm, &CommTimeOuts);
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 10;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;

if(!SetCommTimeouts( m_hComm, &CommTimeOuts ))
{
TRACE( _T("SetCommTimeouts 返回错误") );
return FALSE;
}

m_pPortOwner = pPortOwner;

//指定端口监测的事件集
SetCommMask (m_hComm, EV_RXCHAR);

//分配设备缓冲区
SetupComm(m_hComm,512,512);

//初始化缓冲区中的信息
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);

m_hReadCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
m_hWriteCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
//创建读串口线程
m_hReadThread = CreateThread(NULL,0,ReadThreadFunc,this,0,&m_dwReadThreadID);
//创建写串口线程
m_hWriteThread = CreateThread(NULL,0,WriteThreadFunc,this,0,&m_dwWriteThreadID);

TRACE(_T("串口打开成功"));

return TRUE;
}
这是写串口部分:
//串口写线程函数
DWORD CCESeries::WriteThreadFunc(LPVOID lparam)
{
CCESeries *ceSeries = (CCESeries*)lparam;
MSG msg;
DWORD dwWriteLen = 0;
BYTE * buf = NULL;

while (TRUE)
{
//如果捕捉到线程消息
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.hwnd != 0 )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
if (msg.message == CM_THREADCOMMWRITE)
{
//向串口写
buf = (BYTE*)msg.lParam;
dwWriteLen = msg.wParam;
//向串口写

WritePort(ceSeries->m_hComm,buf,dwWriteLen);

//删除动态分配的内存
delete[] buf;
}
}
//如果收到写线程退出信号,则退出线程
if (WaitForSingleObject(ceSeries->m_hWriteCloseEvent,500) == WAIT_OBJECT_0)
{
break;
}
ceSeries->m_hWriteThread = NULL;
}

return 0;
}


//私用方法,用于向串口写数据,被写线程调用,定义CCESeries m_ceSeries;
BOOL CCESeries::WritePort(HANDLE hComm,const BYTE *buf,DWORD bufLen)
{
DWORD dwNumBytesWritten;
DWORD dwHaveNumWritten =0 ; //已经写入多少;
ASSERT(hComm != INVALID_HANDLE_VALUE);
bool writefile=WriteFile (hComm,
buf+dwHaveNumWritten, //被写数据缓冲区
bufLen-dwHaveNumWritten, //被写数据缓冲区大小
&dwNumBytesWritten, //函数执行成功后,返回实际向串口写的个数 NULL) ; //此处设置NUL
do
{
if(writefile!=0)
{
dwHaveNumWritten = dwHaveNumWritten + dwNumBytesWritten;
//写入完成
if (dwHaveNumWritten == bufLen)
{
break;
}

Sleep(10);
}
else
{
return FALSE;
}
} while (TRUE);

return TRUE;
}
BOOL CCESeries::WritePort(const BYTE *buf,DWORD bufLen)
{
//将要发送的数据传递到写线程消息队列
if (PostThreadMessage(m_dwWriteThreadID,CM_THREADCOMMWRITE,
WPARAM(bufLen), LPARAM(buf)))
{
return TRUE;
}
return FALSE;
}

事件触发:
void CSeriesSampleDlg::OnBtnsend()
{
UpdateData(TRUE);
BYTE * buf;
int bufLen = m_strSend.GetLength()*2;
buf = new BYTE(bufLen);
CopyMemory(buf,m_strSend.GetBuffer(m_strSend.GetLength()),bufLen);
if (!m_ceSeries.WritePort(buf,bufLen))
{
AfxMessageBox(L"写入失败");
}
}


gotooker 2009-09-21
  • 打赏
  • 举报
回复
怎么可能呢,不太相信
April的Orange 2009-09-21
  • 打赏
  • 举报
回复
VC++串口WriteFile()的问题我也遇到过,和楼主的描述一样,也是执行WriteFile()后就停止了,不过我没注意关闭之后是否发送数据了。
不过这个问题出现的几率很低,貌似是我第一次运行程序的时候才会出现。我用串口调试助手3.0把我程序使用到的串口(比如COM1)打开,然后再关闭,以后运行程序都不会出现WriteFile()阻塞的问题了。
我的串口代码很少,只用到以下一些部分:(省略无关部分)
hCom = CreateFile(strCom, GENERIC_READ | GENERIC_WRITE, 0, NULL , OPEN_EXISTING, 0, NULL); //strCom是串口值,比如"COM1"..
SetupComm(hCom, BUFF_LEN, BUFF_LEN); //BUFF_LEN = 1024
DCB wdcb;
GetCommState (hCom, &wdcb);
// wdcb.BaudRate = 9600;
SetCommState (hCom, &wdcb);
PurgeComm(hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );

以上是打开代码,之后我是直接使用WriteFile()函数操作,结果如楼主描述。
至今不知道是怎么回事。。。
高人可以帮忙看看~
wyymay 2009-09-21
  • 打赏
  • 举报
回复
谢谢schlafenhamster。不过我的另外一些参数设置的都是False,应该没有什么影响吧。
schlafenhamster 2009-09-21
  • 打赏
  • 举报
回复
commParam.fDtrControl = DTR_CONTROL_ENABLE;
commParam.fRtsControl = RTS_CONTROL_ENABLE;
// 三线协议不要这些(这是7线,全协议),只要Tx,Rx,地
// 或者RCS短接CTS,DSR短接DTR
一条晚起的虫 2009-09-20
  • 打赏
  • 举报
回复
//串口打开部分没有问题。
//串口初始化的代码?
//或者多贴一些代码吧。
schlafenhamster 2009-09-20
  • 打赏
  • 举报
回复
串口初始化时有没有流控制?
wyymay 2009-09-20
  • 打赏
  • 举报
回复
试过了还是不行。程序关闭后数据才发送过去,可能是什么原因造成的呢?我还试出来一个问题,就是发送数据和读取数据同时进行时,对方会显示我发送的数据,但程序会报错终止。
feilinhe 2009-09-20
  • 打赏
  • 举报
回复
倒数第二个参数使用FILE_ATTRIBUTE_NORMAL
加载更多回复(2)

2,640

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 硬件/系统
社区管理员
  • 硬件/系统社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧