user-0 提问: 如何用C语言读取串口数据

回复:
user: user-1
content: 搜“serial库”

user: user-2
content: #ifndef _COMM_H_  #define _COMM_H_  #define WM_FOUNDCOMM WM_USER+1  //自定义消息WM_FOUNDCOMM,收到该消息表示串口已经找到 #define WM_READCOMM WM_USER+2   //自定义消息WM_READCOMM,收到该消息缓冲区有数据, 可以读取 extern void FindComm();     //申明为外部函数  extern void OpenComm(int nBaud, int nData, int nStop, int nCal); extern void CloseComm(); extern UINT ThreadFunc(LPVOID pParam); //申明全局线程处理函数  extern CString DisplayCString2Hex(CString Data, bool Blank_allow); extern CString DisplayHex2CString(CString Data); extern int ConvertHexC2String(CString str, CByteArray &senddata); extern bool ComIsOK;     //申明为外部变量  extern HANDLE hCom; extern CString strcomname; #endif  #include "stdafx.h"  #include "commassist.h"  #include "commassistDlg.h"  #include "comm.h"  char ConvertHexChar(char ch); HANDLE hCom;   //串口句柄  CString strcomname;  //串口名,如"COM1"  bool ComIsOK;   //串口打开状态标识,为真表示已打开,否则未打开  //============自动寻找串口函数=================================  //函数功能:通过扫描注册表来找出当前所有物理串口  //输入参数:无  //返回类型:无  //说    明:若搜索成功,则每搜到一个串口便发送消息通知主对话框,并将串口号以WPARAM传递 void FindComm() { 	//枚举当前系统中的串口  	LONG result = 0; 	HKEY key = NULL; 	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, //需要打开的主键的名称  		"HARDWARE\\DEVICEMAP\\SERIALCOMM", //需要打开的子键的名称, 设备串口 		0,      //保留必须设置为0  		KEY_READ,  //安全访问标记也就是权限  		&key);     //得到的将要打开键的句柄当不再需要句柄 	//必须调用 RegCloseKey 关闭它  	if (result) 	{ 		AfxMessageBox("无法获取串口请确认是否安装并连接串口!"); return; 	} 	TCHAR portname[250];     //串口名  	TCHAR data[250]; 	DWORD portnamelen = 0;     //串口名长度  	DWORD datalen = 0; 	int index = 0; 	while (1)    //找完COM后跳出  	{ 		portnamelen = 255; 		datalen = 255; 		result = RegEnumValue(key,   //Long一个已打开项的句柄或者指定一个标准项名 			index++,   //Long欲获取值的索引。注意第一个值的索引编号为零 			portname,  //String用于装载位于指定索引处值名的一个缓冲区 			&portnamelen, //Long用于装载lpValueName缓冲区长度的一个变量。 			//一旦返回它会设为实际载入缓冲区的字符数量 			NULL,   //Long未用设为零  			NULL,   //Long用于装载值的类型代码的变量  			(LPBYTE)data, //Byte用于装载值数据的一个缓冲区   			&datalen);  //Long用于装载lpData缓冲区长度的一个变量。 		//一旦返回它会设为实际载入缓冲区的字符数量 		if (result)  break; 		//发送消息,WM_USER+1为自定义消息,即找到串口的,并将串口号"COMx"通过WPARAM参数传送给主对话框窗口 		//::AfxGetMainWnd()->m_hWnd,获得主对话框句柄  		//(WPARAM)(LPCTSTR)data,类型转换   		::SendMessage(::AfxGetMainWnd()->m_hWnd, WM_FOUNDCOMM, (WPARAM)(LPCTSTR)data, 0); 	} 	RegCloseKey(key);      //调用 RegCloseKey 关闭打开键的句柄  } //============自动寻找串口函数结束==================   //==========串口打开函数===========================  //功    能:打开串口,将已打开的串口句柄赋值给hCom,给出串口打开状态ComIsOK,完成串 //输入参数:波特率,数据位,停止位,校验位  //返回类型:无  void OpenComm(int nBaud, int nData, int nStop, int nCal) { 	hCom = CreateFile(strcomname,   //串口号  		GENERIC_READ | GENERIC_WRITE,  //允许读或写  		0,         //独占方式  		NULL, 		OPEN_EXISTING,      //打开而不是创建  		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,//重叠方式,用于异步通信 		NULL);  	if (hCom == INVALID_HANDLE_VALUE) 	{ 		AfxMessageBox("打开COM失败串口不存在或已被占用!"); 		ComIsOK = false; 		return; 	} 	ComIsOK = true; 	SetCommMask(hCom, EV_TXEMPTY | EV_RXCHAR);  //设置事件掩码,暂时没用上 	SetupComm(hCom, 1024, 1024);  //设置输入缓冲区和输出缓冲区的大小都是1024  	COMMTIMEOUTS TimeOuts; 	//设定读超时  	TimeOuts.ReadIntervalTimeout = MAXDWORD; 	TimeOuts.ReadTotalTimeoutConstant = 0; 	TimeOuts.ReadTotalTimeoutMultiplier = 0; 	//设定写超时  	TimeOuts.WriteTotalTimeoutConstant = 500; 	TimeOuts.WriteTotalTimeoutMultiplier = 100; 	if (SetCommTimeouts(hCom, &TimeOuts) == false) 	{ 		CloseHandle(hCom); 		ComIsOK = false; 		return; 	} 	//串口属性配置  	DCB dcb; 	GetCommState(hCom, &dcb); 	dcb.BaudRate = nBaud; //dcb.BaudRate=9600; //波特率为9600  	dcb.ByteSize = nData; //dcb.ByteSize=8; //每个字节为8位  	dcb.StopBits = nStop; //dcb.StopBits=ONESTOPBIT;   //1位停止位  	dcb.Parity = nCal; //dcb.Parity=NOPARITY; //无奇偶检验位  第 18 页 共 39 页    	SetCommState(hCom, &dcb); 	PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR); 	if (SetCommState(hCom, &dcb) == false) 	{ 		CloseHandle(hCom); 		ComIsOK = false; 		return; 	} 	return; } //==========串口打开函数结束=====================    //==========串口关闭控制函数=====================  void CloseComm() { 	CloseHandle(hCom); 	hCom = NULL; 	ComIsOK = false; } //==========串口关闭控制函数结束==================   //==========串口监听线程函数======================  UINT ThreadFunc(LPVOID pParam) { 	// CCommassistDlg* pdlg = (CCommassistDlg*)pParam;  //定义指针指向主对话框  	COMSTAT ComStat; 	DWORD dwErrorFlags; 	while (ComIsOK) 	{ 		DWORD dwBytesRead = 100; 		ClearCommError(hCom, &dwErrorFlags, &ComStat); 		dwBytesRead = min(dwBytesRead, (DWORD)ComStat.cbInQue); 		if (!dwBytesRead) 		{ 			Sleep(10);//continue;//使用continue时打开串口后CPU占用率非常高  		} 		else ::SendMessage(::AfxGetMainWnd()->m_hWnd, WM_READCOMM, 1, 0); //发 送消息, 已读到 	} 	return 0; } //==========串口监听线程函数结束===============  //=================字符串转16进制显示==========  //字符串转16进制显示的函数  //传入参数Data为字符串  //Blank_allow为空格允许标志,为真则代表允许加入空格  //函数返回为CString的结果sResult  CString DisplayCString2Hex(CString Data, bool Blank_allow) { 	CString sResult; 	CString sTemp; 	int Data_Length; 	Data_Length = Data.GetLength(); 	if (Data_Length == 0) return ""; 	char *pchar = new char[Data_Length];  //用了new分配内存空间,要记得释放  	strncpy(pchar, Data, Data_Length); 	for (int i = 0; i<Data_Length; i++) 	{ 		sTemp.Format("%02X", pchar[i]); 		if (Blank_allow) 		{ 			if (i == Data_Length - 1) sResult = sResult + sTemp; //去掉最后一个空格  			else 				sResult = sResult + sTemp + " "; 		} 		else sResult = sResult + sTemp; 	} 	delete pchar;   //释放内存空间  	return sResult; } //===============函数结束============================   //=================16进制转字符串======================  //16进制转字符串,输入16进制的字符串,输出转换为16进制码  //传入参数str为字符串,判断输入是否按照16进制格式输入  int ConvertHexC2String(CString str, CByteArray &senddata) { 	//先判断输入字符串是否2个字符一组  	int str_Length, iLength; 	int hexdata, l_data; 	char hstr, lstr; 	char cTemp; 	str_Length = str.GetLength(); 	iLength = 0; 	senddata.SetSize(str_Length / 2);  //预先设置数组长度,不设置时,允许有错  	char *ppchar = new char[str_Length]; 	strncpy(ppchar, str, str_Length); 	for (int i = 0; i<str_Length;) 	{ 		cTemp = ppchar[i]; 		if (cTemp == ' ') 		{ 			//iLength--;  			i++; 			continue; //如检测到空格则跳过继续下一次循环  		} 		else 		{ 			hstr = ppchar[i];  //取出字符作为16进制高位  			i++; 			lstr = ppchar[i];  //取出下一个字符作为16进制低位  			if (lstr == ' ')   //若取出的低位为空格则不符合16进制2个一组的格式终止循环 			{ 				AfxMessageBox("请按照16进制每2个字符一组的方式输入",MB_ICONERROR);  				break; 			} 			else 			{ 				hexdata = ConvertHexChar(hstr);  //高位转换为相应的0进制  				l_data = ConvertHexChar(lstr);  //低位转换为相应的10进制  				if ((hexdata == -1) || (l_data == -1)) 				{ 					AfxMessageBox("请按照16进制字符要求输入", MB_ICONERROR); 					break; 				} 				else hexdata = hexdata * 16 + l_data; //安装16进制方式高位低位合并   				senddata[iLength] = (char)hexdata; //int整型数转换为char字符型并存入数组senddata[] 				i++; //进入下一次循环  				iLength++; //成功转换一组(2个)字符记录长度加1  			} 		} 	} 	senddata.SetSize(iLength); 	delete ppchar; 	return iLength; }  //===============函数结束===========================   char ConvertHexChar(char ch) { 	//将一个字符转换为相应的十六进制  	if ((ch >= '0') && (ch <= '9')) 		return ch - 48;//0x30;  	else if ((ch >= 'A') && (ch <= 'F')) 		return ch - 'A' + 10; 	else if ((ch >= 'a') && (ch <= 'f')) 		return ch - 'a' + 10; 	else 		return (-1); }   //=================16进制转字符串显示=====================  //16进制转字符串显示的函数  //传入参数Data为16进制的字符串  //函数返回为CString的结果sResult  CString DisplayHex2CString(CString Data) { 	CString sResult; 	CString sTemp; 	int Data_Length; 	Data_Length = Data.GetLength(); 	if (Data_Length == 0) return ""; 	char *pchar = new char[Data_Length];  //用了new分配内存空间,要记得释放  	strncpy(pchar, Data, Data_Length); 	for (int i = 0; i<Data_Length; i++) 	{ 		sTemp.Format("%02X", pchar[i]); 		sResult = sResult + sTemp; 	} 	delete pchar;   //释放内存空间  	return sResult; } //===============函数结束=============================