2024年6月11日发(作者:)
第
23
卷第
2
期
2004
年
6
月
计 算 技 术 与 自 动 化
ComputingTechnologyandAutomation
Vol
1
23,No
1
2
Jun
1
2004
文章编号
:1003-6199
(
2004
)
02-0070-04
Win32
环境下基于
VC++6.0
串口通信编程方法
杨 锋
,
桂卫华
,
陈 峰
,
冯磊华
(
中南大学 信息科学与工程学院
,
湖南 长沙
410083
)
摘 要
:
本文介绍了在
Windows32
环境下串口通信的实现机制
,
提出了用
VC++6.0
实现目前常用串口通信程序的四种方法
,
同时分析了这四种方法的优缺点。最后结合深海底
自动采矿实例
,
实现水下工控机与光端机之间串口数据通信。
关键词
:
串口通信
;API
标准通信函数
;
单线程
;
多线程
中图分类号
:TP311.11
文献标识码
:A
SerialCommunicationProgrammingMethodsBasedVisual
C++6.0inWin32Environment
YANGFeng,GUIWei
2
hua,CHENFeng,FENGLei
2
hua
(
CollegeofInformationScienceandEngineering,CentralSouthUniversity,Changsha410083,China
)
Abstract:Therealizedpri
putsforwardfourmethodswhichisusuallyusedtoserialcommunicationprogrammingusingVisualC++6.
0now.,oneofthefourmethods
isusedindeepseabedautomaticminingandtheserialdatacommunicationbetweenthedeepseaengineering
controlmachineandthefiberoptionsisfinished.
Keywords:serialcommunication;APIstandardcommunicationfunction;singleprocess;multipleprocess
1
引言
在远程监控和工业自动化领域系统中
,
串口通
信的应用越来越广泛。在
DOS
环境下
,
其系统接
口中
DOSINT21H
的
03H
和
04H
号功能调用为
异步串行通信的接受和发送功能
,
而
BIOS
INT14H
有
4
组功能调用为串行通信服务
,
因此采
用寄存器直接读写
,BIOS
调用
,
通信中断程序等方
法就可以比较容易实现串口通信。但是在
Win
2
dows
环境下
,Windows
采用消息驱动和设备统一
管理
,
以及利用消息队列进行程序控制
,
所以
DOS
下的方法都不宜采用。在
Windows
中为实现串口
通信
,Windows
的
SDK
提供了完备的
API
函数和
以中断方式驱动的通信驱动程序
,
使编程变得较为
容易。
Windows
提供的标准通信
API
函数很多。
VisualC++
由于功能强大和应用灵活
,
同时得到
Miscrosoft
系统的最好支持
,
因此
VisualC++
经
常用作串口通信开发工具。本文就
Win32
环境下
基于
VC++
开发串口通信四种方式的编程问题展
开讨论
,
最后给出用其中的一种方法
-MSComm
控件实现深海底自动采矿系统中水下工控机与光
端机之间的串口通信应用实例。
2
基于
VC++
串口通信编程的四种方式
及其比较
2
1
1
基于
VC++
串口通信编程的四种方式
2.1.1
利用
VC++
运行时库的标准通信函数实
现串口编程
(
1
)
初始化串行通讯口
通过计算机串口进行通讯之前
,
必须根据监控
设备的有关通讯参数
,
约定双方的通讯方式
,
包括
波特率的设置、奇偶位校验及停止位的设立。确定
收稿日期
:2004-02-05
)
,
男
,
湖北黄冈人
,
硕士研究生
,
主要研究方向
:
工业过程监控
,
自动化仪表。作者简介
:
杨锋
(
1979
—
第
23
卷第
2
期杨 锋等
:Win32
环境下基于
VC++6.0
串口通信编程方法
71
数据传输帧格式
,
确定
UART
操作方式。逐个对
线路控制寄存器、波特率因子寄存器和
MODEM
寄存器写入操作。
(
2
)
查询发送流程
———只需
CPU
检测到
UART
发送器保持寄
存器为空
,
即向
UART
输出一个字符。发送方首
先输出
RTS
和
DTR
有效
,
检测
MODEM
寄存器
,
只有收到
DEC
输入的
CTS
、
DSR
有效
,CPU
才向
UART
输出一发送字符。
(
3
)
查询接收流程
———只需
CPU
检测到
UART
接收器数据准
备就绪
,
即可从接收器数据寄存器中读取一字符。
接收方首先输出数据终端就绪有效
(
DTR=1
)
,
然
后检测
MODEM
状态寄存器
,
只有
DSR=1,CPU
才接收一字符。
2.1.2
采用
ActiveX
控件
(
MSComm
控件
)
编程
MicrosoftCommunicationsControl
(
以下简称
MSComm
)
是
Microsoft
公司提供的简化
Windows
下串行通信编程的
ActiveX
控件
,
它为应用程序提
供了通过串行接口收发数据的简便方法。具体地
说
,
它提供了两种处理通信问题的方法
:
一是事件
驱动
(
Event-driven
)
方法
:
主要是利用
OnComm
事件捕获并处理这些通信事件
,
也可以检查和处理
通信错误
;
一是查询法
:
在这种情况下
,
每当应用程
序执行完某一串行口操作后
,
将不断检查
MSComm
控件的
CommEvent
属性以检查执行结
果或者检查某一事件是否发生。
以下介绍在
VC
集成开发环境下对该控件编
程的步骤。
(
1
)
在当前的
Workspace
中插入
MSComm
控件
(
2
)
在
MainFrm.h
中加入
MSComm
控件
protected:
CMSCommm
-
ComPort;
(
3
)
初始化串口
m
-
mPort
(
1
)
;//
选择
COM1
m
-
ufferSize
(
1024
)
;//
设置
输入缓冲区的大小
,Bytes
m
-
BufferSize
(
512
)
;//
设置
有一个字符引发一个事件
m
-
utLen
(
0
)
;
(
4
)
捕捉串口事件
MSComm
控件可以采用轮询或事件驱动的两
种方法从端口获取数据。比较常用的是事件驱动
方法
:
有事件
(
如接收到数据
)
时通知程序。在程序
中需要捕获并处理这些通讯事件。
(
5
)
串口读写
完成读写的两个函数的原型是
VARIANT
GetInput
()
;
及
voidSetOutput
(
constVARIANT&
newValue
)
;
都要使用
VARIANT
类型。首先由函
数
GetInBufferCount
()
检查串口接收到的字符数
,
然后由
GetInput
()
函数读取这些已接收的字节。
用
SetOutput
函数将数据从串口发送出去。
2.1.3
在单线程中实现自定义的串口通信类
———控件简单易用
,
但由于必须拿到对话框
中使用
,
在一些需要在线程中实现通信的应用场
合
,
控件的使用显得捉襟见肘。此时
,
若能够按不
同需要定制灵活的串口通信类将弥补控件的不足
,
以下将介绍如何在单线程中建立自定义的通信类。
———该通信类
CSimpleComm
需手动加入头文
件与源文件
,
其基类为
CObject,
大致建立步骤如下
:
(
1
)
打开串口
,
获取串口资源句柄
———通信程序从
CreateFile
处指定串口设备
及相关的操作属性
,
再返回一个句柄
,
该句柄将被
用于后续的通信操作
,
并贯穿整个通信过程。
(
2
)
串口设置
———串口打开后
,
其属性被设置为默认值
,
根
据具体需要
,
通过调用
GetCommState
(
hComm,
&dcb
)
读取当前串口设备控制块
DCB
(
DeviceCon
2
trolBlock
)
设置
,
修改后通过
SetCommState
(
hComm,&dcb
)
将其写入。再需注意异步读写的
超时控制设置
,
通过
COMMTIMEOUTS
结构设
置超时
,
调用
SetCommTimeouts
(
hComm,&time
2
outs
)
将结果写入。见下示例
:BOOLCSim
2
pleComm::Open
()
{
DCBdcb;
m
-
hIDComDev=CreateFile
(
“
COM2
“
,
GENERIC
-
READ|GENERIC
-
WRITE,0,
NULL,OPEN
-
EXISTING,FILE
-
ATTRIBUTE
-
NORMAL|FILE
-
FLAG
-
OVERLAPPED,
NULL
)
;//
打开串口
,
异步操作
if
(
m
-
hIDComDev==NULL
)
return
(
FALSE
)
;
gth=sizeof
(
DCB
)
;
输出缓冲区的大小
,Bytes,
if
(
!m
-
tOpen
())
;//
打开串口
m
-
tOpen
(
TRUE
)
;
m
-
utMode
(
1
)
;//
设置输入
方式为二进制方式
(
9600,n,8,1
”
)
;//m
-
tings
“
设置波特率等参数
m
-
reshold
(
1
)
;//
为
1
表示
72
计算技术与自动化
2004
年
6
月
GetCommState
(
m
-
hIDComDev,&dcb
)
;//
获得端口默认设置
te=CBR
-
4800;
……
}
(
3
)
串口读写操作
———主要运用
ReadFile
()
与
WriteFile
()
API
函数
,
若为异步通信方式
,
两函数中最后一个参数
为指向
OVERLAPPED
结构的非空指针
,
在读写函
数返回值为
FALSE
的情况下
,
调用
GetLastError
()
函数
,
返回值为
ERROR
-
IO
-
PENDING,
表明
I/O
操作悬挂
,
即操作转入后台继续执行。此时
,
可以用
WaitForSingleObject
()
来等待结束信号并
设置最长等待时间。举例如下
:
BOOLbReadStatus;
bReadStatus=ReadFile
(
m
-
hIDComDev,
buffer,dwBytesRead,&dwBytesRead,&m
-
OverlappedRead
)
;
if
(
!bReadStatus
)
{
if
(
GetLastError
()
==ERROR
-
IO
-
PEND
2
ING
)
{
WaitForSingleObject
(
m
-
OverlappedRead.
hEvent,1000
)
;
return
((
int
)
dwBytesRead
)
;}
return
(
0
)
;}
return
((
int
)
dwBytesRead
)
;}
———定义全局变量
m
-
Serial
作为新建通信类
CSimpleComm
的对象
,
通过调用类的成员函数即
可实现所需串行通信功能。与方法二相比
,
方法三
赋予串行通信程序设计较大的灵活性
,
端口的读写
可选择较简单的查询式
,
或通过设置与外设数据发
送时间间隔
TimeCycle
相同的定时器
:SetTimer
(
1,TimeCycle,NULL
)
,
进行定时读取或发送。
———若对端口数据的响应时间要求较严格
,
可
采用事件驱动
I/O
读写
,Windows
定义了
9
种口
通信事件
,
较常用的有
:EV
-
RXCHAR
、
EV
-
TX
2
EMPTYEV
-
RXFLAG
。在用
SetCommMask
()
指
定了有用的事件后
,
应用程序可调用
WaitCom
2
mEvent
()
来等待事件的发生。
SetCommMask
(
hComm,0
)
可使
WaitCommEvent
()
中止。
2.1.4
多线程下实现串行通信
———
VC++
把线程分为两种
:
用户界面线程和
实现方式
优点
缺点
运用标准通信函数
编程原理简单
需要了解硬件电路
结构原理
CMSComm
控件
工作者线程。用户界面线程能够提供界面和用户交
互
,
通常用于处理用户输入并相应各种事件和消息
;
而工作者线程主要用来处理程序的后台任务。程序
通过调用
AfxBeginThread
()
函数就会自动创建一个
CWinThread
对象
,
从而开始一个进程。线程的终止
取决于下列事件之一
:
线程函数返回
;
线程调用
ExitThread
()
退出
;
异常情况下用线程的句柄调用
TerminateThread
()
退出
;
线程所属的进程被终止。进
行串口通信处理的不同线程之间需要协调运行。
VC++
提供了同步对象来协调多线程的并行
,
常用
的有以下几种
:Csemaphore
(
信号灯对象
)
、
Cmutex
(
互斥量对象
)
、
Cevent
(
事件对象
)
、
CcriticalSection
(
临界区对象
)
多线程下串口初始化与单线程相似。
在串口初始化成功后
,
就可以建立监控线程处理串
口通信事件。下面是该线程的关键代码。
UINTCommThread
(
LPVOIDpParam
)
//
用
于监控串口的工作者线程
{BOOLbResult=FALSE;
if
(
m
-
hComm
)
//
查看端口是否打开
PurgeComm
(
m
-
hComm,PURGE
-
RX
2
CLEAR|PURGE
-
TXCLEAR|PURGE
-
RX
2
ABORT|PURGE
-
TXABORT
)
;
for
(
;;
)
//
只要线程运行
,
就处于监视端口行
为的无限循环
{bResult=WaitCommEvent
(
m
-
hComm,
&Event,&m
-
ov
)
;
//m
-
ov
是
OVERLAPPED
类型的成员变量
if
(
!bResult
)
{//
进行出错处理
}
else{Event=WaitForMultipleObjects
(
4,m
-
hEvent,FALSE,INFINITE
)
;
//
无限等待设定的事件发生
switch
(
Event
)
{//
读写事件的响应处理过程
,
在此略
}
}
return0;
}
这样监控主程序就可以使用
AfxBeginThread
()
函数来产生
CommThread
串口监控线程。如果
要实现对所有端口的同时监控
,
可以分别对端口建
立监控线程。
2
1
2
四种串口通信编程方法的比较
:
单线程
较灵活
只适用于较简单的
系统
多线程
灵活
,
准确
,CPU
利用率高
,
适用
于要求较高的实时监控系统
线程同步较难
编程容易实现
,
简洁
方便
,
不需了解细节
仅在对话框中使用
第
23
卷第
2
期杨 锋等
:Win32
环境下基于
VC++6.0
串口通信编程方法
73
图
1
深海底采矿机器人遥测遥控系统结构图
3
实例
深海底自动采矿系统如图
1
。在通信方面
,
水
面遥控站与水下监控站之间的通信采用光纤实现。
而针对深海底工控机与水下光端机之间
,
传输的数
据量
(
传感器数据
)
较多
,
不宜采用并口。我们采用
简单易用的
MSComm
通信控件来进行深海底工控
机与水下光端机之间的串口通信。
通信协议数据包的格式为
:
$
xxxx%ssss%
…
%ssss
3
hh
(
串头为$
,
串尾为3
;xxxx
为传输数
据变量的个数
,
共有
4
位
,
如果数据位不够
,
前面的
数据补零标识
;ssss
为传输数据变量
,
中间以
%
隔
开
,
最后是
hh
校验
)
编程环境为
:VisualC++6.0,Windows2000
(
源程序略
)
本串口通信程序在
VC++6.0
下编译通过
,
经调试运行
,
效果良好。
4
结论
VC++
是一个非常优秀的用户平台
,
采用
MSComm
控件进行串口通信编程非常简便实用
,
在深海底自动采矿系统中得到了充分应用。在具
体实践中要结合功能需要
,
综合考虑复杂程度、灵
活性等因素
,
选择合适的方法
,
实现串口通信。
参考文献
:
[1]
王颖
.
用
VC6.0
实现串行通信的三种方法
[J].VC
知识库在
线帮助期刊第
9
期
.
[2]
吴凤化
.WIN95
界面下的
VC++
串口通信程序
[J].
南京石
油物探研究所
.
[3]
李现勇
.VisualC++
串口通信技术与工程实践
[M].
北京
:
人
民邮电出版社
.
[4]
陆尔东
,
邓利平
.
多线程技术在
VC++
串口通信程序中的应
用研究
[J].
啸峰工作室串口通信
VC
编程
.
[5]
陈峰
,
桂卫华
,
王随平
,
沈德耀
,
唐朝晖
,
深海底采矿机器人遥
测遥控系统
[J].
中南大学学报
,2003
年
34
期增刊
2.
发布评论