查看微软相关的串口通信文档,可以发现在桌面操作系统中,串口通信分为两种模式:同步和异步.而WinCE只有一种,但文档中却没标明归属哪种模式.实际上,WinCE的串口通信模式更像介于同步和异步之间. 在此先简要地介绍何为同步和异步.所谓的同步,指得是对同一个设备或文件(在文中只的是串口COM1)的读或写操作必须要等待上一个操作完成才能进行.比如说,调用ReadFile()函数读取串口,但由于上一个WriteFile()操作没完成,ReadFile()的操作就被阻塞,直到WriteFile()完成后才能运行.而异步,则无论上一个操作是否完成,都会执行目前调用的操作.还是拿前面举的例子,在异步模式下,即使WriteFile()没有执行完成,ReadFile()也会立刻执行. 1.CreateFile()参数的差异 首先说明一下WinCE和WinXP打开串口时参数的差异.以打开串口COM1为例子,WinCE下的名字为"COM1:",而WinXP为"COM1",两者的唯一区别仅仅在于WinCE下多个分号. 例如: HANDLE hd = CreateFile(TEXT("COM1:"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinCE HANDLE hd = CreateFile(TEXT("COM1"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinXP 在这稍微多说一下,在默认的环境下,TEXT宏在WinCE下会编译为双字节,而WinXP为单字节.换句话说,TEXT("COM1")在WinCE下相当于L"COM1",而WinXP则为"COM1". 2.单线程比较 还是用代码做例子来说明比较形象.这是一段单线程的代码,先对串口进行写操作,然后再读.对于WinXP来说,这是同步模式.(与主题无关的代码省略) int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { ... HANDLE hCom = CreateFile(TEXT("COM1:"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinCE //HANDLE Com = CreateFile(TEXT("COM1"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinXP ... DWord dwBytes; if(WriteFile(hCom,TEXT("COM1:"),5,&dwBytes,NULL) == FALSE) //WinCE //if(WriteFile(hCom,TEXT("COM1"),5,&dwBytes,NULL) == FALSE) //WinXP { return 0x05; } ... DWord dwRead; char szBuf[MAX_READ_BUFFER]; if(ReadFile(hCom,szBuf,MAX_READ_BUFFER,&dwRead,NULL) == FALSE) { return 0x10; } ... } 经过实验,可以发现这段代码在WinCE和WinXP下都能正常工作,并且其表现也相同,都是在WriteFile()函数返回后才执行ReadFile(). 由于异步模式在单线程中也能正常运作,唯一的不同只是在执行WriteFile()时可能也会执行ReadFile()(依WriteFile()函数执行的时间而定),所在此不表. 3.多线程比较 单线程两者表现相同,那多线程呢?下面这段代码采用多线程,先是创建一个读的线程,用来监控串口是否有新数据到达,然后在主线程中对串口写出数据. 这里假设是这么一个情况,有两台设备,分别为A和B,下面的代码运行于设备A,设备B仅仅只是应答而已.换句话说,只有A向B发送数据,B才会返回应答信号. //主线程 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { ... CreateThread(NULL,0,ReadThread,0,0,&dwThrdID); //创建一个读的线程. ... HANDLE hCom = CreateFile(TEXT("COM1:"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinCE //HANDLE Com = CreateFile(TEXT("COM1"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinXP ... DWORD dwBytes; if(WriteFile(hCom,"AT\r\n",4,&dwBytes,NULL) == FALSE) //WinCE //if(WriteFile(hCom,"AT\r\n",5,&dwBytes,NULL) == FALSE) //WinXP { return 0x05; } ... } //读线程 DWORD WINAPI ReadThread() { ... SetCommMask(hCom),EV_RXCHAR); DWORD dwCommStatus = 0; if(WaitCommEvent(hCom),&dwCommStatus,NULL) == FALSE) { //Clear the error flag DWORD dwErrors; COMSTAT comStat; memset(&comStat,0,sizeof(comStat)); ClearCommError(hCom,&dwErrors,&comStat); return 0x15; } ... char szBuf[MAX_READ_BUFFER]={0}; DWORD dwRead; if(ReadFile(hCom),szBuf,MAX_READ_BUFFER,&dwRead,NULL) == FALSE || dwRead == 0) { return 0x20; } ... } 这段代码在WinCE下运行完全正常,读线程在监听收到的数据的同时,主线程顺利地往外发数据. 然而同样的代码,在WinXP下则根本无法完成工作.运行此代码,我们将发现CPU的占用率高达99%.通过单步调试,发现两个线程分别卡在WaitCommEvent()和WriteFile()函数中.因为根据同步模式的定义,当前对设备的操作必须要等待上一个操作完毕方可执行.在以上代码中,因为设备B没接到设备A的命令而不会向设备A发送应答,故WaitCommEvent()函数因为没有检测到接受数据而一直在占用串
|