各位高手请赶快帮我出出主意。我已经被这个问题困扰很长时间了。 目前我正在Win CE.Net 4.2操作系统下开发一个串口通信项目。开发环境如下:我们的嵌入式开发板使用National Geode的X86架构的CPU,操作系统用的是Win CE.Net 4.2,当然Platform builder4.2是操作系统自带的,软件开发工具是EVC4。 嵌入式板子上有4个Com口,根据说明,其中Com1应该是Debug用的,因此我们的程序只使用Com2和Com3。Com2与嵌入式电力线Modem相连,这样Com2就可以通过电网与终端采集器进行数据通信。程序通过Com2经电力线Modem将数据包通过电网发送给终端采集器,终端采集器根据数据包中的具体命令执行采集任务,然后将采集到的数据打包,通过电网经电力线Modem解调后返回给Com2,程序从Com2口中将数据包读取并做处理。以上就是对需求的一个 简单描述。 目前,我们用EVC4和VC6构造了相同的程序,EVC4开发的程序是为了在嵌入式开发板上运行,是我们的最终目的;而VC6开发的程序则是为了调试方便,专门在PC上运行的。两个程序完全相同。 但是,现在VC6开发的程序在PC上运行,通过PC机的Com口与嵌入式电力线Modem相连后,可以顺畅无误地收发数据。而使用EVC4开发的程序,部署到嵌入式开发板上之后,通过Com2口发送数据没有问题,但是经常接收不到数据。如果要是纯粹地接收不到数据,我也没那么郁闷,肯定是程序哪里错了,挑出来就是了。但是目前的情况是,一会儿收得到,一会儿收不到。只有在关机重新启动后,运行程序,才有可能收到。经过反复试验,从8:00-22:00,连续收发正常的时间不超过半小时,一旦发生数据接收失败,则一直都是失败,只有重新启动操作系统后才有可能继续收发数据。如果只是重启程序,都不会再收到数据。而且发现在收不到数据之后,ComStat的cbInQueue为0,也就是串口的输入缓冲区中根本就没有数据进来。曾经实验发现,晚上23:00以后,数据收发成功的时间比较长,最长的一次是1个半小时,最后还是因为我要睡觉了,才关闭了程序。有人肯定会说Com2口本身是否正常,我做了实验,用串口电缆将PC机的Com口和嵌入式板子的Com2相连,在PC机上用串口调试工具向嵌入式板子的Com2口发送数据,嵌入式板子上的程序会监听到数据并应答,PC机可以收到应答。因此看来,Com2的工作能力似乎没有什么问题。但是对于这个项目,Com2口接收到的数据完全是来自于电网的经过电力线Modem解调后的数据包,那么会不会是电力线Modem出的问题导致Com2口收不到数据呢?可情况并不是这样,因为VC6开发的程序在PC机上运行,通过PC上Com口与电力线Modem相连,却可以很好的收发数据,因此只好排除Modem有问题的可能。 说了这么多废话,我就是希望您能明白我遇到的麻烦。目前,我怀疑两种情况, 1、我使用Platform Builder配置Platform时,在串口这部分是不是没有配置好。我在National Geode:X86下的Device Driver下的Serial下添加了Com16550,Com16550(Second Instance),Com16550(Third Instance)。然后根据嵌入式开发板BIOS中的具体设定,将原Platform注册表文件中Serial部分的文件: IF BSP_NOSERIAL ! [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial] "SysIntr"=dword:13 "IoBase"=dword:02F8 "IoLen"=dword:8 "DeviceArrayIndex"=dword:0 "Prefix"="COM" "Dll"="Com16550.Dll" "Order"=dword:0 "Priority"=dword:0 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial\Unimodem] "Tsp"="Unimodem.dll" "DeviceType"=dword:0 "FriendlyName"=LOC_FRIENDLYNAME_SERIAL "DevConfig"=hex: 10,00, 00,00, 05,00,00,00, 10,01,00,00, 00,4B,00,00, 00,00, 08, 00, 00, 00,00,00,00 IF BSP_SERIAL2 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial2] "SysIntr"=dword:14 "IoBase"=dword:03E8 "IoLen"=dword:8 "DeviceArrayIndex"=dword:1 "Prefix"="COM" "Dll"="Com16550.Dll" "Order"=dword:0 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial2\Unimodem] "Tsp"="Unimodem.dll" "DeviceType"=dword:0 "FriendlyName"=LOC_FRIENDLYNAME_SERIAL2 "DevConfig"=hex: 10,00, 00,00, 05,00,00,00, 10,01,00,00, 00,4B,00,00, 00,00, 08, 00, 00, 00,00,00,00 ENDIF BSP_SERIAL2 IF BSP_SERIAL3 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial3] "SysIntr"=dword:15 "IoBase"=dword:02E8 "IoLen"=dword:8 "DeviceArrayIndex"=dword:2 "Prefix"="COM" "Dll"="Com16550.Dll" "Order"=dword:0 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial3\Unimodem] "Tsp"="Unimodem.dll" "DeviceType"=dword:0 "FriendlyName"=LOC_FRIENDLYNAME_SERIAL3 "DevConfig"=hex: 10,00, 00,00, 05,00,00,00, 10,01,00,00, 00,4B,00,00, 00,00, 08, 00, 00, 00,00,00,00 ENDIF BSP_SERIAL3 改成了: IF BSP_NOSERIAL ! [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial] "SysIntr"=dword:14 "IoBase"=dword:03F8 "IoLen"=dword:8 "DeviceArrayIndex"=dword:0 "Prefix"="COM" "Dll"="com16550.Dll" "Order"=dword:0 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial\Unimodem] "Tsp"="Unimodem.dll" "DeviceType"=dword:0 "FriendlyName"=LOC_FRIENDLYNAME_SERIAL "DevConfig"=hex: 10,00, 00,00, 05,00,00,00, 10,01,00,00, 00,4B,00,00, 00,00, 08, 00, 00, 00,00,00,00 IF BSP_SERIAL2 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial2] "SysIntr"=dword:13 "IoBase"=dword:02F8 "IoLen"=dword:8 "DeviceArrayIndex"=dword:1 "Prefix"="COM" "Dll"="com16550.Dll" "Order"=dword:0 "Priority"=dword:0 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial2\Unimodem] "Tsp"="Unimodem.dll" "DeviceType"=dword:0 "FriendlyName"=LOC_FRIENDLYNAME_SERIAL2 "DevConfig"=hex: 10,00, 00,00, 05,00,00,00, 10,01,00,00, 00,4B,00,00, 00,00, 08, 00, 00, 00,00,00,00 ENDIF BSP_SERIAL2 IF BSP_SERIAL3 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial3] "SysIntr"=dword:1A "IRQ"=dword:0A "IoBase"=dword:03E8 "IoLen"=dword:8 "DeviceArrayIndex"=dword:2 "Prefix"="COM" "Dll"="com16550.Dll" "Order"=dword:0 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial3\Unimodem] "Tsp"="Unimodem.dll" "DeviceType"=dword:0 "FriendlyName"=LOC_FRIENDLYNAME_SERIAL3 "DevConfig"=hex: 10,00, 00,00, 05,00,00,00, 10,01,00,00, 00,4B,00,00, 00,00, 08, 00, 00, 00,00,00,00 ENDIF BSP_SERIAL3 原因是,BIOS里设定了Com1的IRQ是4,IOBase是3F8;Com2的IRQ是3,IOBase是2F8;Com3的IRQ是10,IOBase是3E8。 如此修改之后,Com2口Com3口应该算是驱动起来了,因为他们起码都可以工作,可以收发数据,只是不稳定。不知道我这么 改是否有错误或者疏漏的地方,请高手指教!!! 2、由于相同的程序在PC上运行和在嵌入式板子上运行发生了如此大的差异。因此我怀疑嵌入式板子上的Com口的工作能力和PC上Com口的工作能力有差异,那么我的串口初始化和串口接收函数是否写的有问题,我把这两段程序罗列在此,请高手指教: 这是构造函数: CSerial::CSerial(BYTE bPort) :m_bPort(bPort) { m_hCom = NULL; m_dwInQueue = 4096;//用来设定串口输入缓冲区 m_dwOutQueue = 4096;//用来设定串口输出缓冲区 memset(&m_dcb ,0 ,sizeof(DCB)); m_dcb.DCBlength=sizeof(m_dcb); m_dcb.fBinary = TRUE; m_dcb.fParity = TRUE; m_dcb.fNull = FALSE; m_dcb.BaudRate = 1200; //电力线载波通信协议规定BuadRate为1200 m_dcb.ByteSize = 8; m_dcb.Parity = NOPARITY; m_dcb.StopBits = ONESTOPBIT; m_dcb.fNull = FALSE; m_dcb.fDtrControl=DTR_CONTROL_DISABLE; m_dcb.fDsrSensitivity=FALSE; m_dcb.fOutxCtsFlow = FALSE; m_dcb.fOutxDsrFlow = FALSE; switch(m_bPort) { case 1: m_IoPortBase=(PUCHAR)COM1_BASE;//COM1_BASE代表0x3F8 break; case 2: m_IoPortBase=(PUCHAR)COM2_BASE;//COM2_BASE代表0x2F8 break; case 3: m_IoPortBase=(PUCHAR)COM3_BASE;//COM3_BASE代表0x3E8 break; case 4: m_IoPortBase=(PUCHAR)COM4_BASE; break; } } 这是打开串口的函数: BOOL CSerial::OpenSerial(BOOL bOpen) { DWORD dwError; TCHAR szComName[32]; COMMTIMEOUTS CommTimeOuts ; if (bOpen)//bOpen为TRUE时: 表示要打开串口 { if(m_hCom!=NULL) { CloseHandle(m_hCom); m_hCom=NULL; } // open COMM device wsprintf(szComName,TEXT("COM%1d:"),m_bPort); m_hCom = CreateFile (szComName,GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (m_hCom == INVALID_HANDLE_VALUE) { dwError = GetLastError(); return FALSE; } dwError=SetCommMask( m_hCom, EV_RXCHAR|EV_ERR); dwError=SetupComm( m_hCom, m_dwInQueue, m_dwOutQueue);//设置串口输入和输出缓冲区的大小 dwError=PurgeComm( m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ); memset(&CommTimeOuts,0,sizeof(CommTimeOuts));//I add this CommTimeOuts.ReadIntervalTimeout = MAXDWORD; CommTimeOuts.ReadTotalTimeoutMultiplier = 0; CommTimeOuts.ReadTotalTimeoutConstant = 0; CommTimeOuts.WriteTotalTimeoutMultiplier = 0; CommTimeOuts.WriteTotalTimeoutConstant = 0; dwError=SetCommTimeouts( m_hCom, &CommTimeOuts ); if(!SetCommState(m_hCom, &m_dcb)) { dwError = GetLastError(); CloseHandle(m_hCom); m_hCom=NULL; return FALSE; } return TRUE; } else //关闭串口 { if (m_hCom!=NULL) { CloseHandle(m_hCom); m_hCom = NULL; return TRUE; } else { m_hCom = NULL; return TRUE; } } } 接收数据的时机是由程序过程控制的,在程序通过Com2口向采集终端发送数据之后,等待500毫秒后执行读取数据任务,读取函数里是一个do-While循环,以不超过16秒和未接收到有效数据为条件循环执行Receive函数,该函数如下所示: BOOL CSerial::Receive(LPVOID lpRev,DWORD& dwReadLen) { COMSTAT ComStat ; DWORD dwErrorFlags; DWORD dwLength; DWORD dwError; BOOL fRet; if (m_hCom == NULL) return FALSE ; ClearCommError(m_hCom, &dwErrorFlags, &ComStat); dwLength =ComStat.cbInQue; dwReadLen<=dwLength?dwReadLen:dwReadLen=dwLength; fRet = ReadFile( m_hCom, lpRev, dwReadLen, &dwReadLen,NULL); if (!fRet) { dwError = GetLastError(); return FALSE; } return TRUE; } 在读取函数结束返回之前,不论是否接收到有效数据,都执行PurgeComm(m_hCom,PURGE_RXCLEAR);来清空 串口的输入缓冲区。
09-12-11 09:18