MainFrm.pas
上传用户:psxgmh
上传日期:2013-04-08
资源大小:15112k
文件大小:12k
源码类别:

Delphi/CppBuilder

开发平台:

Delphi

  1. unit MainFrm;
  2. interface
  3. uses
  4.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  5.   Dialogs, StdCtrls, Buttons, ComCtrls, ExtCtrls;
  6. const
  7.   WM_COMMNOTIFY = WM_USER + 365; // 通讯消息
  8. type
  9.   //接收串口数据的线程
  10.   TRecvThread = Class(TThread)
  11.   public
  12.     procedure Execute;override;
  13.   end;
  14.   TfrmMain = class(TForm)
  15.     pgcMain: TPageControl;
  16.     TabSheet1: TTabSheet;
  17.     TabSheet2: TTabSheet;
  18.     Panel1: TPanel;
  19.     btnOpenSend: TBitBtn;
  20.     btnSendData: TBitBtn;
  21.     btnCloseSend: TBitBtn;
  22.     Label5: TLabel;
  23.     edtSendCommName: TEdit;
  24.     edtSendBaudRate: TEdit;
  25.     Label1: TLabel;
  26.     Label2: TLabel;
  27.     cmbSendByteSize: TComboBox;
  28.     cmbSendStopBits: TComboBox;
  29.     Label3: TLabel;
  30.     Label4: TLabel;
  31.     cmbSendParity: TComboBox;
  32.     Panel2: TPanel;
  33.     Label6: TLabel;
  34.     Label7: TLabel;
  35.     Label8: TLabel;
  36.     Label9: TLabel;
  37.     Label10: TLabel;
  38.     btnOpenRecv: TBitBtn;
  39.     btnRecvData: TBitBtn;
  40.     btnCloseRecv: TBitBtn;
  41.     edtRecvCommName: TEdit;
  42.     edtRecvBaudRate: TEdit;
  43.     cmbRecvByteSize: TComboBox;
  44.     cmbRecvStopBits: TComboBox;
  45.     cmbRecvParity: TComboBox;
  46.     mmoRecv: TMemo;
  47.     Panel3: TPanel;
  48.     Panel4: TPanel;
  49.     mmoSend: TMemo;
  50.     Label11: TLabel;
  51.     edtSend: TEdit;
  52.     stbSend: TStatusBar;
  53.     stbRecv: TStatusBar;
  54.     procedure btnOpenSendClick(Sender: TObject);
  55.     procedure btnSendDataClick(Sender: TObject);
  56.     procedure btnCloseSendClick(Sender: TObject);
  57.     procedure btnOpenRecvClick(Sender: TObject);
  58.     procedure btnRecvDataClick(Sender: TObject);
  59.     procedure btnCloseRecvClick(Sender: TObject);
  60.     procedure FormCreate(Sender: TObject);
  61.     procedure edtSendBaudRateExit(Sender: TObject);
  62.     procedure edtRecvBaudRateExit(Sender: TObject);
  63.   private
  64.     //数据接收消息处理函数
  65.     procedure WMCOMMNOTIFY(var Message: TMessage); message WM_COMMNOTIFY;
  66.     procedure SetSendButton ;
  67.     procedure SetRecvButton;
  68.     { Private declarations }
  69.   public
  70.     { Public declarations }
  71.   end;
  72. var
  73.   frmMain: TfrmMain;
  74.   Post_Event: THandle;//创建事件同步对象的句柄
  75.   hSend : THandle;//发送串口的句柄
  76.   hRecv : THandle;//接收串口的句柄
  77.   Read_os: Toverlapped;//重叠结构的变量
  78.   Receive: Boolean; //开关变量,代表是否接收
  79. implementation
  80. {$R *.dfm}
  81. //主窗体被创建时,初始化界面显示
  82. procedure TfrmMain.FormCreate(Sender: TObject);
  83. begin
  84.   edtSendCommName.text := 'COM1';
  85.   edtSendBaudRate.text := '9600';
  86.   cmbSendByteSize.ItemIndex :=3;
  87.   cmbSendStopBits.ItemIndex :=0;
  88.   cmbSendParity.ItemIndex :=0;
  89.   edtRecvCommName.text := 'COM2';
  90.   edtRecvBaudRate.text := '9600';
  91.   cmbRecvByteSize.ItemIndex :=3;
  92.   cmbRecvStopBits.ItemIndex :=0;
  93.   cmbRecvParity.ItemIndex :=0;
  94. end;
  95. //互置发送按钮和输入框的有效性
  96. procedure TfrmMain.SetSendButton ;
  97. begin
  98.   edtSendCommName.Enabled := not edtSendCommName.Enabled ;
  99.   edtSendBaudRate.Enabled := not edtsendBaudRate.Enabled ;
  100.   cmbSendByteSize.Enabled := not cmbSendByteSize.Enabled ;
  101.   cmbSendStopbits.Enabled := not cmbSendStopbits.Enabled ;
  102.   cmbSendParity.Enabled := not cmbSendParity.Enabled ;
  103.   btnOpenSend.Enabled := not btnOpenSend.Enabled ;
  104.   btnSendData.Enabled := not btnSendData.Enabled ;
  105.   btnCloseSend.Enabled := not btnCloseSend.Enabled ;
  106. end;
  107. //互置接收按钮和输入框的有效性
  108. procedure TfrmMain.SetRecvButton ;
  109. begin
  110.   edtRecvCommName.Enabled := not edtRecvCommName.Enabled ;
  111.   edtRecvBaudRate.Enabled := not edtRecvBaudRate.Enabled ;
  112.   cmbRecvByteSize.Enabled := not cmbRecvByteSize.Enabled ;
  113.   cmbRecvStopbits.Enabled := not cmbRecvStopbits.Enabled ;
  114.   cmbRecvParity.Enabled := not cmbRecvParity.Enabled ;
  115.   btnOpenRecv.Enabled := not btnOpenRecv.Enabled ;
  116.   btnRecvData.Enabled := not btnRecvData.Enabled ;
  117.   btnCloseRecv.Enabled := not btnCloseRecv.Enabled ;
  118. end;
  119. //打开发送的串口
  120. procedure TfrmMain.btnOpenSendClick(Sender: TObject);
  121. var
  122.   dcb: TDCB;
  123.   Error: Boolean;
  124.   CommName : string;
  125. begin
  126.   CommName := edtSendCommName.Text ;
  127.   // 打开发送串口
  128.   hSend := CreateFile(PChar(CommName), GENERIC_WRITE, 0,
  129.     nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
  130.   if hSend = INVALID_HANDLE_VALUE then
  131.     raise Exception.Create('打开'+edtSendCommName.Text+'端口错误!');
  132.   // 设置输入和输出缓冲区大小
  133.   SetupComm(hSend, 1024, 1024);
  134.   //设置串口的波特率、字符位数、奇偶校验、停止位
  135.   GetCommState(hSend, dcb);
  136.   dcb.BaudRate := strToInt(edtSendBaudRate.Text);
  137.   dcb.ByteSize := strToInt(cmbSendByteSize.Text);
  138.   dcb.StopBits := cmbSendStopBits.ItemIndex ;
  139.   dcb.Parity := cmbSendParity.ItemIndex ;
  140.   Error := SetCommState(hSend, dcb);
  141.   if (not Error) then
  142.     raise Exception.Create('设置'+edtSendCommName.text+'错误');
  143.   stbSend.Panels[0].Text :=edtSendCommName.Text +'端口已打开';
  144.   stbSend.Refresh ;
  145.   SetSendButton;
  146. end;
  147. //向发送串口写数据
  148. procedure TfrmMain.btnSendDataClick(Sender: TObject);
  149. var
  150.   dwNumberOfBytesWritten, dwNumberOfBytesToWrite,
  151.   ErrorFlag, dwWhereToStartWriting: DWORD;
  152.   pDataToWrite: PChar;
  153.   write_os: Toverlapped;
  154. begin
  155.   dwWhereToStartWriting := 0;
  156.   dwNumberOfBytesWritten := 0;
  157.   //设置将要向串口里写的数据长度
  158.   dwNumberOfBytesToWrite := edtSend.GetTextLen;
  159.   if (dwNumberOfBytesToWrite = 0) then
  160.     raise Exception.Create('发送缓冲区为空');
  161.     //将edtcomm里的文本传到pDataToWrite缓冲区
  162.     pDataToWrite := Pchar(edtSend.Text);
  163.     FillChar(Write_Os, SizeOf(write_os), 'a');
  164.     // 为重叠写创建事件对象
  165.     Write_Os.hEvent := CreateEvent(nil, True, False, nil);
  166.     //设置直到最后一个字符被发送
  167.     SetCommMask(hSend, EV_TXEMPTY);
  168.     repeat
  169.        // 发送通讯数据
  170.       if not WriteFile(hSend, pDataToWrite[dwWhereToStartWriting],
  171.         dwNumberOfBytesToWrite, dwNumberOfBytesWritten,
  172.         @write_os) then
  173.       begin
  174.         ErrorFlag := GetLastError;
  175.         if ErrorFlag <> 0 then
  176.         begin
  177.           if ErrorFlag = ERROR_IO_PENDING then
  178.           begin
  179.             WaitForSingleObject(Write_Os.hEvent, INFINITE);
  180.             //等待设置好的事件发生
  181.             GetOverlappedResult(hSend, Write_os,
  182.               dwNumberOfBytesWritten, False);
  183.           end
  184.           else
  185.             raise Exception.Create('发送数据失败');
  186.         end;
  187.       end;
  188.       //减去已发生的数据长度
  189.       Dec(dwNumberOfBytesToWrite, dwNumberOfBytesWritten);
  190.       //记录已发送的数据长度
  191.       Inc(dwWhereToStartWriting, dwNumberOfBytesWritten);
  192.     //直到全部发送完
  193.     until (dwNumberOfBytesToWrite <= 0);
  194.     mmoSend.Lines.Add('已发送:'+intToStr(dwWhereToStartWriting)+'个字节的数据');
  195. end;
  196. //关闭发送串口
  197. procedure TfrmMain.btnCloseSendClick(Sender: TObject);
  198. begin
  199.   CloseHandle(hSend);
  200.   stbSend.Panels[0].Text :=edtSendCommName.Text +'端口已关闭';
  201.   stbSend.Refresh ;
  202.   setSendButton;
  203. end;
  204. //打开接收串口
  205. procedure TfrmMain.btnOpenRecvClick(Sender: TObject);
  206. var
  207.   dcb: TDCB;
  208.   Error: Boolean;
  209.   CommName : string;
  210. begin
  211.   CommName := edtRecvCommName.Text ;
  212.   // 打开通讯端口
  213.   hRecv := CreateFile(PChar(CommName),GENERIC_Read, 0,
  214.     nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
  215.   if hRecv = INVALID_HANDLE_VALUE then
  216.     raise Exception.Create('打开'+edtSendCommName.Text+'端口错误!');
  217.   Error := SetCommMask(hRecv,EV_RXCHAR);
  218.   if (not Error) then
  219.   raise Exception.Create('SetCommMask错误');
  220.   // 设置缓冲区大小及主要通讯参数
  221.   SetupComm(hRecv, 1024, 1024);
  222.   //设置串口的波特率、字符位数、奇偶校验、停止位
  223.   GetCommState(hRecv, dcb);
  224.   dcb.BaudRate := strToInt(edtRecvBaudRate.Text);
  225.   dcb.ByteSize := strToInt(cmbRecvByteSize.Text);
  226.   dcb.StopBits := cmbRecvStopBits.ItemIndex ;
  227.   dcb.Parity := cmbRecvParity.ItemIndex ;
  228.   Error := SetCommState(hRecv, dcb);
  229.   if (not Error) then
  230.     raise Exception.Create('设置'+edtRecvCommName.text+'错误');
  231.   stbRecv.Panels[0].Text :=edtSendCommName.Text +'端口已打开';
  232.   stbRecv.Refresh ;
  233.   SetRecvButton;
  234.   btnRecvData.Enabled := True;
  235. end;
  236. //开始接收串口数据
  237. procedure TfrmMain.btnRecvDataClick(Sender: TObject);
  238. var
  239.   dcb: TDCB;
  240.   recvThread : TRecvThread;
  241. begin
  242.   FillChar(Read_Os, SizeOf(Read_Os), 0);
  243.   Read_Os.Offset := 0;
  244.   Read_Os.OffsetHigh := 0;
  245.   // 创建Overlapped事件
  246.   Read_Os.hEvent := CreateEvent(nil, true, False, nil);
  247.   if Read_Os.hEvent = null then
  248.   begin
  249.     CloseHandle(hRecv);
  250.     raise Exception.Create('CreateEvent Error!')
  251.   end;
  252.   //创建Post_Event事件
  253.   Post_Event := CreateEvent(nil, True, True, nil);
  254.   if Post_Event = null then
  255.   begin
  256.     CloseHandle(hRecv);
  257.     CloseHandle(Read_Os.hEvent);
  258.     raise Exception.Create('CreateEvent Error!')
  259.   end;
  260.   // 建立通信监视线程
  261.   recvThread := TRecvThread.Create(false);
  262.   //发送DTR信号
  263.   EscapeCommFunction(hRecv, SETDTR);
  264.   btnRecvData.Enabled := False;
  265.   stbRecv.Panels[0].Text :='正在接收数据';
  266.   stbRecv.Refresh;
  267. end;
  268. //关闭接收串口
  269. procedure TfrmMain.btnCloseRecvClick(Sender: TObject);
  270. begin
  271.   Receive := False;
  272. //关闭事件和串口
  273.   CloseHandle(Read_Os.hEvent);
  274.   CloseHandle(Post_Event);
  275.   CloseHandle(hRecv);
  276.   stbRecv.Panels[0].Text :=edtSendCommName.Text +'端口已关闭';
  277.   stbRecv.Refresh ;
  278.   SetRecvButton;
  279.   btnRecvData.Enabled := False;
  280. end;
  281. //接收串口数据的线程执行体
  282. procedure TRecvThread.Execute ;
  283. var
  284.   dwEvtMask, dwTranser: Dword;
  285.   Ok: Boolean;
  286.   Os: Toverlapped;
  287. begin
  288.   Receive := True;
  289.   FillChar(Os, SizeOf(Os), 0);
  290.   // 创建重叠读事件对象
  291.   Os.hEvent := CreateEvent(nil, True, False, nil);
  292.   if Os.hEvent = null then
  293.   begin
  294.     MessageBox(0, 'Os.Event Create Error !', 'Notice', MB_OK);
  295.     Exit;
  296.   end;
  297.   if (not SetCommMask(hRecv, EV_RXCHAR)) then
  298.   begin
  299.     MessageBox(0, 'SetCommMask Error !', 'Notice', MB_OK);
  300.     Exit;
  301.   end;
  302.   while (Receive) do
  303.   begin
  304.     dwEvtMask := 0;
  305.     // 等待通讯事件发生
  306.     if not WaitCommEvent(hRecv, dwEvtMask, @Os) then
  307.     begin
  308.       if ERROR_IO_PENDING = GetLastError then
  309.         GetOverLappedResult(hRecv, Os, dwTranser, True)
  310.     end;
  311.     if ((dwEvtMask and EV_RXCHAR) = EV_RXCHAR) then
  312.     begin
  313.     // 等待允许传递WM_COMMNOTIFY通讯消息
  314.       WaitForSingleObject(Post_event, INFINITE);
  315.     // 处理WM_COMMNOTIFY消息时不再发送WM_COMMNOTIFY消息
  316.       ResetEvent(Post_Event);
  317.     // 传递WM_COMMNOTIFY通讯消息
  318.       Ok := PostMessage(frmMain.Handle, WM_COMMNOTIFY, hRecv, 0);
  319.       if (not Ok) then
  320.       begin
  321.         MessageBox(0, 'PostMessage Error !', 'Notice', MB_OK);
  322.         Exit;
  323.       end;
  324.     end;
  325.   end;
  326.   CloseHandle(Os.hEvent); // 关闭重叠读事件对象
  327. end;
  328. // 数据接收消息处理函数
  329. procedure TfrmMain.WMCOMMNOTIFY(var Message: TMessage);
  330. var
  331.   CommState: ComStat;
  332.   dwNumberOfBytesRead: Dword;
  333.   ErrorFlag: Dword;
  334.   InputBuffer: array[0..1024] of Char;
  335.   recvString : string;
  336. begin
  337.   if not ClearCommError(hRecv, ErrorFlag, @CommState) then
  338.   begin
  339.     MessageBox(0, 'ClearCommError !', 'Notice', MB_OK);
  340.     PurgeComm(hRecv, Purge_Rxabort or Purge_Rxclear);
  341.     Exit;
  342.   end;
  343.   if (CommState.cbInQue > 0) then
  344.   begin
  345.     fillchar(InputBuffer, CommState.cbInQue, #0);
  346.       // 接收通讯数据
  347.     if (not ReadFile(hRecv, InputBuffer, CommState.cbInQue,
  348.       dwNumberOfBytesRead, @Read_os)) then
  349.     begin
  350.       ErrorFlag := GetLastError();
  351.       if (ErrorFlag <> 0) and (ErrorFlag <> ERROR_IO_PENDING) then
  352.       begin
  353.         Receive := False;
  354.         raise Exception.Create('读串口数据出错!');
  355.       end
  356.       else
  357.       begin
  358.         WaitForSingleObject(hRecv, INFINITE); // 等待操作完成
  359.         GetOverlappedResult(hRecv, Read_os,
  360.           dwNumberOfBytesRead, False);
  361.       end;
  362.     end;
  363.     if dwNumberOfBytesRead > 0 then
  364.     begin
  365.       Read_Os.Offset := Read_Os.Offset + dwNumberOfBytesRead;
  366.       // 处理接收的数据
  367.       InputBuffer[dwNumberOfBytesRead]:=#0;
  368.       mmoRecv.Lines.Add('接收到:'+intToStr(dwNumberOfBytesRead)+'个字节的数据');
  369.       mmoRecv.Lines.Add(strPas(inputBuffer));
  370.     end;
  371.   end;
  372.  // 允许发送下一个WM_COMMNOTIFY消息
  373.   SetEvent(Post_Event);
  374. end;
  375. //检查发送串口的波特率输入框输入的是否是整数
  376. procedure TfrmMain.edtSendBaudRateExit(Sender: TObject);
  377. var
  378.   i: integer;
  379. begin
  380.   try
  381.     i := strToInt(edtSendBaudRate.Text)
  382.   except
  383.     edtSendBaudRate.setfocus;
  384.     raise Exception.Create('波特率设置错误');
  385.   end;
  386. end;
  387. //检查接收串口的波特率输入框输入的是否是整数
  388. procedure TfrmMain.edtRecvBaudRateExit(Sender: TObject);
  389. var
  390.   i: integer;
  391. begin
  392.   try
  393.     i := strToInt(edtRecvBaudRate.Text)
  394.   except
  395.     edtRecvBaudRate.setfocus;
  396.     raise Exception.Create('波特率设置错误');
  397.   end;
  398. end;
  399. end.