VC++ .net 串口操作(简单的上位机串口操作)

C编译 同时被 2 个专栏收录
10 篇文章 0 订阅
38 篇文章 1 订阅

因为我一直使用的是嵌入式芯片,比较擅长C,一直想写点简单的windows程序,发现用C只能使用MFC或者c#,直到发现了VC++ .NET后,觉得这个最简单了,既有C的灵活,又有.net托管界面,因此非常方便,就不用学别的语言,虽然简单,但是C语言用来通信以及内存操作还是非常简单的了,我是用的是VS2010,对于工程建立以及界面就不多说了,比较简单,多折腾几次就会了.


自己写的底层串口相关的函数


#include "StdAfx.h"
#include "UART.h"
#include "WinReg.h"
#include "WINDOWS.h"
#include "tChar.h"
#include "stdio.h"

#pragma comment(lib, "advapi32.lib")


//关闭串口
//UartHandle;串口句柄
BOOL UART_TYPE::UART_Close(HANDLE UartHandle)
{
	return CloseHandle(UartHandle);
}


//初始化串口
//ComNum:串口编号,0-255,对应串口COM1-COM256,串口名称在缓冲区pUartNoBuff中
//返回:0:初始化失败;其他:串口句柄
//BuffSize:收发缓冲区大小
//pError:返回的错误
HANDLE UART_TYPE::UART_Init(BYTE ComNum, DWORD BaudRate, DWORD BuffSize, DWORD *pError)
{
	HANDLE hCom;							//串口句柄
	TCHAR WcharStr[16];
	char CharStr[16];
	WORD len = 0;

	*pError = 0;
	
	if(ComNum > (this->UartNum-1)) return 0;
	if(pUartNoBuff[ComNum]>=9)
	{
		sprintf_s(CharStr,15,"\\\\.\\COM%d",this->pUartNoBuff[ComNum]+1);//格式化字符串,生成COM1-COM256
	}
	else
	{
		sprintf_s(CharStr,15,"COM%d",this->pUartNoBuff[ComNum]+1);//格式化字符串,生成COM1-COM256
	}
	len = strlen(CharStr);		//计算输入字符串长度
	len = MultiByteToWideChar( CP_ACP, 0, CharStr,  len, WcharStr, len); //将char转换为WCHAR
	WcharStr[len] = 0;				//添加结束符
	hCom = CreateFile((LPTSTR)WcharStr, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);	//同步模式打开串口
	if(hCom == INVALID_HANDLE_VALUE)	//打开串口失败
	{
		//dwError = GetLastError();
		//::MessageBox(NULL,(LPCTSTR)_T("打开串口失败!"), (LPCTSTR)_T("提示"), MB_YESNO);
		*pError = GetLastError();
		return 0;
	}
	else	//打开串口成功
	{
		if((MYUART_Setting(hCom, BaudRate) == TRUE) && (MYUART_SetBuff(hCom, BuffSize, BuffSize) == TRUE))//设置串口成功
		{
			MYUART_ClearTxBuff(hCom);		//清除发送缓冲区
			MYUART_ClearRxBuff(hCom);		//清除接收缓冲区
			MYUART_SetTimeOut(hCom);		//设置串口超时时间						 
		}
		else		//设置串口失败
		{
			//this->dwError = GetLastError();
			*pError = GetLastError();
			//::MessageBox(NULL,(LPCTSTR)_T("设置串口失败!"), (LPCTSTR)_T("提示"), MB_YESNO);
			return 0;
		}
	}
	return hCom;
}



