因为我一直使用的是嵌入式芯片,比较擅长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;
}
后面直接调用串口收发即可,同单片机一样,先发送数据,等待收数据,通过获取串口接收数据数量来读取.
操作完毕后关闭即可.