用VC(Visual C++)读取串口数据并通过Flash图表类将其绘制为实时曲线

    我们知道,Flash可以做出很炫很酷的界面,且都是矢量图形,所以我们这里可以通过Active X控件shockwave Flash object将Flash嵌入到VC中,用控件与VC接口对Flash进行操作,如实时读取数据并作图类似的程序。曾经想用Flash连接串口读取数据,但Flash根本不能与串口连接,只好用Flash做用户交互界面,用VC做后台计算,实时通知Flash绘制实时曲线,走曲线救国的路径。( 注意,重要算法不要写到Flash中,Flash极易破解,即使用swf encrypt加密也敌不过action script viewer,用sothink flash decompile虽破解功夫不如ASV,但也能让破解者看透算法。尤其你想保护你的核心算法,所以仅仅用Flash做用户界面即可。)

    使用微软的串口封装类,实现对串口操作(读写)很是方便,API简单明了。微软的串口类CSerial定义如下:

 

//   Serial.h   
    
  #ifndef   __SERIAL_H__   
  #define   __SERIAL_H__   
    
  #define   FC_DTRDSR 0x01   
  #define   FC_RTSCTS 0x02   
  #define   FC_XONXOFF 0x04   
  #define   ASCII_BEL 0x07   
  #define   ASCII_BS 0x08   
  #define   ASCII_LF 0x0A   
  #define   ASCII_CR 0x0D   
  #define   ASCII_XON 0x11   
  #define   ASCII_XOFF 0x13   
    
  class   CSerial   
  {   
    
  public:   
  CSerial();   
  ~CSerial();   
    
  BOOL   Open(int   nPort=2,   int nBaud=9600);   
  BOOL   Close(void);   
    
  int   ReadData(void*,int);   
  int   SendData(const char *,int);   
  int   ReadDataWaiting(void);   
    
  BOOL IsOpened(void){return(m_bOpened);}   
    
  protected:   
  BOOL   WriteCommByte(unsigned char);   
    
  HANDLE   m_hIDComDev;   
  OVERLAPPED   m_OverlappedRead,   m_OverlappedWrite;   
  BOOL   m_bOpened;   
    
  };   
    
  #endif   

 

 

 

    虽然看不懂其内部如何操作硬件,但封装好的类就是好用,实现如下:

 

