⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 com.~cpp

📁 串口数据采集的上位机源码
💻 ~CPP
📖 第 1 页 / 共 2 页
字号:
//实现代码Com.cpp
//---------------------------------------------------------------------------

#pragma package(smart_init)
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "stdio.h"

#include "Com.h"
//#include "Macro.h"  //我自定义的一些宏,简化对MessageBox的调用
//---------------------------------------------------------------------------
//构造函数,初始化,把各数据成员置0
TSerialPort::TSerialPort()
{
m_hComm =INVALID_HANDLE_VALUE;
m_hThread=NULL;
m_hShutdownEvent = NULL;
m_OverLapped.hEvent = NULL;
m_OverLapped.Offset = 0;
m_OverLapped.OffsetHigh = 0;
m_hEventArray[0]=NULL;
m_hEventArray[1]=NULL;
m_bThreadAlive = false;
m_pOwner=NULL;
m_uPortNo=1;
}
//----------------------------------------------------------------------
//析构函数
TSerialPort::~TSerialPort()
{
Clear();  //清除资源
}
//----------------------------------------------------------------------
//释放资源
void __fastcall TSerialPort::Clear()
{
if(m_hThread!=NULL)
{
   //检查串口线程是否被挂起,如果是则恢复它
   int iSuspendCount=ResumeThread(m_hThread);
   while(iSuspendCount>1)
     iSuspendCount=ResumeThread(m_hThread);

   int OldTime,NewTime;    //用于判断超时
   OldTime=GetTickCount();    //从WINDOWS启动到当前的毫秒值
   //终止串口监控线程
   while (m_bThreadAlive)  //串口线程仍存在
   {
     NewTime=GetTickCount();
     if((NewTime-OldTime)>3000)    //超时(3妙)强制终止串口线程
     {
       TerminateThread(m_hThread,200);
      // mErrorMsg("串口线程异常终止!");
      Application->MessageBoxA("串口线程异常终止!","错误",0);
       break;
     }
     SetEvent(m_hShutdownEvent);  //设置关闭串口事件
     SetEvent(m_OverLapped.hEvent);
   }
   m_bThreadAlive=false;
   CloseHandle(m_hThread);
   m_hThread=NULL;
}

//释放对象,如果句柄有效,则关闭
if (m_hComm!=INVALID_HANDLE_VALUE)
{
   CloseHandle(m_hComm);
   m_hComm=INVALID_HANDLE_VALUE;
}
if(m_hShutdownEvent!=NULL)
{
   CloseHandle(m_hShutdownEvent);
   m_hShutdownEvent=NULL;
}
if(m_OverLapped.hEvent!=NULL)
{
   CloseHandle(m_OverLapped.hEvent);
   m_OverLapped.hEvent=NULL;
}
}

