土木在线论坛 \ 电气工程 \ 工业自动化 \ 工控系统串口通讯设计

工控系统串口通讯设计

发布于:2007-01-02 14:05:02 来自:电气工程/工业自动化 [复制转发]

   工控系统串口通讯设计
  工控系统通常由工控仪器和计算机终端组成,工控仪器和计算机终端之间通过符合RS-232协议的串口通讯,计算终端可以通过双方既定的数据协议,向工控仪器查询状态信号和发送控制信号。
  一、硬件协议:定义了RS-232串口的电气规范。
  1)DTE/DCE:
  一般把工控仪器称为DCE,计算机终端称为DTE,设备之间通过RS-232电缆连接,DCE端采用母连接器(有槽),DTE端采用公连接器(有针)。但如果工控仪器和计算机终端都采用公连接器,则两者都是DTE设备,它们之间的连接应采用零调制解调器方式。
  2)RS-232信号:
  标准的RS-232管脚通常有D-25PIN和D-9PIN两种类型,常用的信号如下:
  信号分类 D-9PIN D-25PIN 信号名称 信号缩写 信号方向
  数据信号 3 2 数据传输 TD DTE->DCE
   2 3 接收数据 RD DTE<-DCE
  控制信号 7 4 请求发送 RTS DTE<-DCE
   8 5 清除发送 CTS DTE<-DCE
   6 6 数据发送就绪 DSR DTE<-DCE
   1 8 载波检测 CD DTE<-DCE
   4 20 数据终端就绪 DTR DTE->DCE
   9 22 振铃指示 RI DTE<-DCE
  接地信号 5 7 接地信号 GND
   3)零调制解调连接(ZERO MODEM):
   ZERO MODEM处理DTE和DTE设备的对称连接,其连接原理为,一方的传送数据信号为另一方的接收数据信号,一方的控制请求信号为另一方的控制应答信号,接地信号互连。连接示意如下:
  信号分类 DTE DTE
  数据信号 TD-- RD
   RD-- TD
  控制信号 RTS-- CTS
   CTS-- RTS
   (DSR-DCD-RI)-- DTR
   DTR-- (DSR-DCD-RI )
  接地信号 GND-- GND
   二、软件协议:定义了DTE的串口配置,DTE和DCE之间连接协议和数据传输协议。
   1)串口参数配置:
   波特率(BaudRate):在CBR_110到CBR_256000之间指定,参照仪器指定
   数据位(ByteSize):每个字节的位数,一般用7或8,默认为8
   停止位(StopBits):停止位的位数,一般有:ONESTOPBIT、TOWSTOPBITS、ONE5STOPBITS,默认为ONESTOPBIT
   奇偶校验(Parity): 定义了奇偶校验的模式,一般有:NO_PARITY、EVEN_PARITY、ODD_PARITY,默认NO_PARITY
   流量控制(FlowCtrl):定义了流量控制方式,一般有:无控制、硬件方式、XON/XOFF方式,详见握手协议。
   2)握手协议:常见有硬件方式RTS/CTS和DTR/DSR方式,软件方式有XON/XOFF和自定义的方式。
   RTS/CTS:对于DTE来说,设置OutCtsFlow则CTS低水平位时停止输出,直至高水平位时恢复输出。设置RtsControl为HANDSHAKE则当输入缓冲区数据小于1/4时,DTE将RTS置为高水平位,通知DCE可以传输数据,当输入缓冲区数据大于3/4时,DTE将RTS置为低水平位,通知DCE停止传输数据。DTE(计算机)的缓冲区较大,通常都将RtsControl设置位ENABLE,即保持高水平位。
   DTR/DSR:对于DTE来说,设置OutDsrFlow则DSR低水平位时停止输出,直至高水平位时恢复输出。设置DtrControl为HANDSHAKE则当DTR设置为高水平位时容许数据输入,当DTR为低水平位时阻止数据输入。DTE(计算机)的缓冲区较大,通常都将DtrControl设置位ENABLE,即保持高水平位。
   XON/XOFF:对于DTE来说,设置OutX时,输出流在DTE收到XoffChar时停止,在收到XonChar时恢复。设置InX时,输入流在缓冲区空闲不足XoffLim时DTE发送XoffChar,通知DCE中止传输数据。当输入流达到缓冲区空闲超过XonLim时,DTE发送XonChar,通知DCE恢复传输数据。
  三、编程模式:
   在WIN32环境中,串口作为文件访问,但与其他文件不同,串口文件的操作是采用阻塞方式的,读写动作通常会在后台阻塞,用户可以通过响应串口事件,获知端口状态和控制读写动作。因此在WIN32环境中处理串口,应采用重叠I/0机制访问串口文件和在线程中完成读写操作,这样意味着当读写线程阻塞时,不会使主线程锁定而失去响应。
   1、串口文件操作方式:根据如上要求,串口一般采用独占和重叠方式打开,如:CreateFile(_T("\\\\.\\COM1"),/*端口名称*/
  GENERIC_READ|GENERIC_WRITE,/*文件可读写*/
  0,/*独占方式*/
  NULL,/*无权限属性*/
  OPEN_EXISTING,/*端口必须存在*/
  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,/*重叠的操作方式*/
  NULL/*不支持临时文件*/)。
  有效的串口文件打开后,可以进行重叠的读写操作,其中要使用一个重叠操作结构OVERLAPPED:
  struct { DWORD Internal; /*内部使用*/
   DWORD InternalHigh; /*内部使用*/
   DWORD Offset; /*操作开始的文件位置(低位),串口文件不支持*/
   DWORD OffsetHigh;/* 操作开始的文件位置(高位),串口文件不支持*/
   HANDLE hEvent; /*异步事件句柄,重叠操作完成或中断时被激发*/
  } OVERLAPPED;
  写串口的方式如下:
  WriteFile(hCom,/*串口文件句柄*/
  (void*)data,/*数据指针*/
  dwDataBytes,/*请求写的数据字节数*/
  &dwOperaBytes,/*函数返回的已写的字节数,在重叠I/O中通常返回0*/
  &ov/*重叠操作结构指针*/);
  读串口的方式如下:
  ReadFile(hCom,/*串口文件句柄*/
  (void*)buf,/*缓冲区指针*/
  dwDataBytes,/*请求读的数据字节数*/
  &dwOperaBytes,/*函数返回的已读的字节数,在重叠I/O中通常返回0*/
  &ov/*重叠操作结构指针*/);
  重叠方式调用读写函数后即返回,程序稍后调用等待事件函数进入阻塞状态,直至异步事件被激发,调用方式如下:
  WaitForSingleObject(hEvent,/*OVERLAPPED中异步事件句柄*/
  dwTimeouts/*读写超时毫秒数*/)
  读写超时设置可以由串口配置超时参数COMMTIMEOUTS获得,读超时数 =ReadTotalTimeoutMultiplier * 读字节数 + ReadTotalTimeoutConstant; 写超时数 =WriteTotalTimeoutMultiplier * 写字节数 + WriteTotalTimeoutConstant;
  异步事件返回后,可以调用重叠I/O查询函数查看后台读写状况:
  GetOverlappedResult(hCom, /*端口文件句柄*/
  &ov, /*重叠结构指针*/
  &dwOperaBytes, /*重叠操作完成的字节数*/
  FALSE/*是否需要等待重叠操作完成*/);
  以上时串口文件的操作方式,需要注意的是,这些操作除了打开文件外,其他都应当在某个读写线程中调用,让线程在后台阻塞,主线程保持响应。
   2、端口事件侦听:WIN32提供串口事件查询函数用以查看端口触发的事件,端口可侦听事件一般有:
  EV_BREAK :端口中断信号
  EV_CTS :CTS信号改变
  EV_DSR :DSR信号改变
  EV_RXCHAR :收到一个或多个字符
  EV_RXFLAG :收到特殊字符
  EV_ERR :端口错误信号
  EV_TXEMPTY:输出缓冲区数据发送完成
  可以通过SetCommMask(hCom/*端口文件句柄*/,dwMask/*事件组合*/)来设置需要侦听的事件,然后应采用重叠模式调用查询事件函数:
  WaitCommEvent(hCom, /*端口文件句柄*/
  &dwMask,/*端口事件组合*/
  &ov/*重叠I/O结构*/);
  该函数在重叠I/0方式调用后即返回,侦听例程稍后调用WaitForSingleObject进入阻塞状态,OVERLAPPED中的异步事件被激发后返回,程序可以根据dwMask中返回的事件标志做进一步的处理,如:
 

