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