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

📄 com.cpp

📁 一个简明的串口通讯例子
💻 CPP
字号:
//---------------------------------------------------------------------------
//串口控制类
//基本用WINAPI实现,采用事件响应方式,用一个线程处理各种消息
//用一个线程进行监控串口以接收字符,直接向串口写字符
//作者:冯华亮
//最后修改日期:2002年5月
#include <vcl.h>
#pragma hdrstop

#include "stdio.h"

#include "Com.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
int g_iSerialPort;                         //端口号:COM1,COM2,COM3,COM4
//---------------------------------------------------------------------------
//构造函数,初始化,把各数据成员置0
TSerialPort::TSerialPort()
{
	hComm =INVALID_HANDLE_VALUE; 	//串口句柄
	ComThread=NULL;		       	//串口监控线程
        //异步写操作中用到的重叠结构中的事件
	ov_Write.hEvent=CreateEvent(NULL, true, false, NULL);
}
//----------------------------------------------------------------------
//析构函数
TSerialPort::~TSerialPort()
{
        if(ComThread!=NULL)
        {
		//如果线程挂起则启动它,只要这样Terminate()方法才会有效,
                //线程才会FreeOnTerminated
        	while(ComThread->Suspended)
                	ComThread->Resume();
                ComThread->Terminate();
        	ComThread=NULL;
        }
	//释放对象,如果句柄有效,则关闭
	if(ov_Write.hEvent!=NULL)
	{
		CloseHandle(ov_Write.hEvent);
		ov_Write.hEvent=NULL;
	}
}
//----------------------------------------------------------------------
//串口初始化,可用于串口1到4,参数意义如下:
//pPortOwner-父窗口,uPortNo-串口号,uBaud-波特率,cParity-奇偶校验,uDatabits-数据位数,
//uStopbits-停止位数,dwCommEvents-需要监控的串口事件
bool TSerialPort::InitPort(HWND Parent ,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);
		Application->MessageBox(sTemp,"错误",MB_ICONSTOP);
		return false;
	}

	if(Parent==NULL)
	{
		Application->MessageBox("串口的父窗口无效,串口监控线程无法正常工作.","错误",MB_ICONSTOP);
		return false;
	}

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

	if (hComm==INVALID_HANDLE_VALUE)    //句柄无效,打开串口失败
        {
		sprintf(sTemp,"无法打开串口%d(COM%d),请检查串口是否正确安装,或是否被已经被占用.",
			uPortNo,uPortNo);
		Application->MessageBox(sTemp,"错误",MB_ICONSTOP);
		return false;
        }

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

	sprintf(sTemp,"baud=%d parity=%c data=%d stop=%d",uBaud,
		cParity,uDataBits,uStopBits);	//合成串口参数字符串
	//配置串口
	if (SetCommTimeouts(hComm,&CommTimeouts))		//超时参数
	{
		if (SetCommMask(hComm,dwCommEvents))		//需要监控的事件
		{
			if (GetCommState(hComm,&ComDCB))	//获取原始DCB
			{
				//禁止硬流控,因为本系统不需要
                                ComDCB.fOutxCtsFlow=false;
                                ComDCB.fOutxDsrFlow=false;
                                ComDCB.fDsrSensitivity=false;
                                ComDCB.fDtrControl=DTR_CONTROL_DISABLE;
				ComDCB.fRtsControl=RTS_CONTROL_DISABLE;

				//设置串口设备控制块(DCB)
				if (BuildCommDCB(sTemp,&ComDCB))
				{
					if (!SetCommState(hComm,&ComDCB))
						ProcessErrorMessage("设置串口");
				}
				else
					ProcessErrorMessage("建立串口设备控制块");
			}
			else
			    ProcessErrorMessage("获取串口状态");
		}
		else
			ProcessErrorMessage("设置串口事件掩码");
	}
	else
		ProcessErrorMessage("串口超时参数设置");

	//清空串口缓冲区,退出所有相关操作
	PurgeComm(hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);

	//创建串口监控线程
	ComThread=new TComThread(true,hComm,Parent);
	if(ComThread==NULL)	//无法创建线程
	{
		ProcessErrorMessage("创建线程");
		return false;
	}
	return true;
}
//----------------------------------------------------------------------
//启动串口监控线程
void __fastcall TSerialPort::StartMonitoring()
{
	ComThread->Resume();
}
//----------------------------------------------------------------------
//挂起线程
void __fastcall TSerialPort::StopMonitoring()
{
	ComThread->Suspend();
}
//----------------------------------------------------------------------
//向串口写一个字符
bool TSerialPort::WriteToPort(unsigned char ucTxChar)
{
	if(hComm==INVALID_HANDLE_VALUE)
	{
		Application->MessageBox("串口句柄无效,无法发送数据.","错误",MB_ICONSTOP);
		return false;
	}

	//初始化重叠结构
	ov_Write.Offset=0;
	ov_Write.OffsetHigh=0;

	//清空串口
	PurgeComm(hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
	//写串口
	DWORD BytesSent=0;
	bool bResult = WriteFile(hComm,	//串口句柄
			&ucTxChar,	//输出缓冲区
			1,  		//每次只发送一个字符
			&BytesSent,    	//实际读入的字符数
			&ov_Write);	//重叠结构
	if(!bResult) 	//写串口失败
	{
		DWORD dwError=GetLastError();	//得到失败原因
		switch(dwError)
		{
			case ERROR_IO_PENDING:  //串口操作正在后台进行
			{
				BytesSent=0;
                                //等待重叠结果
                                bResult=GetOverlappedResult(hComm,
                                                &ov_Write,
                                                &BytesSent, 	//实际发送字符数
                                                true);
                                if (!bResult)	//重叠操作失败
                                        return false;
				break;
			}
			default:	//失败
				return false;
		}
	}
	//检查实际发送的字符数是否与要求相符
	if (BytesSent!=1)
		return false;
        return true;
}
//---------------------------------------------------------------------------
//错误处理,显示原因
void __fastcall ProcessErrorMessage(char* ErrorText)
{
	char ErrorMsg[400];
	LPVOID lpMsgBuf;
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
			NULL,GetLastError(),     //获取错误信息标识
			MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),//使用系统缺省语言
			(LPTSTR)&lpMsgBuf, //消息缓冲区
			0,
			NULL);
	sprintf(ErrorMsg, "\"%s\" 由于以下错误而失败: \n\n%s",ErrorText,lpMsgBuf);
	Application->MessageBox(ErrorMsg, "串口错误", MB_ICONSTOP);
	LocalFree(lpMsgBuf);
}
//----------------------------------------------------------------------
//---------------------------------------------------------------------------

⌨️ 快捷键说明

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