• RS232串口通讯模块


    应为工作需要自己编写的RS232通讯模块,该模块已经编写了蛮久,在实际使用中可能有没有考虑和不完善的地方。

    //=================================================================================

    //如果使用该模块请保留该注释,如果被修改或编辑请将修改后的代码发送一份给我

    //编写:戴琪英

    //E_Mail:qiyingdai@163.com

    //2000-09-01

    //=================================================================================

    unit R232Comm;

    interface
    uses
      Windows,SysUtils;
    const
      INITR12COMM_SUCCESS=0;
      INITR12COMM_FAILURE=-1;
    var
      bSendFinish:boolean=True;//发送完标志
      iRecvLen:DWORD=0;
      RecvBuff,TempBuff:PChar;
      SendCommand,RecvCommand:String;//发送和接收到的命令
      RecvFinish:BOOL=False;
      RecvBuffInit:BOOL=False;
      SendCommandSuccess:BOOL; //切换台命令被成功发送标志

    function  InitR12CommDev(comNo:PChar):String;  //初始化切换台串口,返回状态字符
    procedure SwitchR12(WriteBuffer:PChar);//对切换台进行切换函数
    procedure SwitchR12Byte(WriteBuffer:Byte);
    procedure CommSendNotify;//串口接收到字符事件响应过程
    procedure CommRecvNotify; //串口发送缓冲区空事件响应过程
    procedure CommWatchThread(var lpdwParam:DWORD);//通信口监视线程
    function  ConInfo :String;

    implementation
    var
      //comMask,comBuf,ComState:Integer;
      dcb:_DCB; //DCB结构用于配置串口,程序中涉及各域含义如下:
                //DWORD DCBlength :DCB结构大小
                //DWORD BaudRate :  波特率
                //DWORD fBinary  : 1 二进制模式
                //DWORD fParity  : 1 进行奇偶校验
                //BYTE  ByteSize: 字符位数 4~8
                //BYTE  Parity:   奇偶校验位 0-4分别表示无、奇、偶、传号、空号校验
                //BYTE  StopBits: 停止位数 0-2分别表示 1、1.5、2个停止位
                //WORD  XonLim :XON 阈值
                //WORD  XoffLim  XOFF 阈值
                //char  XonChar: XON 字符
                //char  XoffChar: XOFF 字符
                //char  EvtChar:  事件字符
      comStat:_COMSTAT; //COMSTAT结构用于存放有关通信设备的当前信息
                        //程序中涉及各域含义如下:
                        //cbInQue :接收缓冲区中字符个数
                        //cbOutQue:发送缓冲区中字符个数
      dwErrorFlag:LongWord;
      hCommDev,comThreadHwnd:Thandle;//通信串口句柄和通信监视线程句柄
      comMask,comBuf,comState:BOOL;
      read_os,write_os:_OVERLAPPED;  //OVERLAPPED 结构,用于异步操作的Win32函数中
                                    //程序中涉及各域含义如下:
                                    //DWORD Interval 保留给操作系统使用
                                    //DWORD IntervalHigh 保留给操作系统使用
                                    //DOWD  hEvent 当I/O操作完成时被设置为有信号状态
                                    //的事件;当调用ReadFile和WriteFile函数之前,调
                                    //用进程设置该事件
      postRecvEvent,postSendEvent:Thandle;//发送缓冲区空和接收到字符事件句柄
      dwThreadID1:DWORD; //通信监视线程ID号

    ///串口初始化函数
    //该函数主要完成串口初始化设置和通信线程的启动
    //入口参数:串口号
    //返回值;初始化是否成功的状态字符
    function  InitR12CommDev(comNo:PChar) :String;
    begin
       ///打开串口
       hCommDev:=CreateFile(comNo,   //串口好
                           GENERIC_READ or GENERIC_WRITE,//对串口以读写方式打开
                           0,
                           nil,
                           OPEN_EXISTING,
                           FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,//允许重叠操作
                           0
                           );
       if hCommDev=INVALID_HANDLE_VALUE then
            InitR12CommDev:='切换台通讯端口初始化失败.'
       else
          InitR12CommDev:='切换台通讯端口初始化成功.';
       comMask:=SetCommMask(hCommDev,EV_RXFLAG);//设置事件掩码
       //comBuf:=SetupComm(hCommDev,4096,4096);//设置接收和发送缓冲区大小皆为4096字节
       comBuf:=SetupComm(hCommDev,1,1);//设置接收和发送缓冲区大小皆为4096字节
       if  comBuf=False then
             InitR12CommDev:='切换台通讯端口初始化失败.'
       else
          begin
             InitR12CommDev:='切换台通讯端口初始化成功.';
             //清空缓冲区
             PurgeComm(hCommDev,PURGE_TXABORT or PURGE_RXABORT or
                                          PURGE_TXCLEAR or PURGE_RXCLEAR ) ;
          end;

       //以下对串口进行配置
       dcb.DCBlength:=sizeof(_DCB);
       comState:=GetCommState(hCOmmDev,dcb);  //得到缺省设置
       if  comState=False then
             InitR12CommDev:='切换台通讯端口初始化失败.'
       else
           InitR12CommDev:='切换台通讯端口初始化成功.';
       dcb.BaudRate:=9600;  //波特率 9600
       dcb.ByteSize:=8;//7;  //数据长度7位
       dcb.Parity:=NOPARITY;//ODDPARITY; //校验方式 奇校验
       dcb.StopBits:=ONESTOPBIT; //停止位 1 位

       dcb.Flags := 0;         // Enable fBinary
       dcb.Flags := dcb.Flags or 2;          // Enable parity check
       dcb.XonChar:= chr($00) ;
       dcb.XoffChar:= chr($00) ;
       dcb.XonLim:= 100 ;
       dcb.XoffLim:= 100 ;
       dcb.EvtChar := Char($ff);

       comState:=SetCommState(hCommDev,dcb);  //设置串口
       if comState=False then
             InitR12CommDev:='切换台通讯端口初始化失败.'
       else
          InitR12CommDev:='切换台通讯端口初始化成功.';
         //设置通信接收到字符事件句柄
       postRecvEvent:=CreateEvent(NIL,
                                  TRUE,//手工重置事件
                                  TRUE, //初始化为有信号状态
                                  NIL
                                  );
       //设置读异步I/O操作事件句柄
       read_os.hEvent:=CreateEvent(NIL,
                                  TRUE,//手工重置事件
                                  FALSE, //初始化为无信号状态
                                  NIL
                                  );
       //设置发送缓冲区空事件句柄
       postSendEvent:=CreateEvent(NIL,
                                  TRUE,//手工重置事件
                                  TRUE, //初始化为有信号状态
                                  NIL);
       //设置写异步I/O操作事件句柄
       write_os.hEvent:=CreateEvent(NIL,
                                  TRUE,//手工重置事件
                                  FALSE,//初始化为无信号状态
                                  NIL);
       //创建通信监视线程
       comThreadHwnd:=CreateThread(NIL,
                             0,
                             @CommWatchThread, //通信线程函数的地址
                             nil,
                             0,   //创建后立即运行
                             dwThreadID1);//通信线程ID号
       if comThreadHwnd=INVALID_HANDLE_VALUE  then
          InitR12CommDev:='INITR12COMM_FAILURE'
       else
          InitR12CommDev:='切换台通讯端口初始化成功.';
    end;

    ///切换台切换控制函数
    ///输入参数;切换命令字符串
    procedure SwitchR12(WriteBuffer:PChar);
    var
     dwWriteByte,TxCount:DWORD;
     bl:BOOL;
     dwError:DWORD;

    begin
         //WriteBuffer:=chr($0D)+'03A00';
         TxCount:=StrLen(WriteBuffer);
         if bSendFinish=True then  //发送缓冲区空发送
         begin
             dwWriteByte:=0;
             bSendFinish:=False;
             bl:=WriteFile(hCommDev,Byte(WriteBuffer^),TxCount,dwWriteByte,@write_os);
             if bl=True then
             begin
              bSendFinish:=True;
              PurgeComm(hCommDev,PURGE_TXCLEAR );//如果发送完成,置缓冲区空标志,并清空缓冲区
             end;
             if bl=False then
             begin
               dwError:=GetLastError();
               if (dwError=ERROR_IO_PENDING) or (dwError=ERROR_IO_INCOMPLETE) then
               begin
                 bl:=GetOverLappedResult(hCommDev,
                                 write_os,dwWriteByte,TRUE);//如果未发送完命令字符
                                                        //等待发送完成
                 if bl=True then
                 begin
                    bSendFinish:=True;
                    PurgeComm(hCommDev,PURGE_TXCLEAR ); //发送完成 置缓冲区空标志,并清空缓冲区
                    //Result:=True;
                 end;
               end;
             end;
         end;
         //Result:=True;
    end;

    procedure SwitchR12Byte(WriteBuffer:Byte);
    var
     dwWriteByte,TxCount:DWORD;
     bl:BOOL;
     dwError:DWORD;

    begin
         //WriteBuffer:=chr($0D)+'03A00';
         TxCount:= 1 ;//StrLen(WriteBuffer);
         if bSendFinish=True then  //发送缓冲区空发送
         begin
             dwWriteByte:=0;
             bSendFinish:=False;
             bl:=WriteFile(hCommDev,WriteBuffer,TxCount,dwWriteByte,@write_os);
             if bl=True then
             begin
              bSendFinish:=True;
              PurgeComm(hCommDev,PURGE_TXCLEAR );//如果发送完成,置缓冲区空标志,并清空缓冲区
             end;
             if bl=False then
             begin
               dwError:=GetLastError();
               if (dwError=ERROR_IO_PENDING) or (dwError=ERROR_IO_INCOMPLETE) then
               begin
                 bl:=GetOverLappedResult(hCommDev,
                                 write_os,dwWriteByte,TRUE);//如果未发送完命令字符
                                                        //等待发送完成
                 if bl=True then
                 begin
                    bSendFinish:=True;
                    PurgeComm(hCommDev,PURGE_TXCLEAR ); //发送完成 置缓冲区空标志,并清空缓冲区
                    //Result:=True;
                 end;
               end;
             end;
         end;
         //Result:=True;
    end;

    ////通信监视线程
    procedure CommWatchThread(var lpdwParam:DWORD);
    var
        dwTransfer,dwEvtMask,dwError:DWORD;
        os:_OVERLAPPED;
        bl:boolean;

    begin
        os.hEvent:=CreateEvent(nil,
                              TRUE,
                              FALSE,
                              NIL);

        comMask:=SetCommMask(hCommDev,EV_RXCHAR or EV_TXEMPTY);//设置监视的事件为接
                                                            //收到字符或发送缓冲区空
        if comMask=True then
        begin
            while True do
            begin
               dwEvtMask:=0;
               bl:=WaitCommEvent(hCommDev,dwEvtMask,@os); //查询所监视的通信事件是否
                                                           //已经发生
               if bl=False then
               begin
                 dwError:=GetLastError();
                 if dwError=ERROR_IO_PENDING then
                    GetOverlappedResult(hCOmmDev,os,dwTransfer,TRUE);//若未监测到通信事件
                                               //则在此等待事件发生
               end;
               //有事件,进行如下处理
               if (dwEvtMask and EV_RXCHAR)=EV_RXCHAR then //判断是否为接收到 字符事件
               begin
                  WaitForSingleObject(postRecvEvent,$FFFFFFFF);//等待接收事件句柄为有
                                                          //信号状态
                  ResetEvent(postRecvEvent); //置接收事件句柄为无信号状态,以免接收
                                            //缓冲区被覆盖
                  CommRecvNotify; //调用接收到字符处理函数
                  continue; //处理完接收字符,继续监测通信事件
               end;
               if (dwEvtMask and EV_TXEMPTY)=EV_TXEMPTY then //判断是否为发送缓冲区空事件
               begin
                  WaitForSingleObject(postSendEvent,$FFFFFFFF);//等待发送事件句柄为有
                                                               //信号状态
                  ResetEvent(postSendEvent); //置发送事件句柄为无信号状态,,以免发送
                                            //缓冲区被覆盖
                  CommSendNotify; //调用发送缓冲区空处理函数
                  continue;//处理完,继续监测通信事件
               end;
            end;
        end;
        CloseHandle(os.hEvent);
    end;

    //发送缓冲区空处理过程
    procedure CommSendNotify;
    begin
        SetEvent(postSendEvent);//置发送事件未有信号状态,以便进行下一次发送
    end;

    ///接收到字符处理函数
    procedure CommRecvNotify;
    var
         RxCount,dwReadByte:DWORD;
         inData :Byte;
    begin
         ClearCommError(hCommDev,dwErrorFlag,@ComStat);
         RxCount:=ComStat.cbInQue; //获取接收缓冲区的字符个数
         if RxCount>0 then
         begin
           if not RecvBuffInit then
           begin
              StrCopy(RecvBuff,'');
              RecvBuffInit:=True;
           end;
           StrCopy(TempBuff,'');
           ReadFile(hCommDev,Byte(TempBuff^),RxCount,dwReadByte,@read_os);//读字符存入
                                                                          //临时缓冲区中
           iRecvLen:=iRecvLen+dwReadByte; //接收到字符个数统计

           if iRecvLen >=1 then
           begin
                inData := Byte(TempBuff^);
                if inData = $D9 then
                begin
                     SendCommandSuccess:=True;  //如果状态一致,则置该标志为真,标志切换成功
                end
                else
                begin
                     SendCommandSuccess:=False;//否则,置该标志为假,表示切换失败
                end;

                iRecvLen:=0;
                StrCopy(RecvBuff,'');
                RecvBuffInit:=False;
                PurgeComm(hCommDev,PURGE_RXCLEAR ); //清空接收缓冲区
           end
        end;
        ////////////////
        SetEvent(postRecvEvent); //置接收事件句柄为有信号状态,以便接收新字符

    end;

    function ConInfo :String;
    begin
         if  SendCommandSuccess =True then
         begin
              Result := '切换器联机监测成功!';
         end
         else
         begin
              Result := '切换器联机监测失败!';
         end;
    end;

    {
    procedure CommSendNotify;
    begin
        SetEvent(postSendEvent);//置发送事件未有信号状态,以便进行下一次发送
    end;

    ///接收到字符处理函数
    {procedure CommRecvNotify;
    var
         RxCount,dwReadByte:DWORD;
         inData :Byte;
    begin
         ClearCommError(hCommDev,dwErrorFlag,@ComStat);
         RxCount:=ComStat.cbInQue; //获取接收缓冲区的字符个数
         if RxCount>0 then
         begin
           if not RecvBuffInit then
           begin
              StrCopy(RecvBuff,'');
              RecvBuffInit:=True;
           end;
           StrCopy(TempBuff,'');
           ReadFile(hCommDev,Byte(TempBuff^),RxCount,dwReadByte,@read_os);//读字符存入
           //ReadFile(hCommDev,Byte(TempBuff^),RxCount,dwReadByte,@read_os);//读字符存入
                                                  //临时缓冲区中
           iRecvLen:=iRecvLen+dwReadByte; //接收到字符个数统计
           {
           if iRecvLen<13 then
           begin
              strcat(Recvbuff,TempBuff); //若接收到的切换台状态字符小于13个,
                              //将临时缓冲区中的字符拷贝到接收命令缓冲区,准备继续读
           end
           else
           begin
             strcat(Recvbuff,TempBuff);
             RecvCommand:=RecvBuff;
             //若接收到13个切换台状态字符进行如下处理
             if (RecvCommand[7]='P')
                and(RecvCommand[8]=SendCommand[7])     //比较读入的切换台端口状态
                and  (RecvCommand[9]=SendCommand[8])   //是否与切换指令中切换的端口
                and (RecvCommand[10]=SendCommand[9])   //一致
                and (RecvCommand[11]=SendCommand[10])  then

             begin
                SendCommandSuccess:=True;  //如果状态一致,则置该标志为真,标志切换成功
             end
             else
             begin
               SendCommandSuccess:=False;//否则,置该标志为假,表示切换失败
             end;
             iRecvLen:=0;
             StrCopy(RecvBuff,'');
             RecvBuffInit:=False;
             PurgeComm(hCommDev,PURGE_RXCLEAR ); //清空接收缓冲区
           end;
           }
           {
           if iRecvLen >=1 then
           begin
                inData := Byte(TempBuff^);
                if inData = $D9 then
                begin
                     SendCommandSuccess:=True;  //如果状态一致,则置该标志为真,标志切换成功

                end
                else
                begin
                     SendCommandSuccess:=False;//否则,置该标志为假,表示切换失败
                end;

                iRecvLen:=0;
                StrCopy(RecvBuff,'');
                RecvBuffInit:=False;
                PurgeComm(hCommDev,PURGE_RXCLEAR ); //清空接收缓冲区
           end
        end;
        ////////////////
        SetEvent(postRecvEvent); //置接收事件句柄为有信号状态,以便接收新字符

    end;
    }

    initialization
        RecvBuff:=StrAlloc(50*sizeof(Char));
        TempBuff:=StrAlloc(50*sizeof(Char));
    Finalization
        StrDispose(RecvBuff);
        StrDispose(TempBuff);
        CloseHandle(PostRecvEvent);
        CloseHandle(read_os.hEvent);
        CloseHandle(PostSendEvent);
        CloseHandle(write_os.hEvent);
    end.


     
  • 相关阅读:
    SVG PATH d参数的 ace
    如果你想动态创建一个iframe
    canvas构建一个平面直角坐标系
    JavaScript版几种常见排序算法
    【分享】 Stip,让表单验证轻松愉快。
    【分享】javascript合并混淆压缩
    【分享】页面提示插件更新
    nodejs 的 session 简单实现
    页面模块之间的通信依赖解决方案
    在平面旋转一个点
  • 原文地址:https://www.cnblogs.com/jimeper/p/340452.html
Copyright © 2020-2023  润新知