- 在线时间
- 0 小时
- 最后登录
- 2007-9-23
- 注册时间
- 2004-9-10
- 听众数
- 3
- 收听数
- 0
- 能力
- 0 分
- 体力
- 9975 点
- 威望
- 7 点
- 阅读权限
- 150
- 积分
- 4048
- 相册
- 0
- 日志
- 0
- 记录
- 0
- 帖子
- 1893
- 主题
- 823
- 精华
- 2
- 分享
- 0
- 好友
- 0

我的地盘我做主
该用户从未签到
 |
< > </P>
' u4 O1 L9 S* [- H( G< >姜滨 </P>
6 R. m9 {7 s9 H% F+ j8 D< > </P>! e* u. T/ S, r$ O% _
< > ·串口操纵的基本方法· </P>: ] n/ {* X* g: P; d0 e
< > </P>: q& a( y0 B" `& B. X7 G
< > </P>3 Y& n+ N0 B. o* m# b
< > 在Win32下,对串口的操作就如同对文件一样打开或关闭,对串行数据的读 </P>3 s2 m$ C6 C0 O G% h }
< >写可在用户定义的读写缓冲区中进行。具体使用的函数为: </P>
: i+ m9 ^, S0 I* a< > </P>/ v' F4 k$ _( e- @. S* c7 `; U+ n
< > 首先用CreateFile( )打开通信串口,其中参数lpFileName指向串口逻辑名 </P>3 `6 M& ^( e, O$ I. P$ g
< >,如“COM1”或“COM2”等,参数dwDesiredAccess定义文件的读写权限,一般 </P>, O% N: j* M; c. c
< >设为GENERIC—READ|GENERIC—WRITE;参数dwShareMode定义资源共享方式,此 </P>
3 ]! B6 Q2 ]5 T& @8 V5 o- t! y* G! i< >处必须设为0,为独占方式;lpSecurityAttributes定义安全属性,Win 95下为 </P>4 Q9 p4 C* U4 [# m- a& V, V
< >NULL;dwCreationDistribution定义文件创建方式;dwFlagsAndAttributes定义 </P>) P4 q% g5 b2 v, x
< >文件属性和标记,应设为FILE—FLAG—OVERLAPPED,表示异步通信方式; </P>7 u9 |! p5 W* z, Y2 u( q
< >hTemplateFile 指向一个模板文件的句柄,在 Windows 95下为NULL。 </P>" z8 Z) e8 E1 n% d
< > </P>
5 R* y$ R, H% ?2 I( y% J% M: i' i< > 然后用BuildCommDCB( )和SetCommState( )函数通过通信设备控制块DCB( </P>0 f2 M$ c: f( L8 b. ]
< >Device Control Block)设置串口通信参数(如波特率、停止位、数据位、校验 </P>
' q! B& O3 z4 x, d$ q4 x< >位等),其中BuildCommDCB( )中的字符串参数lpDef 定义同DOS命令中MODE的参 </P>
3 `' A' C$ e. T5 R0 J, p4 n< >数格式,关于DCB更具体的设置需要根据用户对数据流定义、握手信号及通信控 </P># g6 t# C+ K0 t
< >制要求具体定义,参见有关Windows技术资料。用GetCommState()可以得到当前 </P>
6 z/ J3 T2 u; ]% b4 n< >的DCB参数值。如果需要还可通过SetCommTimeouts()和GetCommTomeouts()重新 </P>
8 N; A: ^4 m# |( x$ g* d< >设置读写的超时参数;读写缓冲区的设置使用SetupComm(),参数dwInQueue和 </P>% |! r& _7 N; k1 x9 Z, q
< >dwOutQueue分别定义为输入和输出缓冲区的大小。 </P>
2 Q1 B' \) P7 G/ L9 w, @< > </P>/ e9 l- _2 D# e+ ^4 A
< > 在串口初始化完毕后,还要建立与通信有关的事件对象。一般使用 </P>
7 T) K) t1 V5 A5 |5 O2 I/ Y< >CreateEvent()函数,它返回一事件句柄,其中参数lpEventAttributes指向安全 </P>
H4 W. z! c1 k9 E; i* b; d2 a< >属性结构地址,在Win 95(无安全属性)中为NULL;布尔参数bManualReset 定 </P>
4 V' O/ b' v2 E" I/ ]) e7 M< >义事件重置方式,true 表示手工重置,false表示自动重置(相关函数为 </P>1 @# {1 Y1 J0 S
<P>SetEvent()和ResetEvent());参数bInitialState定义事件初始状态,true表 </P>
0 |* g8 S4 l/ Y<P>示发信号,否则为不发信号;lpName是为多进程设置的事件名,对于单进程定义 </P>
' R7 k7 s$ y# E4 l/ X1 R<P>为NULL。然后用SetCommMask()定义用户程序可监视的通信事件类别。 </P>
$ y" q, I) o( |2 G. _- n0 ~<P> </P>
! x- ~. L6 c7 S$ @3 K<P> 以上设置完成后,用户程序就可以等待通信事件的产生,一般调用函数 </P>1 b* t8 g: h4 P! d5 x
<P>WaitCommEvent()监视通信事件,其中参数lpEvtMask指向产生事件的掩码地址, </P>9 j& I: f8 z; ]0 ]9 I; u$ B- S
<P>用于判断事件产生的性质,lpOverlapped指向重叠结构地址,可简单定义为 </P>
( x9 c9 U% @6 N3 E4 e<P>NULL。对于串口事件的响应一般有四种方式:查询、同步I/O、异步I/O和事件驱 </P>6 ]# X9 e h6 B5 \1 K8 M
<P>动I/O,需要根据用户不同控制要求而定。查询方式占用较长的计算机时间,同 </P>
; ^0 @8 G+ L9 x' O2 C& A; x<P>步I/O方式直到读取完指定的字节数或超时时才返回,容易造成线程阻塞,异步 </P>
6 Q0 t f: B( i j: |; r% F<P>I/O用于后台处理,事件驱动是由系统通知用户程序发生的事件并进行串口操作 </P> O4 S# u0 G4 i3 j- Q
<P>。 比较而言事件驱动I/O方式较灵活。 </P>% V6 e& J( z% Z+ N; h
<P> </P>0 W1 b- w; d5 r& u! I! n
<P> 当有通信事件产生时,就可用函数ReadFile()和WriteFile()直接对串口缓 </P>; Q8 i5 v7 f3 }; n* N+ D
<P>冲区进行读写操作了。其中lpBuffer 指向读写缓冲区,nNumberOfBytes为要读 </P>+ J5 F4 s4 L7 q- U( H1 G0 C
<P>写的字节数,lpNumberOfBytes为实际读写的字节数,lpOverlapped指定同步或 </P>: l* n8 k2 d1 O2 K6 d! ]/ b
<P>异步操作。通信结束后,调用函数CloseHandle()将串口关闭。 </P>
d( Q8 ?6 Q, A' j<P> </P>
' b1 Z: F& a) T+ i+ r8 ]; d0 `<P> ·应用实例说明· </P>3 h( w: a: ~7 {2 n
<P> </P>
, ?' p4 f* {+ q: b0 S$ F<P> </P>& Q* u4 c+ y; }9 u; e4 n- Y
<P> 使用以上的API函数,笔者给出了简化后的串口初始化的实例。图1为使用C </P>( Y; u" P6 I x e
<P>++ Builder 组件生成的串口通信基本参数设置的界面实例。 </P>/ `' t/ e+ }% n5 b+ q( |8 O
<P> </P>
! a- N2 l- t1 t! W3 p8 W<P> HANDLE hcom; //定义句柄 </P>1 x6 b6 M4 U5 o! j' X: f8 v8 e5 X
<P> </P>& F4 E1 q1 ^, k- T
<P> DCB dcb; </P>1 U. E8 N3 T/ w9 `3 m |
<P> </P>5 U0 k' y/ P I9 a
<P> OVERLAPPED e; //定义重叠结构 </P>6 p8 s. \3 B+ J4 k
<P> </P>. v7 i$ E# o* s; f9 b
<P> void —fastcall TForm1::OkBtnClick(TObject?Sender) </P>
. r, H/ b& Q6 o' @4 s& z5 V* m<P> </P>0 s1 U2 a; ~$ g; D
<P> { hcom=CreateFile("COM2",GENERIC—READ|GENERIC—WRITE,0,NULL,OPEN </P>
$ _2 r$ Z; i7 _! @# `<P>—EXISTING, </P>
( |3 L# t/ v; a3 o- q<P>FILE—ATTRIBUTE—NORMAL|FILE—FLAG—OVERLAPPED,NULL); //打开通讯口 </P>
0 y9 {5 B6 a" ~3 O<P> </P> w1 f* o% I* t
<P> BuildCommDCB("9600,O,8,1",&dcb); </P>
* Y8 U4 M I: p" j5 y% S! m, N<P> </P>: O( q4 M w# y1 w& f! j8 I
<P>//第一个字符串参数实际使用时由图1选择后组合,这里仅简单说明其格式 </P>
# @. f( a# k- Z4 p# }- C+ U" @, l<P> </P>2 T7 A- }2 _& n- p4 [% c
<P> SetCommState(hcom,&dcb); </P>
: M, v, q+ k& N5 Q% r% K: w<P> </P>
& I* L+ q5 x: J8 M+ G8 R) I<P> SetupComm(hcom,512,512);//设置读写缓冲区 </P>5 q$ H$ g3 |/ G$ F) v& j! f& |* A S# K
<P> </P>
- @! L8 u5 [' ~, @<P> e.hEvent=CreateEvent(NULL,false,false,NULL); //设置事件 </P>
$ R" q4 v' X& Z. _! ^<P> </P>
4 f, s' N. U- d$ t7 A<P> SetCommMask(hcom,EV—RXCHAR| EV—TXEMPTY); //设置事件掩码 </P>
: |. N" Q- k% j3 s# Q<P> </P>
1 z1 y; \( Y/ N+ p0 F) n<P> OkBtn-〉Enabled=false;} </P> |
zan
|