VS2015串口通信编程(MFC)笔记
2016-04-10 00:00
232 查看
前言:
一直很喜欢CSDN这个平台,这是第一次在这里写博客,内容若有不当之处还请多多指教,谢谢!
本笔记主要是记录一些开发过程中可能会遇到的一些注意事项,以加强记忆和提醒。
一、 开发目的:
开发一个简单的上位机界面程序,实现上位机与下位机串口通信,从而对下位机进行程序升级。
二、 开发环境:
win7系统; VS2015社区版(免费);USB转TTL模块*2(用于调试);
三、内容:
1.创建MFC项目工程,界面设计直接使用VS2015提供的控件,无非也就是一些按钮、编辑框、下拉框、文本、进度条。
这写可视化操作还是比较简单的。
2.语言细节:
(1). 移位运算: 使用 >> 时高位补1, 使用 << 时低位补0;
(2). int转CString: str.Format(_T("%d"), k); // int k; CString str;
(3) CString转int:k = _ttoi(str); //int k; CString str;
(4).取字符串中的某一部分:str.Mid(s, n); //str的第s个字符开始的n个字符(包括s在内)
(5).将unicode 转换为 char:
iLength = WideCharToMultiByte(CP_ACP,0, FilePath, -1,NULL,0,NULL,NULL);//先取得长度
WideCharToMultiByte(CP_ACP,0, FilePath, -1, FPchar, iLength,NULL,
NULL);//转换后存入FPchar数组中
3. 选用MSCOMM控件方式进行串口通信
(1). 只能打开不大于COM16的串口;该控件不能在其他线程中直接被调用,但可以将其操作封装到函数中被间接使用。
(2). 接收:MSCOMM控件中断事件,用于接收下位机消息。
(3). 发送:另外创建一个子线程用于控制发送流程。
m_pThread = AfxBeginThread(UpgradeThread, (LPVOID)(this), THREAD_PRIORITY_BELOW_NORMAL,
256 * 1024);//stack size = 256*1024
4. 选用API函数方式进行串口通信
(1). 使用API函数CreateFile打开串口时传入的串口号参数前面需加“\\\\.\\”,否则无法打开大于COM9的串口。(例如打开COM10: "\\\\.\\COM10");
主要有四个函数:
CreateFile //打开
CloseHandle //关闭
ReadFile //读取
WriteFile //写入
主要三个变量:
HANDLE m_HdlSerial = INVALID_HANDLE_VALUE; //串口句柄
OVERLAPPED m_osRead; //用于读取控制
OVERLAPPED m_osWrite; //用于发送控制
(2). 打开串口(异步重叠方式)
//异步重叠,8个数据位,无校验,1个停止位
HANDLE KSerialOpen(LPCTSTR COMx, DWORD baudrate)
{
HANDLE hCom;
BOOL state;
DCB SerialDCB;
//打开
hCom = CreateFile(
COMx,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL
);
if (hCom == INVALID_HANDLE_VALUE) {//打开失败
return INVALID_HANDLE_VALUE;
}
state = GetCommState(hCom, &SerialDCB);
SerialDCB.BaudRate = baudrate;
/* Baudrate at which running, CBR_115200 */
SerialDCB.ByteSize =
8; /* Number of bits/byte, 4-8 */
SerialDCB.Parity = NOPARITY;
/* 0-4=None,Odd,Even,Mark,Space */
SerialDCB.StopBits = ONESTOPBIT;
/* 0,1,2 = 1, 1.5, 2 */
state = SetCommState(hCom, &SerialDCB);
if (!state) {
CloseHandle(hCom);
return INVALID_HANDLE_VALUE;
}
//设置缓冲区大小
state = SetupComm(hCom, SERIAL_RECV_BUFFER, SERIAL_SEND_BUFFER);//扱˙, ‰»Îª∫≥Â¥Û–°£¨ ‰≥ˆª∫≥Â¥Û–°
if (!state) {
CloseHandle(hCom);
return INVALID_HANDLE_VALUE;
}
PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);
return hCom;
}
(3). 接收:创建一个线程用于接收下位机消息。
//接收线程
UINT ComRxThread(LPVOID pParam)
{
CmyFileMissionDlg *pMainDlg = (CmyFileMissionDlg *)pParam;
DWORD dwBytes;
int iReadBytes, res;
DWORD dwError =
0;
DWORD dwEvtMask =
0;
unsigned
char RxBuffer[1024];
//设置接收时间掩码
if (SetCommMask(m_HdlSerial, EV_RXCHAR) ==
0) {
AfxMessageBox(_T("…Ë÷√ ¬º˛—⁄¬Î ß∞‹!"));
return
1;
}
while (TRUE)
{
if (m_HdlSerial == INVALID_HANDLE_VALUE) {
return
0;
}
if (WaitCommEvent(m_HdlSerial, &dwEvtMask, &m_osRead)) {
if (dwEvtMask & EV_RXCHAR) { //接收事件
//TODO
res = WaitForSingleObject(m_osRead.hEvent, INFINITE);//一直等到异步处理完成
if (WAIT_OBJECT_0 == res) {
//TODO:进行读取及其他应用操作 (ReadFile)
}
PurgeComm(m_HdlSerial, PURGE_RXABORT | PURGE_RXCLEAR);
}
}
}
return
0;
}
(4). 发送:创建一个线程用于控制发送流程。
//发送函数
int KSerialWrite(HANDLE hCom, LPOVERLAPPED lpOverlTx,
unsigned
char *Buffer,
int cnt)
{
BOOL bStatus;
DWORD dwErrorFlags;
DWORD dwBytes =
0;
COMSTAT ComStat;
ClearCommError(hCom, &dwErrorFlags, &ComStat);
bStatus = WriteFile(hCom, Buffer, cnt, &dwBytes, lpOverlTx);
if (!bStatus) {
if (GetLastError() == ERROR_IO_PENDING) {//
GetOverlappedResult(hCom, lpOverlTx, &dwBytes,
TRUE);
}
else {
dwBytes =
0;
}
}
return dwBytes;
}
5. 关于实现文件选择
//选择文件,并将文件名显示在编辑框中
void CmyFileMissionDlg::OnBnClickedButton2()
{
CString fileName = _T("");//
CString filter = _T("Œƒº˛ (*.bin; *.hex; *.txt)|*.bin;*.hex;*.txt||");//默认文件类型
CString defaultDir;
TCHAR exeDirectory[MAX_PATH];
GetCurrentDirectory(MAX_PATH, exeDirectory);//获取当前路径作为默认路径
defaultDir.Format(_T("%s"),exeDirectory);
/* 打开方式打开 */
CFileDialog openFileDlg(TRUE, defaultDir, fileName, OFN_HIDEREADONLY|OFN_READONLY, filter,NULL);
openFileDlg.GetOFN().lpstrInitialDir = defaultDir;
INT_PTR result = openFileDlg.DoModal();//选择文件
if(result == IDOK) {//选择确定后,将文件名显示到 m_edit1 编辑框中
m_edit1.SetWindowTextW(openFileDlg.GetPathName());
}
}
6.后话:
由于本人主要是作嵌入式程序开发,对于上位机程序一般是作为辅助工具,主要用于开发一些简单调试工具。
对于VC++编程还只是接触皮毛,所以本文难免会有见解有误的地方,但是本着相互交流学习的态度还是毅然拙笔狂飞。
结尾之处,应该有:谢谢!
一直很喜欢CSDN这个平台,这是第一次在这里写博客,内容若有不当之处还请多多指教,谢谢!
本笔记主要是记录一些开发过程中可能会遇到的一些注意事项,以加强记忆和提醒。
一、 开发目的:
开发一个简单的上位机界面程序,实现上位机与下位机串口通信,从而对下位机进行程序升级。
二、 开发环境:
win7系统; VS2015社区版(免费);USB转TTL模块*2(用于调试);
三、内容:
1.创建MFC项目工程,界面设计直接使用VS2015提供的控件,无非也就是一些按钮、编辑框、下拉框、文本、进度条。
这写可视化操作还是比较简单的。
2.语言细节:
(1). 移位运算: 使用 >> 时高位补1, 使用 << 时低位补0;
(2). int转CString: str.Format(_T("%d"), k); // int k; CString str;
(3) CString转int:k = _ttoi(str); //int k; CString str;
(4).取字符串中的某一部分:str.Mid(s, n); //str的第s个字符开始的n个字符(包括s在内)
(5).将unicode 转换为 char:
iLength = WideCharToMultiByte(CP_ACP,0, FilePath, -1,NULL,0,NULL,NULL);//先取得长度
WideCharToMultiByte(CP_ACP,0, FilePath, -1, FPchar, iLength,NULL,
NULL);//转换后存入FPchar数组中
3. 选用MSCOMM控件方式进行串口通信
(1). 只能打开不大于COM16的串口;该控件不能在其他线程中直接被调用,但可以将其操作封装到函数中被间接使用。
(2). 接收:MSCOMM控件中断事件,用于接收下位机消息。
(3). 发送:另外创建一个子线程用于控制发送流程。
m_pThread = AfxBeginThread(UpgradeThread, (LPVOID)(this), THREAD_PRIORITY_BELOW_NORMAL,
256 * 1024);//stack size = 256*1024
4. 选用API函数方式进行串口通信
(1). 使用API函数CreateFile打开串口时传入的串口号参数前面需加“\\\\.\\”,否则无法打开大于COM9的串口。(例如打开COM10: "\\\\.\\COM10");
主要有四个函数:
CreateFile //打开
CloseHandle //关闭
ReadFile //读取
WriteFile //写入
主要三个变量:
HANDLE m_HdlSerial = INVALID_HANDLE_VALUE; //串口句柄
OVERLAPPED m_osRead; //用于读取控制
OVERLAPPED m_osWrite; //用于发送控制
(2). 打开串口(异步重叠方式)
//异步重叠,8个数据位,无校验,1个停止位
HANDLE KSerialOpen(LPCTSTR COMx, DWORD baudrate)
{
HANDLE hCom;
BOOL state;
DCB SerialDCB;
//打开
hCom = CreateFile(
COMx,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL
);
if (hCom == INVALID_HANDLE_VALUE) {//打开失败
return INVALID_HANDLE_VALUE;
}
state = GetCommState(hCom, &SerialDCB);
SerialDCB.BaudRate = baudrate;
/* Baudrate at which running, CBR_115200 */
SerialDCB.ByteSize =
8; /* Number of bits/byte, 4-8 */
SerialDCB.Parity = NOPARITY;
/* 0-4=None,Odd,Even,Mark,Space */
SerialDCB.StopBits = ONESTOPBIT;
/* 0,1,2 = 1, 1.5, 2 */
state = SetCommState(hCom, &SerialDCB);
if (!state) {
CloseHandle(hCom);
return INVALID_HANDLE_VALUE;
}
//设置缓冲区大小
state = SetupComm(hCom, SERIAL_RECV_BUFFER, SERIAL_SEND_BUFFER);//扱˙, ‰»Îª∫≥Â¥Û–°£¨ ‰≥ˆª∫≥Â¥Û–°
if (!state) {
CloseHandle(hCom);
return INVALID_HANDLE_VALUE;
}
PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);
return hCom;
}
(3). 接收:创建一个线程用于接收下位机消息。
//接收线程
UINT ComRxThread(LPVOID pParam)
{
CmyFileMissionDlg *pMainDlg = (CmyFileMissionDlg *)pParam;
DWORD dwBytes;
int iReadBytes, res;
DWORD dwError =
0;
DWORD dwEvtMask =
0;
unsigned
char RxBuffer[1024];
//设置接收时间掩码
if (SetCommMask(m_HdlSerial, EV_RXCHAR) ==
0) {
AfxMessageBox(_T("…Ë÷√ ¬º˛—⁄¬Î ß∞‹!"));
return
1;
}
while (TRUE)
{
if (m_HdlSerial == INVALID_HANDLE_VALUE) {
return
0;
}
if (WaitCommEvent(m_HdlSerial, &dwEvtMask, &m_osRead)) {
if (dwEvtMask & EV_RXCHAR) { //接收事件
//TODO
res = WaitForSingleObject(m_osRead.hEvent, INFINITE);//一直等到异步处理完成
if (WAIT_OBJECT_0 == res) {
//TODO:进行读取及其他应用操作 (ReadFile)
}
PurgeComm(m_HdlSerial, PURGE_RXABORT | PURGE_RXCLEAR);
}
}
}
return
0;
}
(4). 发送:创建一个线程用于控制发送流程。
//发送函数
int KSerialWrite(HANDLE hCom, LPOVERLAPPED lpOverlTx,
unsigned
char *Buffer,
int cnt)
{
BOOL bStatus;
DWORD dwErrorFlags;
DWORD dwBytes =
0;
COMSTAT ComStat;
ClearCommError(hCom, &dwErrorFlags, &ComStat);
bStatus = WriteFile(hCom, Buffer, cnt, &dwBytes, lpOverlTx);
if (!bStatus) {
if (GetLastError() == ERROR_IO_PENDING) {//
GetOverlappedResult(hCom, lpOverlTx, &dwBytes,
TRUE);
}
else {
dwBytes =
0;
}
}
return dwBytes;
}
5. 关于实现文件选择
//选择文件,并将文件名显示在编辑框中
void CmyFileMissionDlg::OnBnClickedButton2()
{
CString fileName = _T("");//
CString filter = _T("Œƒº˛ (*.bin; *.hex; *.txt)|*.bin;*.hex;*.txt||");//默认文件类型
CString defaultDir;
TCHAR exeDirectory[MAX_PATH];
GetCurrentDirectory(MAX_PATH, exeDirectory);//获取当前路径作为默认路径
defaultDir.Format(_T("%s"),exeDirectory);
/* 打开方式打开 */
CFileDialog openFileDlg(TRUE, defaultDir, fileName, OFN_HIDEREADONLY|OFN_READONLY, filter,NULL);
openFileDlg.GetOFN().lpstrInitialDir = defaultDir;
INT_PTR result = openFileDlg.DoModal();//选择文件
if(result == IDOK) {//选择确定后,将文件名显示到 m_edit1 编辑框中
m_edit1.SetWindowTextW(openFileDlg.GetPathName());
}
}
6.后话:
由于本人主要是作嵌入式程序开发,对于上位机程序一般是作为辅助工具,主要用于开发一些简单调试工具。
对于VC++编程还只是接触皮毛,所以本文难免会有见解有误的地方,但是本着相互交流学习的态度还是毅然拙笔狂飞。
结尾之处,应该有:谢谢!
相关文章推荐
- C#6.0中10大新特性的应用和总结
- Visual C++中MFC消息的分类
- MFC中Radio Button的用法详解
- MFC对话框中添加状态栏的方法
- MFC创建右键弹出菜单的方法
- MFC中动态创建控件以及事件响应实现方法
- C++ 关于MFC多线程编程的注意事项
- MFC程序对文件的处理方法
- MFC自定义消息的实现方法
- MFC实现在文件尾追加数据的方法
- MFC之ComboBox控件用法实例教程
- MFC绘制不规则窗体的方法
- 深入分析Visual C++进行串口通信编程的详解
- IE8引发 VS2005/2008 MFC向导出错的解决方案
- MFC实现全屏功能代码实例
- 使用VS2010创建MFC ActiveX工程项目
- C#串口通信程序实例详解
- C++中MFC Tab Control控件的使用详解
- MFC程序设计常用技巧汇总
- MFC扩展DLL中导出类和对话框的实现方法