MFC串口通信的两种方法及注意事项

原文:http://blog.csdn.net/cjdxzy2010/article/details/6120391

1.基于Active控件的方式(MSComm)

        优点是:直接利用控件,在串口有数据到达时,会促发相应的事件响应函数,然后你可以在实践响应函数里,进行数据的读取。

        缺点是:数据在发送和接受的过程中VARIANT、   COleSafeArray 类型的转换,显得繁琐。

        步骤:

       ①插入控件

        选择Project菜单下Add To Project子菜单中的 Components and Controls…选项,在弹出的对话框中双击Registered ActiveX Controls项,则所有注册过的ActiveX控件出现在列表框中。 选择Microsoft Communications Control, version 6.0,单击Insert按钮将它插入到我们的Project中来,接受缺省的选项。这时在ClassView视窗中就可以看到CMSComm类了,并且在控件工具栏Controls中出现了电话图标,现在要做的是用鼠标将此图标拖到对话框中,程序运行后,这个图标是看不到的。

        ②为拖入对话框的 CMSComm控件添加对应的控制变量 m_ctrlComm。

        ③添加对应的消息响应函数OnComm()

        打开ClassWizard->Message Maps,选择类CSCommTestDlg,选择IDC_MSCOMM1,双击消息OnComm,将弹出的对话框中将函数名改为OnComm,这个函数是用来处理串口消息事件的,如每当串口接收到数据,就会产生一个串口接收数据缓冲区中有字符的消息事件,我们刚才添加的函数就会执行,我们在OnComm()函数加入相应的处理代码就能实现自已想要的功能了。请你在函数中加入如下代码:

[cpp]  view plain  copy
  1. void CSCommTestDlg::OnComm()   
  2. {  
  3.     // TODO: Add your control notification handler code here  
  4.     VARIANT variant_inp;  
  5.     COleSafeArray safearray_inp;  
  6.     LONG len,k;  
  7.     BYTE rxdata[2048]; //设置BYTE数组 An 8-bit integerthat is not signed.  
  8.     CString strtemp;  
  9.     if(m_ctrlComm.GetCommEvent()==2) //事件值为2表示接收缓冲区内有字符  
  10.     {             ////////以下你可以根据自己的通信协议加入处理代码  
  11.         variant_inp=m_ctrlComm.GetInput(); //读缓冲区  
  12.         safearray_inp=variant_inp; //VARIANT型变量转换为ColeSafeArray型变量  
  13.         len=safearray_inp.GetOneDimSize(); //得到有效数据长度  
  14.         for(k=0;k<len;k++)  
  15.             safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组  
  16.         for(k=0;k<len;k++) //将数组转换为Cstring型变量  
  17.         {  
  18.             BYTE bt=*(char*)(rxdata+k); //字符型  
  19.             strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放  
  20.             m_strRXData+=strtemp; //加入接收编辑框对应字符串   
  21.         }  
  22.     }  
  23.     UpdateData(FALSE); //更新编辑框内容  
  24. }  

      ④.打开串口和设置串口参数

扫描二维码关注公众号,回复: 1920057 查看本文章

       现在我们在主对话框的CSCommTestDlg::OnInitDialog()打开串口,加入如下代码:

[cpp]  view plain  copy
  1. // TODO: Add extra initialization here  
  2. if(m_ctrlComm.GetPortOpen())  
  3. m_ctrlComm.SetPortOpen(FALSE);  
  4.   
  5. m_ctrlComm.SetCommPort(1); //选择com1  
  6. if( !m_ctrlComm.GetPortOpen())  
  7. m_ctrlComm.SetPortOpen(TRUE);//打开串口  
  8. else  
  9. AfxMessageBox("cannot open serial port");  
  10.   
  11. m_ctrlComm.SetSettings("9600,n,8,1"); //波特率9600,无校验,8个数据位,1个停止位  
  12.   
  13. m_ctrlComm.SetInputModel(1); //1:表示以二进制方式检取数据  
  14. m_ctrlComm.SetRThreshold(1);   
  15. //参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件  
  16. m_ctrlComm.SetInputLen(0); //设置当前接收区数据长度为0  
  17. m_ctrlComm.GetInput();//先预读缓冲区以清除残留数据  

        ⑤.发送数据

        

