请给讲一下TDCB、TCOMSTAT什么意思?怎么用? (100分)

  • 主题发起人 主题发起人 w_yt1977
  • 开始时间 开始时间
W

w_yt1977

Unregistered / Unconfirmed
GUEST, unregistred user!
请给讲一下TDCB、TCOMSTAT什么意思?怎么用?
 
在win32api的帮助里查DCB、COMSTAT
 
To:Pipi<br>&nbsp; 哪里有win32api。<br>&nbsp; 请告知下载地址。<br>&nbsp; 如你有,可寄我一份:wyt_1977@21cn.com<br>&nbsp; 谢谢!<br>
 
开始菜单/delphi5/help/ms sdk help files/win32 sdk reference
 
To Pipi:<br><br>&nbsp; 你可以去看以上贴子:<br>&nbsp; http://www.delphibbs.com/delphibbs/dispq.asp?lid=959701<br>&nbsp; 想做一个如:KILL杀毒软件中带选择功能的目录树<br>&nbsp; http://www.delphibbs.com/delphibbs/dispq.asp?lid=959704<br>&nbsp; 把其所对应的字体大小列表加入到ComboBox2的Items,如何实现 <br>&nbsp; http://www.delphibbs.com/delphibbs/dispq.asp?lid=996117<br>&nbsp; 请给讲一下TDCB、TCOMSTAT什么意思?怎么用? <br>&nbsp; 其中http://www.delphibbs.com/delphibbs/dispq.asp?lid=996117<br>&nbsp; 你去了就给分,不过请你给讲一下各分类主题是如何分类的。要不然我提出的问题没人理!<br>
 
