Win API 串口的Modbus 通讯 VS2005

本文介绍了一段使用C语言实现与施耐德PLC异步通信的代码,通过创建并管理线程进行串口读写操作。程序首先打开COM3端口,设置波特率、数据位、校验位等参数,然后创建读写线程,线程1负责交替写入不同数据,线程2则监听串口接收数据。当串口事件发生时,通过消息机制通知窗口读取数据。通过这种方式,成功解决了VB中串口通信的问题。
摘要由CSDN通过智能技术生成
最初以VB做串口与PLC通信的程序,发现有些问题,就改为C ,问题果然解决。下面的是主要实现代码,部分变量声明得自己在头文件中声明。

程序与施耐德PLC连接通信,运行良好。


   
   
  1. 以异步读写方式打开COM3
  2. void CMscommDlg::OnBnClickedBitOpen()
  3. DWORD dwError;
  4. hCom=CreateFile(_T("COM3"),GENERIC_READ |GENERIC_WRITE, 0, NULL,
  5. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL);
  6. if(hCom==(HANDLE)0XFFFFFFFF)
  7. {
  8. MessageBox("串口打开失败");
  9. return;
  10. }
  11. MScommOpen=true;
  12. DCB dcb;
  13. dcb.DCBlength=sizeof(dcb);
  14. GetCommState(hCom,&dcb);
  15. dcb.BaudRate = 19200; //波特率为9600
  16. dcb.ByteSize =8; //数据位数为8位
  17. dcb.Parity = NOPARITY; //偶校验
  18. dcb.StopBits = 2; //两个停止位
  19. dcb.fBinary = TRUE;
  20. dcb.fParity = TRUE;
  21. if (!SetCommState(hCom,&dcb))
  22. {
  23. MessageBox(_T("串口设置出错!"));
  24. }
  25. SetupComm(hCom, 1024, 1024);
  26. PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT |PURGE_TXCLEAR |
  27. PURGE_RXCLEAR);
  28. COMMTIMEOUTS to;
  29. memset(&to, 0,sizeof(to));
  30. to.ReadIntervalTimeout = 10;
  31. SetCommTimeouts(hCom,&to);
  32. SetCommMask(hCom,EV_RXCHAR|EV_TXEMPTY);//设置串口监听事件
  33. }
  34. ///创建读写线程///
  35. void CMscommDlg::OnBnClickedBitRece()
  36. {
  37. RECVPARAM *pRecvParam=newRECVPARAM; //创建结构体,以向线程函数传输多个参数
  38. pRecvParam->m_com=hCom; //串口标识
  39. pRecvParam->hwnd=m_hWnd; //窗体句柄
  40. );
  41. //创建写数据线程
  42. hThread1=CreateThread(NULL,10000,FunPro1,(LPVOID)pRecvParam,0,NULL);
  43. //创建读数据线程
  44. hThread2=CreateThread(NULL,10000,FunPro2,(LPVOID)pRecvParam,0,NULL);
  45. CloseHandle(hThread1);// 关闭线程句柄
  46. CloseHandle(hThread2);//关闭线程句柄
  47. }
  48. /线程1写数据
  49. //线程交替实现向站1的0号寄存器写入值0和100,每写入完成,读取该数据
  50. DWORD WINAPI FunPro1(LPVOID lpParameter)
  51. {
  52. HANDLEhCom=((RECVPARAM*)lpParameter)->m_com;
  53. HWND hwnd=((RECVPARAM*)lpParameter)->hwnd;
  54. HANDLEhMutex=((RECVPARAM*)lpParameter)->Mutex;
  55. bool Sign=true;
  56. intData=100;
  57. DWORD CRC;
  58. unsigned charlpOutBuffer[8];
  59. while(1)
  60. {
  61. Sleep(100);
  62. lpOutBuffer[0]=1; //站
  63. lpOutBuffer[2]=0; //寄存器高地址
  64. lpOutBuffer[3]=0; //寄存器底地址
  65. if(Sign)
  66. {
  67. lpOutBuffer[1]=3; //读操作
  68. lpOutBuffer[4]=0; //字节高位
  69. lpOutBuffer[5]=1; //字节地位
  70. Sign=false;
  71. }
  72. else
  73. {
  74. if(Data==100)
  75. Data=0;
  76. else
  77. Data=100;
  78. lpOutBuffer[1]=6; //写操作
  79. lpOutBuffer[4]=0; //字节高位
  80. lpOutBuffer[5]=Data; //字节地位
  81. Sign=true;
  82. }
  83. CRC=GetCheckCode(lpOutBuffer, 6); //校验
  84. lpOutBuffer[6]=(char)CRC;
  85. lpOutBuffer[7]=CRC>>8;
  86. DWORDdwNumberWrite;
  87. BOOL bWriteStat;
  88. OVERLAPPED m_OverlappedWrite;
  89. memset(&m_OverlappedWrite, 0, sizeof( OVERLAPPED ));
  90. m_OverlappedWrite.hEvent= CreateEvent( NULL, TRUE, FALSE, NULL );
  91. bWriteStat = WriteFile(hCom, (LPSTR) lpOutBuffer, 8,&dwNumberWrite,
  92. &m_OverlappedWrite );
  93. if( !bWriteStat && ( GetLastError()== ERROR_IO_PENDING ) )
  94. if( WaitForSingleObject(m_OverlappedWrite.hEvent, 1000 ) )
  95. dwNumberWrite = 0;
  96. else
  97. GetOverlappedResult( hCom,&m_OverlappedWrite, &dwNumberWrite,FALSE );
  98. if (dwNumberWrite == 0)
  99. AfxMessageBox("写操作失败");
  100. }
  101. return 0;
  102. }
  103. ///线程2:监视串口
  104. DWORD WINAPI FunPro2(LPVOID lpParameter)
  105. {
  106. LPDWORD lpEvtMask;
  107. LPOVERLAPPED lpOverlapped;
  108. charSendBuf[1024];
  109. HANDLE hCom=((RECVPARAM*)lpParameter)->m_com;
  110. HWND hwnd=((RECVPARAM*)lpParameter)->hwnd;
  111. HANDLEhMutex=((RECVPARAM*)lpParameter)->Mutex;
  112. while(1)
  113. {
  114. OVERLAPPED m_osRead;
  115. DWORD dwMask,dwTrans,dwError=0,err;
  116. memset(&m_osRead,0,sizeof(OVERLAPPED));
  117. m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
  118. if(!WaitCommEvent(hCom,&dwMask,&m_osRead)) //判断异步操作是否完成
  119. {
  120. if(GetLastError()==ERROR_IO_PENDING) //若异步操作正在进行,判断是否是读写事件
  121. {
  122. GetOverlappedResult(hCom,&m_osRead,&dwTrans,true); //等待事件发生
  123. if(EV_RXCHAR==dwMask) //判读是否是读事件发生
  124. ::PostMessage(hwnd,WM_READDATA,0,(LPARAM)data);//串口有数据,通知窗口
  125. }
  126. }
  127. }
  128. return 0;
  129. }
  130. //窗口消息响应函数,读取串口数据///
  131. LRESULT CMscommDlg::OnReadData(WPARAM wParam,LPARAMlParam)
  132. {
  133. unsigned char lpOutBuffer[1024];
  134. DWORD dwBytesRead=1024;
  135. COMSTAT ComStat;
  136. DWORD dwErrorFlags;
  137. OVERLAPPED m_osRead;
  138. int Data ;
  139. CString Temp;
  140. CString Str;
  141. memset(&m_osRead,0,sizeof(OVERLAPPED));
  142. m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
  143. ClearCommError(hCom,&dwErrorFlags,&ComStat);
  144. dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
  145. if(dwBytesRead)
  146. {
  147. BOOL bReadStatus;
  148. bReadStatus=ReadFile(hCom,lpOutBuffer,dwBytesRead,&dwBytesRead,&m_osRead);
  149. if(!bReadStatus)
  150. if(GetLastError()==ERROR_IO_PENDING)
  151. WaitForSingleObject(m_osRead.hEvent,2000);
  152. }
  153. PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|
  154. PURGE_RXCLEAR); //清空缓冲区;
  155. if(dwBytesRead==lpOutBuffer[2]+5)
  156. {
  157. Str="";
  158. for(int i=3;i<dwBytesRead-2;i+=2)
  159. {
  160. Data=256*lpOutBuffer[i]+lpOutBuffer[i+1];
  161. Temp.Format("%d",Data);
  162. Str+=Temp;
  163. Str+=" ";
  164. }
  165. GetDlgItemText(IDC_EDIT_RECE,Temp);
  166. Str+=_T("\r\n");
  167. Str+=Temp;
  168. SetDlgItemText(IDC_EDIT_RECE,Str);
  169. }
  170. return0;
  171. }
  172. //CRC校验//
  173. WORD GetCheckCode(const unsigned char * pSendBuf, intnEnd)//获得校验码
  174. {
  175. WORD wCrc = WORD(0xFFFF);
  176. for(int i=0; i<nEnd; i++)
  177. {
  178. wCrc ^= WORD(BYTE(pSendBuf[i]));
  179. for(int j=0; j<8; j++)
  180. {
  181. if(wCrc & 1)
  182. {
  183. wCrc >>= 1;
  184. wCrc ^= 0xA001;
  185. }
  186. else
  187. {
  188. wCrc >>= 1;
  189. }
  190. }
  191. }
  192. return wCrc;
  193. }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值