//设置串口
//8个数据位,1个起始位,1个停止位,无奇偶校验
//hCom:串口句柄
//BaudRate:串口波特率
//返回:FALSE:设置失败,TRUE:设置成功
BOOL UART_TYPE::MYUART_Setting(HANDLE hCom, int BaudRate)
{
	DCB dcb;

	dcb.BaudRate = BaudRate;	//设置波特率
	dcb.fBinary = TRUE;			//二进制数据模式
	dcb.fParity = FALSE;		//无奇偶校验,无错误报告
	dcb.fOutxCtsFlow = FALSE;	//关闭CTS流控
	dcb.fOutxDsrFlow = FALSE;	//关闭DSR流控
	dcb.fDtrControl = DTR_CONTROL_DISABLE;//禁用DTR流控
	dcb.fDsrSensitivity = FALSE;//DSR忽略
	dcb.fTXContinueOnXoff = FALSE;//接收缓冲区满后停止接收
	dcb.fOutX = FALSE;			//关闭字符流控制
	dcb.fInX = FALSE;			//关闭接收字符流控制
	dcb.fErrorChar = FALSE;		//关闭奇偶校验错误替换指定字节
	dcb.fNull = FALSE;			//保留空字节,也就是接收数据0
	dcb.fRtsControl = RTS_CONTROL_DISABLE;//关闭发送请求流控
	dcb.fAbortOnError = FALSE;	//忽略错误
	dcb.wReserved = 0;			//保留,必须为0
	dcb.XonLim = FALSE;			//关闭流量控制
	dcb.XoffLim = FALSE;		//关闭流量控制
	dcb.ByteSize = 8;			//数据位数为8
	dcb.Parity = NOPARITY;		//无奇偶校验
	dcb.StopBits = ONESTOPBIT;	//一个停止位
	dcb.XonChar = 0;			//传输开始字符,无效
	dcb.XoffChar = 0;			//传输结束字符,无效
	dcb.ErrorChar = 0;			//替代奇偶校验错误字节,无效
	dcb.EofChar = 0;			//数据结束信号,无效
	dcb.EvtChar = 0;			//使用的字符值的信号事件

	return SetCommState(hCom, &dcb);//配置,并返回状态
}


//获取串口接收计数器
//hCom:串口句柄
//返回:接收缓冲区接收的数据数量
DWORD UART_TYPE::MYUART_GetRxCnt(HANDLE hCom)
{
	DWORD ComError;
	COMSTAT ComStat;

	ClearCommError(hCom, &ComError, &ComStat);
	return ComStat.cbInQue;		//返回接收到的数据数量
}



//清除接收缓冲区
//hCom:串口句柄
//返回:TRUE:成功,FALSE;失败
BOOL UART_TYPE::MYUART_ClearRxBuff(HANDLE hCom)
{
	return PurgeComm(hCom, PURGE_RXABORT | PURGE_RXCLEAR);	//清除输入缓冲器
}


//清除发送缓冲区
//hCom:串口句柄
//返回:TRUE:成功,FALSE;失败
BOOL UART_TYPE::MYUART_ClearTxBuff(HANDLE hCom)
{
	return PurgeComm(hCom, PURGE_TXABORT | PURGE_TXCLEAR);	//清除输入缓冲器
}



//设置缓冲区大小
//hCom:串口句柄
//RxBuffSize:接收缓冲区大小;TxBuffSize:发送缓冲区大小
//返回:TRUE:成功,FALSE;失败
BOOL UART_TYPE::MYUART_SetBuff(HANDLE hCom, DWORD RxBuffSize, DWORD TxBuffSize)
{
	return SetupComm(hCom, RxBuffSize, TxBuffSize);		//设置输入输出缓冲区
}




//设置串口超时
BOOL UART_TYPE::MYUART_SetTimeOut(HANDLE hCom)
{
	COMMTIMEOUTS to;

	to.ReadIntervalTimeout = 10;	//字节超时
	to.ReadTotalTimeoutMultiplier = 100;
	to.ReadTotalTimeoutConstant=100;
	to.WriteTotalTimeoutMultiplier = 10;
	to.WriteTotalTimeoutConstant = 10;
	
	return SetCommTimeouts(hCom, &to);
}


//读取串口接收到的数据
DWORD UART_TYPE::MYUART_ReadData(HANDLE hCom, BYTE *pBuff, DWORD BuffSize)
{
	DWORD cnt;
	OVERLAPPED lpOverlapped;

	lpOverlapped.hEvent = 0;	//事件句柄设置为无效

	if(ReadFile(hCom, pBuff, BuffSize, &cnt, &lpOverlapped) == TRUE)
		return cnt;
	else
		return 0;
}



