Windows 中通过Windows API 进行串口通信主要有以下步骤:

  1. 打开串口
  2. 配置串口
  3. 读写串口
  4. 关闭串口

打开串口

关键API: CreateFile

Windows 中进行设备的操作,第一步都是需要通过CreateFile 函数进行打开设备。

HANDLE WINAPI CreateFile(
_In_ LPCTSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);

具体函数说明可以参考MSDN。

此处针对串口设备,稍微解释一下各个参数:

lpFileName:串口名,常见szPort.Format(_T("\\\\.\\COM%d"), nPort),nPort 是串口号;

dwDesiredAccess:设置访问权限,一般设置为GENERIC_READ | GENERIC_WRITE,即可读可写;

dwShareMode:串口不可共享,所以这个值必须是0;

lpSecurityAttributes:文件安全模式,必须设置为NULL

dwCreationDisposition:创建方式,串口必须是OPEN_EXISTING

dwFlagsAndAttributes:涉及到同步操作和异步操作的概念,具体可参考MSDN。一般如果同步的话就是设置为0;如果异步设置为FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED

hTemplateFile:文件句柄,对于串口通信必须设置为NULL

通过判断函数返回值是否是有效的handle,判断是否有成功打开串口设备。

配置串口

关键数据结构:DCB structure; COMMTIMEOUTS structure

关键API:BuildCommDCB; GetCommState; SetCommState; SetupComm; SetCommTimeouts

DCB structure:

DCB结构体中包含了许多信息,对于串口而已主要有波特率、数据位数、奇偶校验和停止位数等信息。在查询或配置串口的属性时,都需要使用到DCB 结构体。

在使用SetCommState对端口进行配置前,需要使用BuildCommDCB 先build 好DCB 结构体;或是使用GetCommState 拿到DCB 结构体,然后再相应修改对应数据。

一般在使用SetCommState 配置串口后,还需要使用SetupComm 设置串口的缓冲区大小。

COMMTIMEOUTS structure:

这个结构体和SetCommTimeouts 函数主要是用来设置读写超时的信息的,可以具体参考MSDN。

其中读写串口的超时有两种:间隔超时和总超时。

  • 间隔超时:是指在接收时两个字符之间的最大时延。
  • 总超时:是指读写操作总共花费的最大时间。写操作只支持总超时,而读操作两种超时均支持。

参考代码

BOOL OpenComDev(int nPort, LPCTSTR lpDef, int nControl)
{
CloseComDev(); //
DCB dcb;
CString szPort;
CString szDcb; szPort.Format(_T("\\\\.\\COM%d"), nPort);
if (lpDef == NULL)
{
szDcb.Format(_T("baud=1200 parity=N data=8 stop=1"));
}
else
{
szDcb = lpDef;
} m_hDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
if (m_hDev == INVALID_HANDLE_VALUE)
{
DWORD dwError = GetLastError();
return FALSE;
} COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = MAXDWORD; //0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 5000;
SetCommTimeouts( m_hDev, &CommTimeOuts ); FillMemory(&dcb, sizeof(dcb), 0);
dcb.DCBlength = sizeof(dcb);
if (!BuildCommDCB(szDcb, &dcb))
{
goto _Fail;
} // DCB is ready for use.
if (!SetCommState(m_hDev, &dcb ) ||
!SetupComm(m_hDev, 1024*16, 1024*16))
{
DWORD dwError = GetLastError();
goto _Fail;
} return TRUE; _Fail:
CloseComDev();
return FALSE;
}

读写串口

关键数据结构:OVERLAPPED structure(当采用异步读写时需要)

关键API:ReadFile, WriteFile

在读写串口时,要注意是同步操作还是异步操作,这个是由上文"打开串口"中的CreateFile 参数决定的。

同步读写操作简单,当调用ReadFile 和 WriteFile 时会阻塞,直到处理结束这两个函数才会完成;

异步操作时,调用ReadFile 和 WriteFile 时会立刻返回,费事的IO操作将在后台执行,此时需要自己去设置Event 等去进行同步等待。

下面主要是异步操作的code,其中异步操作需要使用到OVERLAPPED structure,且event 是定义的全局变量。

BOOL UART_ReadData(HANDLE hIDComDev, LPVOID lpBuffer, int num)
{
if (hIDComDev == NULL) return FALSE; OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.hEvent = g_hReadEvent;
ResetEvent(overlapped.hEvent); BOOL bReadStatus;
DWORD dwBytesRead, dwErrorFlags;
COMSTAT ComStat; ClearCommError(hIDComDev, &dwErrorFlags, &ComStat);
if (!ComStat.cbInQue) return FALSE; dwBytesRead = (DWORD)ComStat.cbInQue;
if (num < (int) dwBytesRead) dwBytesRead = (DWORD)num; bReadStatus = ReadFile(hIDComDev, lpBuffer, dwBytesRead, &dwBytesRead, &overlapped);
if (!bReadStatus)
{
if (GetLastError() == ERROR_IO_PENDING)
{
WaitForSingleObject(overlapped.hEvent, 2000);
return (int)dwBytesRead;
}
return FALSE;
} return dwBytesRead;
} BOOL UART_WriteData(HANDLE hIDComDev, LPCVOID lpBuffer, int num )
{
if (hIDComDev == NULL) return FALSE ; BOOL bWriteStat;
DWORD dwBytesWritten; OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.hEvent = g_hWriteEvent;
ResetEvent(overlapped.hEvent); bWriteStat = WriteFile(hIDComDev, (LPVOID) lpBuffer, num, &dwBytesWritten, &overlapped);
if (!bWriteStat && (GetLastError() == ERROR_IO_PENDING))
{
if (WaitForSingleObject(overlapped.hEvent, 2000))
{
dwBytesWritten = 0;
}
else
{
GetOverlappedResult(hIDComDev, &overlapped, &dwBytesWritten, FALSE);
overlapped.Offset += dwBytesWritten;
}
} return dwBytesWritten;
}

 

