WINDOWS环境下PC机与单片机的通信
扫描二维码
随时随地手机看文章
在自动控制系统中,PC机与单片机组成上位机和下位机,其基本构成是:下位机(单片机系统)完成信号检测、A/D转换和简单的控制功能,通过系统总线(如RS-232、RS-485、USB)与上位机(PC机)相连,进行监测、控制,形成主从式结构。下面就上位机和下位机之间目前几种常用的通讯方法作一些介绍。
1、RS-232的串行通讯
在工业控制中,串口是常用的计算机与外部串行设备之间的数据传输通道,由于串行通信方便易行,成本低,且完全能满足要求,所以应用广泛。
1.1、利用VC++的标准通信函数
利用VC++的标准通信函数_inp和_outp可实现串口通信。下面是一个串口初始化的程序:
Void init_com (PORT)
{char i;
outp(PORT+3,0x80);
outp(PORT,0x0C);
outp(PORT+1,0);
outp(PORT+3 ,0x3a);
outp(PORT+3 ,0x03);
i=inp(PORT+5) && 0xfe;
outp(PORT+5,i);}
1.2、使用串行通信控件MSComm
MSCOMM控件,即Microsoft Communication Control,是Microsoft为简化Windows下串行通信编程而提供的ActiveX控件。它提供了一系列标准通信命令的使用接口,利用它可以建立与串口的连接,并可以通过串口连接到其他通信设备(如调制解调器),发出命令,交换数据以及监视和响应串行连接中发生的事件和错误。MSCOMM控件可用于创建电话拨号程序、串口通信程序和功能完备的终端程序。
串行通信控件MSComm32.OCX提供了使用RS-232来进行数据通信的所有协议,VC编程语言为该控件提供了标准的事件处理函数、过程,并通过属性和方法提供了串行通信的设置。它使用户能够方便地访问Windows串行通信驱动程序的大多数特性,包括输入、输出缓冲区的大小及决定何时使用流控制命令挂起数据传输等。
在ClassWizard中为新创建的通信控件定义成员对象(CMSComm m_Serial),通过该对象便可以对串口属性进行设置,MSComm控件共有27个属性。如果需要通过多个串行口与多台设备通信,那么每一个串行口对应于一个单独的MSComm控件。串行口的设置参数既可以在对话框编辑器里设定,也可以在程序代码中通过调用CMSComm类的成员函数设定。例如,我们可以在MyCOMDlg类的OnInitDialog成员函数中初始化MSComm控件的参数,代码如下:
BOOL CMyCOMDlg::OnInitDialog ()
? {
CDialog::OnInitDialog ();
m_wndCOM1.SetCommPort(1);
m_wndCOM1.SetSettings("9600,e,7,1");
m_wndCOM1.SetRThreshold(1);
m_wndCOM1.SetSThreshold(0);?
m_wndCOM1.SetInputLen(1);?
m_wndCOM1.SetPortOpen(TRUE);
Return TRUE
?}
打开所需串口后,我们需要考虑串口通信的时机。在接收或发送数据过程中,可能需要监视并响应一些事件和错误,所以事件驱动是处理串行端口交互作用的一种非常有效的方法。使用OnComm事件和CommEvent属性捕捉并检查通信事件和错误的值。发生通信事件或错误时将触发OnComm事件,CommEvent属性的值将被改变,应用程序通过检查CommEvent属性值并做出相应的反应。
如图1是PC机与多个单片机连接的原理图,图2是其通信程序流程图。
1.3、使用API函数
Windows 应用程序要与标准串口通信,Windows函数库中提供了24个低级函数,这些函数为与外部设备的通信提供了基本的工具,文件输入和文件输出函数为通信资源句柄的打开、关闭以及执行读写操作提供了基本的接口,Win32 API也包含一系列访问通信资源的通信函数,具体工作过程如下:首先打开一个通信资源句柄CreateFile(),接着进行串行通信资源的配置(包括波特率、奇偶校验、停止位和数据位等信息),通过SetCommState()、GetCommState()进行修改和查询完成初始化设置;串行通信资源的读写通过ReadFile()、WriteFile()来完成收发数据,监视串行通信资源某些可能发生的事件可通过WaitCommEvent()来完成,向与某通信资源相关的设备驱动程序发送控制命令,使驱动程序执行特定任务。
控件虽然简单易用,但由于必须拿到对话框中使用,在一些需要在线程中实现通信的应用场合下,控件的使用显得捉襟见肘。API是附带在Windows内部的一个极其重要的组成部分。Windows的32位API主要是一系列很复杂的函数和消息集合。它可以看作是Windows系统为在其下运行的各种开发系统提供的开放式通用功能增强接口。通信程序在CreateFile处指定串口设备及相关的操作属性,再返回一个句柄,该句柄将被用于后续的通信操作,并贯穿整个通信过程。串口打开后,其属性被设置为默认值,根据具体需要,通过调用GetCommState(hComm,&&dcb)读取当前串口设备控制块DCB设置,修改后通过 SetCommState(hComm,&&dcb)将其写入。运用ReadFile()与WriteFile()这两个API函数实现串口读写操作,若为异步通信方式,两函数中最后一个参数为指向OVERLAPPED结构的非空指针,在读写函数返回值为FALSE的情况下,调用 GetLastError()函数,返回值为ERROR_IO_PENDING,表明I/O操作悬挂,即操作转入后台继续执行。此时,可以用 WaitForSingleObject()来等待结束信号并设置最长等待时间,举例如下:
BOOL bReadStatus;
bReadStatus = ReadFile (m_hIDComDev, buffer,
dwBytesRead, &&dwBytesRead, &&m_OverlappedRead);
if (! bReadStatus){
if(GetLastError()==ERROR_IO_PENDING){
WaitForSingleObject(m_OverlappedRead.hEvent,1000);
return ((int)dwBytesRead);}
return(0);}
return ((int)dwBytesRead);
1.4、多线程下的串行通信
Windows内部的抢先调度程序在活动的线程之间分配CPU时间,Windows区分两种不同类型的线程,一种是用户界面线程(User Interface Thread),它包含消息循环或消息泵,用于处理接收到的消息;另一种是工作线程(Work Thread),它没有消息循环,用于执行后台任务、监视串口事件的线程即为工作线程。多线程程序的编写在端口的配置、连接部分与单线程的相同,在端口配置完毕后,最重要的是根据实际情况,建立多线程之间的同步对象,如信号灯、临界区和事件等。多线程的实现可以使得各端口独立,准确地实现串行通信,使串行通信具有更广泛的灵活性与严格性,且充分利用CPU时间。但在具体的实时监控系统中如何协调多个线程、线程之间以何种方式实现同步,这是多线程串行通信程序实现的难点。
2、RS-485的串行通讯
RS-485与RS-232C相类似,其区别在于它使用了双端平衡驱动及半双工模式,这些措施使RS- 485传输距离更远,同时,RS-485还可以组网。在同一个RS-485网络中,可以多达32个模块,某些器件可以多达256个甚至更多。相应的,RS-485具有接收/发送控制端,RS-485的接收控制端可以在需要接收的时候打开或者一直打开以便无条件的接收线路上的数据。RS-485的发送控制端仅在需要发送时打开,平时应关闭发送器,因为在同一RS-485网络中在同一时刻仅允许一个发送器工作。在数据发送完成后关闭发送器。这可以通过以下两种方法实现。①、在数据完全移出后,对于PC机为发送移位寄存器空,以MCS-51系列单片机为例则为TI置位。这些条件既可使用查询的方法得到,也可以在中断程序中实现。②、将RS-485的接收器始终打开,这样一来,所有在RS-485上的数据均被接收回来,包括自己发送出去的数据。因此,当自己发送的数据完全被自己接收回来时即可关闭发送器。原则上说,这一方法无论是查询或中断方式都适用,但实际上,由于RS-485的数据通常打包后发送,因此,使用查询的方法并不理想。这一方法非常适合中断方式,尤其是以数据包传送的RS-485通讯。
3、USB接口的通讯:
USB(通用串行总线Universal Serial Bus),其传输方式分为4种:控制传输,块传输,同步传输和中断传输。在实际开发中使用了控制传输和块传输。控制传输主要用来完成主机对设备的各种控制操作,也就是用来实现位于主机上的USB总线驱动程序(USBD.SYS)以及编写的功能驱动程序对设备的各种控制操作。块传输主要用来完成主机和设备间的大批量数据传输以及对传输数据进行错误检测(若发生错误,它支持"重传"功能)。单片机系统控制USB控制器的工作过程可以简单地概括为:当USB控制器从USB总线检测到主机启动的某一传输请求后,通过中断方式将此请求通知单片机系统,单片机系统通过访问USB控制器的状态寄存器和数据寄存器获得与此次传输有关的各种参数,并根据具体的传输参数,对USB控制器的控制寄存器和数据寄存器进行相应的操作,以完成主机的传输请求。USB设备驱动程序包括如下几部分:
①初始化模块提供一个入口函数DriverEntry(),所有对各种IRP(I/O Request Packet,IRP请求包)的处理例程都在此入口函数中做出定义。②即插即用管理模块实现USB设备的热拔插及动态配置。当硬件检测到USB设备接入时,Windows查找响应的驱动程序,并调用它的DriverEntry例程,PnP(即插即用)管理器调用驱动程序的AddDevice例程,告诉它添加了一个设备;在此处理过程中,驱动程序收到一个设备启动请求(IRP_MN_START_DEVICE)的IRP。同理,当要拔除时,PnP管理器会发出一个设备删除请求(IRP_MN_REMOVE_DEVICE)的IRP,由驱动程序进行处理。通过对这些PnP请求的处理,可支持设备的热插拔和即插即用功能。③电源管理模块负责设备的挂起与唤醒。④I/O功能实现模块完成I/O请求的大部分工作。若应用程序想对设备进行I/O操作,它便使用 Windows API函数,对WIN32子系统进行WIN32调用。此调用由I/O系统服务接收并通知I/O管理器,I/O管理器将此请求构造成一个合适的I/O请求包 (IRP)并把它传递给USB设备驱动程序,USB设备驱动程序接收到这个IRP以后,根据IRP中包含的具体操作代码,构造相应的USB请求块并把此 URB(USB请求块)放到一个新的IRP中,然后把此IRP传递到USB总线驱动程序,USB总线驱动程序根据IRP中所含的URB执行相应的操作(如从USB设备读取数据等),并把操作结果通过IRP返还给USB设备驱动程序。USB设备驱动程序接收到此IRP后,将操作结果通过IRP返还给I/O管理器,最后I/O管理器将此IRP中操作结果返还给应用程序,至此应用程序对USB设备的一次I/O操作完成。
4、以上几种通讯模式的比较
对于RS-232和RS-485两种通讯方式,速度相对而言慢一点,但传输的距离远,完全能满足工业控制的要求,因而在工业控制领域得到了广泛的应用。我们知道PC机的串口个数是有限的,它在单片机较多的情况下要实现相互通讯有一定的困难。而USB接口的通讯方式是后起之秀,它的通讯速度快,但不能实现远距离传输,而将RS-485与USB结合能有效地解决这一问题。
参考文献
1.张念淮,江浩. USB总线接口开发指南. [M] 北京:国防工业出版社 .2002
2.李朝青. PC机及单片机数据通信技术 [M] .北京:北京航空航天出版社 .2000
3.高登芳,潘承武,朱英杰. 微型计算机实用测控接口技术 [M]. 北京:北京科学技术出版社 1990.
4.余永权 汪明慧 黄英 单片机在控制系统中的应用 [M] 北京:电子工业出版社 2003
5.刘复华 8098单片机及其应用系统设计 [M] 北京:清华大学出版社 1991