//   Serial.cpp   
 
  #include   "stdafx.h"
  #include   "CSerial.h"
 //CSerial::CSerial是类构造函数,不带参数,
 //负责初始化所有类成员变量
  CSerial::CSerial()
  {
  memset(&m_OverlappedRead,0,sizeof(OVERLAPPED));
  memset(&m_OverlappedWrite,0,sizeof(OVERLAPPED));
  m_hIDComDev=NULL;
  m_bOpened=FALSE;
  }
 
  CSerial::~CSerial()
  {
  Close();
  }
 //CSerial::Open是打开通信端口的成员函数,带两个参数,
 //一个是串行端口号,另一个是波特率。
  BOOL CSerial::Open(int nPort,int nBaud)
  {
 
  if(m_bOpened)   return(TRUE);
 
  char   szPort[15];
  char   szComParams[50];
  DCB   dcb;
 
  wsprintf(szPort,"COM%d",nPort);
 
  m_hIDComDev=CreateFile(szPort,GENERIC_READ|GENERIC_WRITE,
 0,
 NULL,
 OPEN_EXISTING,
 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,NULL);
 
  if(m_hIDComDev==NULL)   return(FALSE);
 
  memset(&m_OverlappedRead,0,sizeof(OVERLAPPED));
 memset(&m_OverlappedWrite,0,sizeof(OVERLAPPED));
 
  COMMTIMEOUTS CommTimeOuts;
  CommTimeOuts.ReadIntervalTimeout=0xFFFFFFFF;
  CommTimeOuts.ReadTotalTimeoutMultiplier=0;
  CommTimeOuts.ReadTotalTimeoutConstant=0;
  CommTimeOuts.WriteTotalTimeoutMultiplier=0;
  CommTimeOuts.WriteTotalTimeoutConstant=5000;
  SetCommTimeouts(m_hIDComDev,&CommTimeOuts);
 
  wsprintf(szComParams,"COM%d:%d,n,8,1",nPort,nBaud);
 
  m_OverlappedRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
  m_OverlappedWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
 
  dcb.DCBlength=sizeof(DCB);
  GetCommState(m_hIDComDev,&dcb);
  dcb.BaudRate=nBaud;
  dcb.ByteSize=8;
  unsigned   char   ucSet;
  ucSet=(unsigned char)((FC_RTSCTS&FC_DTRDSR)!=0);
  ucSet=(unsigned char)((FC_RTSCTS&FC_RTSCTS)!=0);
  ucSet=(unsigned char)((FC_RTSCTS&FC_XONXOFF)!=0);
  if(!SetCommState(m_hIDComDev,&dcb)||
  !SetupComm(   m_hIDComDev,10000,10000)||
  m_OverlappedRead.hEvent==NULL||
  m_OverlappedWrite.hEvent==NULL)
  {
  DWORD dwError=GetLastError();
  if(m_OverlappedRead.hEvent!=NULL)   CloseHandle(m_OverlappedRead.hEvent);
  if(m_OverlappedWrite.hEvent!=NULL)   CloseHandle(m_OverlappedWrite.hEvent);
  CloseHandle(m_hIDComDev);
  return(FALSE);
  }
 
  m_bOpened=TRUE;
 
  return(m_bOpened);
  }


 //CSerial::Close是关闭通信端口的成员函数。类析构函数调用这个函数,
 //因此可不用显式调用这个函数
  BOOL CSerial::Close(void)
  {
  if(!m_bOpened||m_hIDComDev==NULL)
  return(   TRUE   );
 
  if(   m_OverlappedRead.hEvent!=NULL)
  CloseHandle(m_OverlappedRead.hEvent);
 
  if(   m_OverlappedWrite.hEvent!=NULL)
  CloseHandle(m_OverlappedWrite.hEvent);
 
  CloseHandle(m_hIDComDev);
  m_bOpened=FALSE;
  m_hIDComDev=NULL;
 
  return(TRUE);
  }
 
  //++///
  BOOL CSerial::WriteCommByte(unsigned char ucByte)
  {
  BOOL bWriteStat;
  DWORD dwBytesWritten;
 
  bWriteStat=WriteFile(m_hIDComDev,
  (LPSTR)&ucByte,
  1,
  &dwBytesWritten,
  &m_OverlappedWrite);
 
  if(!bWriteStat&&(GetLastError()==ERROR_IO_PENDING))
  {
  if(WaitForSingleObject(m_OverlappedWrite.hEvent,1000))
  dwBytesWritten=0;
  else   
  {
  GetOverlappedResult(m_hIDComDev,&m_OverlappedWrite,&dwBytesWritten,FALSE);
  m_OverlappedWrite.Offset+=dwBytesWritten;
  }
  }
  return(TRUE);
  }
 

  /*CSerial::ReadData函数从端口接收缓冲区读入数据。第一个参数是缓冲区指针,
  第二个参数是个整数值,给出缓冲区的大小*/
  int CSerial::SendData(const char *buffer,int size)
  {
 
  if(!m_bOpened||m_hIDComDev==NULL)
  return(0);
 
  DWORD dwBytesWritten=0;
  int i;
  for(i=0;i<size;i++)
  {
  WriteCommByte(buffer[i]);
  dwBytesWritten++;
  }
 
  return((int)dwBytesWritten);
  }


 /*CSerial::ReadDataWaiting函数返回等待在
 通信端口缓冲区中的数据,不带参数*/
  int CSerial::ReadDataWaiting(void)
  {
  if(!m_bOpened||m_hIDComDev==NULL)
  return(0);
 
  DWORD   dwErrorFlags;
  COMSTAT   ComStat;
 
  ClearCommError(m_hIDComDev,&dwErrorFlags,&ComStat);
 
  return((int)ComStat.cbInQue);
  }
 

  /*CSerial::ReadData函数从端口接收缓冲区读入数据。第一个参数
  是缓冲区指针,第二个参数是个整数值,给出缓冲区的大小*/
  int CSerial::ReadData(void*buffer,int limit)
  {
  if(!m_bOpened||m_hIDComDev==NULL)
  return(0);
 
  BOOL   bReadStatus;
  DWORD   dwBytesRead,   dwErrorFlags;
  COMSTAT   ComStat;
 
  ClearCommError(m_hIDComDev,&dwErrorFlags,&ComStat);
 
  if(!ComStat.cbInQue)
  return(0);
 
  dwBytesRead=(DWORD)ComStat.cbInQue;
 
  if(limit<(int)dwBytesRead)
  dwBytesRead=(DWORD)limit;
 
  bReadStatus=ReadFile(m_hIDComDev,
  buffer,
  dwBytesRead,
  &dwBytesRead,
  &m_OverlappedRead);
 
  if(!bReadStatus)
  {
  if(GetLastError()==ERROR_IO_PENDING)
  {
  WaitForSingleObject(m_OverlappedRead.hEvent,2000);
  return((int)dwBytesRead);
  }
  return(0);
  }
 
  return((int)dwBytesRead);
  }

 

 

 

     强烈建议开启一个线程,监视串口数据,如此便可实现Active X控件MSComm的监听功能。串口使用很简单,初始化串口(设置波特率,串口号等);初始化成功后就可以读写串口了:

 