关闭串口

关键API:CloseHandle

关闭串口很简单,只是将上文中"打开串口" 中获得的Handle 正确close 即可。

[Windows] Windows API 串口通信的更多相关文章

  1. VM中linux和windows主机进行串口通信

    最近在做关于AIS的内容.为了对AIS电文进行解码,串口收发. 数据有PC机模拟发送,为了调试方便,不用次次将程序放到开发板上运行,所以利用pc主机和虚拟机进行串口通信模拟该过程. 首先需要用到一个软 ...

  2. mfc 调用Windows的API函数实现同步异步串口通信(源码)

    在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信方便易行,应用广泛. 一般情况下,工控机和各智能仪表通过RS485总线进行通信.RS485的通信方式是半 ...

  3. Windows API串口编程详解

    (一)Windows API串口通信编程概述 Windows环境下的串口编程与DOS环境下的串口编程有很大不同.Windows环境下的编程的最大特征之一就是设备无关性,它通过设备驱动程序将Window ...

  4. Linux与Windows串口通信

    串口是常用的计算机与外部串行设备之间的数据传输通道,由于串行通信方便易行,所以应用广泛.现在国际上不断有串口新技术及新规格推出,结合社会各方面需要,串口通信发展的空间庞大.串口通讯技术因其自身的优势和 ...

  5. Qt串口通信专题教程

    查看以前的教程:Qt编写串口通信程序全程图文讲解 查看Wincom和Lincom介绍:Qt跨平台串口通信软件Wincom与Lincom 下载软件,文档和源码:资源下载 ——————————————20 ...

  6. c#中实现串口通信的几种方法

    c#中实现串口通信的几种方法 通常,在C#中实现串口通信,我们有四种方法: 第一:通过MSCOMM控件这是最简单的,最方便的方法.可功能上很难做到控制自如,同时这个控件并不是系统本身所带,所以还得注册 ...

  7. 【必杀】为应用程序池“XXX”提供服务的进程在与 Windows Process Activation Service 通信时出现严重错误。该进程 ID 为“XXXX”。数据字段包含错误号。

    之前写过一篇文章,https://www.cnblogs.com/qidian10/p/6028784.html 解释如何解决此类问题,但现在回过头来想一下,之前的文章还是太过浅显,无法完全有效的彻底 ...

  8. (Delphi) Windows 32 API程序设计目录

    这里所有程序均使用Delphi调用Windows 32 API方式实现,并不是使用VCL已经封装好的类实现的! (一)第一个窗口程序 01 创建第一个窗口.

  9. 为应用程序池“XX”提供服务的进程在与 Windows Process Activation Service 通信时出现严重错误

    场景 WCF应用程序部署在IIS7中,使用net.tcp协议对外给几百台客户端提供服务,应用程序池不断崩溃重启. 分析过程 在事件查看器中看到的错误信息类似于 为应用程序池“XX”提供服务的进程在与 ...

随机推荐

  1. 1月18日 LCA专项训练

    A. Lorenzo Von Matterhorn B.Minimum spanning tree for each edge C.Misha, Grisha and Underground D.Fo ...

  2. Python-查找并保存特定字符串后面的字符串

    -- -- 本算法用于查找并存储“特定字符串”后面的字符串. -- 举例: strli = "kaka is li is da is wei !" #用于查找的字符串 sep_li ...

  3. git commit 后 尚未push到远程,撤销commit

    执行commit后,还没执行push时,想要撤销这次的commit,该怎么办? 解决方案: 使用命令: git reset --soft HEAD^ 这样就成功撤销了commit,如果想要连着add也 ...

  4. 【leetcode困难】968. 监控二叉树

    968. 监控二叉树 瞎**分析评论区Rui大佬的答案,这题想直接递归return min还是有坑的,分计数和状态.有个状态转换的思想

  5. docker安装宝塔面板

    1.下载centos docker docker pull centos:7.2.1511 2.运行镜像设置端口 docker run -d -it -p 4001:8888 -p 4000:80 - ...

  6. Python笔记_第四篇_高阶编程_实例化方法、静态方法、类方法和属性方法概念的解析。

    1.先叙述静态方法: 我们知道Python调用类的方法的时候都要进行一个实例化的处理.在面向对象中,一把存在静态类,静态方法,动态类.动态方法等乱七八糟的这么一些叫法.其实这些东西看起来抽象,但是很好 ...

  7. Django框架(七):模型(三) 关联、模型类的属性

    1. 关联 1.1 模型类关系 关系型数据库的关系包括三种类型: ForeignKey:一对多,将字段定义在多的一端中. ManyToManyField:多对多,将字段定义在任意一端中. OneToO ...

  8. Python与mongo交互

    # 导入模块 import pymongo # 连接MongoDB数据库 conn = pymongo.MongoClient('localhost', 27017) # 建库 db = conn.g ...

  9. 01 语言基础+高级:1-9 网络编程_day11【网络编程】

    day11[网络编程] 主要内容 软件架构CS/BS 网络通信三要素 TCP通信 Socket套接字 ServerSocket 教学目标 能够辨别UDP和TCP协议特点 能够说出TCP协议下两个常用类 ...

  10. intellij idea安卓开发配置

    1.java sdk 2.java ndk 3.gradle https://gradle.org/install/#manually 配置properties 删除根目录下android{} htt ...