首页 毕业设计(论文)-基于嵌入式系统的PC键盘与鼠标交互控制模拟研究

毕业设计(论文)-基于嵌入式系统的PC键盘与鼠标交互控制模拟研究

举报
开通vip

毕业设计(论文)-基于嵌入式系统的PC键盘与鼠标交互控制模拟研究毕业设计(论文)-基于嵌入式系统的PC键盘与鼠标交互控制模拟研究 ***大学毕业论文(设计) 基于嵌入式系统的PC键盘与鼠标 交互控制模拟研究 班 *** 2006级计算机科学与技术* 指导教师 张三 【摘要】随着信息技术发展,各类应用软件不断丰富。已有的商用软件的高效 率切入成为一个十分棘手的问题。如一款基于PC的性能完备的操纵训练软件, 常以键盘与鼠标作为模拟输入设备,但这与真实的操作方式大相径庭,若能采 用嵌入式系统开发一款操纵方式更加人性化、可再现原有键盘与鼠标控制功能 的软硬结合的模拟系统,将使...

毕业设计(论文)-基于嵌入式系统的PC键盘与鼠标交互控制模拟研究
毕业设计(论文)-基于嵌入式系统的PC键盘与鼠标交互控制模拟研究 ***大学毕业论文(设计) 基于嵌入式系统的PC键盘与鼠标 交互控制模拟研究 班 *** 2006级计算机科学与技术* 指导教师 张三 【摘要】随着信息技术发展,各类应用软件不断丰富。已有的商用软件的高效 率切入成为一个十分棘手的问 快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题 。如一款基于PC的性能完备的操纵训练软件, 常以键盘与鼠标作为模拟输入设备,但这与真实的操作方式大相径庭,若能采 用嵌入式系统开发一款操纵方式更加人性化、可再现原有键盘与鼠标控制功能 的软硬结合的模拟系统,将使原有商用软件应用功能得到极大升华。 随着硬件技术和自动化技术的不断发展,基于嵌入式技术各种系统模拟技术 已经相当成熟。本系统是基于ARM嵌入式系统以及PC系统,结合所学计算机专 业课程 知识点 高中化学知识点免费下载体育概论知识点下载名人传知识点免费下载线性代数知识点汇总下载高中化学知识点免费下载 开发设计一个基于嵌入式系统的PC键盘与鼠标交互控制模拟系 统。 【关键字】键盘鼠标模拟;ARM嵌入式系统;PC系统;交互控制模拟; VC++ Simulation for Interactive Contrals of PC Keyboard and Mouse Based on Embedded System Zhang Sand 【Abstract】With the development of information technology,the kinds of applications software are greatly enriched。So communicating efficiencily with a commercial software has been a very difficult problem。 Such as a complete PC-based manipulation -training software, its input device are always keyboard and mouse ,but there are much difference with the real input ways。So if we can develop a analog system that have a more Human-based and convenient input ways and can present the function of Keyboard and Mouse perfectly,the function of the software will be improved greatly。 As the hardware technology and automation technology continues to evolve, various systems based on embedded technology is already quite mature analog technology 。 【Key words】 Keyboard and Mouse Simulation; ARM Embedded System; PC System ;Simulation of Interactive Control;VC++ 1 ***大学毕业论文(设计) 目录 1 绪论..............................................................................................................4 1.1开发背景介绍 ..................................................................................................................... 4 1.2 系统主要实现目标 ............................................................................................................ 4 1.3 论文结构概述 .................................................................................................................... 4 2 开发环境和开发工具简介 ...........................................................................4 2.1 Microsoft Visual c++ 6.0项目概述 : .............................................................................. 4 2.2 C++语言简介 .................................................................................................................. 5 2.2.1 C++语言特性........................................................................................................ 5 2.2.2 WINAPI编程特性 ............................................................................................... 5 2.3 ADT概述: ........................................................................................................................ 7 2.3.1 ADT嵌入式系统开发环境概述 .......................................................................... 7 2.3.2 ADT与ARM嵌入式系统及PC系统的连接 ....................................................... 7 2.3.3 JX44B0-2嵌入式系统实验平台概绍..................................................................... 8 3 程序结构、思想和相关技术介绍 ............................................................................................. 8 3.1 PC端软件的键盘与鼠标事件的仿真实现 .................................................................... 8 3(1(1 PC端软件功能概绍 .......................................................................................... 8 3.1.2 键盘事件的模拟仿真 ..................................................................................................... 8 3.1.3 鼠标事件的模拟仿真 .......................................................................................... 10 3.1.4多线程技术的引入 ................................................................................................ 13 3.2 ARM嵌入式系统端程序的设计与实现 ......................................................................... 14 3.2.1 ARM端程序功能概绍 .......................................................................................... 14 3.2.2 异部串行通信的实现 ........................................................................................... 14 3.2.3 S3C44B0异步串行口控制器及相关寄存器 ....................................................... 15 3.2.4 键盘输入与IO...................................................................................................... 16 3.2 PC端与ARM嵌入式端的串行通讯实现 ...................................................................... 16 3.2.1 端与端串口通讯概绍 ........................................................................................... 16 3.2.2串口通讯工作方式 ................................................................................................ 17 3.2.1 串口数据接收的VC实现 ................................................................................... 17 4系统需求 分析 定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析 .............................................................................................................................. 19 4.1 系统角色及其功能分析 .................................................................................................. 19 4.2 系统主要功能详细描述 .................................................................................................. 19 4.3 系统功能模块设计 .......................................................................................................... 20 5 总体设计及实现 ......................................................................................................................... 21 5.1 总体模块设计 .................................................................................................................. 21 5.2 各子系统模块总体设计 .................................................................................................. 22 5.2.1 JX44BO-2嵌入式系统端设计.............................................................................. 22 5.2.2 PC系统端程序设计 .............................................................................................. 25 6 系统详细设计 ..................................................................................................................... 27 6.1 PC端系统的具体实现与程序编写 ................................................................................. 27 6.1.1 鼠标事件模拟的实现 ........................................................................................... 27 2 ***大学毕业论文(设计) 6.1.2 键盘事件模拟的实现 ........................................................................................... 30 6.1.3 多线程技术的实现 ............................................................................................... 32 6.1.4串口数据接收程序的VC实现 ............................................................................ 35 6.2 ARM嵌入式系统端的具体实现与程序编写 ................................................................. 41 6.2.1串口通讯的实现 .................................................................................................... 41 6.2.2 键盘扫描功能的实现 ........................................................................................... 46 7 结束语................................................................................................................................. 48 8致谢...................................................................................................................................... 48 9 参考文献............................................................................................................................. 49 附录1 PC端程序清单 ........................................................................................................ 50 附录2 ARM嵌入式系统端程序清单 ................................................................................ 56 3 ***大学毕业论文(设计) 1 绪论 1.1开发背景介绍 在Windows大行其道的今天,windows界面程序受到广大用户的欢这些程序的操作不外乎两种,键盘输入控制和鼠标输入控制。有时,对于繁杂的,或重复性的输入操作,我们能否通过编制程序来代替手工输入,而用程序来模拟键盘及鼠标的输入呢,答案是肯定的。本系统就是基于ARM嵌入式系统以及PC系统的 PC键盘与鼠标交互控制模拟系统。这一研究不仅可解决已有操纵训练系统的直观输入问题,而且还可能更大限度的发挥已有软件面向个性化应用的极大效率,具有很大的现实意义。 1(2 系统主要实现目标 主要实现目标:首先要求完成PC端软件的键盘与鼠标事件仿真。PC端软件的键盘与鼠标事件仿真主要通过以下两个WINDOWS API 函数来实现:模拟键盘用Keybd_event这个api函数,模拟鼠标按键用mouse_event函数。编程语言选用VC++语言。并增加增加异步通信功能可通过WINDOWS下的异步调用来实现。 然后,在嵌入式系统端完成D/A控制与模拟量,开关量控制,并开发实时异步通信功能。编程调试环境为ARM7嵌入式系统。最后,实现PC端与嵌入式系统端整体连接并调试,通信采用串行通讯方式。 1(3 论文结构概述 在此次毕业论文中,首先对开发中所有到的相关技术进行了简单介绍:包括ADT1000体系结构和安装,以及开发环境的配置;VC++语言的特征和他的应用前景;WINDOWS API的编程的工作原理和他的优点;ARM嵌入式编程的技术原理;程序的整体框架和工作原理。然后是对需求分析和详细设计 ,以及对本人所作模块的展示和部分实现代码。 2 开发环境和开发工具简介 2(1 Microsoft Visual c++ 6.0项目概述 : Visual C++ 6.0是微软公司推出的开发Win32应用程序,面向Windows95/98/2000/XP/NT操作系统的、面向对象的可视化集成工具。它的最大优点就是提供了功能强大的MFC类库,MFC是一个很大的C 类层次结构,其中封装了大量的类及其函数,很多Windows程序所共有的 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 内容可以由MFC 4 ***大学毕业论文(设计) 的类来提供,MFC类为这些内容提供了用户接口的标准实现方法,程序员所要做的就是通过预定义的接口把具体应用程序特有的东西填入这个轮廓,这将简化编程工作,大大的减少程序员编写的代码数量,使编程工作变得更加轻松容易。 本项目中主要用到的是WINDOWS API编程的WindowsSDK(软件开发工具)。 2(2 C++语言简介 2(2(1 C++语言特性 C语言系列的编程语言是当今非常流行的程序设计语言,它是由Dennis Richie在贝尔实验室研制开发的一个具有通用性的结构化程序设计语言,它融汇了高效,灵活等设计思想,具有较高的可移植性。 C语言的另一个重要特点是,比起其他编程语言来,C语言的使用非常灵活。比如在使用典型的结构化语言pascal时,必须要实现在指定的区域声明变量或函数,然后在另一指定位置实现函数等。又比如,使用QBASIC语言,需要指定每行语句的行号,程序将按代码的行号依次执行。C语言在变量声明、函数定语言的组织、算法设计等方面并没有过于严格的限制。 在基本语法特点方面,C++语言保持与C语言兼并,二者没有本质上的差别,大多数使用C语言编写的代码可以在C++语言中直接使用。这也是C++语言很快普及的一个重要原因。 C++语言与C语言的主要区别是编程思想上的更新,即编码由面向过程变为面向对象,基于此,C++语言引入了类与对象机制,包括类的定于,类的继承与派生,类的多态性等。 在类定义方面,C++语言一方面自定义结构类型进行扩充,另一方面也支持新的类构造。 数据封装和隐藏是与类的定义紧密相关,并且在C++语言中经常碰到的现象,也是C++语言中的一大特点。数据的封装和隐藏使重要的内部数据得到保护。 2(2(2 WINAPI编程特性 视窗操作系统应用程序接口(Windows API),有非正式的简称法为WinAPI,是微软对于Windows操作系统中可用的内核应用程序编程接口的称法。它设计为由C/C++程序调用,而且它也是应用软件与Windows系统最直接的交互方式。而大多数驱动程序所需要的对Windows系统的更底层次访问接口,由所用版本的Windows的Native API来提供接口。 Windows有一个软件开发包(SDK, software development kit)提供相应的文档和工具,以使程序员开发使用Windows API的软件和利用Windows技术。 Windows API总会为程序员提供大量的构建不同Windows的底层结构,这有助于为Windows程序员开发应用程序提供大量的灵活性和功能。但是,它同样使Windows applications要负责处理大量底层且有时是繁琐的与图形用户界面(GUI)相关的操作。WINDOWS API应用程序框架如下图所示: 5 ***大学毕业论文(设计) 图1 WINDOWS API应用程序框架 Windows API所提供的功能可以归为七类: 基础服务(Base Services)[5],提供对Windows系统可用的基础资源的访问接口。比如象:文件系统(file system)、外部设备(device)、, 进程(process)、线程(thread)以及访问注册表(Windows registry)和错误处理机制(error handling)。这些功能接口位于,16位Windows下的kernel。exe、krnl286。exe 统文件中;以及32位Windows下的 kernel32。dll和advapi32。或krnl386。exe系 dll中。 [6],提供功能为:输出图形内容到显示器、打印机 图形设备接口(GDI) 以及其他外部输出设备。它位于16位Windows下的gdi。exe;以及32位Windows下的gdi32。dll。 图形化用户界面(GUI)[7],提供的功能有创建和管理屏幕和大多数基本控件(control),比如按钮和滚动条。接收鼠标和键盘输入,以及其他与GUI有关的功能。这些调用接口位于:16位Windows下的user。exe, 以及32位Windows下的user32。dll。从Windows XP版本之后, 基本控件和通用对话框控件(Common Control Library)的调用接口放在comctl32。dll中。 通用对话框链接库(Common Dialog Box Library)[8],为应用程序提供标准对话框,比如打开/保存文件对话框、颜色对画框和字体对话框等等。这个链接库位于:16位Windows下的commdlg。dll中,以及32位Windows下comdlg32。 dll中。它被归类为User Interface API之下。 通用控件链接库(Common Control Library)[9],为应用程序提供接口来访问操作系统提供的一些高级控件。比如像:状态栏(status bar)、进度条(progress bars)、工具栏(toolbar)和标签(tab)。这个链接库位于:16位Windows下的commctrl。dll中,以及32位Windows下comctl32。dll中。。 它被归类为User Interface API之下。 Windows外壳(Windows Shell)[10][11],作为Windows API的组成部分,不仅允许应用程序访问操作系统shell提供的功能,还对之有所改进和增强。它 6 ***大学毕业论文(设计) 位于16位Windows下的shell。dll中,以及32位Windows下的shell32。dll中(Windows 95则在 shlwapi。dll中)。 它被归类为User Interface API之下。 网络服务(Network Services)[12],为访问操作系统提供的多种网络 功能提供接口。它包括NetBIOS、Winsock、NetDDE及RPC等。 2(3 ADT概述: 2(3(1 ADT嵌入式系统开发环境概述 ADT(ARM Development tools)嵌入式系统开发环境是由武汉创维特信息技术有限公司开发的具有自主知识产权的应用于嵌入式软件开发的集成软,硬件开发平台。它为基于ARM核的嵌入式应用提供了一整套完备的开发 方案 气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载 ,包括程序编辑,工程管理和设置,程序调试等。ADT嵌入式开发环境由ADT Emulator for ARM和ADT IDE for ARM组成。本设计主要用到ADT IDE for ARM来完成。 ADT IDE for ARM为用户提供高效明晰的图形化嵌入式软件开发环境,包括一套完备的面向嵌入式系统开发和调试工具:集源码编辑器,工程管理器,工程编译器,集成调试环境,ADT Emulator for ,,,调试接口等。其界面同,icrosoft ,isual ,tudio环境相似,用户可以在,,, ,,, for ,,,集成开发环境中创建工程,打开工医嘱,建立打开和编译文件,编译,连接,设置,运行,调试嵌入式应用程序。 2(3(2 ADT与ARM嵌入式系统及PC系统的连接 连续图如下所示: 图2 ADT与PC系统及嵌入式系统连接图 7 ***大学毕业论文(设计) 2.3.3 JX44B0-2嵌入式系统实验平台概绍 JX44B0-1B是一购入式系统教学系统采用统一的豪华实验箱包装,除ADT1000仿真器外,所有配件均放置于实验箱之内,所包含配件如下: 1、JX44B0-1B主板一块; 2、ADT1000仿真器一套(为可选配置); 3、320 X 240 256色彩色LCD显示器一块(带触摸屏); 4、4 X 4键盘一套; 5、USB连接电缆一条; 6、PC并口延长电缆一条; 7、RS-232串口通讯线一条; 8、直连网线一根;9、软件光盘一张; 10、实验指导书一本; 3 程序结构、思想和相关技术介绍 3(1 PC端软件的键盘与鼠标事件的仿真实现 3(1(1 PC端软件功能概绍 PC端的软件设计要求实现对键盘事件的按键动作(包括单键按下及组合键按下)和鼠标事件(包括移动光标位置,鼠标左右键的单击,双击等)的模拟仿真。并且在程序中要增加异步通信功能,并且引入多线程技术,使得程序具有更好和响应性和高效率。 3(1(2 键盘事件的模拟仿真 我们来先了解一下windows中响应键盘事件的机制。当用户按下键盘上的一个键时,键盘内的芯片会检测到这个动作,并把这个信号传送到计算机。键盘上的所有按键都有一个编码,称作键盘扫描码。当按下一个键时,这个键的扫描码就被传给系统。扫描码是跟具体的硬件相关的,同一个键,在不同键盘上的扫描码有可能不同。键盘控制器就是将这个扫描码传给计算机,然后交给键盘驱动程序。键盘驱动程序会完成相关的工作,并把这个扫描码转换为键盘虚拟码。什么是虚拟码呢,因为扫描码与硬件相关,不具有通用性,为了统一键盘上所有键的编码,于是就提出了虚拟码概念。无论什么键盘,同一个按键的虚拟码总是相同的,这样程序就可以识别了。简单点说,虚拟码就是我们经常可以看到的像VK_A,VK_B这样的常数,比如键A的虚拟码是65,写成16进制就是&H41。当键盘驱动程序把扫描码转换为虚拟码后,会把这个键盘操作的扫描码和虚拟码还有其它信息一起传递给操作系统。然后操作系统则会把这些信息封装在一个消息中,并把这个键盘消息插入到消息列队。 掌握了这个过程,我们就可以编程实现在其中的某个环节来模拟键盘操作了。有多种方法可以实现键盘模拟,我们就介绍几种比较典型有: (1)局部级模拟: -------------PostMessageA -------------SendMessageA -------------MapVirtualKeyA 8 ***大学毕业论文(设计) 从上面的流程可以看出,键盘事件是最终被送到活动窗口,然后才引起目标程序响应的。所以局部级模拟方法就是利用PostMessageA,SendMessageA,MapVirtualKeyA这三个API函数相互配合,直接伪造一个键盘消息发给目标程序。由于本设计没用这种方法,故不做深入探讨。 (2)驱动级模拟: 驱动级模拟直接读写键盘的硬件端口,这种直接读写键盘端口的方法来模拟硬件事件的方法绕过了windows的消息机制,而直接与键盘驱动程序打交道,效率提高了很多。在此因本设计没涉及,故不深入讨论。 (3)全局级模拟: -------------keybd_event -------------SendInput -------------SetWindowsHookExA 在全局事件中,键盘事件不是直接送到活动窗口,而是送给了操作系统,模拟全局键盘息常用API函数keybd_event来实现。 下面具体讨论全局级模拟: 有些程序(特别是一些游戏)出于某些原因,会禁止用户对它使用模拟按键程序,或者能够检查出收到的键盘消息与真实的按键和模拟的按键消息总是有一些小差别,从这些小差别上,目标程序就能判断出:这是假的~是伪造的~~因此,如果用PostMessage发送局部消息模拟按键不成功的话,你可以试一试全局级的键盘消息。 模拟全局键盘消息常见的可以有以下一些方法: (1) 用API函数keybd_event,这个函数可以用来模拟一个键盘事件,它的声明为: VOID keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,DWORD dwExtralnfo); 参数说明: bVk:定义一个虚拟键码。键码值必须在1,254之间。 bScan:定义该键的硬件扫描码。 dwFlags:定义函数操作的名个方面的一个标志位集。应用程序可使用如下一些预定义常数的组合设置标志位。 KEYEVENTF_EXETENDEDKEY:若指定该值,则扫描码前一个值为OXEO(224)的前缀字节。KEYEVENTF_KEYUP:若指定该值,该键将被释放;若未指定该值,该键交被接下。dwExtralnfo:定义与击键相关的附加的32位值。 (2) 返回值:该函数无返回值。 (3) 举例说明,比如要模拟按下A键,可以这样: Const KEYEVENTF_KEYUP = &H2 keybd_event( VK_A, 0, 0, 0 );// '按下A键 keybd_event( VK_A, 0, KEYEVENTF_KEYUP, 0 ); // '释放A键 注意有时候按键的速度不要太快,否则会出问题,可以用API函数Sleep来进行延时。 那么如果要模拟按下功能键怎么做呢,比如要按下Ctrl+C实现拷贝这个功能,可以这样: 9 ***大学毕业论文(设计) keybd_event (VK_Ctrl, 0, 0, 0 ); // '按下Ctrl键 keybd_event (VK_C, 0, 0, 0 ) ; // '按下C键 Sleep (500 ) ; //延时500毫秒 keybd_event (VK_C, 0, KEYEVENTF_KEYUP, 0 ); // '释放C键 keybd_event (VK_Ctrl, 0, KEYEVENTF_KEYUP, 0 ) ; // '释放Ctrl键 尽管keybd_event传递一个与OEM相关的硬件扫描码给系统,但应用程序不能用此扫描码。系统在内部将扫描码转换成虚拟键码,并且在传送给应用程序前清除键码的UP/down位。应用程序可以摸拟PRINTSCREEN键的按下来获得一个屏幕快照,并把它存放到剪切板中。若要做到这一点,则要将keybd_event的bVk参数置为VK_SNAPSHOT,bScan参数置为0(用以获得全屏快照)或hScan置为1(仅获得活动窗口的快照)。Windows CE:WindowsCE支持dwFlags参数附加的标志位。即使用KEYEVENTF_SILENT标志模拟击键,而不产生敲击的声音。Windows CE不支持KEYEVENTF_EXTENDEDKEY标志。 3(1(3 鼠标事件的模拟仿真 鼠标事件的模拟主要由以下三个函数来实现: (1)mouse_event函数 函数功能:该函数综合鼠标击键和鼠标动作。 函数原型: VOID mouse_event( DWORD dwFlags, // motion and click options DWORD dx, // horizontal position or change DWORD dy, // vertical position or change DWORD dwData, // wheel movement ULONG_PTR dwExtraInfo // application-defined information ); 参数: dwFlags:标志位集,指定点击按钮和鼠标动作的多种情况。此参数里的各位可以是下列值的任何合理组合: MOUSEEVENTF_ABSOLUTE:表明参数dX,dy含有规范化的绝对坐标。如果不设置此位,参数含有相对数据:相对于上次位置的改动位置。此标志可被设置,也可不设置,不管鼠标的类型或与系统相连的类似于鼠标的设备的类型如何。要得到关于相对鼠标动作的信息,参见下面备注部分。 MOUSEEVENTF_MOVE:表明发生移动。 MOUSEEVENTF_LEFTDOWN:表明接按下鼠标左键。 MOUSEEVENTF_LEFTUP:表明松开鼠标左键。 MOUSEEVENTF_RIGHTDOWN:表明按下鼠标右键。 MOUSEEVENTF_RIGHTUP:表明松开鼠标右键。 10 ***大学毕业论文(设计) MOUSEEVENTF_MIDDLEDOWN:表明按下鼠标中键。 MOUSEEVENTF_MIDDLEUP:表明松开鼠标中键。 MOUSEEVENTF_WHEEL:在Windows NT中如果鼠标有一个轮,表明鼠标轮被移动。移动的数量由dwData给出。 dx:指定鼠标沿x轴的绝对位置或者从上次鼠标事件产生以来移动的数量,依赖于MOUSEEVENTF_ABSOLUTE的设置。给出的绝对数据作为鼠标的实际X坐标;给出的相对数据作为移动的mickeys数。一个mickey表示鼠标移动的数量,表明鼠标已经移动。 dy:指定鼠标沿y轴的绝对位置或者从上次鼠标事件产生以来移动的数量,依赖于MOUSEEVENTF_ABSOLUTE的设置。给出的绝对数据作为鼠标的实际y坐标,给出的相对数据作为移动的mickeys数。 dwData:如果dwFlags为MOUSEEVENTF_WHEEL,则dwData指定鼠标轮移动的数量。正值表明鼠标轮向前转动,即远离用户的方向;负值表明鼠标轮向后转动,即朝向用户。一个轮击定义为WHEEL_DELTA,即120。 如果dwFlagsS不是MOUSEEVENTF_WHEEL,则dWData应为零。 dwExtralnfo:指定与鼠标事件相关的附加32位值。应用程序调用函数GetMessgeExtraInfo来获得此附加信息。 返回值:无。 备注:如果鼠标被移动,用设置MOUSEEVENTF_MOVE来表明,dX和dy保留移动的信息。给出的信息是绝对或相对整数值。 如果指定了MOUSEEVENTF_ABSOLUTE值,则dX和dy含有标准化的绝对坐标,其值在0到65535之间。事件程序将此坐标映射到显示表面。坐标(0,0)映射到显示表面的左上角,(65535,65535)映射到右下角。 如果没指定MOUSEEVENTF_ABSOLUTE,dX和dy表示相对于上次鼠标事件产生的位置(即上次报告的位置)的移动。正值表示鼠标向右(或下)移动;负值表示鼠标向左(或上)移动。 鼠标的相对移动服从鼠标速度和加速度等级的设置,一个最终用户用鼠标控制面板应用程序来设置这些值,应用程序用函数SystemParametersln fo来取得和设置这些值。 在应用加速时系统对指定相对鼠标移动提供了两个测试。如果指定的沿X轴y轴的距离比第一个鼠标阈值大,并且鼠标的加速等级非零,则操作系统将距离加倍。如果指定的沿X轴或y轴的距离比第二个鼠标阈值大,并且鼠标的加速等级为2,则操作系统将从第一个阈测试得来的距离加倍。这样就允许操作系统将指定鼠标沿X轴或y轴的相对位移加到4倍。 一旦应用了加速,系统用期望的鼠标速度换算合成的值。鼠标速度的范围是从1(最慢)到20(最快),并代表基于鼠标移动的距离指示符移动的数量。缺省值是10,表示对鼠标的移动设有附加的修改。 函数mouse_event需要用的应用程序用来合成鼠标事件。也被应用程序用来取得鼠标位置和鼠标按键状态之外的鼠标信息。例如,如果输入板制造商想将基于画笔的信息传给自己的应用程序,可以写一个直接与输入板 11 ***大学毕业论文(设计) 硬件通信的动态键接库(DLL),获得附加的信息,并保存到一个队列中。DLL然后调用 mouse_event,用标准按键和x/y位置数据,并在参数dwExtralnfo设置排列的附加信息的指针或索引。当应用程序需要附加信息时,调用 DLL(连同存贮在dwEXtralnfo中的指针或索引),则DLL返回附加信息。 (2)GetCursorPos函数 函数功能:该函数检取光标的位置,以屏幕坐标表示。 函数原型:BOOL GetCursorPos(LPPOlNT IpPoint); 参数: IpPint:POINT结构指针,该结构接收光标的屏幕坐标。 使用时要先定义一个数据结构: Public Type POINTAPI x As Long y As Long End Type 例如: dim biao as POINTAPI GetCursorPos biao 那么biao。x用来存放当前光标的x轴坐标,biao。y用来存放当前y轴的坐标。 返回值:如果成功,返回值非零;如果失败,返回值为零。若想获得更多错误信息,请调用GetLastError函数。 备注:。光标的位置通常以屏幕坐标的形式给出,它并不受包含该光标的窗口的映射模式的影响。该调用过程必须具有对窗口站的WINSTA_READATTRIBUTES访问权限。。此函数为api函数,调用时要函数声明:Public Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long。 (3)SetCursorPos函数 函数功能:该函数把光标移到屏幕的指定位置。如果新位置不在由 ClipCursor函数设置的屏幕矩形区域之内,则系统自动调整坐标,使得光标在矩形之内。 函数原型:BOOL SetCursorPos(int X,int Y); 参数: X:指定光标的新的X坐标,以屏幕坐标表示。 Y:指定光标的新的Y坐标,以屏幕坐标表示。 返回值:如果成功,返回非零值;如果失败,返回值是零,若想获得更多错误信息,请调用GetLastError函数。 备注:该光标是共享资源,仅当该光标在一个窗口的客户区域内时它才能移动该光标。 12 ***大学毕业论文(设计) 3(1(4多线程技术的引入 在以前只有进程的操作系统中,进程是处理器调用的对象,但是多个进程并发时,进程切换带来的开销所占的比例越来越大,而且进程之间的通信效率也大大受到限制,因此就引入了多线程技术,此时线程成了处理器处理的对象,大大改善了处理器的效率,并减少了开发并行程序时的空间和时间开销。 所以,在本设计的PC端程序中引入多线程是有必要的,本线程次设计中主要用到两个线程,一个工作线程,主要用来处理数据,对键盘鼠标事件进行模拟,另一个线程主要用于接收串口数据。在两个线程的相互配合下,实现了PC端程序的异步通信,大大提高了程序和效率和响应速度。 多线程程序的一般框架如下: 图3 多线程应用程序框架 线程函数的输入一个LPVOID型的参数,可以是一个DWORD型的整数,也可以是一个指向一个缓冲区的指针, 返回一个DWORD型的值。象WinMain函数一样,这个函数并不由操作系统调用, 操作系统调用包含在KERNEL32。DLL中的非C运行时的一个内部函数,如StartOfThread,然后由StartOfThread函数建立起一个异常处理框架后,调用我们的函数。 一个进程的主线程是由操作系统自动生成,如果你要让一个主线程创建额外的线程,你可以调用来CreateThread完成。CreateThread定义如下: HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpsa, DWORDcbstack, LPTHREAD_START_ROUTINElpStartAddr, LPVOID lpvThreadParm, DWORDfdwCreate,LPDWORDlpIDThread); 其中lpsa参数为一个指向SECURITY_ATTRIBUTES结构的指针。如果想让对象为缺省安全属性的话,可以传一个NULL,如果想让任一个子进程都可继承一个该线程对象句柄,必须指定一个SECURITY_ATTRIBUTES结构,其中bInheritHandle成员初始化为TRUE。参数cbstack表示线程为自己所用堆栈分配 13 ***大学毕业论文(设计) 的地址空间大小,0表示采用系统缺省值。 参数lpStartAddr为新线程开始执行时所在函数的地址,即为线程函数。lpvThreadParm为传入线程函数的参数,fdwCreate参数指定控制线程创建的附加标志,可以取两种值。如果该参数为0,线程就会立即开始执行,如果该参数为CREATE_SUSPENDED,则系统产生线程后,初始化CPU,登记CONTEXT结构的成员,准备好执行该线程函数中的第一条指令,但并不马上执行,而是挂起该线程。最后一个参数lpIDThread 是一个DWORD类型地址,返回赋给该新线程的ID值。 3.2 ARM嵌入式系统端程序的设计与实现 3.2.1 ARM端程序功能概绍 在ARM端实现用查询方式对串口数据的收发功能。‘收’是指接收PC程序发到嵌入式系统端的数据,‘发’是指从嵌入式系统通过串口向PC端发数据。嵌入式系统端的数据输入通过实验箱上小键盘输入完成。 3.2.2 异部串行通信的实现 异步串行方式是将传输数据的每个字符一位接一位(例如先低位、后高位)地传送。数据的各不同位可以分时使用同一传输通道,因此串行I/O 可以减少信号连线,最少用一对线即可进行。 接收方对于同一根线上一连串的数字信号,首先要分割成位,再按位组成字符。为了恢复发送的信息,双方必须协调工作。 在微型计算机中大量使用异步串行I/O 方式,双方使用各自的时钟信号,而且允许时钟频率有一定误差,因此实现较容易。但是由于每个字符都要独立确定起始和结束(即每个字符都要重新同步),字符和字符间还可能有长度不定的空闲时间,因此效率较低。 图4 异步串行通信中的字符传送格式 具体过程如下: 开始前,线路处于空闲状态,送出连续“1”。传送开始时首先发一个“0”作为起始位,然后出现在通信线上的是字符的二进制编码数据。每个字符的数据位长可以约定为5位、6位、7位或8位,一般采用ASCII编码。后面是奇偶校验位, 14 ***大学毕业论文(设计) 根据约定,用奇偶校验位将所传字符中为“1”的位数凑成奇数个或偶数个。也可以约定不要奇偶校验,这样就取消奇偶校验位。最后是表示停止位的“1”信号,这个停止位可以约定持续1 位、1。5 位或2 位的时间宽度。 至此一个字符传送完毕,线路又进入空闲,持续为“1”。经过一段随机时间后,下一个字符开始传送才又发出起始位。每一个数据位的宽度等于传送波特率的倒数。微机异步串行通信中,常用的波特率为110,150,300,600,1200,2400,4800,9600 ,115200等。 程序控制流程图如下所示: 子操作完成键盘鼠标的模拟,键盘处理程序负责接收用户输入的信息。各 部分实现可下文。 3.2.3 S3C44B0异步串行口控制器及相关寄存器 S3C44B0自带两个异步串行口控制器,每个控制器有16字节的FIFO(先入先出寄存器),最大波特率115。2K。每个UART有7种状态:溢出错误,校验错误,帧错误,暂停态,接收缓冲区准备好,发送缓冲区空,发送移位缓冲器空,这些状态可以由相应的UTRSTATn或UERSTATn寄存器表示,并且与发送接收缓冲区相对应的有错误缓冲区。 波特率的大小可以通过设置波特率寄存器(UBRDIVn)控制。计算公式如下: UBRDIVn = (int)(MCLK/(bps x 16) ) -1, 其中MCLK 是系统频率,在40MHz的情况下,当波特率取115200时, UBRDIVn = (int)(40000000 / (115200 x 16) + 0。5 ) – 1 = 21 15 ***大学毕业论文(设计) 现将相关寄存器名称中英文对照列表如下: 寄存器名称 英文表示 线路控制寄存器 ULCONn 控制寄存器 UCONn FIFO控制寄存器 UFCONn 控制寄存器 UMCONn 状态寄存器 UTRSTAT 错误状态寄存器 UERSTAT FIFO状态寄存器 UFSTAT 发送寄存器 UTXH 接收寄存器 URXH 波特率因子寄存器 UBRDIV 表1 UART相关的寄存器中英文名称对照 3.2.4 键盘输入与IO 这部分主要是通过编写矩阵键盘扫描程序,并将按键键值送往PC端应用程序。键盘扫描过程就是让微处理器按有规律的时间间隔查看键盘矩阵,以确定是否有键被按下,一旦处理器判定有一个键按下,键盘扫描软件将过滤掉抖动并且判定哪个键被按下,每个键被分配一个称为扫描码的唯一标识符。应用程序利用该扫描码,根据按下的键来判定应该采取什么行动,换句话说,扫描码将告诉应用程序按下哪个键。 实现方法如下: 1,初始化:所有的行(输出端口)被强行设置为低电平 2,在没有任何键按下时,所有的列(输入端口)将读到高电平。 3,任何键的闭合将造成其中的一列变为低电平。 4,一旦检测到有键被按下,就需要找出是哪一个键。过程很简单,微处理器只需在其中一列上输出一个低电平。如果它在输入端口上发现一个0值,微处理器就知道在所选择行上产生了键的闭合。 3.2 PC端与ARM嵌入式端的串行通讯实现 3.2.1 端与端串口通讯概绍 串口通信(Serial Communication), 是指外设和计算机间,本设计是指JX44BO-2嵌入式系统与PC之间,通过串口数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式。这种通信方式使用的数据线少,在远距离通信中可以节约通信成本,但其传输速度比并行传输低。串行通信接口电路一般由可编程的串行接口芯片、波特率发生器、EIA与TTL电平转换器以及地址译码电路组成。 16 ***大学毕业论文(设计) 3.2.2串口通讯工作方式 由于 CPU 与接口之间按并行方式传输,接口与外设之间按串行方式传输,因此,在串行接口中,必须要有接收移位寄存器 (串?并)和发送移位寄存器(并?串)。 在数据输入过程中,数据一位一位地从外设进入接口的接收移位寄存器,当接收移位寄存器中已接收完 1 个字符的各位后,数据就从接收移位寄存器进入数据输入寄存器 在数据输出过程中,CPU 把要输出的字符(并行地)送入数据输出寄存器,数据输出寄存器的内容传输到,发送移位寄存器,然后由发送移位寄存器移位,把数据 一 位一位地送到外设。发送移位寄存器的移位速度由发送时钟确定。 串口通讯数据线接口引脚如下图: 图5 串口数据线引脚图 3.2.1 串口数据接收的VC实现 Win 32系统为串行通信提供了全新的服务。传统的OpenComm、ReadComm、WriteComm、CloseComm等函数已经过时,WM_COMMNOTIFY消息也消失了。取而代之的是文件I/O函数提供的打开和关闭通信资源句柄及读写操作的基本接口。 新的文件I/O函数(CreateFile、ReadFile、WriteFile等)支持重叠式输入输出,这使得线程可以从费时的I/O操作中解放出来,从而极大地提高了程序的运行效率。 (1) 串行口的打开和关闭 Win 32系统把文件的概念进行了扩展。无论是文件、通信设备、命名管道、邮件槽、磁盘、还是控制台,都是用API函数CreateFile来打开或创建的。该函数的声明为: 17 ***大学毕业论文(设计) HANDLE CreateFile( LPCTSTR lpFileName, // 文件名 DWORD dwDesiredAccess, // 访问模式 DWORD dwShareMode, // 共享模式 LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 通常为NULL DWORD dwCreationDistribution, // 创建方式 DWORD dwFlagsAndAttributes, // 文件属性和标志 HANDLE hTemplateFile // 临时文件的句柄,通常为NULL ); 如果调用成功,那么该函数返回文件的句柄,如果调用失败,则函数返回INVALID_HANDLE_VALUE。 (2)串行口的初始化 在打开通信设备句柄后,常常需要对串行口进行一些初始化工作。这需要通过一个DCB结构来进行。DCB结构包含了诸如波特率、每个字符的数据位数、奇偶校验和停止位数等信息。在查询或配置置串行口的属性时,都要用DCB结构来作为缓冲区。 调用GetCommState函数可以获得串口的配置,该函数把当前配置填充到一个DCB结构中。一般在用CreateFile打开串行口后,可以调用GetCommState函数来获取串行口的初始配置。要修改串行口的配置,应该先修改DCB结构,然后再调用SetCommState函数用指定的DCB结构来设置串行口。 除了在DCB中的设置外,程序一般还需要设置I/O缓冲区的大小和超时。Windows用I/O缓冲区来暂存串行口输入和输出的数据,如果通信的速率较高,则应该设置较大的缓冲区。调用SetupComm函数可以设置串行口的输入和输出缓冲区的大小。 在用ReadFile和WriteFile读写串行口时,需要考虑超时问题。如果在指定的时间内没有读出或写入指定数量的字符,那么ReadFile或WriteFile的操作就会结束。要查询当前的超时设置应调用GetCommTimeouts函数,该函数会填充一个COMMTIMEOUTS结构。调用SetCommTimeouts可以用某一个COMMTIMEOUTS结构的内容来设置超时。 COMMTIMEOUTS结构如下: typedef struct _COMMTIMEOUTS{ DWORD ReadIntervalTimeout; // 读间隔超时 DWORD ReadTotalTimeoutMultiplier; // 读时间系数 DWORD ReadTotalTimeoutConstant; // 读时间常量 DWORD WriteTotalTimeoutMultiplier; // 写时间系数 DWORD WriteTotalTimeoutConstant; // 写时间常量 } COMMTIMEOUTS,*LPCOMMTIMEOUTS; (3)串口的读与写 在用ReadFile和WriteFile读写串行口时,既可以同步执行,也可以重叠(异步)执行。在同步执行时,函数直到操作完成后才返回。这意味着在同步执行时线程会被阻塞,从而导致效率下降。在重叠执行时,即使操作还未完成,调用的 18 ***大学毕业论文(设计) 函数也会立即返回。费时的I/O操作在后台进行,这样线程就可以干别的事情。例如,线程可以在不同的句柄上同时执行I/O操作,甚至可以在同一句柄上同时进行读写操作。“重叠”一词的含义就在于此。 ReadFile函数只要在串行口输入缓冲区中读入指定数量的字符,就算完成操作。而WriteFile函数不但要把指定数量的字符拷入到输出缓冲中,而且要等这些字符从串行口送出去后才算完成操作。 ReadFile和WriteFile函数是否为执行重叠操作是由CreateFile函数决定的。如果在调用CreateFile创建句柄时指定了FILE_FLAG_OVERLAPPED标志,那么调用ReadFile和WriteFile对该句柄进行的读写操作就是重叠的,如果未指定重叠标志,则读写操作是同步的。 函数ReadFile和WriteFile的参数和返回值很相似。这里仅列出ReadFile函数 的声明: BOOL ReadFile( HANDLE hFile, // 文件句柄 LPVOID lpBuffer, // 读缓冲区 // 要求读入的字节数 DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, // 实际读入的字节数 LPOVERLAPPED lpOverlapped // 指向一个OVERLAPPED结构 ); //若返回TRUE则表明操作成功 当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,线程应该调用GetLastError函数分析返回的结果。例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,而且GetLastError函数返回ERROR_IO_PENDING。 4系统需求分析 4(1 系统角色及其功能分析 由于本设计并不涉及到数据库系统,所以该系统的系统角色只有用户而已。 用户主要可以用的功能:通过JX44B0-2系统上的键盘按钮控制并完成与PC端模拟软件的交互。 4(2 系统主要功能详细描述 该系统有两大功能,即键盘事件模拟和鼠标事件模拟。用户操作主要在JX44B0-2嵌入式系统上进行。现将用户能够进行操作列举如下: 鼠标事件: (1)鼠标左键单击,由小键盘(位于JX44B0系统)数字键“1”控制。 19 ***大学毕业论文(设计) (2)鼠标左键双击,由小键盘(位于JX44B0系统)数字键“3”控制。 (3)鼠标光标向上移动,由小键盘(位于JX44B0系统)数字键“2”控制。 (4)鼠标光标向下移动,由小键盘(位于JX44B0系统)数字键“5”控制。 (5)鼠标光标向左移动,由小键盘(位于JX44B0系统)数字键“4”控制。 (6)鼠标光标向右移动,由小键盘(位于JX44B0系统)数字键“6”控制。 键盘事件: (7)打印字符串“hello world”,由小键盘(位于JX44B0系统)数字键“7” 控制。 (8)”ctrl+O”快捷键打开“打开”动作框,由小键盘(位于JX44B0系统)数字键“8”控制。 (9)打印字符“a”, 由小键盘(位于JX44B0系统)数字键“9”控制。 4(3 系统功能模块设计 功能结构图如下: 图6 功能模块设计图 从图中可以看出,系统主要实现了以下功能:鼠标左键单击、鼠标左键双击、鼠标光标向上移动,鼠标光标向下移动、由小键盘(位于JX44B0系统)数字键“5”控制、鼠标光标向左移动、鼠标光标向右移动、打印字符串“hello world”、”ctrl+O”快捷键打开“打开”动作框,打印字符“a”。 20 ***大学毕业论文(设计) 5 总体设计及实现 5.1 总体模块设计 该系统是基于架构。实现键盘鼠标事件的模拟。系统使用语言开发,利用到串口通信和多线程等技术,整个系统分成两层,有效实现了系统各部分的低偶合。 整个系统主要有:表现层。业务层。数据访问层。利用软件分层把系统偶合度降低。在数据访问层,使用接口和和实现分离。上层的服务只依赖于底层的接口,底层的实现方式改变不会影响到上层的服务。这样就会最大程度的降低了软件各部分之间的偶合。便于以后修改底层的实现。在分层的基础上。有将软件分模块,从而使系统横向上面分模块,纵向上面分层次。 整个系统的模块层次是: 图总体模块图 从上读也可看出,本设计主要有两个模块,ARM7嵌入式系统模块和PC系统模块。ARM7嵌入式系统模块利用JX44BO系统上的小键盘接收用户输入的数据,这里主要是数字键,JX44BO 系统接收到数据后将数据写到串口上。PC系统通过串口读写程序,根据读到的数据,做不同的动作,完成不同的操作。两个模块相互配合,通过分层把系统偶合度降低。 系统控制流程图如下所示: 21 ***大学毕业论文(设计) 图8 系统控制流程图 从控制流程图看出整个系统的运行过程如下: 启动程序后,首先对串口进行初始化,比如波特率、字符的数据位数、奇偶校验和停止位数等信息,同时启动监控程序,对JX44B0系统小键盘进行安键监控,一旦监控程序接收到用户按键消息,就将键值通过串口传送到PC端应用程序。PC端应用程序主程序对串口进行监控,一旦有数据送到就执行相应的动作。总之,该系统就在嵌入式系统端和PC端应用程序的两个循环中实现键盘鼠标事件的模拟操作。 5.2 各子系统模块总体设计 5.2.1 JX44BO-2嵌入式系统端设计 端系统控制流程图如下: 22 ***大学毕业论文(设计) 图9 ARM端系统控制流程图 从上图可以看出: S3C44B0自带两个异步串行口控制器,每个控制器有16字节的FIFO(先入先出寄存器)最大波特率115.2K每个UART有7种状态:溢出错误,校验错误,帧错误,暂停态,接收缓冲区准备好,发送缓冲区空,发送移位缓冲器空,这些状态可以由相应的UTRSTATn或UERSTATn寄存器表示,并且与发送接收缓冲区相对应的有错误缓冲区。 从PC机和单片机帧格式可知:通过软件编程,使得PC机在发送地址(单片机编号)时,奇偶位为1,发送数据时为0;单片机接收时,TB8为1表示收到的地址,为0表示收到的数据。 主程序流程图如下: 23 ***大学毕业论文(设计) 图10 主程序的流程图 从上图看出,关键步骤为“初始化串行口”,和“主程序踏步”处。初始化主要为串行口为11位UART,传送波特率与SMOD有关。发送或接收的一帧数据中包括1位起始位0,8位数据位,1位可编程位(用于奇偶校验)和1位停止位1。串行口为波特率可调的10位通用异步接口UART。每发送或接收的一帧信息中,包括1位起始位0,8位数据位和1位停止位1。 根据串行通信的格式及约定(如:同步方式、通讯速率、数据块格式、信号电平……等)不同,形成了多种串行通信的协议与接口标准。通信线上传送的所有位信号都保持一致的信号持续时间,每一位的信号持续时间都由数据传送速度确定。 数据传送速率:每秒传送的二进制代码的位数。波特率反映了串行通信的速率,也反映了对于传输通道的要求。波特率越高,要求传输通道的频率越宽,一般异步通信的波特率在50b/s~19200b/s之间。相互通信的甲乙双方必须具有相同的波特率,否则无法成功地完成串行数据通信。 键盘扫描算法的算法流程图如下: 24 ***大学毕业论文(设计) 图11 键盘扫描算法算法流程图 5.2.2 PC系统端程序设计 PC机与单片机构成主从式上下位计算机系统。 从PC机键盘上输入一个字符,然后将这个字符发送给单片机,单片机接收到这个字符后,不做任何处理,又将它发回给PC机,PC机将这个字符显示在屏幕上。连接电路如下: 25 ***大学毕业论文(设计) 图12 PC机与ARM嵌入式系统连接电路图 EIA电平:双极性信号逻辑电平, 它是一套负逻辑定义; -3V到-25V之间的电平表示逻辑“1”; +3V到+25V之间的电平表示逻辑“0”; TTL电平:计算机内部(S3C44B0)使用TTL电平; 电平转换电路:常用专门的RS-232接口芯片,如SP3232、SP3220等,在TTL电平和EIA电平之间实现相互转换; 程序流程图如下: 图13 多线程实现算法流程图 首先,设置串行口为方式2,并且设置数据块指针,以及设置数据块长度,然后启动接收;接收时判断是否接收完一帧。若完,清RI,读入数据 ;未完等待;P=1,RB8=0,则出错 ,二者全为1,则正确;P=0,RB8=1,则出错 否则正确,更新地址指针;接下来判断数据块是否接收完若完,接收正确,且接收完清F0标志,返回。否则,出错,置F0标志为1返回。 26 ***大学毕业论文(设计) 6 系统详细设计 6(1 PC端系统的具体实现与程序编写 6(1(1 鼠标事件模拟的实现 使用API函数mouse_event可以模拟一次鼠标事件,比如左键单击、双击和 右键单击等。 (1)鼠标光标向上移动事件模拟 鼠标光标向上移动动作的关键实现代码如下: …… case MOUSEMOVEUP: { …… POINT p; GetCursorPos(&p); SetCursorPos(p.x,p.y-LENGT); …… } break; …… 下面对上面代码作下说明: 首先,POINT是一个结构,它定义了一个点的坐标(x,y)。 结构的定义下: typedef struct tagPOINT { LONG x; LONG y; }POINT; 参数说明: X: 指出一个点的x坐标。 Y: 指出一个点的y坐标。 然后,GetCursorPos()和SetCursorPos()分别为获取鼠标当前位置和设置鼠标 光标新位置的函数,形参LENGTH为鼠标移动和位移量,通过设置LENGTH值 的大小可以改变鼠标移动的快慢。 (2)鼠标光标向下移动事件模拟 鼠标光标向下移动动作的关键实现代码如下: …… case MOUSEMOVEUP: { 27 ***大学毕业论文(设计) …… POINT p; GetCursorPos(&p); SetCursorPos(p.x,p.y+LENGT); …… } break; …… 其中所用参数及函数用法同鼠标向上移动程序代码。 (3)鼠标光标向左移动事件模拟 鼠标光标向左移动动作的关键实现代码如下: …… case MOUSEMOVEUP: { …… POINT p; GetCursorPos(&p); SetCursorPos(p.x-LENGTH,p.y); …… } break; …… 其中所用参数及函数用法同鼠标向上移动程序代码。 (4)鼠标光标向右移动事件模拟 鼠标光标向右移动动作的关键实现代码如下: …… case MOUSEMOVEUP: { …… POINT p; GetCursorPos(&p); SetCursorPos(p.x+LENGTH,p.y); …… } break; …… 其中所用参数及函数用法同鼠标向上移动程序代码。 (5)鼠标左键单击 鼠标左键单击实现关键代码如下: case MOUSECLICKLEFT: 28 ***大学毕业论文(设计) { ……. if(LeftD==false) { ……. { mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0); LeftD=true; Sleep(500); mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0); LeftD=false; } ……. } } break; …….. 现对如上代码作如下说明: 首先,mouse_event函数,该文件包含在文件包windows.h中。Mouse_event()函数使用规则如下: Mouse_event函数功能:该函数综合鼠标击键和鼠标动作。 函数原型说明: VOID mouse_event ( DWORD dwFlags, // motion and click options DWORD dx, // horizontal position or change DWORD dy, // vertical position or change DWORD dwData, // wheel movement ULONG_PTR dwExtraInfo // application-defined information ); 参数说明: dwFlags:标志位集,指定点击按钮和鼠标动作的多种情况。此参数里的各位可以是下列值的任何合理组合: MOUSEEVENTF_ABSOLUTE:表明参数dX,dy含有规范化的绝对坐标。如果不设置此位,参数含有相对数据:相对于上次位置的改动位置。此标志可被设置,也可不设置,不管鼠标的类型或与系统相连的类似于鼠标的设备的类型如何。要得到关于相对鼠标动作的信息,参见下面备注部分。 MOUSEEVENTF_MOVE:表明发生移动。 MOUSEEVENTF_LEFTDOWN:表明接按下鼠标左键。 MOUSEEVENTF_LEFTUP:表明松开鼠标左键。 29 ***大学毕业论文(设计) MOUSEEVENTF_RIGHTDOWN:表明按下鼠标右键。 MOUSEEVENTF_RIGHTUP:表明松开鼠标右键。 MOUSEEVENTF_MIDDLEDOWN:表明按下鼠标中键。 MOUSEEVENTF_MIDDLEUP:表明松开鼠标中键。 MOUSEEVENTF_WHEEL:在Windows NT中如果鼠标有一个轮,表明鼠标轮被移动。移动的数量由dwData给出。 然后,Sleep函数是为了防止过快发送按键抬起消息而造成失误,参数500以毫秒为单位。 最后,如上面所示如果我们要使用两个dwFlags常数的组合时,可以用Or将其连接起来。本例中我们把dx,dy参数都设为0,是指每次模拟事件的位置是鼠标的当前位置,dx,dy在没有使用MOUSEEVENTF_ABSOLUTE标志时是相对于鼠标当前位置的坐标,如果设置为使用绝对坐标,则dx,dy是相对于屏幕的坐标。 (6)鼠标左键双击 鼠标左键双击是由两次单击完成的,故实现代码如下 …….. for(i=0;i<2;i++) { …….. mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0); Sleep(500); mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0); LeftD=false; …….. } …….. 程序中使用的变量和函数均同鼠标单击相同,不再说明。其中LeftD是变量是否处于按下状态标志。 6.1.2 键盘事件模拟的实现 本设计用用API函数keybd_event,这个函数可以用来模拟一个键盘事件,比如键盘按键等。 keybd_event函数用法如下: 函数功能:该函数合成一次击键事件。系统可使用这种合成的击键事件来产生WM_KEYUP或WM_KEYDOWN消息,键盘驱动程序的中断处理程序调用keybd_event函数。在Windows NT中该函数己被使用SendInput来替代它。 函数原型:VOID keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,DWORD dwExtralnfo); 30 ***大学毕业论文(设计) 参数说明: bVk:定义一个虚拟键码。键码值必须在1,254之间。 bScan:定义该键的硬件扫描码。 dwFlags:定义函数操作的名个方面的一个标志位集。应用程序可使用如下一些预定义常数的组合设置标志位。 KEYEVENTF_EXETENDEDKEY:若指定该值,则扫描码前一个值为OXEO(224)的前缀字节。KEYEVENTF_KEYUP:若指定该值,该键将被释放;若未指定该值,该键交被接下。dwExtralnfo:定义与击键相关的附加的32位值。 返回值说明:该函数无返回值。 (1)打印单个字符‘a’ 关键程序代码如下所示: ……… case KEYBOARD: { …….. if(KeyD==true) { keybd_event( GetKeyValue(), 0, KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0); KeyD=false; Sleep(500); keybd_event( GetKeyValue(), 0, KEYEVENTF_EXTENDEDKEY| 0, 0); KeyD=true; } …….. } break; …….. 注意有时候按键的速度不要太快,否则会出问题,可以用API函数Sleep来进行延时参数dwMilliseconds表示延时的时间,以毫秒为单位。GetKeyValue()函数为自定义的获取输入字符的函数,KeyD为 是否有键按下标志。 另外,用keybd_event函数发送的消息为全局级消息,GetKeyValue() 函数接收的是要模拟的键值的虚拟码。 (2)打印字符串“hello ,world” 31 ***大学毕业论文(设计) 程序实现的关键代码如下: …….. Char* str=” hello ,world”; i=0; While(ch=str[i++]!=’\0’) { ……… keybd_event( ch, 0, KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0); KeyD=false; Sleep(500); keybd_event( ch, 0, KEYEVENTF_EXTENDEDKEY| 0, 0); KeyD=true; ………. } ………. 现对程序做如下说明: 该操作实现原理很简单,就是连续打印若干个字符,相当于由若干次单个字符打印过程组成。程序中使用的变量和函数均和打印单个字符时相同,不再累述。 6.1.3 多线程技术的实现 线程被分为两种:用户界面线程和工作线程(又称为后台线程)。用户界面线程通常用来处理用户的输入并响应各种事件和消息,其实,应用程序的主执行线程CWinAPP对象就是一个用户界面线程,当应用程序启动时自动创建和启动,同样它的终止也意味着该程序的结束,进程终止。工作线程用来执行程序的后台处理任务,比如计算、调度、对串口的读写操作等,它和用户界面线程的区别是它不用从CWinThread类派生来创建,对它来说最重要的是如何实现工作线程任务的运行控制函数。 (1)线程的启动 若利用VC创建一个用户界面线程,首先要从类CwinThread产生一个派生类,同时必须使用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE来声明和实现这个CwinThread派生类。第二步是根据需要重载该派生类的一些成员函数如:ExitInstance()、InitInstance()、OnIdle()、PreTranslateMessage()等函数。最后调用 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, 32 ***大学毕业论文(设计) DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); 对于工作线程来说,启动一个线程,首先需要编写一个希望与应用程序的其余部分并行运行的函数如Fun1(),接着定义一个指向CwinThread对象的指针变量*pThread,调用AfxBeginThread(Fun1,param,priority)函数,返回值赋给pThread变量的同时一并启动该线程来执行上面的Fun1()函数,其中Fun1是线程要运行的函数的名字,也既是上面所说的控制函数的名字,param是准备传送给线程函数Fun1的任意32位值,priority则是定义该线程的优先级别,它是预定义的常数。 本设计中线程启动代码如下: …….. HANDLE m_pThread; .. …… unsigned long threadid; m_pThread=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)CommProc, NULL, CREATE_SUSPENDED, &threadid); // 创建并挂起线程 if(m_pThread==NULL) { CloseHandle(m_hCom); return FALSE; } else { m_bConnected=TRUE; //连接上 ResumeThread(m_pThread); // 恢复线程运行 } …….. 代码说明: 首先,HANDLE为对象句柄类型,HANDLE m_pThread则是定义m_pThread为线程句柄。 然后,对CreateThread函数的参数作下说明,其中最重要的便是(LPTHREAD_START_ROUTINE)CommProc这个参数,这他定义了一个指向线程函数的地址,由它找到线程函数入口地址并执行。 CREATE_SUSPENDED参数规定了线程的初始状态为挂起。 最后,CloseHandle和ResumeThread分别起关闭线程句柄和激活线程执行的功能。 (2)线程优先级的设置 33 ***大学毕业论文(设计) 线程优先级被线程调度用来判定何时 每个线程允许运行 。理论上,优先级高的线程比优先级低的线程获得更多的CPU时间。设置线程的优先级,用setPriority()方法,该方法也是Tread的成员。它的通常形式为: final void setPriority(int level) 不过由于本设计线程数量并不太多,故优先级都按默认优先级。 (3)线程的悬挂和恢复 Windows API中包含了应用程序悬挂和恢复它所创建的线程的函数,其中SuspendThread()用来悬挂线程,暂停线程的执行;ResumeThread()用来恢复线程的执行。如果你对一个线程连续若干次执行SuspendThread(),则需要连续执行相应次的ResumeThread()来恢复线程的运行。 用法如下: ResumeThread(m_pThread); // 恢复线程运行 (4)结束线程 终止线程有三种途径,线程可以在自身内部调用AfxEndThread()来终止自身的运行;可以在线程的外部调用BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode )来强行终止一个线程的运行,然后调用CloseHandle()函数释放线程所占用的堆栈;第三种方法是改变全局变量,使线程的执行函数返回,则该线程终止。下面以第三种方法为例,给出部分代码: //////CtestView message handlers /////Set to True to end thread Bool bend=FALSE;//定义的全局变量,用于控制线程的运行; //The Thread Function; UINT ThreadFunction(LPVOID pParam)//线程函数 { while(!bend) { Sleep(1000); } return 0; } ///////////////////////////////////////////////////////////// CwinThread *pThread; HWND hWnd; pThread=AfxBeginThread(ThradFunction,hWnd);//启动线程 pThread->m_bAutoDelete=FALSE;//线程为手动删除 34 ***大学毕业论文(设计) Cview::OnInitialUpdate(); } //////////////////////////////////////////////////////////////// Void CtestView::OnDestroy() { bend=TRUE;//改变变量,线程结束 WaitForSingleObject(pThread->m_hThread,INFINITE);//等待线程结束 delete pThread;//删除线程 Cview::OnDestroy(); } ……. 通常情况下,一个次级线程要为主线程完成某种特定类型的任务,这就隐含着表示在主线程和次级线程之间需要建立一个通信的通道。一般情况下,有下面的几种方法实现这种通信任务:使用全局变量(上一节的例子其实使用的就是这种方法)、使用事件对象、使用消息。 6.1.4串口数据接收程序的VC实现 串口数据的接收是本设计的一大难点,下面分块实现 (1) 串行通信与重叠I/O Win32系统为串行通信提供了全新的服务。传统的OpenComm、ReadComm、WriteComm、CloseComm等函数已经过时,WM_COMMNOTIFY消息也消失了。取而代之的是文件I/O函数提供的打开和关闭通信资源句柄及读写操作的基本接口。 新的文件I/O函数(CreateFile、ReadFile、WriteFile等)支持重叠式输入输出,这使得线程可以从费时的I/O操作中解放出来,从而极大地提高了程序的运行效率。 (2) 串行口的初始化 在打开通信设备句柄后,常常需要对串行口进行一些初始化工作。这需要通过一个DCB结构来进行。DCB结构包含了诸如波特率、每个字符的数据位数、奇偶校验和停止位数等信息。在查询或配置置串行口的属性时,都要用DCB结构来作为缓冲区。 调用GetCommState函数可以获得串口的配置,该函数把当前配置填充到一个DCB结构中。一般在用CreateFile打开串行口后,可以调用GetCommState函数来获取串行口的初始配置。要修改串行口的配置,应该先修改DCB结构,然后再调用SetCommState函数用指定的DCB结构来设置串行口。 35 ***大学毕业论文(设计) 除了在DCB中的设置外,程序一般还需要设置I/O缓冲区的大小和超时。Windows用I/O缓冲区来暂存串行口输入和输出的数据,如果通信的速率较高,则应该设置较大的缓冲区。调用SetupComm函数可以设置串行口的输入和输出缓冲区的大小。 在用ReadFile和WriteFile读写串行口时,需要考虑超时问题。如果在指定的时间内没有读出或写入指定数量的字符,那么ReadFile或WriteFile的操作就会结束。要查询当前的超时设置应调用GetCommTimeouts函数,该函数会填充一个COMMTIMEOUTS结构。调用SetCommTimeouts可以用某一个COMMTIMEOUTS结构的内容来设置超时。 有两种超时:间隔超时和总超时。间隔超时是指在接收时两个字符之间的最大时延,总超时是指读写操作总共花费的最大时间。写操作只支持总超时,而读操作两种超时均支持。用COMMTIMEOUTS结构可以规定读/写操作的超时,该结构的定义为: typedef struct _COMMTIMEOUTS { DWORD ReadIntervalTimeout; // 读间隔超时 DWORD ReadTotalTimeoutMultiplier; // 读时间系数 DWORD ReadTotalTimeoutConstant; // 读时间常量 DWORD WriteTotalTimeoutMultiplier; // 写时间系数 DWORD WriteTotalTimeoutConstant; // 写时间常量 } COMMTIMEOUTS,*LPCOMMTIMEOUTS; COMMTIMEOUTS结构的成员都以毫秒为单位。总超时的计算公式是: 总超时=时间系数×要求读/写的字符数 + 时间常量 例如,如果要读入10个字符,那么读操作的总超时的计算公式为: 读总超时,ReadTotalTimeoutMultiplier×10 + ReadTotalTimeoutConstant 可以看出,间隔超时和总超时的设置是不相关的,这可以方便通信程序灵活地设置各种超时。 初始化部分程序代码如下: HANDLE hCom; DWORD dwError; DCB dcb; COMMTIMEOUTS TimeOuts; hCom=CreateFile(“COM2”, // 文件名 GENERIC_READ | GENERIC_WRITE, // 允许读和写 0, // 独占方式 NULL, 36 ***大学毕业论文(设计) OPEN_EXISTING, //打开而不是创建 FILE_ATTRIBUTE_NORMAL| FILE_FLAG_OVERLAPPED, // 重叠方式 NULL ); if(hCom = = INVALID_HANDLE_VALUE) { dwError=GetLastError( ); . . . // 处理错误 } SetupComm( hCom, 1024, 1024 ) //缓冲区的大小为1024 TimeOuts. ReadIntervalTimeout=1000; TimeOuts.ReadTotalTimeoutMultiplier=500; TimeOuts.ReadTotalTimeoutConstant=5000; TimeOuts.WriteTotalTimeoutMultiplier=500; TimeOuts.WriteTotalTimeoutConstant=5000; SetCommTimeouts(hCom, &TimeOuts); // 设置超时 GetCommState(hCom, &dcb); dcb.BaudRate=115200; // 波特率为2400 dcb.ByteSize=8; // 每个字符有8位 dcb.Parity=NOPARITY; //无校验 dcb.StopBits=ONESTOPBIT; //一个停止位 SetCommState(hCom, &dcb); 如果所有写超时参数均为0,那么就不使用写超时。如果ReadIntervalTimeout为0,那么就不使用读间隔超时,如果ReadTotalTimeoutMultiplier和 ReadTotalTimeoutConstant都为0,则不使用读总超时。如果读间隔超时被设置成 MAXDWORD并且两个读总超时为0,那么在读一次输入缓冲区中的内容后读操 作就立即完成,而不管是否读入了要求的字符。 在用重叠方式读写串行口时,虽然ReadFile和WriteFile在完成操作以前就 可能返回,但超时仍然是起作用的。在这种情况下,超时规定的是操作的完成时 间,而不是ReadFile和WriteFile的返回时间。 (3) 串行口的打开和关闭 Win 32系统把文件的概念进行了扩展。无论是文件、通信设备、命名管道、 邮件槽、磁盘、还是控制台,都是用API函数CreateFile来打开或创建的。该函 数的声明为: HANDLE CreateFile( LPCTSTR lpFileName, // 文件名 DWORD dwDesiredAccess, // 访问模式 DWORD dwShareMode, // 共享模式 37 ***大学毕业论文(设计) LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 通常为 NULL , DWORD dwCreationDistribution, // 创建方式 DWORD dwFlagsAndAttributes, // 文件属性和标志 HANDLE hTemplateFile // 临时文件的句柄,通常为NULL ); 如果调用成功,那么该函数返回文件的句柄,如果调用失败,则函数返回INVALID_HANDLE_VALUE。 如果想要用重叠I/O方式打开COM1口,可调用CreateFile函数。注意在打开一个通信端口时,应该以独占方式打开,另外要指定GENERIC_READ、GENERIC_WRITE、OPEN_EXISTING和FILE_ATTRIBUTE_NORMAL等属性。如果要打开重叠I/O,则应该指定 FILE_FLAG_OVERLAPPED属性。 相关程序代码段如下: „„. HANDLE hCom; DWORD dwError; hCom=CreateFile(“COM2”, // 文件名 GENERIC_READ | GENERIC_WRITE, // 允许读和写 0, // 独占方式 NULL, OPEN_EXISTING, //打开而不是创建 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, // 重叠方式 NULL ); if(hCom = = INVALID_HANDLE_VALUE) { dwError=GetLastError( ); „„ } „„ 当不再使用文件句柄时,应该调用CloseHandle函数关闭之。 (4) 重叠I/O 在用ReadFile和WriteFile读写串行口时,既可以同步执行,也可以重叠(异步)执行。在同步执行时,函数直到操作完成后才返回。这意味着在同步执行时 38 ***大学毕业论文(设计) 线程会被阻塞,从而导致效率下降。在重叠执行时,即使操作还未完成,调用的函数也会立即返回。费时的I/O操作在后台进行,这样线程就可以干别的事情。例如,线程可以在不同的句柄上同时执行I/O操作,甚至可以在同一句柄上同时进行读写操作。“重叠”一词的含义就在于此。 ReadFile函数只要在串行口输入缓冲区中读入指定数量的字符,就算完成操作。而WriteFile函数不但要把指定数量的字符拷入到输出缓冲中,而且要等这些字符从串行口送出去后才算完成操作。 ReadFile和WriteFile函数是否为执行重叠操作是由CreateFile函数决定的。如果在调用CreateFile创建句柄时指定了FILE_FLAG_OVERLAPPED标志,那么调用ReadFile和WriteFile对该句柄进行的读写操作就是重叠的,如果未指定重叠标志,则读写操作是同步的。 函数ReadFile和WriteFile的参数和返回值很相似。这里仅列出ReadFile函数的声明: BOOL ReadFile( HANDLE hFile, // 文件句柄 LPVOID lpBuffer, // 读缓冲区 DWORD nNumberOfBytesToRead, // 要求读入的字节数 LPDWORD lpNumberOfBytesRead, // 实际读入的字节数 LPOVERLAPPED lpOverlapped // 指向一个OVERLAPPED结构 ); //若返回TRUE则表明操作成功 需要注意的是如果该函数因为超时而返回,那么返回值是TRUE。参数lpOverlapped在重叠操作时应该指向一个OVERLAPPED结构,如果该参数为NULL,那么函数将进行同步操作,而不管句柄是否是由 FILE_FLAG_OVERLAPPED标志建立的。 当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,线程应该调用GetLastError函数分析返回的结果。例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,而且GetLastError函数返回ERROR_IO_PENDING。 在使用重叠I/O时,线程需要创建OVERLAPPED结构以供读写函数使用。OVERLAPPED结构最重要的成员是hEvent,hEvent是一个事件对象句柄,线程应该用CreateEvent函数为hEvent成员创建一个手工重置事件,hEvent成员将作为线程的同步对象使用。如果读写函数未完成操作就返回,就那么把hEvent成员设置成无信号的。操作完成后(包括超时),hEvent会变成有信号的。 如果GetLastError函数返回ERROR_IO_PENDING,则说明重叠操作还为完成,线程可以等待操作完成。有两种等待办法:一种办法是用象 39 ***大学毕业论文(设计) WaitForSingleObject这样的等待函数来等待OVERLAPPED结构的hEvent成员,可以规定等待的时间,在等待函数返回后,调用GetOverlappedResult。另一种办法是调用GetOverlappedResult函数等待,如果指定该函数的bWait参数为TRUE,那么该函数将等待OVERLAPPED结构的hEvent 事件。GetOverlappedResult可以返回一个OVERLAPPED结构来报告包括实际传输字节在内的重叠操作结果。 如果规定了读/写操作的超时,那么当超过规定时间后,hEvent成员会变成有信号的。因此,在超时发生后,WaitForSingleObject和GetOverlappedResult都会结束等待。WaitForSingleObject的dwMilliseconds参数会规定一个等待超时,该函数实际等待的时间是两个超时的最小值。注意GetOverlappedResult不能设置等待的时限,因此如果hEvent成员无信号,则该函数将一直等待下去。 在调用ReadFile和WriteFile之前,线程应该调用ClearCommError函数清除错误标志。该函数负责报告指定的错误和设备的当前状态。 本部分程序实现代码如下: ……… m_hCom=CreateFile( m_sPort, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL FILE_FLAG_OVERLAPPED, NULL); // 重叠方式 if(m_hCom==INVALID_HANDLE_VALUE) return FALSE; SetupComm(m_hCom,MAXBLOCK,MAXBLOCK); SetCommMask(m_hCom, EV_RXCHAR); //把间隔超时设为最大,而把总超时设置为0 。 TimeOuts.ReadIntervalTimeout=MAXDWORD; TimeOuts.ReadTotalTimeoutMultiplier=0; TimeOuts.ReadTotalTimeoutConstant=0; //设置写超时以指定WriteComm成员函数中的GetOverlappedResult函数的 //等待时间*/ TimeOuts.WriteTotalTimeoutMultiplier=50; TimeOuts.WriteTotalTimeoutConstant=2000; SetCommTimeouts(m_hCom, &TimeOuts); if(ConfigConnection()) { m_pThread=AfxBeginThread(CommProc, this, THREAD_PRIORITY_NORMAL, 40 ***大学毕业论文(设计) 0, CREATE_SUSPENDED, NULL); // 创建并挂起线程 if(m_pThread==NULL) { CloseHandle(m_hCom); return FALSE; } else { m_bConnected=TRUE; m_pThread->ResumeThread(); // 恢复线程运行 } } else { CloseHandle(m_hCom); return FALSE; } ……… (4)串口数据读写程序的实现 经过以上几步之后,再用Readfile函数来实现读串口数据就容易多了,具体实现不再累述,代码如下所示: DWORD ReadComm(char *buf,DWORD dwLength) { DWORD length=0; COMSTAT ComStat; DWORD dwErrorFlags; ClearCommError(m_hCom,&dwErrorFlags,&ComStat); length=min(dwLength, ComStat.cbInQue); ReadFile(m_hCom,buf,length,&length,&m_osRead); return length; } 6.2 ARM嵌入式系统端的具体实现与程序编写 6.2.1串口通讯的实现 ARM端设计是在JX44B0-2嵌入式系统实验箱上进行的。JX44B0-2的相关信息可参见2.3.3节。 (1)异步串口通信串口线引脚说明 在实际异步串行通信中,并不要求用全部的RS-232C 信号,许多PC/XT兼容机仅用15针接插件(DB-15)来引出其异步串行I/O信号,而PC中更是大量采用9针接插件(DB-9)来担当此任。 41 ***大学毕业论文(设计) 图14 DB-9插件引脚图 以上各引脚信息说明如下: 表2 DB-9插件引脚说明 (2)主要用到的几个寄存器位设置及功能说明 FIFO控制寄存器UFCONn ,FIFO设计的难点在于怎样判断FIFO的空/满状态。为了保证数据正确的写入或读出,而不发生益处或读空的状态出现,必须保证FIFO在满的情况下,不能进行写操作。在空的状态下不能进行读操作。怎样判断FIFO的满/空就成了FIFO设计的核心问题,这里就用到了FIFO控制寄存器UFCONn,其各位设置及功能如下表所示: 42 ***大学毕业论文(设计) 表3 FIFO控制寄存器位设置表 本设计中,设置串口的FIFO属性,并清除FIFO中的内容 ,可如下设置: rUFCON0=0xf7; 线路控制寄存器ULCONn,它的主要功能是确定异步通信的数据格式,包括波特率因子的锁存,奇偶校验位的设定,停止位数和数据位数的确定,其各位功能设置如下表所示 : 表4 线路控制寄存器位设置表 本设计中,设置8位数据位、1位停止位、无奇偶校验串口模式 ,可如下设置: rULCON0=0x3; 43 ***大学毕业论文(设计) 控制寄存器UCONn,主要用于定时,计数,中断控制等,它各位功能如下表所示: 表5 控制寄存器位设置表 设置收发的中断模式为电平触发,关闭超时功能 ,可如下设置: rUCON0=0x345; MODEM控制寄存器UMCONn,它反映JX44B0-2嵌入式系统与Modem之间联络应答输入信号的当前状态以及这些信号的变化信息 它各位功能如下表所示: 44 ***大学毕业论文(设计) 表6 MODEM控制寄存器位设置表 本设计中,关闭流控功能 ,可如下设置: rUMCON0=0x0; 波特率因子寄存器保存串行通信的波特率因子,在波特率指定后,输入移位寄存器/输出移位寄存器在接收时钟/发送时钟控制下,按指定的波特率速度进行移位。一般几个时钟脉冲移位一次。要求:接收时钟/发送时钟是波特率的16、32或64倍。波特率因子就是发送,接收1个数据(1个数据位)所需要的时钟脉冲个数,其单位是个,位。其各位功能如下表所示: 表7 波特率因子寄存器位设置表 本设计中, 设置波特率和波特率因子如下:其中,mclk为CPU主频,波特率因子为16,baud为波特率 ,rUBRDIV0=( (int)(mclk/16./baud + 0.5) -1 ); 串口通讯程序关键代码如下: …….. unsigned int mclk = 60*1024*1024; /* 60MHZ unsigned int baud = 115200; /* 115200 BPS rUFCON0=0xf7; /* 设置FIFO属性,并清除FIFO中的内容 rUMCON0=0x0; /* 关闭流控功能 */ rULCON0=0x3; /* 设置8数据位,1停止位,无奇偶校验 45 ***大学毕业论文(设计) rUCON0=0x345; /* 设置中断为电平触发,关闭超时功能 */ rUBRDIV0=( (int)(mclk/16.0/baud + 0.5) -1 );/* 设置波特率 */ …….. input_key = (*keyboard_port_value) & key_mask;/*获取第一次扫描值 if(input_key == key_mask) continue; /* 没有按键 */ delay(10000); if (((*keyboard_port_value) & key_mask) != input_key) continue; ascii_key = key_get_char(row, input_key); /* 查表 */ while(!(rUTRSTAT0 & 0x2)); /* 等待发送缓冲空.*/ rUTXH0 = ascii_key; /* 将数据写到数据端口 */ …….. 6.2.2 键盘扫描功能的实现 本设计中采用软件实现键盘扫描。 ×4的软键盘。原理图如下: JX44B0具有4 图15 JX44B04×4软键盘原理图 开关并不完善,因为当它们被按下或者被释放时,并不能够产生一个明确的1或者0。尽管触点可能看起来稳定而且很快地闭合,但与微处理器快速的运行速度相比,这种动作是比较慢的。当触点闭合时,其弹起就像一个球。弹起效果将产生如下图所示的好几个脉冲。弹起的持续时间通常将维持在5ms,30ms 之间。 46 ***大学毕业论文(设计) 图16 开关振荡示意图 解决方法如下: 键盘扫描过程就是让微处理器按有规律的时间间隔查看键盘矩阵,确定是否有键被按下,一旦处理器判定有一个键按下,键盘扫描软件将过滤掉抖动并且判定哪个键被按下,每个键被分配一个称为扫描码的唯一标识符。应用程序利用该扫描码,根据按下的键来判定应该采取什么行动,换句话说,扫描码将告诉应用程序按下哪个键。 依次将键盘的每一行输出低电平,延时一段时间,然后获取该行中 列的输入情况,如果各列全部为1则继续查询下一行,否则延时一段时间并重新扫描一次,如果扫描结果与上次扫描结果相同则调用key_get_char获取键码,然后调用display_num在LED上显示相应键值。 通过如下程序将键盘的row行输出低电平: unsigned char* keyboard_port = (unsigned char*)0x2000000; *keyboard_port = ~(0x00000001 << row); 键盘扫描算法如下: char key_get_char(int row, int col) { char key; switch( row ) { case 0: if(col == 0x0b ) key = '0'; else if(col == 0x0e) key = '7'; else if(col == 0x07) key = '4'; else if(col == 0x0d) key = '1'; break; case 1: if(col == 0x0b ) key = 'A'; else if(col == 0x0e) key = '8'; else if(col == 0x07) key = '5'; else if(col == 0x0d) key = '2'; 47 ***大学毕业论文(设计) break; case 2: if(col == 0x0b ) key = 'B'; else if(col == 0x0e) key = '9'; else if(col == 0x07) key = '6'; else if(col == 0x0d) key = '3'; break; case 3: if(col == 0x0b ) key = 'C'; else if(col == 0x0e) key = 'D'; else if(col == 0x07) key = 'E'; else if(col == 0x0d) key = 'F'; break; default: break; } return key; } 7 结束语 本次系统设计与开发完成了一个软件设计人员应尽的职责按照软件工 程的软件开发方法进行,包括需求分析和详细设计,都经过自己的深思熟虑 以及不断的完善。在设计过程中也经常遇到一些小问题,这些都是需要付出 努力去解答的,比如如何选择工程模型的问题,用工程的思想去解决应用程 序的编写问题等等。经过查阅资料以及吸收一些前辈们的经验,而终于解决。 当然本系统还有一些不足,比如效率性问题:虽然这次闪设计引入了多 线程技术,但毕业是作为初学者,因此对如何高效运用这些技术还并不十分 成熟,还有待于不断提高软件设计中“效率”、“可靠性”、“复杂度”等重要 性能的驾驭能力。面对自身存在不足感觉以后还得脚踏实地的汲取更多更有 用的知识来完善自己。我相信,这次设计将为我以后的职业打下坚实的基础。 8致谢 时光飞逝,弹指一挥间四年的大学生活已到尾声。在即将结束的大学生活时,为了巩固我们在大学中所学的知识,学校为我们每个人安排了毕业设计。在平时在学习中我们学习的都是理论知识,动手展示自己的机会不多,所以这次毕业设计对我们每个人来说都是大学中最后一门课,一门锻炼自己的动手能力,巩固已学知识的实践课。 本次毕业设计我做的是键盘与鼠标的交互式模拟系统,在做这个系统当中遇到了很多问题,也学到了很多知识。在此我要感谢我的导师徐东平老师,他给了我 48 ***大学毕业论文(设计) 很多的指点和帮助,正是他的悉心指导和严格要求,为使我能够顺利完成本科阶段重要的毕业设计做出了极大的贡献任务。最后我要感谢我的室友李决定同学,他在我的设计遇到困难时给了我非常多的帮助,提供了非常好的材料,在我的设计过程中起到了很大的作用。 感谢各位老师和同学们,你们的信任和慰勉是我前进的动力~感谢我的朋友们,感谢你们在我失意时给我鼓励,在失落时给我支持,感谢你们和我一路走来,在此过程中我倍感温暖~ 9 参考文献 [1] 严蔚敏,吴伟明.数据结构(C语言版)[M].北京:清华大学出版社,1997.4 [2] 闵联营,何克右.,,,程序设计[M].武汉:武汉理工大学出版社,2005.7 [3]沈美明,温冬婵.IBM-PC汇编语言程序设计[M].北京:清华大学出版社,2003.4 [4]范书瑞,赵燕飞,高铁成.ARM处理器与C语言开发应用[M] . 北京:北京航空航天大学出版社,2008.8 [5] (美)杰夫瑞(Jeffrey,J.),(法)克里斯托夫(Christophe,N).葛子昂,周靖,廖敏译[M].北京:清华大学出版社,2008.9 [6]王险峰,刘宝宏. Windows环境下的多线程编程原理与应用[M] .北京:清华大学出版社,2002.6 [7]张迎新. 单片微型计算机原理、应用及接口技术 [M].北京:国防工业出版社,2003.4 [8] 周立功,张华等. 深入浅出ARM7--LPC213x/214x(上册)[M] ..北京: 北京航空航天大学出版社,2005.6 [9] 乔林/杨志刚等 . VisualC++6.0高级编程技术-MFC与多线程篇 [M] .北京: 中国铁道出版社,2000.2 [10] (美)Microsoft公司著;希望图书创作室译. 北京希望电脑公司/北京希望. [M] . 电子工汪出版社科技咨询导报,2006(20) [11] (美)Jim Beveridge & Robert Wiener 侯捷/(美)Jim Beveridge & Robert Wiener. Win32多线程程序设计[M] .武汉:华中科技大学出版社.2002.01 [12] 王立峰,延伟东等.软件工程理论与实践[M] .北京:清华大学出版社,2003.12 [13] 黄国平(C#实用开发参考大全[M] .北京:电子工业出版社,2008.1 [14] Nikhil Kothari Vandara Datye. ASP.NET服务器控件与组件开发[M] ..北京:机械工业出版社, 2004.12. [15] John Kauffman Thiru Thangarathinam.Beginning ASP.NET2. 0 Databases[M] . 北京:清华大学出版社,2006.6[16] 王行言.计算机程序设计基础[M] .北京:清华大学出版社,1998.09 [16] [17] 张俊,乔字峰等(C#程序设计入门[M](吉林:吉林电子出版社,2005.6 [18] (美)John L.Hennessy David A.Patterson(计算机系统结构:量化研究方法:第3版[M](北京:清华大学出版社.2003.6 [19] 李兰友,杨晓光(ASP.NET实用程序设计[M].北京:清华大学出版社.2005.3 [20] 郝文化,文自勇,王浩强,曹华伟等(Windows多线程编程技术与实例. 北京:中国水利水电出版社,2005.10 49 ***大学毕业论文(设计) 附录1 PC端程序清单 /***********键盘鼠标模拟程序*************/ #include #define THREAD_AMOUNT 6 #define DOWN 1 #define UP 2 #define MOUSEMOVEUP 1 #define MOUSEMOVEDOWN 2 #define MOUSEMOVELEFT 3 #define MOUSEMOVERIGHT 4 #define MOUSECLICKLEFT 5 #define MOUSECLICKRIGHT 6 #define KEYBOARD 7 #define LENGTH 8 #define BAUD 115200 #define MAXBLOCK 2048 #define XON 0x11 //流控制 #define XOFF 0x13 //流控制 BOOL m_bConnected=false; /*用来表明当前是否存在一个通信连接*/ HANDLE m_hPostMsgEvent; // 用于WM_COMMNOTIFY消息的事件对象 OVERLAPPED m_osRead, m_osWrite; // 用于重叠读/写 HANDLE m_hCom; HANDLE m_pThread; LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; /*******************读串口函数***********************/ DWORD ReadComm(char *buf,DWORD dwLength) { DWORD length=0; COMSTAT ComStat; DWORD dwErrorFlags; ClearCommError(m_hCom,&dwErrorFlags,&ComStat); length=min(dwLength, ComStat.cbInQue); ReadFile(m_hCom,buf,length,&length,&m_osRead); return length; } /******************消息处理函数*************************/ void OnCommNotify(DWORD*lpEvtMask) { char buf[MAXBLOCK/4]; 50 ***大学毕业论文(设计) char str='\0'; int nLength; if(!m_bConnected||!GetCommMask(m_hCom,lpEvtMask)||*lpEvtMask!=EV_R XCHAR) // 是否是EV_RXCHAR事件? { SetEvent(m_hPostMsgEvent); // 允许发送下一个 WM_COMMNOTIFY消息 } nLength=ReadComm(buf,1); if(nLength) { for(int i=0;i********************/ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("mousekeyboardApp") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; 52 ***大学毕业论文(设计) wndclass.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName= szAppName ; if (!RegisterClass (&wndclass)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow( szAppName, // window class name TEXT ("键盘鼠标模拟"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT,// initial x position CW_USEDEFAULT,// initial y position CW_USEDEFAULT,// initial x size CW_USEDEFAULT,// initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL) ; // creation parameters // ShowWindow (hwnd, iCmdShow) ; ShowWindow(hwnd,SW_NORMAL); UpdateWindow (hwnd) ; int i = 0; /***************新加入变量***************************/ bool m_bEcho = FALSE; int m_nFlowCtrl = 0; //bool m_bNewLine = FALSE; char*m_sPort = "COM1"; DCB dcb; if((m_hPostMsgEvent=CreateEvent(NULL,TRUE,TRUE,NULL))==NULL )//初始化为有信号 return 0; /****************I/O重叠口设置**********************/ memset(&m_osRead, 0, sizeof(OVERLAPPED)); memset(&m_osWrite, 0, sizeof(OVERLAPPED)); if((m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL))==NULL) //初始化为无信号状态 return 0; if((m_osWrite.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL))==NULL) return 0; /****************I/O重叠口设置**********************/ 53 ***大学毕业论文(设计) /******打开并配置串行口,建立工作者线程-> ************/ // BOOL OpenConnection() // { COMMTIMEOUTS TimeOuts; if(m_bConnected) //连接已打开,返回错误 return FALSE; m_hCom=CreateFile(m_sPort,GENERIC_READ|GENERIC_WRITE,0,NU LL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL| FILE_FLAG_OVERLAPPED, NULL); // 重叠方式 if(m_hCom==INVALID_HANDLE_VALUE) return FALSE; SetupComm(m_hCom,MAXBLOCK,MAXBLOCK); //设置缓冲区为 2048 /************设置DCB结构->***********************/ if(!GetCommState(m_hCom, &dcb)) return 0; dcb.fBinary=TRUE; dcb.BaudRate=BAUD; // 波特率 dcb.ByteSize=8; // 每字节位数 dcb.Parity=NOPARITY; dcb.StopBits=1; dcb.fInX=dcb.fOutX=m_nFlowCtrl==2; dcb.XonChar=XON; dcb.XoffChar=XOFF; dcb.XonLim=50; dcb.XoffLim=50; SetCommState(m_hCom, &dcb); /****************设置SCB结构<-******************/ SetCommMask(m_hCom, EV_RXCHAR); TimeOuts.ReadIntervalTimeout=MAXDWORD; TimeOuts.ReadTotalTimeoutMultiplier=0; TimeOuts.ReadTotalTimeoutConstant=0; /* 设置写超时以指定WriteComm成员函数中的GetOverlappedResult函数的等待时间*/ TimeOuts.WriteTotalTimeoutMultiplier=50; TimeOuts.WriteTotalTimeoutConstant=2000; SetCommTimeouts(m_hCom, &TimeOuts); unsigned long threadid; m_pThread=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)CommProc, NULL, CREATE_SUSPENDED, 54 ***大学毕业论文(设计) &threadid); // 创建并挂起线程 if(m_pThread==NULL) { CloseHandle(m_hCom); return FALSE; } else { m_bConnected=TRUE; //连接上 ResumeThread(m_pThread); // 恢复线程运行 } while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (message) { case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; DrawText (hdc, TEXT ("模拟已经开始"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: m_bConnected=FALSE; SetEvent(m_hPostMsgEvent); SetCommMask(m_hCom, 0); //等待辅助线程终止 // WaitForSingleObject(m_pThread->m_hThread, INFINITE); CloseHandle(m_pThread); CloseHandle(m_hCom); PostQuitMessage (0) ; return 0 ; 55 ***大学毕业论文(设计) } return DefWindowProc (hwnd, message, wParam, lParam) ; } 附录2 ARM嵌入式系统端程序清单 /*********************** includes********************************** */ #include "option.h" #include "44blib.h" #include "44b.h" void delay(int count); /******************************************************************** ********* // Function name : key_get_char // Description : 根据键盘行列键值查询键 // Return type : char // Argument : int row // Argument : int col ********************************************************************* ********/ char key_get_char(int row, int col) { char key; switch( row ) { case 0: if(col == 0x0b ) key = '0'; else if(col == 0x0e) key = '7'; else if(col == 0x07) key = '4'; else if(col == 0x0d) key = '1'; break; case 1: if(col == 0x0b ) key = 'A'; else if(col == 0x0e) key = '8'; else if(col == 0x07) key = '5'; else if(col == 0x0d) key = '2'; break; case 2: if(col == 0x0b ) key = 'B'; else if(col == 0x0e) key = '9'; else if(col == 0x07) key = '6'; 56 ***大学毕业论文(设计) else if(col == 0x0d) key = '3'; break; case 3: if(col == 0x0b ) key = 'C'; else if(col == 0x0e) key = 'D'; else if(col == 0x07) key = 'E'; else if(col == 0x0d) key = 'F'; break; default: break; } return key; } /******************************************************************** ********* // Function name : delay // Description : 延时子程序 // Return type : void // Argument : count,延时的数值 ********************************************************************* ********/ void delay( int count ) { for( ; count>0; count--); } void Main() { // unsigned char data; int row; unsigned char ascii_key, input_key, key_mask = 0x0F; unsigned char* keyboard_port_scan = (unsigned char*)0x02000000; unsigned char* keyboard_port_value = (unsigned char*)0x02000002; unsigned int mclk = 60*1024*1024; /* 60MHZ */ unsigned int baud = 115200; /* 115200 BPS */ rUFCON0=0xf7; /* 设置FIFO属性,并清除FIFO中的 内容 */ rUMCON0=0x0; /* 关闭流控功能*/ rULCON0=0x3; /* 设置8数据位,1停止位,无奇偶校验 */ rUCON0=0x345; /* 设置中断为电平触发,关闭超时功能 */ rUBRDIV0=( (int)(mclk/16.0/baud + 0.5) -1 ); /* 设置波特率 */ 57 ***大学毕业论文(设计) while(1) { for( row = 0; row < 4; row++) { *keyboard_port_scan = ~(0x00000001<
本文档为【毕业设计(论文)-基于嵌入式系统的PC键盘与鼠标交互控制模拟研究】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_713593
暂无简介~
格式:doc
大小:541KB
软件:Word
页数:92
分类:生活休闲
上传时间:2017-09-25
浏览量:40