DCB、COMSTAT这两个结构都是应用于串口通讯的,看看下面的代码吧,非常好,非常完整!<br><br>//串口控制类,基本用WINAPI实现,可以不用做修改的用在BCB程序中<br>//读数据采用事件驱动方式,用一个线程处理相应事件,收到的字符用消息发往父窗口<br>//由于我编的软件中写串口的数据不多,所以采用直接写的方式<br>//以下代码在BCB5/Win98下编译通过,在Win95/Win98/Win2000下运行良好<br><br>//---------------------------------------------------------------------------<br>头文件Com.h<br>//---------------------------------------------------------------------------<br>//定义串口控制类<br>#ifndef ComH<br>#define ComH<br>//---------------------------------------------------------------------------<br>#define WM_COMM_RXCHAR WM_USER+1 //自定义消息:串口接收到一个字符<br>//---------------------------------------------------------------------------<br>class TSerialPort<br>{<br>public:<br>TSerialPort(); //构造函数<br>~TSerialPort(); //析构函数<br>//串口初始化,缺省参数为:COM1,19200Baud,无奇偶校验,8数据为,1停止位,监控读写事件<br>bool InitPort(TForm* pPortOwner,unsigned uPortNo=1,unsigned uBaud=19200,<br>char cParity='N',unsigned uDataBits=8,unsigned uStopBits=1,<br>DWORD dwCommEvents=EV_RXCHAR);<br>bool StartMonitoring(); //启动串口监控线程<br>int RestartMonitoring(); //恢复串口监控线程<br>int StopMonitoring(); //挂起口监控线程<br>void __fastcall WriteToPort(unsigned char ucTxData); //向串口写一个字符<br>private:<br>void __fastcall Clear(); &nbsp; //清除占用的资源<br>void __fastcall ProcessErrorMessage(char* ErrorText); //处理出错信息<br>static DWORD WINAPI CommThread(LPVOID lpvParam); //串口线程的实现函数<br>static void __fastcall ReceiveChar(TSerialPort* Port); //接收一个字符<br>bool WriteChar(unsigned char ucChar); //向串口写一个字符<br><br>HANDLE m_hComm; &nbsp; &nbsp; &nbsp;//串口句柄<br>HANDLE m_hThread; &nbsp; &nbsp;//串口操作线程<br>HANDLE m_hShutdownEvent; //关闭串口事件句柄<br>//事件数组,每个元素代表一个事件,每个串口线程监控两个事件,<br>//即读和关闭串口事件,读事件即重叠结果中的hEvent事件<br>HANDLE m_hEventArray[2];<br>OVERLAPPED m_OverLapped; &nbsp;//重叠结果<br>COMMTIMEOUTS m_CommTimeouts; //超时参数<br>DCB m_DCB; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //串口设备控制块<br>DWORD m_dwCommEvents; //串口要监控的事件<br>TForm* m_pOwner; //父窗口句柄<br>unsigned m_uPortNo; //串口号<br>bool m_bThreadAlive; //串口线程存在标志<br>};<br>//---------------------------------------------------------------------------<br>#endif<br>//---------------------------------------------------------------------------<br>//---------------------------------------------------------------------------<br><br><br>实现代码Com.cpp<br>//---------------------------------------------------------------------------<br>//---------------------------------------------------------------------------<br>#include &lt;vcl.h&gt;<br>#pragma hdrstop<br><br>#include "stdio.h"<br><br>#include "Com.h"<br>#include "Macro.h" //我自定义的一些宏,简化对MessageBox的调用<br>//---------------------------------------------------------------------------<br>//构造函数,初始化,把各数据成员置0<br>TSerialPort::TSerialPort()<br>{<br>m_hComm =INVALID_HANDLE_VALUE;<br>m_hThread=NULL;<br>m_hShutdownEvent = NULL;<br>m_OverLapped.hEvent = NULL;<br>m_OverLapped.Offset = 0;<br>m_OverLapped.OffsetHigh = 0;<br>m_hEventArray[0]=NULL;<br>m_hEventArray[1]=NULL;<br>m_bThreadAlive = false;<br>m_pOwner=NULL;<br>m_uPortNo=1;<br>}<br>//----------------------------------------------------------------------<br>//析构函数<br>TSerialPort::~TSerialPort()<br>{<br>Clear(); //清除资源<br>}<br>//----------------------------------------------------------------------<br>//释放资源<br>void __fastcall TSerialPort::Clear()<br>{<br>if(m_hThread!=NULL)<br>{<br>//检查串口线程是否被挂起,如果是则恢复它<br>int iSuspendCount=ResumeThread(m_hThread);<br>while(iSuspendCount&gt;1)<br>iSuspendCount=ResumeThread(m_hThread);<br><br>int OldTime,NewTime; //用于判断超时<br>OldTime=GetTickCount(); //从WINDOWS启动到当前的毫秒值<br>//终止串口监控线程<br>while (m_bThreadAlive) //串口线程仍存在<br>{<br>NewTime=GetTickCount();<br>if((NewTime-OldTime)&gt;3000) &nbsp; //超时(3妙)强制终止串口线程<br>{<br>TerminateThread(m_hThread,200);<br>mErrorMsg("串口线程异常终止!");<br>break;<br>}<br>SetEvent(m_hShutdownEvent); //设置关闭串口事件<br>SetEvent(m_OverLapped.hEvent);<br>}<br>m_bThreadAlive=false;<br>CloseHandle(m_hThread);<br>m_hThread=NULL;<br>}<br><br>//释放对象,如果句柄有效,则关闭<br>if (m_hComm!=INVALID_HANDLE_VALUE)<br>{<br>CloseHandle(m_hComm);<br>m_hComm=INVALID_HANDLE_VALUE;<br>}<br>if(m_hShutdownEvent!=NULL)<br>{<br>CloseHandle(m_hShutdownEvent);<br>m_hShutdownEvent=NULL;<br>}<br>if(m_OverLapped.hEvent!=NULL)<br>{<br>CloseHandle(m_OverLapped.hEvent);<br>m_OverLapped.hEvent=NULL;<br>}<br>}<br>//----------------------------------------------------------------------<br>//串口初始化,可用于串口1到4,参数意义如下:<br>//pPortOwner-父窗口,uPortNo-串口号,uBaud-波特率,cParity-奇偶校验,uDatabits-数据位数,<br>//uStopbits-停止位数,dwCommEvents-需要监控的串口事件<br>bool TSerialPort::InitPort(TForm* pPortOwner,unsigned uPortNo,unsigned uBaud,<br>char cParity,unsigned uDataBits,unsigned uStopBits,DWORD dwCommEvents)<br>{<br>char sTemp[100];<br>if(uPortNo&lt;1||uPortNo&gt;4)<br>{<br>sprintf(sTemp,"无法打开串口COM%d,串口号只能是COM1、COM2、COM3或COM4中的一个.",<br>uPortNo);<br>mErrorMsg(sTemp);<br>return false;<br>}<br>if(pPortOwner==NULL)<br>{<br>mErrorMsg("串口的父窗口无效,串口监控线程无法正常工作.");<br>return false;<br>}<br><br>Clear(); //清除没有被释放的资源<br><br>//创建新对象<br>m_OverLapped.hEvent = CreateEvent(NULL, //安全属性<br>true, &nbsp; &nbsp;//手工复位<br>false, &nbsp; //初始为无事件状态<br>NULL); //事件名称<br>m_hShutdownEvent=CreateEvent(NULL, true, false, NULL);<br>//初始化事件数组<br>m_hEventArray[0] = m_hShutdownEvent; //关闭串口事件,优先级最高<br>m_hEventArray[1] = m_OverLapped.hEvent; //重叠结果中的事件<br><br>m_pOwner = pPortOwner; &nbsp; //父窗口,即控制串口的对象<br>m_uPortNo =uPortNo; //指定串口号<br>m_dwCommEvents = dwCommEvents; //串口要监控的事件<br><br>sprintf(sTemp,"COM%d",uPortNo); //合成串口号字符串<br>//打开串口,获取串口句柄<br>m_hComm = CreateFile(sTemp, //串口号<br>GENERIC_READ|GENERIC_WRITE,//读写方式<br>0, &nbsp; &nbsp; &nbsp; &nbsp;//通讯设备必须以独占方式打开<br>NULL, &nbsp; &nbsp; &nbsp; &nbsp; //无安全属性<br>OPEN_EXISTING, &nbsp; &nbsp; &nbsp; &nbsp;//通讯设备已存在<br>FILE_FLAG_OVERLAPPED, &nbsp;//异步I/O<br>0); &nbsp; &nbsp; &nbsp; &nbsp; //通讯设备不能用模板打开<br><br>if (m_hComm==INVALID_HANDLE_VALUE) &nbsp; &nbsp;//句柄无效,打开串口失败<br>return false;<br><br>//设置超时参数,总时间=Multiplier*字符数+Constant<br>//Interval为读入的字符串中任意两个字符间的最大间隔<br>m_CommTimeouts.ReadIntervalTimeout=1000;<br>m_CommTimeouts.ReadTotalTimeoutMultiplier=1000;<br>m_CommTimeouts.ReadTotalTimeoutConstant=1000;<br>m_CommTimeouts.WriteTotalTimeoutMultiplier=1000;<br>m_CommTimeouts.WriteTotalTimeoutConstant=1000;<br><br>sprintf(sTemp,"baud=%d parity=%c data=%d stop=%d",uBaud,<br>cParity,uDataBits,uStopBits); //合成串口参数字符串<br>//配置串口<br>if (SetCommTimeouts(m_hComm,&amp;m_CommTimeouts)) //超时参数<br>{<br>if (SetCommMask(m_hComm,m_dwCommEvents)) //需要监控的事件<br>{<br>if (GetCommState(m_hComm,&amp;m_DCB)) //获取原始DCB<br>{<br>//设置串口设备控制块(DCB)<br>m_DCB.fRtsControl=RTS_CONTROL_ENABLE;<br>if (BuildCommDCB(sTemp,&amp;m_DCB))<br>{<br>if (!SetCommState(m_hComm,&amp;m_DCB))<br>ProcessErrorMessage("设置串口");<br>}<br>else<br>ProcessErrorMessage("建立串口设备控制块");<br>}<br>else<br>&nbsp; &nbsp; ProcessErrorMessage("获取串口状态");<br>}<br>else<br>ProcessErrorMessage("设置串口事件掩码");<br>}<br>else<br>ProcessErrorMessage("串口超时参数设置");<br><br>//清空串口缓冲区,退出所有相关操作<br>PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);<br>return true;<br>}<br>//----------------------------------------------------------------------<br>//启动串口监控线程<br>bool TSerialPort::StartMonitoring()<br>{<br>DWORD dwThreadId;<br>//创建线程<br>m_hThread=CreateThread( NULL, //无安全属性<br>0, //用主线程的堆栈<br>CommThread, &nbsp;//线程的执行函数<br>this, &nbsp; &nbsp; &nbsp; &nbsp;//传给线程执行函数的参数<br>0, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //初始为激活状态<br>&amp;dwThreadId); &nbsp; //线程标识<br>if(m_hThread==NULL) //无法创建线程<br>{<br>ProcessErrorMessage("创建线程");<br>return false;<br>}<br>return true;<br>}<br>//----------------------------------------------------------------------<br>//挂起线程,返回以前的挂起记数<br>int TSerialPort::StopMonitoring()<br>{<br>return(SuspendThread(m_hThread));<br>}<br>//----------------------------------------------------------------------<br>//重新启动线程,返回以前的挂起记数<br>int TSerialPort::RestartMonitoring()<br>{<br>return(ResumeThread(m_hThread));<br>}<br>//----------------------------------------------------------------------<br>//串口事件处理线程<br>DWORD WINAPI TSerialPort::CommThread(LPVOID lpvParam)<br>{<br>//将void型的pParam转化为TSerialPort类型的指针<br>TSerialPort *Port = (TSerialPort*)lpvParam;<br>Port-&gt;m_bThreadAlive=true; //标志串口线程处于活动态<br><br>DWORD Event=0;<br>DWORD CommEvent=0;<br>DWORD dwError=0;<br>COMSTAT ComStat; &nbsp; &nbsp; &nbsp; &nbsp;//串口状态<br>bool bResult;<br><br>if(Port-&gt;m_hComm==INVALID_HANDLE_VALUE) &nbsp;//串口句柄有效<br>{<br>mErrorMsg("串口句柄无效,串口监控线程无法工作.");<br>Port-&gt;m_bThreadAlive=false;<br>ExitThread(0);<br>}<br>PurgeComm(Port-&gt;m_hComm, PURGE_RXCLEAR|PURGE_TXCLEAR|<br>PURGE_RXABORT|PURGE_TXABORT);<br><br>//进入无限循环,直到关闭串口事件变为有信号.<br>while(1)<br>{<br>//调用WaitCommEvent().这一调用将立即返回,因为我用异步方式<br>//(FILE_FLAG_OVERLAPPED)打开串口,并且指定重叠操作结构,<br>//如果有一个字符到达串口,重叠结构中的事件将被置为有信号态<br>bResult=WaitCommEvent(Port-&gt;m_hComm,&amp;Event,&amp;Port-&gt;m_OverLapped);<br>if (!bResult)<br>{<br>//如果WaitCommEvent()返回FALSE,调用GetLastError()判断原因<br>switch (dwError=GetLastError())<br>{<br>case ERROR_IO_PENDING: &nbsp; &nbsp; &nbsp;//重叠操作正在后台进行<br>{<br>//如果串口这时无字符,这是正常返回值,继续<br>break;<br>}<br>case 87:<br>{<br>//在WIN NT下这是一个可能结果,但我没有找到<br>//它出现的原因,我什么也不做,继续<br>break;<br>}<br>default:<br>{<br>//所有其它错误代码均显示串口出错,显示出错信息<br>Port-&gt;ProcessErrorMessage("等待串口事件");<br>Port-&gt;m_bThreadAlive=false;<br>ExitThread(0);<br>}<br>}<br>}<br>else<br>{<br>//如果WaitCommEvent()返回true,检查输入缓冲区是否确实<br>//有字节可读,若没有,则继续下一循环<br>//ClearCommError()将更新串口状态结构并清除所有串口硬件错误<br>ClearCommError(Port-&gt;m_hComm,&amp;dwError,&amp;ComStat);<br>if (ComStat.cbInQue==0) &nbsp; //输入缓冲队列长为0,无字符<br>continue;<br>}<br><br>//以下为主等待函数,线程将被阻塞直到m_hEventArray中指定的某一<br>//事件产生时函数返回,返回值为这一事件的序号<br>Event=WaitForMultipleObjects(2, //等待的事件的个数<br>Port-&gt;m_hEventArray, //事件数组<br>false, &nbsp; //任一事件产生时返回<br>4000); &nbsp; //等待4秒<br>//判断使等待终止的事件<br>switch (Event)<br>{<br>case 0: //关闭串口事件,优先处理<br>{<br>Port-&gt;m_bThreadAlive = false; //串口活动标志<br>ExitThread(100); &nbsp; &nbsp; &nbsp; &nbsp;//退出线程<br>}<br>case 1: //读串口事件<br>{<br>//获取串口事件掩码<br>GetCommMask(Port-&gt;m_hComm,&amp;CommEvent);<br>if (CommEvent &amp; EV_RXCHAR) //收到一个字符<br>&nbsp; &nbsp; ReceiveChar(Port);//读入一个字符<br>break;<br>}<br>}<br>}<br>}<br>//----------------------------------------------------------------------<br>//接收一个字符<br>void __fastcall TSerialPort::ReceiveChar(TSerialPort* Port)<br>{<br>COMSTAT ComStat;<br>DWORD dwError=0;<br>bool bRead=true;<br>bool bResult;<br>DWORD BytesRead=0;<br>unsigned char ucRxBuff;<br><br>//开始无限循环,因为我不知到需要循环多少次.我的解决方法是开始一个无限循环,<br>//当我已处理了所有的有效数据后才退出.使用这种方法应小心的保证您的程序能<br>//正常退出循环.即便如此,我仍觉得这是最有效的解决办法<br>while(1)<br>{<br>//ClearCommError()将更新串口状态结构并清除所有串口硬件错误<br>ClearCommError(Port-&gt;m_hComm,&amp;dwError,&amp;ComStat);<br>if (ComStat.cbInQue==0)<br>{<br>//缓冲区中已无数据,退出循环<br>break;<br>}<br>//读串口<br>bResult=ReadFile(Port-&gt;m_hComm, //串口句柄<br>&amp;ucRxBuff, &nbsp;//输入缓冲区地址<br>1, //想读入的字符数<br>&amp;BytesRead, &nbsp;//实际被读入的字符数<br>&amp;Port-&gt;m_OverLapped); //重叠结构指针<br>//读串口失败,调用GetLastError()判断原因<br>if(!bResult)<br>{<br>switch (dwError=GetLastError())<br>{<br>case ERROR_IO_PENDING: //重叠操作在后台进行<br>{<br>bRead=false;<br>BytesRead=0;<br>break;<br>}<br>default:<br>{<br>//其它情况说明出错<br>Port-&gt;ProcessErrorMessage("读串口");<br>return;<br>}<br>}<br>}<br>if (!bRead) //没有读到字符<br>{<br>//等待重叠操作结果<br>bResult=GetOverlappedResult(Port-&gt;m_hComm, //串口句柄<br>&amp;Port-&gt;m_OverLapped, &nbsp;//重叠结构<br>&amp;BytesRead, &nbsp;//实际读入字符数<br>true); &nbsp;//等待直到串口操作超时<br>if (!bResult) //重叠操作失败<br>{<br>Port-&gt;ProcessErrorMessage("(读串口时)获取重叠操作结果");<br>return;<br>}<br>bRead = true;<br>}<br>//将收到的字符当作消息的参数投递到父窗口<br>if(BytesRead!=1) //没有读入要求的字符数<br>continue;<br>PostMessage((Port-&gt;m_pOwner)-&gt;Handle,WM_COMM_RXCHAR,<br>(WPARAM)ucRxBuff,(LPARAM)Port-&gt;m_uPortNo);<br>}<br>}<br>//----------------------------------------------------------------------<br>//向串口写一个字符<br>bool TSerialPort::WriteChar(unsigned char ucChar)<br>{<br>bool bWrite=true;<br>bool bResult;<br>DWORD BytesSent=0;<br>OVERLAPPED ov;<br>ov.hEvent=CreateEvent(NULL, true, false, NULL);<br><br>//初始化重叠结构<br>ov.Offset=0;<br>ov.OffsetHigh=0;<br>PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);<br>//写串口<br>bResult = WriteFile(m_hComm, //串口句柄<br>&amp;ucChar, //输出缓冲区<br>1, &nbsp; //每次只发送一个字符<br>&amp;BytesSent, &nbsp; &nbsp; //实际读入的字符数<br>&amp;ov); //重叠结构<br>if(!bResult) &nbsp;//写串口失败<br>{<br>DWORD dwError=GetLastError();<br>switch(dwError)<br>{<br>case ERROR_IO_PENDING: &nbsp;//串口操作正在后台进行<br>{<br>BytesSent=0;<br>bWrite=false;<br>break;<br>}<br>default: //失败<br>return false;<br>}<br>}<br>if(!bWrite)<br>{<br>//等待重叠结果<br>bResult=GetOverlappedResult(m_hComm,<br>&amp;ov,<br>&amp;BytesSent, &nbsp;//实际发送字符数<br>true);<br>if (!bResult) //重叠操作失败<br>return false;<br>}<br>//检查实际发送的字符数是否与要求相符<br>if (BytesSent!=1)<br>{<br>return false;<br>}<br>return true;<br>}<br>//----------------------------------------------------------------------<br>//向串口写一个字符<br>void __fastcall TSerialPort::WriteToPort(unsigned char ucTxData)<br>{<br>if(m_hComm==INVALID_HANDLE_VALUE)<br>{<br>mErrorMsg("串口句柄无效,无法发送数据.");<br>return;<br>}<br>int i=3;<br>while(i) &nbsp; //重发次数不超过3次<br>{<br>if(WriteChar(ucTxData)) //成功发送<br>break;<br>i--;<br>Application-&gt;ProcessMessages();<br>}<br>if(i==0)<br>{<br>char sTemp[100];<br>sprintf(sTemp,"数据'%d'未被成功发送.",ucTxData);<br>mErrorMsg(sTemp);<br>}<br>}<br>//---------------------------------------------------------------------------<br>//错误处理,显示原因<br>void __fastcall TSerialPort::ProcessErrorMessage(char* ErrorText)<br>{<br>char ErrorMsg[400];<br>LPVOID lpMsgBuf;<br>FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,<br>NULL,GetLastError(), &nbsp; &nbsp; //获取错误信息标识<br>MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),//使用系统缺省语言<br>(LPTSTR)&amp;lpMsgBuf, //消息缓冲区<br>0,<br>NULL);<br>sprintf(ErrorMsg, "COM%d: /"%s/" 由于以下错误而失败: /n/n%s",<br>m_uPortNo,ErrorText,lpMsgBuf);<br>Application-&gt;MessageBox(ErrorMsg, "串口错误", MB_ICONSTOP);<br>LocalFree(lpMsgBuf);<br>}<br>//----------------------------------------------------------------------<br>//----------------------------------------------------------------------<br>这个类的使用方法如下:<br>1、建立类的实例,如:<br>SerialPort=new TSerialPort(); //实例化一个串口控制类<br>SerialPort-&gt;InitPort(this,g_iSerialPort,9600);<br>//初始化串口,Baud:9600,DataBits:8,StopBits:1,无校验位<br>SerialPort-&gt;StartMonitoring(); //创建串口监控线程,开始监控<br>2、映射串口消息,在创建以上实例的窗口类的声明中加入:<br>void __fastcall OnComRx(TMessage &amp;Message);<br>BEGIN_MESSAGE_MAP//指定消息WM_COMM_RXCHAR的处理函数为OnComRx<br>MESSAGE_HANDLER(WM_COMM_RXCHAR, TMessage, OnComRx)<br>END_MESSAGE_MAP(TForm)<br>3、实现函数OnComRx(),如:<br>//--------------------------------------//串口消息(接收到一个字符)处理函数<br>//消息的参数WParam就是接收到的字符<br>void __fastcall TDlgProgram::OnComRx(TMessage &amp;Message)<br>{<br>unsigned char ucRxData=(unsigned char)Message.WParam;<br>………………<br>}<br>//---------------------------------------------------------------------------<br>
 
谢谢:Pipi、HD_Copy
 
后退
顶部