串口同步和异步的读取与串口设备编程

串口同步和异步的读取与串口设备编程

本文次要绍介健康状况如何使掉转船头串口的读写生产力。,当串口说得中肯最高纪录抵达时,无准备地读取并处置。,随着健康状况如何将该方法运用到串口设备制作节目中。为了使顺序更焦点对准,文字说得中肯信号使死亡了。发短信在发短信说得中肯绝对显著更为重要,必要更多的关怀。自然在课文中会有独自认不出。,迎将评论。。

文字说得中肯信号下载地址

1、COM举枪窗口有或起作用

CreateFile(“COM1”, …); //翻开串口设备

SetupComm      设置独自串口来发送收执缓存

GetCommState 分配串口、设置波特率、终止位、检验位盼望

PurgeComm     清空收执缓存

SetCommTimeouts   设置发送和收执加班

ClearCommError       泻药COM认不出、查询发送和收执缓存八位字节说得中肯八位字节数

设置CaseMask//设置侦听器事情,设置后可召集WaitCommEvent  盼望事情,假使使时期互相划一翻开串口,此有或起作用泻药事情T。

WaistMeMefEng//盼望监督事情 当 SetCommMask  登记簿事情的过来将无准备地现场恢复。,

                             //假使是以使时期互相划一方法翻开串口必要召集SetCommMask  泻药事情,

                             不然,再次召集WaitCommEvent 它一起就会放回

ReadFile(hCom, ReadBuf, ReadLen, &ReadSize, 空) //读取缓存,当在缓存中读取八位字节最高纪录时,它无准备地现场恢复。,没大人物会如果

                                                                                           //SetCommTimeouts  过来的加班又放回了。

WriteFile  //写信最高纪录

2、串口读取

当我读串口时,我命令在串口中有一次最高纪录。不尊重是使时期互相划一应该异步都有两种方法使掉转船头,他们都在应用WaITCOMMEVER盼望EVHRXCHAR事情。,应用Read Frand有或起作用的独自特点当在缓存中读取八位字节最高纪录时,它无准备地现场恢复。)。

WaitCommEvent 方法:EVHRXCHAR事情率先登记簿,假使在读取缓存中有最高纪录,它将引发及其他事件的一件事事情。,可以布告应用顺序,此后召集Read Fipe停止读取。。

读取排成一行行走的方法:你必要先读独自八位字节 ReadFile(hCom, buf, 1, &ReadSize, 空),现场恢复TRUE后则经过ClearCommError 查询有全部效果最高纪录必要读取,此后再次召集Read排成一行行走来数其余者的最高纪录。。

当WaitCommEvent被使时期互相划一时,在Seri时召集盼望时期。,不克不及由及其他螺纹召集WrreFeFILE。,且WaitCommEvent无加班决定因素因而该方法在起作用的使时期互相划一串口读取根本无实际的重要性。

3、串口使时期互相划一读写

经过读取排成一行行走读取盼望最高纪录的方法

翻开和分配串口