//串口发送数据
BOOL UART_TYPE::MYUART_SendData(HANDLE hCom, BYTE *pBuff, DWORD DataLen)
{
	DWORD cnt;
	OVERLAPPED lpOverlapped;

	lpOverlapped.hEvent = 0;	//事件句柄设置为无效

	MYUART_ClearTxBuff(hCom);
	return WriteFile(hCom, pBuff, DataLen, &cnt, &lpOverlapped);
}


//复制长字符串2到1
static void TcharCopy(TCHAR *Str1, TCHAR *Str2)
{
	while(*Str2 != 0x0000)
	{
		*Str1++ = *Str2++;
	}
	*Str1 = 0;	//添加结束符
}


//冒泡排序,用来排列串口,将串口编号从小到大排列
static void Bubble(BYTE *pBuff, WORD n)
{
	WORD i, j;
	BYTE temp;
			    
	for(i = 0;i < (n - 1);i ++)//排序
	{
		for(j = i + 1;j < n;j ++)
		{
			if(pBuff[i] > pBuff[j])//升序排列
			{
				temp = pBuff[i];
				pBuff[i] = pBuff[j];
				pBuff[j] = temp;
			}
		}
	}	  
} 

//获取系统中存在的串口,通过读取注册表获得
//pComNumBuff:获取的串口编号存储缓冲区,0-255对应COM1-COM256
//ComCnt:最大需要获取的串口数量
//返回系统串口数量
void UART_TYPE::MYUART_GetComNum(void)
{
	HKEY hKey;
	DWORD result;
	WORD i=0;
	WCHAR WcharStr[16];
	char CharStr[16];
	WORD temp;
	WORD len;



	result = RegOpenKeyEx( HKEY_LOCAL_MACHINE,_T( "Hardware\\DeviceMap\\SerialComm" ),NULL,KEY_READ,&hKey );
	if(ERROR_SUCCESS == result)	//打开串口注册表
	{
		TCHAR portName[ 0x100 ];
		DWORD dwLong, dwSize;

		this->UartNum = 0;
		for(i = 0;i < 256;i ++)
		{
			dwSize = sizeof( portName ) / sizeof( TCHAR );
			dwLong = dwSize;
			result = RegEnumValue( hKey, i, portName, &dwLong, NULL, NULL, ( LPBYTE )WcharStr, &dwSize );//枚举串口
			if( ERROR_NO_MORE_ITEMS == result )
			{
				break;   //串口名字"COM2"
			}
			WideCharToMultiByte( CP_ACP, 0, WcharStr, -1, CharStr, wcslen(WcharStr), NULL, NULL );  
			CharStr[wcslen(WcharStr)] = '\0';
			temp = (WORD)atof(&CharStr[3]);	//获取串口编号,跳过COM,获得串口编号为0-256;
			if(temp > 256) break;
			if(temp == 0) break;
			this->pUartNoBuff[i] = temp-1;	//获取串口编号-1,从1-256变为0-255;
		}
		RegCloseKey( hKey ); //关闭注册表
	}
	else return;

	this->UartNum = i;							//串口数量
	Bubble(this->pUartNoBuff, this->UartNum);	//对串口号进行冒泡排序
	
	for(i = 0;i < this->UartNum;i ++)									//循环更新串口
	{
		sprintf_s(CharStr,15,"COM%d",this->pUartNoBuff[i]+1);//格式化字符串,生成COM1-COM256
		len = strlen(CharStr);
		len = MultiByteToWideChar( CP_ACP, 0, CharStr,  len, this->pUartName[i], len); //将char转换为WCHAR
		this->pUartName[i][len] = 0;								//添加结束符
	}
}


头文件

#ifndef _MY_PRO_
#define _MY_PRO_
#include "windows.h"


