自己用API写程序不就的了,用别人的控件总是感到心里没底。其实对串口操作很简单的。

解决方案 »

  1.   


    Delphi中串行通信的实现
    本 文 就 是 介 绍 基 于Windows95/NT 操 作 系 统 用Delphi 来 实 现PC 机 与 下 层PLC 控 制 器 之 间 的 串 口 通 信 方 法。             ---- 基 于WIN95/NT 的 串 行 通 信 机 制             ---- Windows 操 作 系 统 的 机 制 禁 止 应 用 程 序 直 接 访 问 计 算 机 硬 件, 但 它 为 程 序 员 提 供 了 一 系 列 的 标 准API 函 数, 使 得 应 用 程 序 的 编 制 更 加 方 便 并 且 免 除 了 对 有 关 硬 件 的 调 试 麻 烦。 在Windows95/NT 中, 原 来Windows3.X 的WM_COMMNOTIFY 消 息 已 被 取 消, 操 作 系 统 为 每 个 通 信 设 备 开 辟 了 用 户 可 定 义 大 小 的 读/ 写 缓 冲 区, 数 据 进 出 通 信 口 均 由 操 作 系 统 后 台 完 成, 应 用 程 序 只 需 对 读/ 写 缓 冲 区 操 作 即 可。WIN95/NT 中 几 个 常 用 的 串 行 通 信 操 作 函 数 如 下:             CreatFile
                打 开 串 行 口
                CloseHandle
                关 闭 串 行 口
                SetupComm
                设 置 通 信 缓 冲 区 的 大 小
                ReadFile
                读 串 口 操 作
                WriteFile
                写 串 口 操 作
                SetCommState
                设 置 通 信 参 数
                GetCommState
                获 取 默 认 通 信 参 数
                ClearCommError
                清 除 串 口 错 误 并 获 取 当 前 状 态            ---- 除 上 述 几 个 函 数 外, 还 要 经 常 用 到 一 个 重 要 的 记 录DCB( 设 备 控 制 块)。DCB 中 记 录 有 可 定 义 的 串 行 口 参 数, 设 置 串 行 口 参 数 时 必 须 先 用GetCommState 函 数 将 系 统 默 认 值 填 入DCB 控 制 块, 然 后 才 可 把 用 户 想 改 变 的 自 定 义 值 设 定。 
                ---- 在WIN95/NT 中 进 行 串 行 通 信 除 了 解 基 本 的 通 信 操 作 函 数 外, 还 要 掌 握 多 线 程 编 程。 线 程 是 进 程 内 部 执 行 的 路 径, 是 操 作 系 统 分 配CPU 时 间 的 基 本 实 体。 每 个 进 程 都 由 单 线 程 开 始 完 成 应 用 程 序 的 执 行。 串 行 通 信 需 要 利 用 多 线 程 技 术 实 现,其 主 要 的 处 理 逻 辑 可 以 表 述 如 下: 进 程 一 开 始 先 由 主 线 程 做 一 些 必 要 的 初 始 化 工 
    作, 然 后 主 线 程 根 据 需 要 在 适 当 时 候 建 立 通 信 监 视 线 程 监 视 通 信 口, 当 指 定 的 串 
    行 口 事 件 发 生 时, 向 主 线 程 发 送WM_COMMNOTIFY 消 息( 由 于WIN95 取 消 了WM_COMMNOTIFY 消 息, 因 此 必 须 自 己 创 建), 主 线 程 对 其 进 行 处 理。 若 不 需 要WM_COMMNOTIFY 消 息, 则 主 线 程 终 止 通 信 监 视 线 程。             ---- 多 线 程 同 时 执 行, 将 会 引 起 对 共 享 资 源 的 冲 突。 为 避 免 冲 突, 就 要 用 同 步 多 线 程 对 共 享 资 源 进 行 访 问。WIN95 提 供 了 许 多 保 持 线 程 同 步 的 方 法, 笔 者 采 用 创 建 事 件 对 象 来 保 持 线 程 同 步。 通 过CraeteEvent() 创 建 事 件 对 象, 使 用SetEvent() 
    或PulseEvent() 函 数 将 事 件 对 象 设 置 成 信 号 同 步。 在 应 用 程 序 中, 利 用WaitSingleObject() 函 数 等 待 同 步 的 触 发, 等 到 指 定 的 事 件 被 其 它 线 程 设 置 为 有 信 号 时, 才 继 续 向 下 执 行 程 序。             ---- Delphi 下 的 具 体 实 现 方 法             ---- Delphi 的 强 大 功 能 和 支 持 多 线 程 的 面 向 对 象 编 程 技 术, 使 得 实 现 串 行 通 信 非 常 简 单 方 便。 它 通 过 调 用 外 部 的API 函 数 来 实 现, 主 要 步 骤 如 下: 首 先, 利 
    用CreateFile 函 数 打 开 串 行 口, 以 确 定 本 应 用 程 序 对 此 串 行 口 的 占 有 权, 并 封 锁 其 它 应 用 程 序 对 此 串 口 的 操 作; 其 次, 通 过GetCommState 函 数 填 充 设 备 控 制 块DCB, 再 通 过 调 用SetCommState 函 数 配 置 串 行 口 的 波 特 率、 数 据 位、 校 验 位 和 停 止 位。 然 后, 创 建 串 行 口 监 视 线 程 监 视 串 行 口 事 件。 在 此 基 础 上 就 可 以 在 相 应 的 串 口 上 操 作 数 据 的 传 输; 最 后, 用CloseHandle 函 数 关 闭 串 行 口。 具 体 的 程 序 如 下, 本 程 序 用Delphi3.0 编 制 在Win95 环t 境 下 调 试 通 过, 已 投 入 实 际 应 用 中, 供 广 大 读 者 参 考。             ---- 程 序:             unit comdemou;
                interface
                uses
                Windows, Messages, SysUtils, Classes, 
                Graphics, Controls, Forms, Dialogs;            const
                Wm_commNotify=Wm_User+12;
                type
                TForm1 = class(TForm)
                procedure FormCreate(Sender: TObject);
                private
                Procedure comminitialize;
                Procedure MsgcommProcess(Var 
                Message:Tmessage); Message Wm_commnotify;
                { Private declarations }
                public
                { Public declarations }
                end;            //线程声明
                TComm=Class(TThread)
                protected
                procedure Execute;override;
                end;            var
                Form1: TForm1;
                hcom,Post_Event:Thandle;
                lpol:Poverlapped;
                implementation            {$R *.DFM}            Procedure TComm.Execute; //线程执行过程
                var
                dwEvtMask:Dword;
                Wait:Boolean;
                Begin
                fillchar(lpol,sizeof(toverlapped),0);
                While True do Begin
                dwEvtMask:=0;
                Wait:=WaitCommEvent(hcom,dwevtmask,lpol); 
                //等待串行口事件;
                if Wait Then Begin
                waitforsingleobject(post_event,infinite); 
                //等待同步事件置位;
                resetevent(post_event); //同步事件复位;
                PostMessage(Form1.Handle,
                WM_COMMNOTIFY,0,0);//发送消息;
                end;
                end;
                end;            procedure Tform1.comminitialize; 
                //串行口初始化
                var
                lpdcb:Tdcb;
                Begin
                hcom:=createfile('com2',generic_read or
                generic_write,0,nil,open_existing,
                file_attribute_normal or
                file_flag_overlapped,0);//打开串行口
                if hcom=invalid_handle_value then
                else
                setupcomm(hcom,4096,4096); 
                //设置输入,输出缓冲区皆为4096字节
                getcommstate(hcom,lpdcb); 
                //获取串行口当前默认设置
                lpdcb.baudrate:=2400;
                lpdcb.StopBits:=1;
                lpdcb.ByteSize:=8;
                lpdcb.Parity:=EvenParity; //偶校验
                Setcommstate(hcom,lpdcb);
                setcommMask(hcom,ev_rxchar); 
                //指定串行口事件为接收到字符;
                end;            Procedure TForm1.Msgcomm
                Process(Var Message:Tmessage);
                var
                Clear:Boolean;
                Coms:Tcomstat;
                cbNum,ReadNumber,lpErrors:Integer;
                Read_Buffer:array[1..100]of char;
                Begin
                Clear:=Clearcommerror(hcom,lpErrors,@Coms);
                if Clear Then Begin
                cbNum:=Coms.cbInQue;
                ReadFile(hCom,Read_Buffer,
                cbNum,ReadNumber,lpol);
                //处理接收数据
                SetEvent(Post_Event); 
                //同步事件置位
                end;
                end;            procedure TForm1.FormCreate(Sender: TObject);
                begin
                comminitialize;
                post_event:=CreateEvent
                (nil,true,true,nil); //创建同步事件;
                Tcomm.Create(False); 
                //创建串行口监视线程;
                end;            end