您的当前位置:首页正文

基于WinCE的通用便携式串口终端设计与实现

2023-12-22 来源:步旅网
□经验交流□文章编号:1671-1041(2008)04-0114-02

仪器仪表用户基于WinCE的通用便携式串口终端设计与实现

董智强,徐世荣,余雅敏

(69046部队,乌鲁木齐830002)

摘要:WinCE以其良好的界面、强大的功能、类似桌面Windows操作系统的编程环境,受到编程者及使用者的欢迎,以WinCE为平台的各类终端迅速普及。通用串口终端,以WinCE为平台,使用API编程技术、MFC编程技术,采用多线程结构,实现RS232接口的文字、文件传输功能,并与超级终端等通用串口终端程序兼容。关键词:WinCE;API;MFC;多线程;终端中图分类号:TP311  文献标识码:B

1 引言

基于WinCE平台的通用串口终端,具有体积小、重量轻、功能强、界面直观等优点。在WinCE平台下编程,可以借鉴桌面Windows操作系统平台成熟的编程经验,通过API、MFC编程技术,采用多线程结构,软件结构性好,调试方便,编程效率高。同时,WinCE平台软件可靠性高,运行速度快,容错性好,是目前广泛采用的便携式电子通信装备平台。

2 总体设计

硬件平台选择扬创SBC2440开发板,操作系统为WindowsCE.net平台,编程环境为eMbeddedVisualC++4.0,该终端具有拨号(标准AT命令兼容)、应答、挂机、文字接收、文字发送、文件接收、文件发送等功能,并可以设置通信口通信参数。

本终端程序与Windows桌面操作系统的超级终端兼容,文件传输部分采用XModem协议实现,文字接收及文件接收采用辅助线程,构成多线程编程。线程间采用同步机制,避免程序异常。

3 串行通信部分设计

3.1 基础函数设计

(1)串口设置、打开:类似于文件操作,但是串口参数设置部分内容多,需要特别注意。在设计中,采用类成员函数的方法,将串口操作封装成类函数,供应用程序调用。

串口打开与否的判断,是串口终端程序的第一步,也是最基础的一步,必须在准确判断串口状态的基础上,进行其他操作。

(2)接收函数:实现多字符(字节)接收,其他接收函数,例如15秒接收一个字节等,均衍生于此函数。其关键部分代码如下:

DWORDCPSerialPort::ReadPort(char3data,intlength){while(m_hComm!=INVALID_HANDLE_VALUE)

  {……fReadState=ReadFile(m_hComm,data,length,&dwLength,NULL);……}……}另外,还有ReadByte函数、ReadByteWait函数,均为此函数的功能加强改进型。

(3)发送函数:字符(字节)发送,此函数为发送基础函数,是其他高级发送函数原型。

DWORDCPSerialPort::WritePort(char3data,intlength){……fWriteState=WriteFile(m_hComm,data,length3sizeof(char),&dwBytesWritten,NULL);

  returndwBytesWritten;}

另外还有部分特殊功能的发送函数,如WriteByte等,完成特殊功能,均为此函数的特殊变种。3.2 文字通信

(1)文字发送

