I/O 管 理 器 , 用户应用程序的请 求 随 即 返 回 。 访 问 硬 件 时 , 驱 动 程 序 通 过 调 用硬件抽象层的函数实现。 本 文 采 用 NuMega Lab 公 司 开 发 的 DriverStudio 来 开 发 驱 动程序。该软件的 DriverWizard 工具可以根据硬件通过向导直 接生 成框架代码。在 框 架 中 写 入 相 对 与 设 备 的 特 定 代 码 , 编 译 后即可得到所需的驱动程序。在本文中, 来自 DeviceNet 网络底 层数据的接受就是由驱动程序完成 的 。 另 外 , SJA1000 的 初 始 化操作也由驱动程序来完成。编写驱动程序本身不是最终目 的 , 最 终 目 的 是 调 用 驱 动 程 序 管 理 PCI- CAN 接 口 卡 , 并 为 用 户 应用程序使用。驱动程序加载以后, 它的许多进程处于 IDLE 状 态, 实际上需要用户应用程序去调用激活。应用程序利用
技 术 创 新
CWnd::SetTimer 和 CWnd::KillTimer 方 法 来 设 定 和 删 除 定 时 器 。 SetTimer 的函数原型为 : UINT SetTimer( UINT nIDEvent, UINT nElapse,NULL) 其中第一个参数是新建的定时器 ID, 若调用成功则函 数 返 回值为该 ID; 第二个参数是溢出 时间, 以毫秒计时; 第三个参数 为 NULL 型, 表示定时器溢出后系统向应用程序的消息队列中 发 送 WM_TIMER 消 息 。 使 用 VC ++6.0 的 ClassWiazrd 为 WM_TIMER 添 加 处 理 函 数 。 在 该 处 理 函 数 中 完 成 计 时 溢 出 处 理 , 使 用 Windows API 函 数 SendMessage()将 消 息 发 送 给 应 用 程 序。以显性连接定时器为例 : if(global_timer[EXPLICIT]) /* 显性连接定时器 */ { global_timer[EXPLICIT]- - ; /* 递减到 0*/ if(global_timer[EXPLICIT]==0) ::SendMessage(hWnd,EXPLICIT_TIMEOUT,wParam,lParam); } (4)驱动程序与应用程序的通信 当驱动程序 捕 捉 到 中 断 事
件发生时, 说明 DeviceNet 网络发送上来数据。此时应当与应用 程序通信, 将数据存储到内存缓冲区 中 。 我 们 采 用 Win32 事 件 通知的方法实现这一功能。应用程序创建一个事件后, 直接将 事件句柄传递给驱动程序, 然后等待消息的发送。而驱动程序 通过类 Kevent 来获得这一事件的指针, 并且在中断发生时发送 消息来触发应用程序, 通知其接收 SJA1000 FIFO 中的的数据。 综上所述, 整个应用程序的工作框架如图 2 所示 :
Win32API 直接调用驱动程序, 实现驱动程序和应用程序的信息 交互。首先用 CreatFile()打开设备, 获得一个指向设备对象的句 柄 。 然 后 用 DeviceIoControl()进 行 数 据 的 传 送 。 最 后 用 Close- Handle ( ) 关闭设备句柄。
3 DeviceNet 协 议 软 件 设 计
(1) DeviceNet 类 及 头 文 件 定 义 使 用 VisualC++6.0 的 ClassView 工具建立各 DeviceNet 类 :包括 DeviceNet、 Connection 、 Message Router 等。并按照