class UART_TYPE
{
public:
	//变量
	WORD UartNum;			//串口数量,存储系统当前串口数量,由MYUART_GetComNum()获取
	BYTE *pUartNoBuff;		//串口编号缓冲区,存放当前系统串口的编号的,比如串口1-串口256 分别为0,1 .. 255,刚好一个字节
	WCHAR (*pUartName)[16];	//串口名称,如COM1-COM256
	//函数
	BOOL UART_TYPE::UART_Close(HANDLE UartHandle);											//关闭串口
	HANDLE UART_TYPE::UART_Init(BYTE ComNum, DWORD BaudRate, DWORD BuffSize, DWORD *pError);//初始化串口
	BOOL MYUART_ClearTxBuff(HANDLE hCom);													//清除发送缓冲区
	BOOL MYUART_ClearRxBuff(HANDLE hCom);													//清除接收缓冲区
	BOOL MYUART_Setting(HANDLE hCom, int BaudRate);											//配置串口
	BOOL MYUART_SetBuff(HANDLE hCom, DWORD RxBuffSize, DWORD TxBuffSize);					//设置缓冲区大小
	BOOL MYUART_SetTimeOut(HANDLE hCom);													//设置串口超时
	DWORD MYUART_ReadData(HANDLE hCom, BYTE *pBuff, DWORD BuffSize);						//读取串口接收到的数据
	BOOL MYUART_SendData(HANDLE hCom, BYTE *pBuff, DWORD DataLen);							//串口发送数据
	DWORD MYUART_GetRxCnt(HANDLE hCom);														//获取串口接收计数器
	void MYUART_GetComNum(void);
	//构造
	UART_TYPE()
	{
		this->pUartNoBuff = new BYTE[256];		//申请内存
		this->pUartName = new WCHAR[256][16];	//申请内存
		//获取系统串口初始
		MYUART_GetComNum();
	}
	//析构
	~UART_TYPE()
	{
		delete pUartNoBuff;				//释放内存
		delete [16]pUartName;			//释放内存
	}
};

//extern UART_TYPE UARTx;	//全局串口类实例化



#endif


//获取系统的串口,并显示

HANDLE hCom;							//串口句柄
UART_TYPE *UARTx;						//全局串口类实例化
UARTx = new UART_TYPE;				//调用串口类
//动态获取串口号并显示
			UARTx->MYUART_GetComNum();								//更新串口列表
			this->_UART_ComboBox->Items->Clear();					//删除所有选项
			for(i = 0;i < UARTx->UartNum;i ++)						//循环更新串口
			{
				this->_UART_ComboBox->Items->Add(gcnew String(UARTx->pUartName[i]));
			}
			if(this->_UART_ComboBox->Items->Count != 0)			//如果串口数量不为0,则选中第一个
			{
				this->_UART_ComboBox->SelectedIndex = 0;		//默认选择第一个串口
			}

如图:



//初始化串口

//初始化串口
				 this->hCom = UARTx->UART_Init(this->_UART_ComboBox->SelectedIndex, CBR_115200, UART_BUFF_SIZE, &ComError);
				 if(this->hCom != 0)	//初始化串口成功
				 {
					 this->_UART_ComboBox->Enabled = FALSE;		//锁定串口,不可操作
					 this->ComLinkStatus = TRUE;				//状态为连接
					 this->_UART_LinkButton->Text = L"断开连接";
					 //按钮有效
					 this->_UART_ReadConfButton->Enabled = TRUE;
					 this->_UART_ReadDataButton->Enabled = TRUE;
					 this->_UART_WriteConfButton->Enabled = TRUE;
				 }
				 else
				 {
					 pLpStr = new WCHAR[64];
					 pStr = new char[64];
					 sprintf_s(pStr,64-1, "打开串口失败(错误代码:%d)!", ComError);
					 MyChar.CharToWchar(pStr,pLpStr);	//char to WCHAR
					 ::MessageBox(NULL,(LPCTSTR)pLpStr, (LPCTSTR)_T("连接失败"), MB_OKCANCEL);
					 delete pLpStr;
					 delete pStr;
					 return;
				 }


后面直接调用串口收发即可,同单片机一样,先发送数据,等待收数据,通过获取串口接收数据数量来读取.

操作完毕后关闭即可.


  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值