if(SerialPort.IsOpened());
	SerialPort.Close();
if(!SerialPort.Open(Port,Baud))
{
	AfxMessageBox("无法打开计算机串口,程序将退出!!\r\n请检查串口连接或配置是否正常!!");
	exit(0);
}
char buffer[1024];
SerialPort.ReadData(buffer,1024);

 

 

 

 

 

    本人年轻时,为公司制作大量如此的串口应用类程序,虽无技术亮点,但尚能勉强稳定运行于工业现场;然最大遗憾是经常根据公司上级领导指示修改串口接收数据,深知实属不该。  

    如果你想美化VC程序界面,用Flash是不错的选择,至于美化的多好,就看你的Flash制作水平啦。除Flash 8和Flash CS3外还有好多Flash工具可用,生成简单美观的Flash界面,呵呵! 用Flash8做很方便,VC直接控制Flash,但是变量获取算法不当可能不及时得到更新。用FlashCS3虽稍微繁琐,但很容易使Flash与VC交互通信,比JavaScript麻烦点,要有一点点XML的基础,强烈推荐使用AS3与VC通信,毕竟AS1/2过时啦,属于低级脚本语言。AS3强大,如日中天,且有N多第三方类库API,所以应该尽量使用AS3,其与后台的SOCKET通信也较为方便,适用于大量数据交换的情形。AS3与VC编程,也许会遇到很多BUG,只要肯动脑子,就难不倒。 再者Flex 3.0内置了图表组件外,其它组件美观是FLASH CS3不能比的,用Flex作图美观就是灵活性差了点,生成的swf文件也较大。

     如果只做简单图表推荐用Flex 3.0,其中最大问题就是如何让Flex读取外部实时数据(xml格式)转换为arrayCollection,这种方法在网上传滥了,屡试不爽。如果需要传输大量XML数据,建议使用XMLSocket传递数据,用C++做后台。 用Flash绘图另一好处就是不用考虑重绘,对向我一样的VC菜鸟级编程者,绘图本身不难,但重绘就有些繁琐,用Flash就不存在这个问题啦。再者,Flash内核提供较高质量打印服务,不影响VC后台工作。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值