当前位置:求学问校网(武汉培训网) » 论文:用Borland C++3.1实现外设与

按字母查成语词典A|B|C|D|E F G|H|J|K|L|M|N|O|P|Q|R|S|T|W|X|Y|Z
在线新华字典按偏旁部首查询汉字 | 按汉字拼音查询汉字 | 五笔字根查询
工商管理论文 | 工学工业论文 | 社会艺术论文 | 理学医学论文 | 语言教育论文 | 计算机论文
» 论文阅读

用Borland C++3.1实现外设与

摘 要 该文提出了一种在Windows3.1保护模式下,通过动态连接库(DLL)生成中断服务程序代码,实现外设与Windows应用程序实时通信的有效方法。

一、前 言
计算机的日益普及和计算机技术日益成熟,使得计算机在工业控制监测中的应用渐渐深入。但工业应用不同于其它方面,它要求有较强的实时性。现在有很多的DOS软件在运行过程中通过挂接外部中断方式实现DOS应用软件与外设的实时通信,这种方法实现起来十分简单。而在Windows中应用程序能否也能够利用外部硬中断实现外设与Windows应用程序的实时通信呢?答案是肯定的。这里的关键是要解决好中断代码与Windows应用程序相互之间交换信息的问题。
从外设发送异步的硬中断,通过中断处理程序传递一条信息给Windows应用程序。这时可以初始化相关端口,准备好数据,然后进行数据传送,从而做到实时通信。
实现Windows应用程序响应外部中断的方法有很多,如Microsoft公司自己开发的SDK、DDK软件包,使用嵌入式汇编等等。本文将介绍一种在BC++3.1的基础上利用Windows 3.1拥有的一些功能实现Windows实时通信的实例。

二、中断代码的位置
在Windows中,几乎所有的异步事件都是由中断处理程序来管理的。中断处理程序包含在设备驱动程序中,由Windows在环境初始化中安装。例如,KEYBOARD.DRV、MOUSE.DRV和COMM.DRV均含有中断处理程序,以处理相应的键盘、鼠标和串行口的异步中断。可以仿照标准设备驱动程序,编写中断处理代码,以响应外设的通信请求,从而完成一次实时通信。
中断代码既可以包含在应用程序的可执行代码中,也可以包含在动态连接库(DLL)中。包含在应用程序中的代码只能在一个程序中使用,而在动态连接库中的代码则可以在Windows系统中所有的应用程序所共享。这样不仅在整个Windows系统中只有一个中断代码的副本,提高了内存的使用效率,更重要的是可以防止由于同时存在多个中断代码的副本而发生冲突。本文将在DLL中编制中断处理程序。
当动态连接库被装入时,要调用DLL库的入口点LibMain(),利用这一点可以执行一些初始化工作,可以分配一些内存块,可以初始化一些全局变量或者静态变量,可以安装中断服务程序的代码等等。例如:
void interrupt (oldIsr)(--CPPARGS)
/* 旧的中断服务程序地址 */
LibMain(HANDLE hInstance,WORD wDataSeg,WORD cbHeapSize,L
PSTR
lpszCmdLine)
{

oldIsr=getvect(IRQNum);
/* IRQNum指中断号 */
setvect(IRQNum,newIsr);
/* newIsr指新中断服务程序代码 */
return(1);
}
函数setvect()既可在实模式下,也可在保护模式下设置中断处理向量。
上述代码也可以放在一个由用户设置的引出(export)函数中,在应用程序中用户可以调用此引出函数来安装中断服务程序代码。
由于中断可以在任何时刻发生,中断代码必须驻留在内存中,并且在应用程序运行的过程中一直处于某一固定内存中。这一点无论是在实模式还是在保护模式下都是一致的。
在DLL的模块定义文件中应注意:

1.CODE语句为固定代码段,即FIXED;

2.EXPORTS语句要引出被应用程序和其它DLL用作入口点的函数。

三、通信机制
编写实时通信例程关键在于必须认识到,异步事件对应用程序的触发是异步发生的,不在Windows的消息处理机制和多任务范围内。为了使通信例程能够正确地工作,通信例程必须通知Windows有异步事件发生,且不能打断应用程序的任务管理或消息流。要作到这一点,通信例程必须通过调用PostMessage或PostAppMessage函数向应用程序的消息队列中加入一条消息。
需要注意的是,在DLL中调用PostMessage(HWND hwnd, …)时,必须先确定hwnd的实际值,可以通过使用引出函数的办法来实现,如下所示:
static HWND hWndApp;
void FAR PASCAL SetIsrWin(HWND hwnd)
{
hWndApp=hwnd;
}
然后在应用程序的窗口函数中,对WM-CREATE消息进行处理时调用此函数来初始化DLL中的静态变量hWndApp:
CASE WM-CREATE:

SetIsrWin(hwnd); /* hwnd指应用程序窗口句柄 */
定义一个在应用程序中使用的消息:
#define ISRM-RUPT WM-USER+255最后在DLL中的中断服务程序代码中,调用PostMessage即可完成Windows应用程序和中断服务程序代码相互的信息交流:
void interrupt newIsr(--CPPARGS)
{

PostMessage(hWndApp,WM-RUPT,wParam,lParam);

}