voidCSerialPortDlg::OnSend()114  EIC Vo.l15 2008 No.4{……GetDlgItemText(IDC_TRANSMIT,m_strTransmit);

dwCharToWrite=(DWORD)m_strTransmit.GetLength();

dwBytesWritten=m_pSerial->WritePort(buf,dwChar2ToWrite);

m_strTransmit=_T(\"\");//清空

UpdateData(FALSE);//将变量传到控件……}

(2)文字接收

BOOLCPSerialPort::Activate()

{……if(!m_bReceiving)//开始接收线程

{  PurgeComm(m_hComm,PURGE_TXCLEAR|

PURGE_RXCLEAR);m_bReceiving=TRUE;m_hReadThread=CreateThread(NULL,0,Read2PortThread,this,0,NULL);}

……}

3.3 文件通信

(1)XModem概述

Xmodem是文件裸数据传输的重要协议,是YModem、ZMo2dem协议的基础,采用128字节为一帧,采用CHECKSUM或CRC2CCITT校验方式,每帧确认传输方式。

文件传输基于XModem协议,在进行文件传输编程之前,必须完成CRC2CCITT计算,为提高可靠性,避免嵌入式系统与桌面系统地兼容性问题,采用查表计算法。

unsignedintCPSerialPort::update_CRC(unsignedcharinDa2ta,unsignedintchecksum)

{

unsignedintcrc16_table[256]={0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,......0x3eb2,0x0ed1,0x1ef0};

  return(checksum<<8)^crc16_table[(checksum>>8)^inData];

}

(2)文件发送

文件发送方首先根据接收的第一个字符为NAK或‘C’,选择数据发送校验方式;确定校验方式后,读取文件内容的128字节,组装成帧,帧结构如图1所示。

SOH帧号

帧反号128字节数据……校验和

voidCPSerialPort::xmodemTx()//XModem发送文件{ //变量初始化

//开始文件发送

Temp=ReadByteWait(25);//接收并判断接收的首字符,作为选择校验方式的依据。while(!bEOF){ //发送块头

Temp=0x01;WriteByte(Temp);//发送块头Temp=nBlock;WriteByte(Temp);//发送块号

Temp=(~nBlock);WriteByte(Temp);//发送块反号nCheckSum=0;

欢迎光临本刊网站http://www.eic.com.cn

仪器仪表用户cCheckSum=0;//开始发送块数据

for(i=0;i<128;i++){Temp=buff[i];WriteByte(Temp);

cCheckSum+=buff[i];

nCheckSum=update_CRC(buff[i],nCheckSum);//计算校验和}

//发送校验数据

if(chCRCOut==0x43)  //CRC{WriteByte((nCheckSum>>8)&255);WriteByte(nCheckSum&255);}

elseif(chCRCOut==0x15)  //CheckSum{WriteByte((BYTE)(cCheckSum&255));}//读取并判断确认信号Temp=ReadByteWait(20);if(Temp==0x06)  //ACK

{nBlock++;gcTries=0;//块号从1到255}

elseif(Temp==0x15)  //NAK{FileToSend.Seek(2128L,CFile::current);gcTries++;bEOF=false;}

}  //while循环结束FileToSend.Close();}

(3)文件接收

该部分是文件接收中最复杂的部分,下面仅给出关键部分代码,没有包含文件处理、CAN信号处理、传输结束处理、错误处理等部分。

voidCPSerialPort::xmodemRcv(){//变量初始化等

//向发送端发送校验类型数据while(nSOH!=SOH)

  { bCRC=(gcTries++if(bCRC)

{WriteByte(0x43);}else

{WriteByte(0x15);}

nSOH=ReadByteWait(15);if(gcTries>=RETRIES){FileToRcv.Close();return;}

  }

  while((gcTries  { //变量复位等

nBlock=ReadByteWait();//读取块号

nNotBlock=ReadByteWait();//读取块反号for(i=0,wOurChecksum=0;i<128;i++)//读取数据块

  {buff[i]=ReadByteWait();

  wOurChecksum=(wOurChecksum+buff[i]&255)&255;//计算校验和  }

wChecksumSent=ReadByteWait();//读校验和wChecksumSent=wChecksumSent&255;if(bCRC)  //CRC校验{ TempRcv=ReadByteWait();

wChecksumSent=((wChecksumSent<<8)&0xff00)^(((WORD)(TempRcv&255))&0x00ff);

□经验交流□  for(i=0,wOurChecksum=0;i<128;i++)

  {wOurChecksum=update_CRC(buff[i],wOurCheck2sum);}

}

if((wChecksumSent^wOurChecksum)!=0x0000)  //校验检查

  {WriteByte(NAK);gcTries++;continue;}FileToRcv.Write(buff,128);  //接收数据写入文件WriteByte(ACK);  //发确认信号  }……  }

4 多线程结构设计

(1)接收字符线程

DWORDWINAPICPSerialPort::ReadPortThread(LPVOIDlpParameter)

{

  CPSerialPort3m_pSerial;

while((m_pSerial->m_hComm!=INVALID_HAN2DLE_VALUE)&&(m_pSerial->m_bReceiving)){fReadState=ReadFile(m_pSerial->m_hComm,buf,m_pSerial->m_nBufferSize,&dwLength,NULL);  if(fReadState)  {//回送数据}}……}(2)接收文件线程DWORDWINAPICPSerialPort::ReadFileThread(LPVOIDlpParameter)

{

  while(!bEOT)

  {//接收并处理接收到的数据}}

(3)线程同步

在程序中,除主线程外,还有字符读取显示线程和文件接收线程两个辅助线程。运用线程启动变量,采用互锁机制,当调用接收文字线程时,锁定文件线程;当调用文件接收线程时,锁定文字接收线程。

5 应用效果对比与结论

基于WINCE平台,通过eMbeddedVisualC++4.0环境的API和MFC混合编程,结合利用多线程技术,合理同步各子线程,实现某装备串口终端装置。该终端具备串口通信终端的基本功能,在此基础上,还可以扩充其他文件传输协议,也可以针对行业应用开发特殊的文件传输协议。此通用型串口终端,与桌面WINDOWS操作系统自带的超级终端程序兼容,可以互通。应用效果表明:该终端软件结构简单、运行可靠、容错能力强,与超级终端等串口程序兼容性好,编程技术通用,功能可扩充性好。□

参考文献

[1]ProgrammingMicrosoftWindowsCE.NET,ThirdEdition2003

DouglasBolingMicrosoftPress

[2]WindowsCE3.0ApplicationProgramming2000NickGrattan

PrenticeHall

[3]扬创电子.扬创SBC2440开发板技术手册.2006.

[4]胡志坤.VisualC++通信编程工程实例精解.机械工业出版

社,2005.

作者简介:董智强(1974-),学士,1997年毕业于解放军理工大学通信工程学院,现主要从事通信装备维修工作。收稿日期:2008-03-23(8053)

欢迎订阅欢迎撰稿欢迎发布产品广告信息EIC Vo.l15 2008 No.4 115 

因篇幅问题不能全部显示,请点此查看更多更全内容