全部回复(3 )

只看楼主 我来说两句
  • azwsp
    azwsp 沙发
    谢谢!
    2007-01-30 14:35:30

    回复 举报
    赞同0
  • 酷客
    酷客 板凳
    /*查询主线程终止信号*/
       EnterCriticalSection(&pListen->cs);
       bActive = pListen->bActive;
       LeaveCriticalSection(&pListen->cs);
      }
      /*侦听循环停止后处理*/
      CloseHandle(ov.hEvent);
      EnterCriticalSection(&pListen->cs);
      /*做些端口现场清理*/
      …
      LeaveCriticalSection(&pListen->cs);
      /*通知住线程侦听线程结束*/
      SetEvent(pListen->evListen);
      ExitThread(0);
      return 0;
      }
      2)、读线程的处理模式:
      2-1)、端口读的接口函数
      long ReadData(…,long size, BYTE* data)
      {
      COMTIMEOUTS to;
      GetCommTimeouts(hCom,&to); /*取超时参数*/
      ThreadParam tp_read; /*主线程定义的读线程传入参数*/
      tp_read.bActive = TRUE; /*主线程当前活动*/
      tp_read.hCom = hCom; /*已打开的端口句柄*/
      tp_read.evTerm = CreateEvent(NULL,TRUE,FALSE,NULL); /*创建异步事件*/
      tp_read.cs = cs; /*已经创建的临界区*/
      tp_read.data = data; /*缓冲区指针*/
      tp_read.dwQueryBytes = size;
      tp_read.dwResultBytes = 0;
      /*计算读的侦听超时数*/
      tp_read.dwTimeouts = to.ReadTotalTimeoutConstant + to.ReadTotalTimeoutMultiplier * size;
      tp_read.nResultCode = 0; /*初始状态码*/
      /*创建读线程*/
      CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadProc,(void*)&tp_read,0,&dw);
      /*等待线程结束*/
      WaitForSingleObject(tp_read.evTerm,INFINITE);
      CloseHandle(tp_read.evTerm);
      …
      /*返回已经处理的字节数*/
      return tp_read.dwResultBytes;
      }
      2-2)、端口读的线程回调函数
      DWORD WINAPI ReadProc(LPVOID lpParam)
      {
      ThreadParam* pRead = (ThreadParam*)lpParam;
      OVERLAPPED ov;
      memset((void*)&ov,0,sizeof(OVERLAPPED));
      ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
      /*端口异步读*/
      EnterCriticalSection(&(pRead->cs));
      ReadFile(hCom,(void*)pRead->data,pRead->dwQueryBytes,&(pRead->dwResultBytes),&ov);
      LeaveCriticalSection(&(pRead->cs));
      /*等待异步读结果*/
      WaitForSingleObject(ov.hEvent,pRead->dwTimeouts)
      /*取重叠操作结果*/
      GetOverlappedResult(pRead->hCom,&ov,&pRead->dwResultBytes,FALSE);
      CloseHandle(ov.hEvent);
      /*通知主线程读操作完成*/
      SetEvent(pRead->evRead);
      ExitThread(0);
      return 0;
      }
      3)、写线程的处理模式:
      3-1)、端口写的接口函数
      long WriteData(…,long size, BYTE* data)
      {
      COMTIMEOUTS to;
      GetCommTimeouts(hCom,&to); /*取超时参数*/
      ThreadParam tp_write; /*主线程定义的写线程传入参数*/
      tp_write.bActive = TRUE; /*主线程当前活动*/
      tp_write.hCom = hCom; /*已打开的端口句柄*/
      tp_write.evTerm = CreateEvent(NULL,TRUE,FALSE,NULL); /*创建异步事件*/
      tp_write.cs = cs; /*已经创建的临界区*/
      tp_write.data = data; /*缓冲区指针*/
      tp_write.dwQueryBytes = size;
      tp_write.dwResultBytes = 0;
      /*计算写的侦听超时数*/
      tp_write.dwTimeouts = to.WriteTotalTimeoutConstant + to.WriteTotalTimeoutMultiplier * size;
      tp_write.nResultCode = 0; /*初始状态码*/
      /*创建写线程*/
      CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WriteProc,(void*)&tp_write,0,&dw);
      /*等待线程结束*/
      WaitForSingleObject(tp_write.evTerm,INFINITE);
      CloseHandle(tp_write.evTerm);
      …
      /*返回已经处理的字节数*/
      return tp_write.dwResultBytes;
      }
      3-2)、端口写的线程回调函数
      DWORD WINAPI WriteProc(LPVOID lpParam)
      {
      ThreadParam* pWrite = (ThreadParam*)lpParam;
      OVERLAPPED ov;
      memset((void*)&ov,0,sizeof(OVERLAPPED));
      ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
      /*端口异步写*/
      EnterCriticalSection(&(pWrite->cs));
      WriteFile(hCom,(void*)pWrite->data,pWrite->dwQueryBytes,&(pWrite->dwResultBytes),&ov);
      LeaveCriticalSection(&(pWrite->cs));
      /*等待异步写结果*/
      WaitForSingleObject(ov.hEvent,pWrite->dwTimeouts)
      /*取重叠操作结果*/
      GetOverlappedResult(pWrite->hCom,&ov,&pWrite->dwResultBytes,FALSE);
      CloseHandle(ov.hEvent);
      /*通知主线程写操作完成*/
      SetEvent(pWrite->evWrite);
      ExitThread(0);
      return 0;
      }
    2007-01-02 14:06:02

    回复 举报
    赞同0
加载更多
这个家伙什么也没有留下。。。

工业自动化

返回版块

17.93 万条内容 · 385 人订阅

猜你喜欢

阅读下一篇

力控的60个经典问题解答之一

1: 我已经安装加密锁了,为何安装运行包后运行工程还提示找不到加密锁? 这是因为安装运行包后,需要人工对软件进行注册。请打开运行包释放后所在文件夹,手工运行其中的“Registry”程序进行软件注册,这样加密锁就可以找到了。2:安装完运行包后如何卸载? 卸载运行包需要两个步骤: 1、手动删除运行包安装后生成文件夹及文件夹中的内容; 2、删除注册表 (1)Windows2000:进入windows安装系统盘――>WINNT文件夹――>打开regedit.exe文件――>使用查找功能搜索DaQing Sunway――>找到后删除该注册表信息。

回帖成功

经验值 +10