四、程序实例
本示例先安装在DLL中的外中断服务代码,通过386/AT总线上的中断申请线(IRQ12)外触发,由中断服务代码发送一条消息WM-RUPT通知Windows应用程序外设有实时通信请求,应用程序收到这条消息后,在窗口用户区显示一条信息,表明已和外设联络上,并同时鸣叫一声喇叭。
程序分为两部分:DLL库代码和Windows应用程序代码。

1.DLL库代码
/*----------*
* interrupt include file,named handle.h*
*----------*/
void FAR PASCAL SetIsrWin(HWND hwnd);
void FAR PASCAL SetIRQNum(unsigned char IRQ);
/*----------*
* module defination file, named handle.def *
*----------*/
LIBRARY HANDLE
EXETYPES WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD FIXED
DATA PRELOAD SINGLE
HEAPSIZE 1024
EXPORTS
WEP
@1 RESIDENTNAME
SetIRQNum @3
/*----------*
* interrupt service program in dll,named handle.dll *

>*----------*/
#include <windows.h>
#include<dos.h>
#include "handle.h"
#define ISRM-RUPT WM-USER+255 /* 自定义消息 */
static HWND hWndApp; /* 应用程序窗口句柄 */
static char OldIMR-A,OldIMR-B; /* 旧中断屏蔽字 */
static int nCounts=0; /* 中断触发次数 */
static unsigned char IRQNum /* 中断号 */
#ifdef --cplusplus
#define --CPPARGS …
#else
#define --CPPARGS
#endif
void interrupt (*oldISR)(--CPPARGS); /* 旧中断函数指针 *
/
void interrupt newISR(void);
void RestoreStartupIRQ(void);
void initDevice();
#pragma argused
int FAR PASCAL LibMain(HANDLE hInstance,WORD
wDataSeg,WORD cbHeapSize,
LPSTR lpszCmdLine)
{
if(cbHeapSize!=0) UnlockData(0);
initDevice(); /* 初始化相关外设,以准备中断申请信号 */
return(1);
}
void FAR PASCAL SetIsrWin(HWND hwnd)
{
hWndApp=hwnd;
}
void interrupt newISR(void)
{
{
nCounts++;
Postmessage(hWndApp,ISRM-RUPT,nCounts,0L);
outportb(0x20,0x20);
outportb(0xa0,0x20);
}
int FAR PASCAL WEP()
{
RestoreStartupIRQ(); /* 恢复原来的中断向量值 */
return(1);
}
void FAR PASCAL ConfigureIRQ(unsigned char IRQ)
{
OldIMR-A=inportb(0x21); /* 保存旧中断屏蔽字 */
OldIMR-B=inporlb(0xA1); /* 保存旧中断屏蔽字 */
if(IRQNum<8)
{
oldISR=getvect(IRQNum+8); /* 保存旧中断向量 */
setvect(IRQNum+8,newISR); /* 设置新中断向量 */
}
else
{
oldISR=getvect(IRQNum+0x68); /* 保存旧中断向量 */
setvect(IRQNum+0x68,newISR); /* 设置新中断向量 */
}
}
void FAR PASCAL SetIRQNum(unsigned char IRQ)
{
IRQNum=IRQ;
ConfigureIRQ(IRQNum);
}
void RestoreStartupIRQ(void)
{
disable(); /* 屏蔽所有的中断 */
outportb(0x21,OldIMR-A); /* 恢复原来的中断屏蔽字 */
outportb(0xA1,OldIMR-B); /* 恢复原来的中断屏蔽字 */
if(IRQNum<8)
setvect(IRQNum+8,oldISR); /* 恢复原中断向量值 */
else
setvect(IRQNum+0x68,oldISR);
enable(); /* 重新使能中断 */
}

2.Windows应用程序中代码在Windows应用程序中插入
#include "handle.h"
设置如下窗口函数
long FAR PASCAL WndProc(HWND hWnd, UINT Message,WPARAM w
Param, LPARAM lParam)
{
int nCounts;
HDC hDC;
TEXTMETRIC tm;
static short cxChar,cyChar;
char szBuffer[80];
switch(message)
{
case WM-CREATE:
SetIsrWin(hWnd); /* 传递应用程序窗口句柄 */
SetIRQNum(12);
hDC=GetDC(hWnd);
GetTextMetrics(hDC,&tm);
cxChar=tm.tmAveCharWidth;
cyChar=tm.tmHeight+tm.tmExternalLeading;
ReleaseDC (hWnd,hDC);
break;
case ISRM-RUPT:
hDC=GetDC(hWnd);
nCount=wParam; /* 获取消息中的信息 */
TextOut(hDC,cxChar,cyChar*2,szBuffer,wsprintf(szBuffer,"
Total
interrupts=%d",nCounts));
ReleaseDC(hWnd,hDC);
break;
}
}
可以将HANDLE之类源程序组成一个工程文件,编译后生成DLL代码,利用Borland公司的IMPLIBW工具将DLL代码转换成LIB代码,然后在Windows应用程序工程文件加入它,进行编译连接即可。
注意在DLL库代码中的initDevice()函数没有给出,因为这一程序涉及到特殊的设备,用户可以按照自己的需要利用不同外设,由它提出中断申请,从而达到实时通信的目的。


本文摘录自互联网络,在此刊登仅为传递更多信息,版权归作者所有.

» 培训展台

» 学校展示