//----------------------------------------------------------------------
//串口初始化,可用于串口1到4,参数意义如下:
//pPortOwner-父窗口,uPortNo-串口号,uBaud-波特率,cParity-奇偶校验,uDatabits-数据位数,
//uStopbits-停止位数,dwCommEvents-需要监控的串口事件
bool TSerialPort::InitPort(TForm* pPortOwner,unsigned uPortNo,unsigned uBaud,
char cParity,unsigned uDataBits,unsigned uStopBits,DWORD dwCommEvents)
{
char sTemp[100];
if(uPortNo<1||uPortNo>4)
{
   sprintf(sTemp,"无法打开串口COM%d,串口号只能是COM1、COM2、COM3或COM4中的一个.",
     uPortNo);
   //mErrorMsg(sTemp);
   return false;
}
if(pPortOwner==NULL)
{
   //mErrorMsg("串口的父窗口无效,串口监控线程无法正常工作.");
   return false;
}

Clear();  //清除没有被释放的资源

//创建新对象
m_OverLapped.hEvent = CreateEvent(NULL, //安全属性
       true,    //手工复位
       false,    //初始为无事件状态
       NULL);    //事件名称
m_hShutdownEvent=CreateEvent(NULL, true, false, NULL);
//初始化事件数组
m_hEventArray[0] = m_hShutdownEvent;  //关闭串口事件,优先级最高
m_hEventArray[1] = m_OverLapped.hEvent;    //重叠结果中的事件

m_pOwner = pPortOwner;      //父窗口,即控制串口的对象
m_uPortNo =uPortNo;      //指定串口号
m_dwCommEvents = dwCommEvents;    //串口要监控的事件

sprintf(sTemp,"COM%d",uPortNo);  //合成串口号字符串
//打开串口,获取串口句柄
m_hComm = CreateFile(sTemp,    //串口号
     GENERIC_READ|GENERIC_WRITE,//读写方式
     0,            //通讯设备必须以独占方式打开
     NULL,            //无安全属性
     OPEN_EXISTING,          //通讯设备已存在
     FILE_FLAG_OVERLAPPED,  //异步I/O
     0);            //通讯设备不能用模板打开

if (m_hComm==INVALID_HANDLE_VALUE)    //句柄无效,打开串口失败
   return false;

//设置超时参数,总时间=Multiplier*字符数+Constant
//Interval为读入的字符串中任意两个字符间的最大间隔
m_CommTimeouts.ReadIntervalTimeout=1000;
m_CommTimeouts.ReadTotalTimeoutMultiplier=1000;
m_CommTimeouts.ReadTotalTimeoutConstant=1000;
m_CommTimeouts.WriteTotalTimeoutMultiplier=1000;
m_CommTimeouts.WriteTotalTimeoutConstant=1000;

sprintf(sTemp,"baud=%d parity=%c data=%d stop=%d",uBaud,
   cParity,uDataBits,uStopBits);  //合成串口参数字符串
//配置串口
if (SetCommTimeouts(m_hComm,&m_CommTimeouts))    //超时参数
{
   if (SetCommMask(m_hComm,m_dwCommEvents))    //需要监控的事件
   {
     if (GetCommState(m_hComm,&m_DCB))  //获取原始DCB
     {
       //设置串口设备控制块(DCB)
       m_DCB.fRtsControl=RTS_CONTROL_ENABLE;
       if (BuildCommDCB(sTemp,&m_DCB))
       {
         if (!SetCommState(m_hComm,&m_DCB))
           ProcessErrorMessage("设置串口");
       }
       else
         ProcessErrorMessage("建立串口设备控制块");
     }
     else
         ProcessErrorMessage("获取串口状态");
   }
   else
     ProcessErrorMessage("设置串口事件掩码");
}
else
   ProcessErrorMessage("串口超时参数设置");

//清空串口缓冲区,退出所有相关操作
PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
return true;
}
//启动串口监控线程
bool TSerialPort::StartMonitoring()
{
DWORD dwThreadId;
//创建线程
m_hThread=CreateThread( NULL,  //无安全属性
     0,    //用主线程的堆栈
     CommThread,  //线程的执行函数
     this,        //传给线程执行函数的参数
     0,            //初始为激活状态
     &dwThreadId);   //线程标识
if(m_hThread==NULL)  //无法创建线程
{
   ProcessErrorMessage("创建线程");
   return false;
}
return true;
}
//----------------------------------------------------------------------
//挂起线程,返回以前的挂起记数
int TSerialPort::StopMonitoring()
{
return(SuspendThread(m_hThread));
}
//----------------------------------------------------------------------
//重新启动线程,返回以前的挂起记数
int TSerialPort::RestartMonitoring()
{
return(ResumeThread(m_hThread));
}
//----------------------------------------------------------------------
//串口事件处理线程
DWORD WINAPI TSerialPort::CommThread(LPVOID lpvParam)
{
//将void型的pParam转化为TSerialPort类型的指针
TSerialPort *Port = (TSerialPort*)lpvParam;
Port->m_bThreadAlive=true;  //标志串口线程处于活动态

DWORD Event=0;
DWORD CommEvent=0;
DWORD dwError=0;
COMSTAT ComStat;        //串口状态
bool bResult;

if(Port->m_hComm==INVALID_HANDLE_VALUE)  //串口句柄有效
{
   //mErrorMsg("串口句柄无效,串口监控线程无法工作.");
   Port->m_bThreadAlive=false;
   ExitThread(0);
}
PurgeComm(Port->m_hComm, PURGE_RXCLEAR|PURGE_TXCLEAR|
     PURGE_RXABORT|PURGE_TXABORT);

//进入无限循环,直到关闭串口事件变为有信号.
while(1)
{
   //调用WaitCommEvent().这一调用将立即返回,因为我用异步方式
   //(FILE_FLAG_OVERLAPPED)打开串口,并且指定重叠操作结构,
   //如果有一个字符到达串口,重叠结构中的事件将被置为有信号态
   bResult=WaitCommEvent(Port->m_hComm,&Event,&Port->m_OverLapped);
   if (!bResult)
   {
     //如果WaitCommEvent()返回FALSE,调用GetLastError()判断原因
     switch (dwError=GetLastError())
     {
       case ERROR_IO_PENDING:      //重叠操作正在后台进行
       {
         //如果串口这时无字符,这是正常返回值,继续
         break;
       }
       case 87:
       {
         //在WIN NT下这是一个可能结果,但我没有找到
         //它出现的原因,我什么也不做,继续
         break;
       }
       default:
       {
         //所有其它错误代码均显示串口出错,显示出错信息
         Port->ProcessErrorMessage("等待串口事件");
         Port->m_bThreadAlive=false;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -