Visual C++串口通信编程---多线程异步方式
Visual C++串口通信编程---多线程异步方式
1. 串口通信基础
提到串口让人想起并口,它们是计算机中两个比较重要的通信方式。
串口:也叫COM口,把字节的二进制位按位列队进行传输,每个字节占一个固定的时间长,速度慢,但是传输距离远,有9针和25针两种,是阳插座(插座中有针凸起),目前25针较少使用;Modem\鼠标\USB口\老式摄像头等都是用串口。
并口:把字节的二进制位用多条线同时传输,速度快串口8倍左右,传输距离有限,一般计算机内部数据传输用此方式,平常使用的有打印机,扫描仪等;为25针,阴插座(插座有25个针孔)。
串行端口是CPU与串行设备间的编码转换器,当CPU经过串行端口发数据时,字节数据列队成串行位,串行端口接收数据时,串行位转换成字节数据,所以必须安装相应的驱动程序。
串行通信有成本低的特点,而且可以在现有的电话网络上进行传输,家庭通过电话线上网即是这种方式,只要配置一个相应的通信接口,如Modem。
单工:只能从一头传输到另一头,如只能从A向B传或者B向A传,如看电视,只允许电视台向电视发数据,不允许电视向电视台发数据。在单工传输方式上一般采用两个通信,一个通道传输数据,一个通道传输控制信号。
半双工:允许互传信息,但是不能同时进行,如对讲机,A说话时B不能说话,B说话时A不能说话。
物理连接建立后,需要使用一种机制使对方正确解释发送的数据,发送方安位发出数据后,接收方如何识别这些数据,并如何正确组装成正确的字节,这就需要同步技术。数据同步技术一般解决如下问题:
异步传输:按字节为单位传输,异步传输方式也叫起止方式,在被传输的字节前后加起止位,起止位无信号时处于高电平,接收方检测到低电平信号表示开始接收,收到停止信号表示传输完成。
同步传输:以数据块为单位传输,在块的前后加一个特殊字节表示起止,传输效率高,线路利用率高,设备负担也大。
常用标准有RS-232C、RS-485、RS-422等,其中RS-232C被广泛用于计算机串口通信。RS-232C标准要求一般线路不要超过15米。
2. API函数实现串口通信
API函数串口编程,可采用简单的查询方式或定时方式,也可采用复杂的事件驱动方式,所谓事件驱动方式是当输入缓冲区中有数据时,将自动调用某个方法执行相应的操作。定时方式是在一定的时间间隔内判断缓冲区内有数据被写入,此方法效率不高,查询方式就更落后的一种方式。所以设计的好的串口通信程序一般用事件驱动,有实时、高效、灵活等特点。
一般编制串行通信程序分以下几个部分:
- 打开串行端口:打开通信资源,设置通信参数、设置通信事件、创建读、写事件、进入等待串口消息循环。
- 读取串行端口信息:当串口发生EV_RXCHAR(接收到字符并放入了输入缓冲区)消息后读取串口、数据传输错误处理、字符串处理如回车符、空格并相应转化成数据,如果模拟量还要进行数据检验等功能。
- 写串行端口信息:将要发送的信息写入串口,相应进行错误处理。
- 断开串行端口连接:关闭事件,清除通信事件,丢弃通信资源并关闭。
项SERIALCOMM下有一个值“COM11”,表明有一个可用串口,如果目录下包含字符Serial或VCom的项下没有任何值,表明没有串口或者驱动不正常。以下是获取串口逻辑名的代码:
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys=0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
TCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
// Get the class name and the value count.
achClass, // buffer for class name
&cchClassName, // size of class string
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++) {
cchValue = MAX_VALUE_NAME; achValue[0] = '\0';
if (ERROR_SUCCESS == RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL, NULL, NULL)) {
if (-1 != szName.Find(_T("Serial")) || -1 != szName.Find(_T("VCom")) ){
BYTE strDSName[10]; memset(strDSName, 0, 10);
DWORD nValueType = 0, nBuffLen = 10;
if (ERROR_SUCCESS == RegQueryValueEx(hKey, (LPCTSTR)achValue, NULL,
&nValueType, strDSName, &nBuffLen)){
if (-1 == m_nComArray[nIndex]) {
m_nComArray[nIndex] = atoi((char*)(strDSName + 3));
AfxMessageBox(_T("机PC机没有COM口....."));
串口是系统资源,也当作文件一样操作,所以也用CreateFile函数。如果调用成功返回串口句柄,如果失败返回INVALID_HANDLE_VALUE值。函数参数说明如下:
__in LPCTSTR lpFileName,//串口名(逻辑端口名),如:”COM1”,”COM2”
__in DWORD dwDesiredAccess,//访问模式,对串口有读/写权限
__in DWORD dwShareMode,//共享模式,有读/写/删除共享,对串口通信只能独占模式
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,//文件安全属性,对串口设置为NULL
__in DWORD dwCreationDisposition,//创建方式,串口通信设置为OPEN_EXISTING
__in DWORD dwFlagsAndAttributes,//文件属性标记,是否异步方式,在些设置
__in_opt HANDLE hTemplateFile);//文件句柄,如果不为NULL,新文件从该够本复制或扩展,如果函数执行成功,返回新的串口句柄.
- 第一个参数:逻辑串口号,用字符串“COMX”表示,“X”是串口序号。关于电脑中的逻辑串口号,在注册表HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP目录下,包含字符“Serial”或“VCom”项下面的值就是,可以有多个。
- 第二个参数:是对串口的访问权限,串口只有读/写(GENERIC_READ/GENERIC_WRITE)权限,可以同时设置成读/写权限,也可以单独只设置读或写权限。
- 第三个参数:是共享模式,有读/写/删除共享,对串口通信只能独占模式,即是0。
- 第四个参数:文件安全属性,对串口设置成NULL。
- 第五个参数:创建方式,有CREATE_ALWAYS/ CREATE_NEW/ OPEN_EXISTING等方式,但是对串口只能是OPEN_EXISTING,只能打开存在的串口,不像文件一样可创建之类。
- 第六个参数:文件属性与标志,详细信息查看MSDN,如果想把串口设置成异步方式,那么要设置成FILE_FLAG_OVERLAPPED。
- 第七个参数:文件句柄,新文件从该句柄复制或扩展,如果函数执行成功,返回新的句柄,对串口通信,设置成NULL。
HANDLE hCom = CreateFile("COM1", //打开串口1
GENERIC_READ|GENERIC_WRITE, //允许读和写操作
OPEN_EXISTING, //打开存在的串口,必须是OPEN_EXISTING,文件还可以CREATE_NEW,串口不能创建
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //异步方式打开
if (INVALID_HANDLE_VALUE == m_hCom) {
如果执行成功返回串口句柄,如果失败通过GetLastError获取错误码。
szCom.Format(_T("\\\\.\\COM%d"), nPort);
设置IO的缓冲区大小根据自己需求,太小容易丢失数据,所以根据自己的需求设置。
HANDLE hFile, //串口句柄,CreateFile的有效返回值
DWORD DCBlength; // sizeof(DCB)
DWORD BaudRate; // current baud rate 指定当前的波特率
DWORD fBinary: 1; // binary mode, no EOF check 指定是否允许二进制模式,WINDOWS 95中必须为TRUE
DWORD fParity: 1; // enable parity checking 指定奇偶校验是否允许
DWORD fOutxCtsFlow:1;// CTS output flow control 指定CTS是否用于检测发送控制.当为TRUE是CTS为OFF,发送将被挂起
DWORD fOutxDsrFlow:1;// DSR output flow control 指定DSR是否用于检测发送控制.当为TRUE是DSR为OFF,发送将被挂起
DWORD fDtrControl:2; // DTR flow control type DTR_CONTROL_DISABLE值将DTR置为OFF, DTR_CONTROL_ENABLE值将
//DTR置为ON, DTR_CONTROL_HANDSHAKE允许DTR"握手",
DWORD fDsrSensitivity:1; // DSR sensitivity 当该值为TRUE时DSR为OFF时接收的字节被忽略
DWORD fTXContinueOnXoff:1; // XOFF continues Tx 指定当接收缓冲区已满,并且驱动程序已经发送出XoffChar字符时发送
//是否停止.TRUE时,在接收缓冲区接收到缓冲区已满的字节XoffLim且驱动程序已经发送
//出XoffChar字符中止接收字节之后,发送继续进行。FALSE时,在接收缓冲区接收到代表缓冲
//区已空的字节XonChar且驱动程序已经发送出恢复发送的XonChar之后,发送继续进行。
DWORD fOutX: 1; // XON/XOFF out flow control TRUE时,接收到XoffChar之后便停止发送.接收到XonChar之后将重新开始
DWORD fInX: 1; // XON/XOFF in flow control TRUE时,接收缓冲区接收到代表缓冲区满的XoffLim之后,XoffChar发送出
//去.接收缓冲区接收到代表缓冲区空的XonLim之后,XonChar发送出去
DWORD fErrorChar: 1; // enable error replacement 该值为TRUE且fParity为TRUE时,用ErrorChar 成员指定的字符代替奇
DWORD fNull: 1; // enable null stripping TRUE时,接收时去掉空(0值)字节
DWORD fAbortOnError:1; // abort reads/writes on error TRUE时,有错误发生时中止读和写操作
DWORD fDummy2:17; // reserved 未使用
WORD wReserved; // not currently used 未使用,必须为0
WORD XonLim; // transmit XON threshold 指定在XON字符发送这前接收缓冲区中可允许的最小字节数
WORD XoffLim; // transmit XOFF threshold 指定在XOFF字符发送这前接收缓冲区中可允许的最小字节数
BYTE ByteSize; // number of bits/byte, 4-8 指定端口当前使用的数据位
BYTE Parity; // 0-4=no,odd,even,mark,space 指定端口当前使用的奇偶校验方法,可能为:
//EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY
BYTE StopBits; // 0,1,2 = 1, 1.5, 2 指定端口当前使用的停止位数,可能为:ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS
char XonChar; // Tx and Rx XON character 指定用于发送和接收字符XON的值
char XoffChar; // Tx and Rx XOFF character 指定用于发送和接收字符XOFF值
char ErrorChar; // error replacement character 本字符用来代替接收到的奇偶校验发生错误时的值
char EofChar; // end of input character 当没有使用二进制模式时,本字符可用来指示数据的结束
char EvtChar; // received event character 当接收到此字符时,会产生一个事件
WORD wReserved1; // reserved; do not use 未使用
dcb.Parity = ODDPARITY;//奇偶校验方式
dcb.StopBits = ONESTOPBIT;//停止位
设置你关心的事件,当此事件发生时,将得到事件通知,通过SetCommMask函数设置,SetCommMask函数两个参数,第一个为串口句柄,第二个为事件,可通过位或的方式指定多个事件,如下:
SetCommMask(m_hCom, EV_RXCHAR ) ;
EV_RXCHAR事件指当输入缓冲区内有数据时,通过WaitCommEvent函数可获得通知,其他事件同理,其他事件还有EV_BREAK/EV_CTS/EV_RING等,详情参看MSDN。
在接收/发送数据前缓冲区中可能有垃圾数据,或者中途想清空缓冲区数据,可以用以下调用以下函数:
__in DWORD dwFlags//清空方式PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR
PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
__in LPOVERLAPPED lpOverlapped);
第一个参数是串口句柄,第二个参数是Out型指针,接收事件标志的,第三个参数接收事件信息事件状态。以下为示例代码:
hEventArr[1] = *g_OutPutList.GetEvent();
DWORD nResutl = WaitForMultipleObjectsEx(2, hEventArr, FALSE, 200, TRUE/*INFINITE*/);
if (g_OutPutList.GetCount() > 1000)
WORD nLen = (WORD)m_nBuffLen + 2;
memcpy(pIn + 2, m_InPutBuff, m_nBuffLen);
PBYTE pOut = (PBYTE)g_OutPutList.RemoveHead();
int nLen = pOut[0] * 0x100 + pOut[1] - 2;
WriteCommBlock(pOut + 2, nLen);
WaitCommEvent( COMFile, &dwEvtMask, &ShareEvent);//等̨¨待äy串ä?口¨²事º?件t
if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR) {
3. 示例代码
关于本文的代码下载链接:http://download.csdn.net/detail/mingojiang/4425803
szCom.Format(_T("\\\\.\\COM%d"), nPort);
COMFile = CreateFile(szCom.GetBuffer(50), GENERIC_READ | GENERIC_WRITE,//可¨¦读¨¢、¡é可¨¦写¡ä
FILE_SHARE_READ | FILE_SHARE_WRITE,
if (INVALID_HANDLE_VALUE == COMFile){
SetupComm(COMFile,6000,6000) ;
SetCommMask(/*COMFileTemp*/COMFile, EV_RXCHAR ) ;
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF ;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;
CommTimeOuts.ReadTotalTimeoutConstant = 1000 ;
CommTimeOuts.WriteTotalTimeoutMultiplier = 2*CBR_9600/9600 ;
CommTimeOuts.WriteTotalTimeoutConstant = 0 ;
SetCommTimeouts(/*COMFileTemp*/COMFile, &CommTimeOuts ) ;
dcb.DCBlength = sizeof( DCB ) ;
GetCommState(COMFile, &dcb ) ;
dcb.fDtrControl = DTR_CONTROL_ENABLE ;
dcb.fRtsControl = RTS_CONTROL_ENABLE ;
fRetVal = SetCommState(/*COMFileTemp*/COMFile, &dcb ) ;
PurgeComm( /*COMFileTemp*/COMFile, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
EscapeCommFunction( /*COMFileTemp*/COMFile, SETDTR ) ;
hEventArr[1] = *g_OutPutList.GetEvent();
DWORD nResutl = WaitForMultipleObjectsEx(2, hEventArr, FALSE, 200, TRUE/*INFINITE*/);
if (g_OutPutList.GetCount() > 1000)
WORD nLen = (WORD)m_nBuffLen + 2;
memcpy(pIn + 2, m_InPutBuff, m_nBuffLen);
PBYTE pOut = (PBYTE)g_OutPutList.RemoveHead();
int nLen = pOut[0] * 0x100 + pOut[1] - 2;
WriteCommBlock(pOut + 2, nLen);
WaitCommEvent( COMFile, &dwEvtMask, &ShareEvent);
if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR) {
EscapeCommFunction( COMFile, CLRDTR ) ;
//丢弃通信资源的输出或输入缓冲区字符并终止在通信资源上挂起的读、写操操作
PurgeComm( COMFile, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
【转载】https://blog.csdn.net/MingoJiang/article/details/7713529
Visual C++串口通信编程---多线程异步方式相关推荐
- VC串口通信编程-2
VC串口通信编程 (2009-07-08 13:48:40) 转载▼ Win32串口编程(转:韩耀旭) 在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信 ...
- C#中串口通信编程 收藏
C#中串口通信编程 收藏 本文将介绍如何在.NET平台下使用C#创建串口通信程序,.NET 2.0提供了串口通信的功能,其命名 空间是System.IO.Ports.这个新的框架不但可以访问计算机上的 ...
- (转)GPS导航芯片中串口通信同步I/O方式的程序设计
GPS导航芯片中串口通信同步I/O方式的程序设计 时间:2011-01-25 11:38 作者: 来源: Windows CE 是一个开放的.可裁剪的.32位实时嵌入式窗口操作系统,具有可 ...
- MFC 串口通信编程
本篇文章主要介绍了"RS-232/RS-485/RS-422 接口简介与编程",主要涉及到RS-232/RS-485/RS-422 接口简介与编程方面的内容,对于RS-232/RS ...
- 【转载】MFC实现串口通信编程nbsp;-nbsp;yu…
MFC实现串口通信编程 vc++.c#专题 2009-10-08 22:32 在Windows应用程序的开发中,我们常常需要面临与外围数据源设备通信的问题.计算机和单片机(如MCS-51)都具 ...
- (串口通信编程) 开源串口调试助手Common (Com Monitor)
原文地址为: (串口通信编程) 开源串口调试助手Common (Com Monitor) 最新的文档见这里:http://blog.twofei.com/566/ 我写的串口调试助手程序以及源代码. ...
- 单片机与PC机串口通信编程
单片机与PC机串口通信编程 实验目的 利用PROTUES仿真软件.串口调试助手.虚拟串口,搭建单片机与PC通信仿真平台,熟悉单片机串口的配置及与PC机的通信方法. 实验目的 1.PROTUES仿真软件 ...
- C#上位机开发串口通信编程——倒计时器开发
C#上位机开发串口通信编程--倒计时器开发 一.介绍 这是我按照B站上的一个上位机开发视频教程开发的倒计时器开发,本来只有开始计时功能,没有停止计时功能,停止计时功能后面我自己添加了. 视频网址:C# ...
- STC系列芯片的串口通信编程
STC系列芯片的串口通信编程 本人使用的是基于STC15F2K60S2芯片的开发板. 开发板上有关串口通讯的有:TMOD(定时器寄存器).CSON(串口通信寄存器).PCON(开发板电源控制寄存器)以 ...
最新文章
- 计算机教师个人总结及自评,教师个人自评总结
- 存储过程如何处理异常
- pybind11回调函数返回指针
- winSockets编程(二)socket函数
- 文巾解题 196. 删除重复的电子邮箱
- python注释以符号什么开始_python注释以什么符号开始
- 即时通讯音视频开发(八):常见的实时语音通讯编码标准
- 【C语言进阶深度学习记录】二十一 # 和 ## 号操作符的使用与分析
- 2018 java蓝桥杯校赛题目
- workbench出现“Unable to start the geometry editor”
- 对数组下面的数组截取_numpy数组不同索引方式的区别
- linux mysql 每天备份_Linux下Mysql每天自动备份
- Webstorm 2021 开启内存显示设置
- 【读书笔记】终极算法
- 【PyTorch】SiLU激活函数
- mysql如何创建用户代码_mysql 创建用户 并 受权_mysql
- 流程表结构设计第二版
- 一回来又恢复了往日的无聊生活
- 《计算广告》第二部分在线广告产品逻辑——笔记(上)
- 数学建模之储药柜的设计
热门文章
- js与java对json的操作
- MySql实现sequence功能的代码
- 在线图片转base64工具
- 转 13种最为荒谬的编程语言(Bugku 加密)
- [MFC]Sqlite问题小记
- Python中的signal模块和Ctrl+C操作
- 在ASP.NET中如何运行后台任务
- 验证(Authentication)和授权(Authorization)(一):
- Delphi 2010 新增功能之: IOUtils 单元(1): 初识 TDirectory.GetFiles
- 跨浏览器javascript