项目做到最后了,上位机(普通台式计算机)需要接收下位机(实验板)处理过后的数据,由于返回的数据较少,一次可能就是几个字节,传输时间没有严格要求,所以选择了串口通信。串口通信方式简单。调试起来也比较简单。下位机的串口硬件调试是PK同学负责的,我负责上位机的串口程序的调试。
刚开始的调试想法是让计算机COM1口发送数据,然后COM2接收,后来发现计算机就只带有一个串口,那就用邻近同学的计算机发送数据吧,但是这样是无法通信的,因为我的串口线是对等的。后来根据小丫头同学调试串口的经验,让一个串口COM1自发自收,这样就不用考虑对等线还是交叉线的问题了。
调试计算机串口,需要一根串口线,对等线或者交叉线均可。
1、检测串口线是否能连通;检测方法,用万用表检测串口线的1-9号线是否对应连通。
2、检测计算机串口是否能正常工作;检测方法,将串口线一端接入计算机串口,另一端2、3两线用导线连通。下载串口调试助手观察计算机串口的自发自收情况。
3、检测自己程序的正确性;
以下串口类在原始是应用于WINCE下,我稍作修改即可在windows下运行。以下程序在VC2005下编译、测试通过。PSerialPort.cpp增加了TRACE调试的代码。
//From unkown author:unkonwn modified by IndexZ@xinzero.com
//PSerialPort.h
#pragma once
typedef void (*LPDataArriveProc)(char *data,int length,DWORD userdata);
class CPSerialPort
{
public:
CPSerialPort();
virtual ~CPSerialPort();
BOOL OpenPort(LPCTSTR Port,int Baudrate,
/*int DataBits,int StopBits,int Parity,*/
LPDataArriveProc proc=NULL,DWORD userdata=0); //打开串口
BOOL ClosePort(); //关闭串口
//激活与关闭持续接收
BOOL Activate();
BOOL Deactivate();
BOOL IsActive();
//接收数据线程函数
static DWORD WINAPI ReadPortThread(LPVOID lpParameter);
DWORD ReadPort(char *data,int length); //读取一定长度的数据
DWORD WritePort(char *data,int length); //发送数据
DWORD WriteFileToPort(LPCTSTR FileName); //发送文件
private:
HANDLE m_hComm; //串口设备handle
HANDLE m_hReadThread; //读串口线程handle
BOOL m_bReceiving; //是否持续接收
int m_nBufferSize; //缓冲大小
char *Buffer; //缓冲区
LPDataArriveProc m_lpDataArriveProc;
DWORD m_dwUserData;
//串口设置以及超时参数
DCB dcb;
COMMTIMEOUTS CommTimeOuts;
};
//From unkown author:unkonwn modified by IndexZ@xinzero.com
//PSerialPort.cpp
#include "StdAfx.h"
#include "PSerialPort.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPSerialPort::CPSerialPort()
{
m_hComm = INVALID_HANDLE_VALUE;
m_hReadThread = NULL;
m_bReceiving = FALSE;
m_nBufferSize = 256; //缓冲大小
}
CPSerialPort::~CPSerialPort()
{
ClosePort();
}
DWORD WINAPI CPSerialPort::ReadPortThread(LPVOID lpParameter)
{
CPSerialPort* m_pSerial;
m_pSerial=(CPSerialPort*)lpParameter;
BOOL fReadState;
DWORD dwLength;
char* buf=new char[m_pSerial->m_nBufferSize];
while((m_pSerial->m_hComm!=INVALID_HANDLE_VALUE)
&&(m_pSerial->m_bReceiving))
{
fReadState=ReadFile(m_pSerial->m_hComm,
buf,m_pSerial->m_nBufferSize,&dwLength,NULL);
if(!fReadState)
{
AfxMessageBox(_T("无法从串口读取数据!"));
}
else
{
if(dwLength!=0)
{ //调试输出代码开始
TRACE("%d\n",dwLength);
int *pint = (int*)buf;
for(int i=0;i<(dwLength/(sizeof(int)));i++)
{
TRACE("%d\n",pint[i]);
}//调试输出代码结束
//回送数据
if(m_pSerial->m_lpDataArriveProc!=NULL)
{
m_pSerial->m_lpDataArriveProc(buf,
dwLength,m_pSerial->m_dwUserData);
}
}
}
Sleep(100); //休眠cpu
}
delete[] buf;
return 0;
}
BOOL CPSerialPort::OpenPort(LPCTSTR Port,int BaudRate,
/*int DataBits,int StopBits,int Parity,*/
LPDataArriveProc proc,DWORD userdata)
{
m_lpDataArriveProc = proc;
m_dwUserData = userdata;
if(m_hComm==INVALID_HANDLE_VALUE)
{
m_hComm=CreateFile(Port,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
if(m_hComm==INVALID_HANDLE_VALUE )
{
AfxMessageBox(_T("无法打开端口!请检查是否已被占用。"));
return FALSE;
}
GetCommState(m_hComm,&dcb);
dcb.BaudRate=BaudRate;
//dcb.ByteSize=DataBits;
//dcb.Parity=Parity;
//dcb.StopBits=StopBits;
dcb.fParity=FALSE;
dcb.fBinary=TRUE;
dcb.fDtrControl=0;
dcb.fRtsControl=0;
dcb.fOutX=dcb.fInX=dcb.fTXContinueOnXoff=0;
//设置状态参数
SetCommMask(m_hComm,EV_RXCHAR);
SetupComm(m_hComm,16384,16384);
if(!SetCommState(m_hComm,&dcb))
{
AfxMessageBox(_T("无法按当前参数配置端口,请检查参数!"));
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
ClosePort();
return FALSE;
}
//设置超时参数
GetCommTimeouts(m_hComm,&CommTimeOuts);
CommTimeOuts.ReadIntervalTimeout=100;
CommTimeOuts.ReadTotalTimeoutMultiplier=1;
CommTimeOuts.ReadTotalTimeoutConstant=100;
CommTimeOuts.WriteTotalTimeoutMultiplier=0;
CommTimeOuts.WriteTotalTimeoutConstant=0;
if(!SetCommTimeouts(m_hComm,&CommTimeOuts))
{
AfxMessageBox(_T("无法设置超时参数!"));
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
ClosePort();
return FALSE;
}
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
return TRUE;
}
return FALSE;
}
BOOL CPSerialPort::ClosePort()
{
Deactivate();
if(m_hComm!=INVALID_HANDLE_VALUE)
{
SetCommMask(m_hComm,0);
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
CloseHandle(m_hComm);
m_hComm=INVALID_HANDLE_VALUE;
return TRUE;
}
return TRUE;
}
BOOL CPSerialPort::Activate()
{
if(m_hComm==INVALID_HANDLE_VALUE)
{
return FALSE;
}
if(!m_bReceiving)
{
//开始接收线程
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
m_bReceiving=TRUE;
m_hReadThread=CreateThread(NULL,0,ReadPortThread,this,0,NULL);
}
if(m_hReadThread!=NULL)
{
return TRUE;
}
else
{
m_bReceiving=FALSE;
return FALSE;
}
return FALSE;
}
BOOL CPSerialPort::Deactivate()
{
if(m_hComm==INVALID_HANDLE_VALUE)
{
return FALSE;
}
//停止接收线程
if(m_bReceiving)
{
m_bReceiving=FALSE;
WaitForSingleObject(m_hReadThread,500);
CloseHandle(m_hReadThread);
m_hReadThread=NULL;
return TRUE;
}
return FALSE;
}
BOOL CPSerialPort::IsActive()
{
return m_bReceiving;
}
DWORD CPSerialPort::WritePort(char *data,int length)
{
if(m_hComm == INVALID_HANDLE_VALUE)
{
return 0;
}
BOOL bFileWriteState;
DWORD dwBytesWritten=0;
bFileWriteState = WriteFile(m_hComm,data,
length*sizeof(char),&dwBytesWritten,NULL);
// AfxMessageBox(L"正在写串口数据。。。");
return dwBytesWritten;
}
DWORD CPSerialPort::ReadPort(char *data,int length)
{
BOOL bFileReadState;
DWORD dwLength,dwByteRead;
int TimeOutCount;
dwByteRead=0;
TimeOutCount=0;
// AfxMessageBox(L"正在读串口数据。。。");
while(m_hComm!=INVALID_HANDLE_VALUE)
{
char* buf=new char[length];
bFileReadState = ReadFile(m_hComm,data,length,&dwLength,NULL);
if(!bFileReadState)
{
break;
}
else
{
dwByteRead+=dwLength;
data+=dwLength;
}
if(dwByteRead == (unsigned long)length)
{
break;
}
if(dwLength!=0)
{
TimeOutCount=0;
}
else
{
TimeOutCount++;
Sleep(5);
}
if(TimeOutCount==5)
{
break;
}
}
return dwByteRead;
}
DWORD CPSerialPort::WriteFileToPort(LPCTSTR FileName)
{
CFile cf;
BOOL fWriteState,isOpen;
DWORD dwBytesWritten;
DWORD dwCharToWrite;
dwCharToWrite=0;
if(m_hComm==INVALID_HANDLE_VALUE)
{
return 0;
}
isOpen = cf.Open(FileName,CFile::modeRead);
if(!isOpen)
{
//AfxMessageBox(_T("无法打开Hex文件!"));
return 0;
}
dwCharToWrite=(DWORD)cf.GetLength();
cf.Seek(0,CFile::begin);
dwBytesWritten=0;
if(m_hComm!=INVALID_HANDLE_VALUE&&dwCharToWrite!=0)
{
char* buf=new char[dwCharToWrite];
cf.Read(buf,dwCharToWrite);
fWriteState=WriteFile(m_hComm,buf,dwCharToWrite*sizeof(char),
&dwBytesWritten,NULL);
if(!fWriteState)
{
//AfxMessageBox(_T("无法向端口写入数据!"));
}
delete[] buf;
}
cf.Close();
return dwBytesWritten;
}