[cpp]  view plain  copy
  1. CString m_send = _T("你想要发送的数据")  
  2.   
  3. m_ctrlComm.SetOutput(COleVariant(m_send ));  

2.基于win32 API的串口读写

        ①初始化打开串口

         优点:设置、使用更加灵活,因为是基于win32的api函数。所以显得更加通用,适用任何windows程序上引用,不仅仅限于MFC.

         缺点:需要主动的去读取串口上的数据,没有事件通知。

         这里有一点需要注意的是,当COM号大于10的时候,会出现打开错误,一般解决的办法是修改com的名称让它的com号是一位数。除此之外也有其他解决办法,见网上。

[cpp]  view plain  copy
  1. HANDLE InitCom(char* comName)  
  2. {  
  3.     HANDLE hCom;  
  4.     hCom = CreateFile(comName,//COM7口  
  5.         GENERIC_READ|GENERIC_WRITE, //允许读和写  
  6.         0, //独占方式  
  7.         NULL,  
  8.         OPEN_EXISTING, //打开而不是创建  
  9.         0, //同步方式  
  10.         NULL);  
  11.     if(hCom == (HANDLE)-1)  
  12.     {  
  13.         return NULL;  
  14.     }  
  15.     SetupComm(hCom,100,100); //输入缓冲区和输出缓冲区的大小都是100  
  16.     COMMTIMEOUTS TimeOuts;  
  17.     //设定读超时  
  18.     TimeOuts.ReadIntervalTimeout=MAXDWORD;  
  19.     TimeOuts.ReadTotalTimeoutMultiplier=0;  
  20.     TimeOuts.ReadTotalTimeoutConstant=0;  
  21.     //在读一次输入缓冲区的内容后读操作就立即返回,  
  22.     //而不管是否读入了要求的字符。  
  23.     //设定写超时  
  24.     TimeOuts.WriteTotalTimeoutMultiplier=100;  
  25.     TimeOuts.WriteTotalTimeoutConstant=500;  
  26.     SetCommTimeouts(hCom,&TimeOuts); //设置超时  
  27.   
  28.     DCB dcb;  
  29.     GetCommState(hCom, &dcb);  
  30.     dcb.BaudRate=115200; //波特率为9600  
  31.     dcb.ByteSize=8; //每个字节有8位  
  32.     dcb.Parity=NOPARITY; //无奇偶校验位  
  33.     dcb.StopBits=1; //两个停止位  
  34.     SetCommState(hCom, &dcb);  
  35.     PurgeComm(hCom, PURGE_TXCLEAR|PURGE_RXCLEAR);  
  36.     return hCom;  
  37. }  
        ②读串口信息
[cpp]  view plain  copy
  1. int ReadData(HANDLE handler, char* buffer)  
  2. {  
  3.     char readBuffer[512];  
  4.     memset(readBuffer, 0, 512);  
  5.     DWORD wCount= 512;//读取的字节数  
  6.     BOOL bReadStat;  
  7.   
  8.     bReadStat = ReadFile(handler, readBuffer, wCount, &wCount, NULL);  
  9.     if(!bReadStat)  
  10.     {  
  11.         AfxMessageBox("读串口失败!");  
  12.         return -1;  
  13.     }  
  14.     strcpy(buffer, readBuffer);  
  15.     PurgeComm(handler, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);    
  16.     return 0;  
  17. }  

        ③写串口信息
[cpp]  view plain  copy
  1. int WriteData(HANDLE handler, char* buffer)  
  2. {  
  3.     unsigned long dwBytesWrite;  
  4.     COMSTAT ComStat;  
  5.     DWORD dwErrorFlags;  
  6.     BOOL bWriteStat;  
  7.     ClearCommError(handler, &dwErrorFlags, &ComStat);  
  8.     dwBytesWrite = strlen(buffer);  
  9.     bWriteStat=WriteFile(handler, buffer, dwBytesWrite, &dwBytesWrite, NULL);  
  10.     if(!bWriteStat)  
  11.     {  
  12.         AfxMessageBox("写串口失败!");  
  13.         return -1;  
  14.     }  
  15.     return 0;  
  16. }  

猜你喜欢

转载自blog.csdn.net/iwilldoitx/article/details/79123986