HANDLE InitCOM(LPCTSTR 举枪)
{
	HANDLE hCom = INVALID_HANDLE_VALUE;
	hCom = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
0/*使时期互相划一翻开串口, 空);
	if (INVALID_HANDLE_VALUE == hCom)
	{
		return INVALID_HANDLE_VALUE;
	}
	SetupComm(hCom, 4096, 4096);/ /设置缓存
	
	DCB dcb;

	GetCommState(hCom, DCB);/ /设置串行口
	dcb.DCBlength = sizeof(dcb);
	dcb.BaudRate = CBR_9600;
	dcb.StopBits = ONESTOPBIT;
	SetCommState(hCom, DCB)

	PurgeComm(hCom, PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT);//清空缓存

	COMMTIMEOUTS ct;
设置读取加班时期,长时间的的盼望时期
	ct.ReadIntervalTimeout = 0;
	ct.ReadTotalTimeoutConstant = 5000;
	ct.ReadTotalTimeoutMultiplier = 500;

	ct.WriteTotalTimeoutMultiplier = 500;
	ct.WriteTotalTimeoutConstant = 5000;

	SetCommTimeouts(hCom, CT);/ /设置加班

	return hCom;
}

最高纪录读取

bool ComRead(HANDLE hCom, LPBYTE buf, int 莱恩)
{
	DWORD ReadSize = 0;
	BOOL rtn = FALSE;

设置1八位字节最高纪录,当缓存中有最高纪录抵达时则它一起就会放回,直到时期流逝
	rtn = ReadFile(hCom, buf, 1, &ReadSize, 空);

假使是加班RTN=true,虽然Read Stase= 0,假使有最高纪录抵达,将读取八位字节读数=1。
	if (RTN) == TRUE && 1 == ReadSize)
	{
		DWORD Error;
		COMSTAT cs = {0};
		int ReadLen = 0;
过剩的八位字节不读全部效果八位字节,中部贮存
		ClearCommError(hCom, &Error, 政事司理事)
		ReadLen = ( > 莱恩) ? len : ;
		if (ReadLen > 0)
		{
鉴于盼望时期读取八位字节,所欲buf+1
			rtn = ReadFile(hCom, buf+1, ReadLen, &ReadSize, 空);
			len = 0;
			if (RTN))
			{
				len = ReadLen + 1;
			}
		}
	}
	PurgeComm(hCom, PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT);
	return rtn != FALSE;
}

最高纪录写信

bool ComWrite(HANDLE hCom, LPBYTE buf, int 莱恩)
{
	PurgeComm(hCom, PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT);
	BOOL rtn = FALSE;
	DWORD WriteSize = 0;
	rtn = WriteFile(hCom, buf, len, &WriteSize, 空);

	len = WriteSize;
	return rtn != FALSE;
}

鉴于使时期互相划一串口盼望最高纪录读取的WaITCOMMEVE方法根本无实际的重要性,因而无议论。

4、COM举枪的异步读写

由于异步读取是在后盾履行的,最高纪录抵达通常必要独自的螺纹盼望。,因而本文应用独自类来解说。

盼望最高纪录读取的WaITCOMMEVE方法

异步读取类申明

class ComAsy
{
public: 
	ComAsy();
	~ComAsy();
	bool InitCOM(LPCTSTR 举枪);//翻开窗口
	void UninitCOM(); 堵塞串口并清算

	//写信最高纪录
	bool ComWrite(LPBYTE buf, int 莱恩);

读取螺纹
	static unsigned int __stdcall OnRecv(void*);

private:
	HANDLE m_hCom;
	OVERLAPPED MyOVWORD;///用于写信最高纪录
	OVERLAPPED MyOVRAD;///用于读取最高纪录
	OVERLAPPED 盼望最高纪录
	volatile bool MyISOPEN;///串行举枪是吐艳的
	HANDLE MyLoad;//读螺纹句柄
};

ComAsy::ComAsy():
			m_hCom(INVALID_HANDLE_VALUE),
			m_IsOpen(false),
			m_Thread(空)
{
	memset(&m_ovWait, 0, sizeof(m_ovWait));
	memset(&m_ovWrite, 0, sizeof(m_ovWrite));
	memset(&m_ovRead, 0, sizeof(m_ovRead));
}

ComAsy::~ComAsy()
{
	UninitCOM();
}

设定初值和分配串口

bool ComAsy::InitCOM(LPCTSTR 举枪)
{
	m_hCom = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
		FILE_FLAG_OVERLAPPED|FILE_ATTRIBUTE_NORMAL,设置异步高尚
		空);
	if (INVALID_HANDLE_VALUE == m_hCom)
	{
		return false;
	}
	SetupComm(m_hCom, 4096, 4096);//设置接待缓存

	DCB dcb;
	GetCommState(m_hCom, DCB)
	dcb.DCBlength = sizeof(dcb);
	dcb.BaudRate = CBR_9600;
	dcb.StopBits = ONESTOPBIT;
	SetCommState(m_hCom, DCB)分配串口

	PurgeComm(m_hCom, PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT);

	COMMTIMEOUTS ct;
	ct.ReadIntervalTimeout = 无推延读,由于有盼望最高纪录的盼望
	ct.ReadTotalTimeoutConstant = 0;  //
	ct.ReadTotalTimeoutMultiplier = 0;//

	ct.WriteTotalTimeoutMultiplier = 500;
	ct.WriteTotalTimeoutConstant = 5000;

	SetCommTimeouts(m_hCom, CT)

创立事情靶子
	 = CreateEvent(零点), false, false, 空);
	 = CreateEvent(零点), false, false, 空);
	 = CreateEvent(零点), false, false, 空);

	SetCommMask(m_hCom, EV_ERR | EVRRXCHAR;/集收执事情

创立读取螺纹
	m_Thread = (句柄), 0, &ComAsy::OnRecv, this, 0, 空);
	m_IsOpen = true;
	return true;
}

写信最高纪录,大抵,写信最高纪录无高机能命令。,这么,假使最高纪录被写信后盾,当最高纪录被写信异步时,此后盼望写信履行并放弃,此刻等积的于独自使时期互相划一写。

bool ComAsy::ComWrite(LPBYTE buf, int 莱恩)
{
	BOOL rtn = FALSE;
	DWORD WriteSize = 0;

	PurgeComm(m_hCom, PURGE_TXCLEAR|PURGE_TXABORT);
	m_ovWait.Offset = 0;
	rtn = WriteFile(m_hCom, buf, len, &WriteSize, &m_ovWrite);

	len = 0;
	if (假) == rtn && GetLastError() == 认不出读取/后盾读取
	{
盼望最高纪录写信履行
		if (假) == ::GetOverlappedResult(m_hCom, &m_ovWrite, &WriteSize, 真的)
		{
			return false;
		}
	}

	len = WriteSize;
	return rtn != FALSE;
}

读取最高纪录

unsigned int __stdcall ComAsy::OnRecv( void* LPParam)
{
	ComAsy *obj = static_cast(LPParam);

	DWORD WaitEvent = 0, Bytes = 0;
	BOOL Status = FALSE;
	BYTE ReadBuf[4096];
	DWORD Error;
	COMSTAT cs = {0};

	while(obj->m_IsOpen)
	{
		WaitEvent = 0;
		obj->m_ovWait.Offset = 0;
		Status = WaitCommEvent(obj->m_hCom,&WaitEvent, &obj->m_ovWait );
WAITCOMMEVER也异步命令,因而它必要盼望
		if (假) == Status && GetLastError() == ERROR_IO_PENDING)//
		{
假使缓存中无最高纪录螺纹,它将在喂终止。,假使hCom堵塞它一起就会放回False
			Status = GetOverlappedResult(obj->m_hCom, &obj->m_ovWait,  &Bytes, 真的)
		}
		ClearCommError(obj->m_hCom, &Error, 政事司理事)
		if (真) == Status 盼望事情成
			&& WAITEVER和EVHRXCHAR//Cache说得中肯最高纪录抵达
			&&  > 0)/最高纪录
		{
			Bytes = 0;
			obj->m_ovRead.Offset = 0;
			memset(ReadBuf, 0, sizeof(ReadBuf));
最高纪录已抵达缓存区,Read排成一行行走懈怠异步命令,相反,读取并现场恢复到真
			Status = ReadFile(obj->m_hCom, ReadBuf, sizeof(ReadBuf), &Bytes, &obj->m_ovRead);
			if (条款) != 假)
			{
				cout<<"Read:"<<(LPCSTR)ReadBuf<<"   Len:"<< Bytes<m_hCom, PURGE_RXCLEAR|PURGE_RXABORT);
		}

	}
	return 0;
}

堵塞串口

void ComAsy::UninitCOM()
{
	m_IsOpen = false;
	if (INVALID_HANDLE_VALUE != m_hCom)
	{
		CloseHandle(m_hCom);
		m_hCom = INVALID_HANDLE_VALUE;
	}
	if (零点) != )
	{
		CloseHandle();
		 = NULL;
	}
	if (零点) != )
	{
		CloseHandle();
		 = NULL;
	}
	if (零点) != )
	{
		CloseHandle();
		 = NULL;
	}
	if (零点) != m_Thread)
	{
		WaitForSingleObject(m_Thread, 5000);/ /盼望螺纹完毕
		CloseHandle(m_Thread);
		m_Thread = NULL;
	}
}

在起作用的异步读取普通都采取WaitCommEvent的方法盼望最高纪录,也有可能以读取排成一行行走的方法盼望最高纪录。,只必要设置独自大的加班时期,此后盼望读取1八位字节。

5、串口设备切开

普通的串口设备都是首席机发送独自命令设备现场恢复命令工具的算是,使时期互相划一窗口读取完全健壮的这种榜样。大抵,命令是由写排成一行行走发送的。,此后Read排成一行行走读取算是。将加班决定因素设置为设备举措所需的长时间的时期。,这将发生在发送命令后命令的工具算是。。

应用使时期互相划一读取,可以封装设备类。,类的机构列举如下。

class Device
{
public:
	Device();
	~Device();
	bool Init(LPCTSTR Port, ...);
	void UnInit();

	bool Option1(LPCTSTR Param1,...)
	{
每回使运行前锁定设备
		WriteFile(m_hCom, ...);//发送命令

		ReadFile(m_hCom, 获取命令算是
		();
		return true;
	}
	bool Option2(LPCTSTR Param1,...);
	//...


查询条款螺纹,每隔独自时期查询独自条款,知识设备无论在线或离线
	static unsigned int __stdcall QueryStatus(void*);


private:
	HANDLE m_hCom;
	bool m_IsOpen;
	int m_DeviceStatus;

	CCriticalSection m_cs;//

	HANDLE m_ThreadStatus;
};

在起作用的致活最高纪录的设备,应用异步方法更相配的。,由于异步方法永远盼望读取最高纪录。

————————————————————————————————————————————————————————————————————————

串行异步读取的可供选择的事物方法

串口设定初值, 与先前的异步方法划一,只需设置加班时期那就够了将RealTimeTimeToT设置为2MS。, 如此的,当异步读取Read排成一行行走时,会回到假的,而且GetLastError() == ERROR_IO_PENDING,此后召集GETPopReuldDebug盼望最高纪录抵达,假使最高纪录抵达而且时期比2MS长,它将现场恢复。,不然,将盼望很长时期。。

当串行举枪未堵塞时,GET堆叠算是的现场恢复必要两个先决条件的,独自是在ReadFi中取得详述八位字节数的加班或读取八位字节。,二是最高纪录的抵达,除非当履行两个先决条件的时,它才会现场恢复。。

信号列举如下:

设定初值信号:

bool ComAsy::InitCOM(LPCTSTR 举枪)
{
	m_hCom = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
		FILE_FLAG_OVERLAPPED|FILE_ATTRIBUTE_NORMAL,设置异步高尚
		空);
	if (INVALID_HANDLE_VALUE == m_hCom)
	{
		return false;
	}
	SetupComm(m_hCom, 4096, 4096);//设置接待缓存

	DCB dcb;
	GetCommState(m_hCom, DCB)
	dcb.DCBlength = sizeof(dcb);
	dcb.BaudRate = CBR_9600;
	dcb.StopBits = ONESTOPBIT;
	SetCommState(m_hCom, DCB)分配串口

	PurgeComm(m_hCom, PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT);

	COMMTIMEOUTS ct;
    读取推延设置为2MS,这么,当异步读取读排成一行行走时,会回到假的,而且GetLastError() == ERROR_IO_PENDING。
假使设置为,读排成一行行走的异步读取,将回归真实
	//此后召集GETPopReuldDebug盼望最高纪录抵达,假使最高纪录抵达而且时期比2MS长,它将现场恢复。,不然,将盼望很长时期。。
	ct.ReadIntervalTimeout = 2;
	ct.ReadTotalTimeoutConstant = 0;  //
	ct.ReadTotalTimeoutMultiplier = 0;//

	ct.WriteTotalTimeoutMultiplier = 500;
	ct.WriteTotalTimeoutConstant = 5000;

	SetCommTimeouts(m_hCom, CT)

创立事情靶子
	 = CreateEvent(零点), false, false, 空);
	 = CreateEvent(零点), false, false, 空);
	 = CreateEvent(零点), false, false, 空);

	SetCommMask(m_hCom, EV_ERR | EVRRXCHAR;/集收执事情

创立读取螺纹
	m_Thread = (句柄), 0, &ComAsy::OnRecv, this, 0, 空);
	m_IsOpen = true;
	return true;
}

读取螺纹信号:

unsigned int __stdcall ComAsy::OnRecv( void* LPParam)
{
	ComAsy *obj = static_cast(LPParam);

	DWORD Bytes = 0;
	BOOL Status = FALSE;
	BYTE ReadBuf[4096];
	DWORD Error;
	COMSTAT cs = {0};

	while(obj->m_IsOpen)
	{

		ClearCommError(obj->m_hCom, &Error, 政事司理事)

		Bytes = 0;
		obj->m_ovRead.Offset = 0;
		memset(ReadBuf, 0, sizeof(ReadBuf));
		Status = ReadFile(obj->m_hCom, ReadBuf, sizeof(ReadBuf), &Bytes, &obj->m_ovRead);
最高纪录已抵达缓存区,读取它一起就会放回,回归真实, 不然,现场恢复false
		if (条款) == FALSE && GetLastError() == ERROR_IO_PENDING)
		{
假使有最高纪录抵达 且 时期超越RealTimeValimeUT将现场恢复,不然,将盼望很长时期。
			Status = GetOverlappedResult(obj->m_hCom, &obj->m_ovRead, &Bytes, 真的)
		}
		if (假) != Status && Bytes > 0)
		{
			cout<<"Read:"<<(LPCSTR)ReadBuf<<"   Len:"<< Bytes<m_hCom, PURGE_RXCLEAR|PURGE_RXABORT);

	}

	return 0;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注