C++ 串口API 异步操作
Win32API 异步串口通讯
使用Win32API实现Windows下异步串口通讯目录:1.异步非阻塞串口通讯的优点2.异步非阻塞串口通讯的基本原理3.异步非阻塞串口通讯的基础知识4.异步非阻塞串口通讯的实现步骤一,异步非阻塞串口通讯的优点读写串行口时,既可以同步执行,也可以重叠(异步)执行。
在同步执行时,函数直到操作完成后才返回。
这意味着在同步执行时线程会被阻塞,从而导致效率下降。
在重叠执行时,即使操作还未完成,调用的函数也会立即返回。
费时的I/O操作在后台进行,这样线程就可以干别的事情。
例如,线程可以在不同的句柄上同时执行I/O操作,甚至可以在同一句柄上同时进行读写操作。
"重叠"一词的含义就在于此。
二,异步非阻塞串口通讯的基本原理首先,确定要打开的串口名、波特率、奇偶校验方式、数据位、停止位,传递给CreateFile()函数打开特定串口;其次,为了保护系统对串口的初始设置,调用GetCommTimeouts()得到串口的原始超时设置;然后,初始化DCB对象,调用SetCommState() 设置DCB,调用SetCommTimeouts()设置串口超时控制;再次,调用SetupComm()设置串口接收发送数据的缓冲区大小,串口的设置就基本完成,之后就可以启动读写线程了。
三,异步非阻塞串口通讯的基础知识下面来介绍并举例说明一下编写异步非阻塞串口通讯的程序中将会使用到的几个关键函数CreateFile()功能:打开串口设备函数原型HANDLE CreateFile(LPCTSTR lpFileName, // 串口名称字符串;如:"COM1" 或"COM2"DWORD dwDesiredAccess, // 设置读写属性(访问模式);一般为GENERIC_READ|GENERIC_WRITE, DWORD dwShareMode, // 共享模式;"必须"为0, 即不能共享LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全属性;一般为NULLDWORD dwCreationDistribution, // 创建方式,串口设置必须设置此值;在这里"必须"为OPEN_EXISTING DWORD dwFlagsAndAttributes, // 文件属性和标志;在这里我们设置成FILE_FLAG_OVERLAPPED ,实现异步I/OHANDLE hTemplateFile // 临时文件的句柄,通常为NULL);说明:如果调用成功,那么该函数返回文件的句柄,如果调用失败,则函数返回INVALID_HANDLE_VALUE。
利用C#串口操作类实现异步数据接收
// C#异步数据接收串口操作类// dyj057@using System;using System.Runtime.InteropServices;////// (C)2003-2005 C2217 Studio 保留所有权利////// 文件名称: IbmsSerialPort.cs/// 文件ID:/// 文件说明:/// 封装动态链接库IbmsSerialPort.dll的功能,提供在.NET环境中/// 串口异步接收和发送数据的功能。
////// 当前版本: 1.0////// 作者: 邓杨均/// 创建日期: 2005-2-2/// 最后修改日期: 2005-2-2////// 历史修改记录://////namespace Ibms.Tool.IO{////// 当串口接收到数据时,会产生一个事件。
/// SPRecvDataArgs就是该事件的参数,参数中的RecvData包含接收到的数据。
/// 使用方法:///public class SPRecvDataArgs:EventArgs{////// 接收到的数据组成的字节数组///private byte[] recvData;////// 构造函数,需要一个包含数据的byte[]作为初始化参数来实例化SPRecvDataArgs ////// 接收到的数据public SPRecvDataArgs(byte[] recvData){if( recvData == null){throw(new ArgumentNullException());}this.recvData = recvData;}////// 返回接收到的数据内容///public byte[] RecvData{get{return recvData;}}}////// 封装动态链接库IbmsSerialPort.dll的功能,提供在.NET环境中异步/// 串口接收和发送功能。
异步串行通信
//第一个字符串参数实际使用时由图1选择后组合,这里仅简单说明其格式
SetCommState(hcom,&dcb);
SetupComm(hcom,512,512);//设置读写缓冲区
e.hEvent=CreateEvent(NULL,false,false,NULL); //设置事件
以上设置完成后,用户程序就可以等待通信事件的产生,一般调用函数WaitCommEvent()监视通信事件,其中参数lpEvtMask指向产生事件的掩码地址,用于判断事件产生的性质,lpOverlapped指向重叠结构地址,可简单定义为NULL。对于串口事件的响应一般有四种方式:查询、同步I/O、异步I/O和事件驱动I/O,需要根据用户不同控制要求而定。查询方式占用较长的计算机时间,同步I/O方式直到读取完指定的字节数或超时时才返回,容易造成线程阻塞,异步I/O用于后台处理,事件驱动是由系统通知用户程序发生的事件并进行串口操作。 比较而言事件驱动I/O方式较灵活。
·应用实例说明·
使用以上的API函数,笔者给出了简化后的串口初始化的实例。图1为使用C++ Builder 组件生成的串口通信基本参数设置的界面实例。
HANDLE hcom; //定义句柄
DCB dcb;
OVERLAPPED e; //定义重叠结构
void —fastcall TForm1::OkBtnClick(TObjectSender)
{ hcom=CreateFile("COM2",GENERIC—READ|GENERIC—WRITE,0,NULL,OPEN—EXISTING,
FILE—ATTRIBUTE—NORMAL|FILE—FLAG—OVERLAPPED,NULL); //打开通讯口
基于WINDOWS API的异步串口通信软件设计
基于WINDOWS API的异步串口通信软件设计摘要:串口是常用的计算机与外部串行设备之间的数据传输通道,在VC++6.0中利用第三方控件实现串口通信时实时性较差,系统资源利用不足,为了提高串口通信的速度和资源利用率,软件采用WINDOWS API 函数并基于多线程技术和自定义消息机制的异步串口通信的设计理念,结合串口通信的机理和多线程同步技术,分析了Win32系统下多线程异步串口通信软件的开发方法。
软件主线程是数据采集程序的管理者,串口监测线程(辅助线程)在后台对串口进行实时监视,获得了良好稳定的通信效果。
关键词:串口通信;异步(重叠)I/O;多线程;中图分类号:TP311 文献标识码: A 文章编号:0 引言串口通信是计算机与其他设备进行数据通信时经常使用的方法之一,他具有实现简单,使用灵活方便,数据传输可靠等优点,因而在工业控制、数据采集和实时监控系统中得到广泛应用[1]。
在通常的串口通信软件开发的时候,大多数人采用的是使用如MSComm等第三方控件控件进行程序的开发。
MSComm控件在串口编程时非常方便,程序员不必花时间去了解较为复杂的API函数,只需要在串口通信资源的属性(Properties)一项中配置串口,完成串口配置之后即可打开串口,进行数据读写。
但由于控件本身对于接收缓冲区大小设置的限定,如果接收缓冲区不能满足设计的要求,当缓冲区内数据达到消息响应值并响应存储命令,而新的数据传输速度大于已接收到数据的存储速度时,就会造成接收缓冲区的溢出,进而直接导致软件的崩溃[2]。
本文的串口通信软件的开发没有使用任何串口通信的第三方封装控件,全部使用windows API函数对串口进行操作和配置,而且使用了多线程技术和异步I/0操作,提高了串口通信的效率和程序的灵活性。
1软件结构本串口通信软件主要由三个主要模块构成,分别是:串口配置模块,数据采集模块和数据发送模块。
三个模块分别对应CinData,CoutData和CGetComSet三个类。
利用MSCOMM串口通信控件进行异步串行通信的VC程序设计
利用MSCOMM串口通信控件进行异步串行通信的VC程序设计一课程设计题目利用MSCOMM串口通信控件进行异步串行通信的VC程序设计二课程设计要求●环境要求:Windows95/98/2000/XP●功能要求:能将键盘上输入的数据发送到另一台计算机上;能将接收到的数据显示到屏幕窗口内;了解常用通信网络设备的操作和应用,掌握常用的通信协议的工作原理,能利用Visual C++、开发工具完成相应的通信程序的设计工作。
学习简明地介绍自己的设计工作。
三课程设计目的用Visual C++编程工具主机提供的接口,解决网络用户之间的交互式对话问题。
进一步深入掌握网络设计和通信程序的设计原理。
使学生对计算机通信网络的设计实现有较深的了解,培养较高的通信网络设计能力。
四程序思路硬件连接方面:数据的发送和接收由软件控制,不进行硬件握手,其连接方法如图真正需要互相连接的是RXD、TXD和GND;软件方面:串行端口的本质功能是作为CPU和串行设备间的编码转换器。
当数据从 CPU经过串行端口发送出去时,字节数据转换为串行的位。
在接收数据时,串行的位被转换为字节数据在Windows环境(Windows NT、Win98、Windows2000)下,串口是系统资源的一部分。
应用程序要使用串口进行通信,必须在使用之前向操作系统提出资源申请要求(打开串口),通信完成后必须释放资源(关闭串口)。
VC++ 6.0提供的MSComm控件通过串行端口发送和接收数据,为应用程序提供串行通信功能。
使用非常方便。
⑴.在当前的Workspace中插入MSComm控件。
Project菜单------>Add to Project---->Components and Controls----->RegisteredActiveX Controls--->选择Components: Microsoft Communications Control,version 6.0 插入到当前的Workspace中。
异步串口操作
SetCommTimeouts(hComm,&TimeOuts);
///////////////////////////////////////
//默认串口配置
GetCommState(hComm,&dcb);
bool CRS232::setSettings(char *settings)
{
bool result=false;
if(isOpen()&&settings!=NULL){
unsigned long baud=9600;//波特率
unsigned char data=8;//数据位大小
{
bool result=false;
number=0;
if(isOpen()&&str!=NULL)
{
OVERLAPPED ol;
ol.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
ol.Offset=0;
ol.OffsetHigh=0;
dcb.BaudRate=9600;
dcb.ByteSize=8;
dcb.Parity=EVENPARITY;
dcb.StopBits=ONESTOPBIT;
dcb.fOutX=TRUE;
dcb.fInX=TRUE;
SetCommState(hComm,&dcb);
bool CRS232::open(long comm)
{
bool result=false;
if(comm<0)
VC串口通讯,API函数
VC串口通讯,API函数介绍介绍工业控制领域利用串口和外围设备进行通讯。
正文前言:总所周之,利用串口进行数据通讯在在通讯通讯领域重占有着重要的地位。
利用RS232-RS485进行数据信号的采集和传递是VC编程的又一大热点。
串口通讯在通讯软件重有着十分广泛的应用。
如电话、传真、视频和各种控制等。
在各种开发工具中间,VC由于功能强大和灵活,同时也得到了Microsoft的最大支持,所以在一般进行涉及硬件操作的通讯编程中,大都推荐使用VC作为开发工具。
然而工业控制串口通讯这个又不同于一般的串口通讯程序,因为控制外围设备传送的大都是十六进制数据(BYTE类型),所以,为了提高程序的运行稳定性,我们在编写程序进行通讯时可以不考虑传送BYTE类型数据的工作。
串口通讯目前流行的方法大概有两种:一是利用Microsoft提供的CMSCOMM 控件进行通讯,不过现在很多程序员都觉应该放弃这种方式。
二是利用WINAPI 函数进行编程,这种编程的难度最高,要求你要掌握很多的API函数。
三是利用现在网络上面提供的一些串口通讯控件进行编写,比如CSerial类等。
程序实现:我在经过许多的项目的开发和实践中发现,采用WIN API函数进行串口的开发能够给程序员很大的空间,并且程序运也很稳定。
所以我将与串口接触的函数进行封装,然后在各个工程中进行调用,效果还是比较好的,现将各个函数和调用方法列举出来,希望对各位有所帮助。
一、设置串口相关工作#define MAXBLOCK 2048#define XON 0x11#define XOFF 0x13BOOL SetCom(HANDLE &m_hCom, const char *m_sPort, int BaudRate, int Databit, CString parity, CString stopbit){COMMTIMEOUTS TimeOuts; ///串口输出时间超时设置DCB dcb; ///与端口匹配的设备m_hCom=CreateFile(m_sPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); // 以重叠方式打开串口if(m_hCom==INVALID_HANDLE_VALUE){AfxMessageBox("设置串口部分,串口打开失败"); /////重叠方式异步通信(INVALID_HANDLE_VALUE)函数失败。
异步方式winAPI串口通信
使用winAPI串口通信(二)分类:Windows转载2009-09-23 16:51 263人阅读评论(0) 收藏举报采用同步方式的查询方式读取串口数据时,若由于串口操作耗费较长的时间,则程序会被挂起.为解决这种问题,可以在读取数据时采用重叠I/O操作.此时,读写数据的操作在单独的线程中进行,发出读写要求的主线程可以继续运行.当读写数据成功后,读写数据线程可以通过某种方式通知主线程.两个线程协调工作 ,可以明显提高程序的效率.为了实现重叠I/O操作,主要有如下几个编程步骤: 定义全局变量、创建串口、发出读写操作、读写线程函数的建立、关闭串口等.1. 定义全局变量HANDLE hCom; //串口句柄DWORD ThreadProcWrite(LPVOID pParam); //写线程函数DWORD ThreadProcRead(LPVOID pParam); //读线程函数OVERLAPPED Wol = { 0 }; //写操作OVERLAPPED结构变量OVERLAPPED Rol = { 0 }; //读操作OVERLAPPED结构变量HANDLE hThreadWrite; //写线程句柄HANDLE hThreadRead; //读线程句柄HWND hWnd; //窗口句柄2. 创建串口hCom = CreateFile ( "COM2",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,//使用重叠方式NULL );if( hCom != INVALID_HANDLE_VALUE){SetupComm(hCom,1024,512);DCB myDCB;GetCommState( hCom,&myDCB);myDCB.BaudRate=CBR_19200;myDCB.fBinary=TRUE;myDCB.fParity=TRUE;myDCB.ByteSize=8;myDCB.Parity=ODDPARITY;myDCB.StopBits=ONESTOPBIT;SetCommState(hCom,&myDCB);}else{AfxMessageBox("创建串口失败!");}hWnd = GetSafeHwnd(); //获取当前窗口的句柄3. 发出读写操作(1) 读操作在读操作中,只是启动读线程.实际的读操作在读线程函数中完成.DWORD dwThreadID;DWORD dwParam;hThreadRead = CreateThread ( NULL,0,(LPTHREAD_START_ROUTINE)ThreadProcRead,&dwParam,0, //创建线程后,立即执行该线程&dwThreadID);if(hThreadRead==NULL){AfxMessageBox("读线程创建失败!");}CreateThread()函数用于创建一个线程.HANDLE CreateThread (//线程安全属性,NULL表示该线程不能被继承LPSECURITY_ATTRIBUTES lpThreadAttributes,//初始化栈大小.0表示默认值或按调用栈线程配置DWORD dwStackSize,//执行函数名称LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter, //向新线程传递的参数DWORD dwCreationFlags, //创建标志.0表示创建后立即执行LPDWORD lpThreadId);(2) 写操作在写操作中,同样只是启动写线程.实际的写操作在写线程函数中完成.DWORD dwThreadID;DWORD dwParam;hThreadWrite = CreateThread( NULL,0,(LPTHREAD_START_ROUTINE)ThreadProcWrite,&dwParam,0,&dwThreadID);if(hThreadWrite==NULL){AfxMessageBox("写线程创建失败!");}4.读写线程函数的建立读写的实际操作在读写线程函数中执行. 这两个函数都是全局函数.(1) 读线程函数在读线程函数中,首先应初始化重叠结构Rol的成员hEvent,将其设置为无信号状态.当读操作完成或出现通信错误时,该变量会被自动设置为有信号状态.接下来就可以使用ReadFile()函数发出读命令.若该读函数返回TRUE,说明读操作已经完成,可以处理读取的数据.若该读函数返回FALSE,说明读操作未完成.此时使用WaitForSingleObject()函数等待读操作的结构。
PIC单片机软件异步串行口实现技巧
样时间间隔即为28 7 P.整个串行接收或发送是一 s
个过程控制间题, 用状态机方式实现最为高效简易。
图3 给出了申行接收的参考状态机转移过程。
本刊网络补充版( w . c. c) 介绍了 w w d . . 中, 刘 o n
时间的定时即可。按不同的接收技巧并针对PC单 I
片机的特点 这里介绍两种常用且十分可靠的方法
空 闲 状 态
位 始 起
影区, 虽然每次具体的采样点会在此 s 阴影区随机 o 变化。检测到起始位低电平后, 间隔4 : Xt时间, 正 好是第一位数据位的中间 13 图 2中D 阴影 / 处( s
区) 。此后的数据位、 校验位和停止位的采样间隔都
是 3 t 所有采样点均落在码元的中间1 X , 邝处, 采样 数据最可靠。
设申行数据位宽度为t 起始位到来时刻( - 图4 A点) 的下降沿触发一个中断并立即响应该中断 在
此中断服务中立即关闭本 中断使能位( 后续的数据流
万方数据
式来实现可靠的U R A T功能
在讨论具体实现方式前, 我们先来简单回顾一下 异步串行通信的格式定义。发送一个完整的字节信 息, 必须有“ 起始位”“ 、若干数据位”“ 、奇偶校验位” 和 “ 停止位,必须定义每位信息的时间宽度— 每秒发 ; ’ 送的信息位个数, 即为“ 波特率” 。单片机系统中常用 的波特率从 30 9 6s 0 -1 20 。当波特率为 106s 0 / 20/
2 起始位中断捕捉、 定时采样法
实现此法的硬件条件是 PC单片机有外部脉冲 I 下降沿中断触发功能, 在中档以上 PC单片机中有 I
R OI T外部中断脚,C 1C P 脉冲沿擂捉脚, B /N C P/C 2
以上的侧重点是基本原理的介绍, 希望对大家有 所帮助。 在接收数据的可靠性处理方面没有太多涉 及。有兴趣者可以在采样时刻到来时对数据做多次
linux c语言 串口读取数据的方法
linux c语言串口读取数据的方法Linux下使用C语言读取串口数据的方法引言:串口是计算机和外部设备进行通信的一种重要的通信接口。
在Linux系统中,要使用C语言读取串口数据,需要通过打开串口设备文件,设置串口参数,并进行读取数据的操作。
本文将介绍如何通过C语言在Linux下读取串口数据的方法。
目录:1. 了解串口的工作原理2. 打开串口设备文件3. 设置串口参数4. 读取串口数据5. 示例程序6. 总结1. 了解串口的工作原理:在开始编写C语言读取串口数据的方法前,首先需要了解串口的工作原理。
串口是通过硬件电路实现两台设备之间的数据传输,属于一种异步串行通信方式。
典型的串口包含发送数据引脚(TX)、接收数据引脚(RX)、数据位、停止位、奇偶校验位等。
2. 打开串口设备文件:在Linux系统中,每个串口设备都被映射到一个设备文件上,例如/dev/ttyS0代表第一个串口设备,/dev/ttyUSB0代表第一个USB串口设备。
要使用C语言读取串口数据,需要首先打开相应的串口设备文件。
在C语言中,使用open()函数打开串口设备文件。
open()函数的原型如下:cint open(const char *pathname, int flags);其中pathname参数指定要打开的串口设备文件路径,flags参数指定打开方式。
常用的flags参数有O_RDONLY(只读方式打开)、O_WRONLY (只写方式打开)和O_RDWR(读写方式打开)。
例如,要打开第一个串口设备文件,可以调用open()函数如下:cint fd = open("/dev/ttyS0", O_RDWR);if (fd == -1){perror("Error opening serial port");return -1;}当open()函数成功打开串口设备文件时,会返回一个非负整数的文件描述符fd,用于后续的操作。
串行异步通信程序设计
串行异步通信程序设计串行异步通信程序设计串行异步通信,也称为串口通信,是一种常见的计算机间通信方式,它通常用于连接计算机和外部设备,如打印机、调制解调器等。
在串行异步通信中,数据按比特流的形式传输,而不是按字节或块传输,这使得通信速度更快,但也增加了数据传输中的错误检测和校正难度。
在本文中,我们将介绍如何设计一个串行异步通信程序。
一、串口基础知识在介绍串口通信程序设计之前,我们先来了解一些串口的基础知识。
串口是一种异步串行通信接口,通常包括一个发送引脚(TX)、一个接收引脚(RX)、一个数据位(D)、一个校验位(P)和一个停止位(S)。
串口的工作原理如下:1. 将数据按照字节分割成比特,加上校验位和停止位,形成数据帧;2. 将数据帧通过串口发送引脚发送出去;3. 接收端通过串口接收引脚接收到数据,然后进行错误检测和校正。
在串口通信中,数据帧的大小和格式必须在发送和接收端保持一致。
例如,在两台计算机之间使用串口进行通信时,它们必须使用相同的数据位、校验位和停止位参数设置。
二、串口通信程序设计在设计串口通信程序时,需要考虑以下几个方面:1. 设计串口驱动程序;2. 设计串口配置程序;3. 设计串口发送和接收程序。
接下来,我们将逐一介绍这些方面。
1. 设计串口驱动程序串口驱动程序是串口通信的核心部分,它用于控制串口的发送和接收,以及数据帧的格式化和解析。
在设计一个串口驱动程序时,需要考虑以下几个方面:(1)串口的初始化:包括设置数据位、校验位、停止位等参数;(2)数据帧的格式化:将数据按照串口配置中的参数进行格式化,形成数据帧;(3)数据帧的解析:在接收端,需要对接收到的数据帧进行解析,提取出有效数据;(4)发送和接收的状态控制:控制发送和接收的状态,包括启动和停止发送、启动和停止接收等。
2. 设计串口配置程序串口配置程序用于配置串口参数,包括数据位、校验位、停止位等参数。
在设计一个串口配置程序时,需要考虑以下几个方面:(1)接口定义:定义串口配置程序与串口驱动程序之间的接口,包括调用方法和参数格式;(2)界面设计:设计一个用户友好的界面,方便用户进行串口参数配置;(3)参数验证:在用户输入参数后,需要对参数进行验证,确保参数符合串口通信规范。
C++串口API异步操作
C++串口API异步操作C++ 串口API 异步操作50有谁能说下串口API异步操作的例子,最好有代码的。
如果是BCB的更好,谢谢啦,有些函数直接看的不是很懂。
一,我要同时向20个端口发送数据,句柄怎样才能控制好二,如果采用异步操作,怎样操作才最好,需要代码支持谢谢啦初始化://串行设备句柄;HANDLE hComDev=0;//串口打开标志;BOOL bOpen=FALSE;//线程同步事件句柄;HANDLE hEvent=0;DCB dcb;COMMTIMEOUTS timeouts;//设备已打开if(bOpen) return FALSE;//打开COM1if((hComDev=CreateFile(“COM1”,GENERIC?READ|GENERI C?WRITE,0,NULL,OPEN?EXISTING,FILE?ATTRIBUTE?NORMAL,NULL))==INVAL ID?HAN DLE?VALUE)return FALSE;//设置超时控制SetCommTimeouts(hComDev,&timeouts);//设置接收缓冲区和输出缓冲区的大小SetupComm(hComDev,1024,512);//获取缺省的DCB结构的值GetCommState(hComDev,&dcb);//设定波特率为9600 bpsdcb.BaudRate=CBR?9600;//设定无奇偶校验dcb.fParity=NOPARITY;//设定数据位为8dcb.ByteSize=8;//设定一个停止位dcb.StopBits=ONESTOPBIT;//监视串口的错误和接收到字符两种事件SetCommMask(hComDev,EV?ERR|EV?RXCHAR); //设置串行设备控制参数SetCommState(hComDev,&dcb);//设备已打开bOpen=TRUE;//创建人工重设、未发信号的事件hEvent=CreateEvent(NULL,FALSE,FALSE, “WatchEvent”);//创建一个事件监视线程来监视串口事件AfxBeginThread(CommWatchProc,pParam);}数据发送数据发送利用WriteFile()函数实现。
基于Windows API编程的串行异步通信程序设计
*******************实践教学*******************兰州理工大学计算机与通信学院2015年秋季学期计算机通信课程设计题目:基于Windows API编程的串行异步通信程序设计专业班级:姓名:学号:指导教师:王惠琴成绩:摘要本文系统介绍了Visual C++实现异步串行通信的基本原理及过程,讲述了用Windows函数库API函数实现和C运行时的实现方法,利用VC++6.0 来做用户界面,根据所需可以自己设计界面布局,设备的数据设置和ID设置,我们可以将主要工作集中在串口编程方面,结合串口通信的机理和同步技术,最终实现串口异步通信功能。
关键词:串口通信;异步I/O;Visual C++应用目录前言 (2)一.串口简单介绍 (3)1.1 RS-232简介 (3)1.2串口通信参数 (4)1.3数据校验方法 (4)1.4串口通信原理与特点 (4)1.5串口通信的传输方式 (5)二.串行通信中主要的技术问题 (5)2.1调用Win32 API通信函数 (5)2.2 数据的传输 (6)三.串行异步通信系统设计 (6)3.1系统需求分析 (6)3.2系统分析 (7)3.3系统设计 (7)总结 (12)附录: (14)1前言Visual C++是建立在Window Array5和Window NT 32位程序上的可视化编程环境,对于控制系统的可视化开发提供了极大的便利,但是对于计算机控制系统中数据采集、控制,用Visual C++实现的介绍却很少。
基于此,介绍Visual C++在测控系统应用中的基本原理及应用,其中异步串行通信是关键。
其基本构成是:(单片机系统)完成信号检测、A/D转换和简单的控制功能,通过系统总线(如RS-232C)与上位机(PC机)相连,进行监测、控制,形成主从式结构。
串口通信是计算机与其他设备进行数据通信时经常使用的方法之一,他具有实现简单,使用灵活方便,数据传输可靠等优点,因而在工业控制、数据采集和实时监控系统中得到广泛应用本文的串口通信软件的开发没有使用任何串口通信的第三方封装控件,全部使用windows API函数对串口进行操作和配置,而且使用了多线程技术和异步I/0操作,提高了串口通信的效率和程序的灵活性。
实现异步串口
异步传输是一种典型的基于字节的输入输出,指数据按每次一个字节进行传输,其传输速度低。
同步传输是把数据字节组合起来一起发送,这种组合称之为帧,其传输速度比异步传输快,同步串口的传送速率高,异步串口实现简单,这是异步串口与同步串口间最主要的区别。
一,异步非阻塞串口通讯的优点读写串行口时,既可以同步执行,也可以重叠(异步)执行。
在同步执行时,函数直到操作完成后才返回。
这意味着在同步执行时线程会被阻塞,从而导致效率下降。
在重叠执行时,即使操作还未完成,调用的函数也会立即返回。
费时的I/O操作在后台进行,这样线程就可以干别的事情。
例如,线程可以在不同的句柄上同时执行I/O操作,甚至可以在同一句柄上同时进行读写操作。
"重叠"一词的含义就在于此。
二,异步非阻塞串口通讯的基本原理首先,确定要打开的串口名、波特率、奇偶校验方式、数据位、停止位,传递给CreateFile()函数打开特定串口;其次,为了保护系统对串口的初始设置,调用 GetCommTimeouts()得到串口的原始超时设置;然后,初始化DCB对象,调用SetCommState() 设置DCB,调用SetCommTimeouts()设置串口超时控制;再次,调用SetupComm()设置串口接收发送数据的缓冲区大小,串口的设置就基本完成,之后就可以启动读写线程了。
三,异步非阻塞串口通讯的基础知识VC串口通信技术网下面来介绍并举例说明一下编写异步非阻塞串口通讯的程序中将会使用到的几个关键函数CreateFile()功能:打开串口设备函数原型1.HANDLE CreateFile(2.LPCTSTR lpFileName, // 串口名称字符串;如: "COM1" 或 "COM2"3.DWORD dwDesiredAccess, // 设置读写属性(访问模式);一般为GENERIC_READ|GENERIC_WRITE,4.DWORD dwShareMode, // 共享模式;"必须"为 0, 即不能共享5.LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全属性;一般为NULL6.DWORD dwCreationDistribution, // 创建方式,串口设置必须设置此值;在这里"必须"为 OPEN_EXISTING7.DWORD dwFlagsAndAttributes, // 文件属性和标志;在这里我们设置成FILE_FLAG_OVERLAPPED ,实现异步I/O8.HANDLE hTemplateFile // 临时文件的句柄,通常为NULL9.);函数说明:如果调用成功,那么该函数返回文件的句柄,如果调用失败,则函数返回INVALID_HANDLE_VALUE。
异步串口通信VC++
异步串口通信VC++//MyComm.h 多机控制异步串口通信class CMyComm{public:CMyComm();virtual ~CMyComm();void PreOpenSetupQueue(DWORD dwInQueue, DWORD dwOutQueue);// size of input buffer, size of output bufferBOOL Open(int nPort, int nBaud);// 默认无校验,每个字节发送11 个bit ,异步方式。
// 若设置校验后,校验错则字节被替换为0x7EBOOL SetupQueue(DWORD dwInQueue, DWORD dwOutQueue);// size of input buffer, size of output bufferBOOL ResetParity(char Parity);//parity = 'N', 'O', 'E', 'M', 'S'不区分大小写// 分别表示no, odd, even, mark, space// 在Open() 前设置无效。
BOOL SendData(LPCVOID lpBuf, DWORD dwToWrite);DWORD ReadData(LPVOID lpBuf, DWORD dwToRead);void Close();protected:HANDLE m_hCom;BOOL m_bOpened;OVERLAPPED m_osReader;OVERLAPPED m_osWriter;DWORD m_dwInBuf;DWORD m_dwOutBuf;};////////////////////////////////////////////////////////////MyComm.cpp#include "stdafx.h"#include "MyComm.h"///////////////////////////////////////////CMyComm::CMyComm(){m_bOpe ned = FALSE;m_dwl nBuf = 512;m_dwOutBuf = 512;m_hCom = NULL;void CMyComm::PreOpe nSetupQueue(DWORD dwI nQueue, DWORD dwOutQueue) {m_dw In Buf = dwln Queue;m_dwOutBuf = dwOutQueue;}BOOL CMyComm::Ope n(int nPort, i nt nBaud){ASSERT (n Port > 0 || n Port < 5 || nBaud >= 110 || n Baud <= 128000);if( m_bOpe ned ) return TRUE;char szPort[15];char lpDef[15];DCB dcb = {0};dcb.DCBle ngth = sizeof(dcb);wspri ntf(szPort, "COM%d", nPort);wsprintf(lpDef, "%d,n,8,1", nBaud);m_hCom = CreateFile(szPort, GENERIC_READ | GENERIC_WRITE,0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);if( m_hCom == INVALID_HANDLE_VALUE ) return FALSE;FillMemory(&m _osReader, sizeof(OVERLAPPED), 0);FillMemory(&m _osWriter, sizeof(OVERLAPPED), 0);m_osReader.hEve nt = CreateEve nt(NULL, TRUE, FALSE, NULL);m_osWriter.hEve nt = CreateEve nt(NULL, TRUE, FALSE, NULL);int byteUsedTime = 14400 / nBaud +1;COMMTIMEOUTS timeouts = {20 + byteUsedTime, byteUsedTime, 1000, byteUsedTime , 20}; dcb.fParity = TRUE;dcb.fErrorChar = TRUE;dcb.ErrorChar = '~';if( m_osReader.hEve nt == NULL || m_osWriter.hEve nt == NULL|| !SetCommTimeouts(m_hCom, & timeouts)|| !BuildCommDCB(lpDef, &deb) || !SetupComm(m_hCom, m_dwlnBuf, m_dwOutBuf)) { if( m_osReader.hEve nt != NULL )CloseHa ndle( m_osReader.hEve nt );if( m_osWriter.hEvent != NULL )CloseHa ndle( m_osWriter.hEve nt );CloseHa ndle( m_hCom );return FALSE;m_bOpe ned = TRUE;retur n m_bOpe ned;}BOOL CMyComm::SetupQueue(DWORD dwln Queue, DWORD dwOutQueue) {if (m_hCom == NULL) retur n FALSE;m_dw In Buf = dwln Queue;m_dwOutBuf = dwOutQueue;return SetupComm(m_hCom, m_dw In Buf, m_dwOutBuf);}BOOL CMyComm::ResetParity(ehar Parity){if (m_hCom == NULL) retur n FALSE;DCB deb;deb.DCBle ngth = sizeof( DCB );if (!GetCommState(m_hCom, & deb)) retur n FALSE;BYTE eParity;Parity = tolower(Parity);switeh (Parity) {ease 'o':eParity = 1;break;ease 'e':eParity = 2;break;ease 'm':eParity = 3;break;ease 's':eParity = 4;break;default:eParity = 0;break;}deb.Parity = eParity;return SetCommState(m_hCom, &dcb);}精选文库BOOL CMyComm::Se ndData(LPCVOID IpBuf, DWORD dwToWrite){TRACE("SSSSSSSSSSSSS 00\n");if( !m_bOpened || m_hCom == NULL ) return FALSE;DWORD dwWritte n;if (WriteFile(m_hCom, lpBuf, dwToWrite, & dwWritte n, & m_osWriter)) retur n TRUE;if (GetLastError() != ERROR_IO_PENDING) retur n FALSE;GetOverlappedResult(m_hCom, &m _osWriter, &dwWritte n, TRUE);TRACE("SSSSSSSSSSSSS 11\n");return (dwToWrite == dwWritte n);}DWORD CMyComm::ReadData(LPVOID lpBuf, DWORD dwToRead){TRACE("RRRRRRRRRRRR 00\n");if( !m_bOpened || m_hCom == NULL ) return 0;DWORD dwRead;if (ReadFile(m_hCom, lpBuf, dwToRead, &dwRead, & m_osReader) ) return dwRead;if (GetLastError() != ERROR_IO_PENDING) return 0;if (WaitForSi ngleObject(m_osReader.hEve nt, INFINITE) != WAIT_OBJECT_0 )return 0;if (!GetOverlappedResult(m_hCom, &m _osReader, &dwRead, FALSE))return 0;TRACE("RRRRRRRRRRRR 11\ n");retur n dwRead;}void CMyComm::Close(){if (m_osReader.hEve nt != NULL) CloseHa ndle( m_osReader.hEve nt );if (m_osWriter.hEve nt != NULL) CloseHa ndle( m_osWriter.hEve nt );if (m_hCom != NULL) CloseHa ndle( m_hCom );m_bOpe ned = FALSE;}CMyComm::~CMyComm(){Close();}精选文库// mai n.cppchar Buf[40];int nArray[3];CMyCo mn myCom;UINT Sen dDataProc(LPVOID pParam);void On CommSe ndReceive(){myCom.PreOpe nSetupQueue(12, 12);if (!myCom.Open(2, 4800)) return;//如果想改变校验位,在此位置,如:myCom.ResetParity('m');FillMemory(Buf, 40, 0);n Array[0] = 0;nArray[1] = 17;nArray[2] = 88888;AfxBeginThread(SendDataProc, (LPVOID)(12));TRACE("EEEEEEEE\n");int n Read = myCom.ReadData(Buf, 12);in t* nA = (int*) Buf;TRACE("AAAAAAAAAAAAAA %d, %d %d %d\n", nRead, n A[0], nA[1], nA[1]); }UINT Sen dDataProc(LPVOID pParam){return myCom.Se ndData((LPVOID)nArray, (DWORD) pParam);}。
串口API函数大全
串口API在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信。
串口通信方便易行,应用广泛。
一般情况下,工控机和各智能仪表通过RS485总线进行通信。
RS485的通信方式是半双工的,只能由作为主节点的工控PC机依次轮询网络上的各智能控制单元子节点。
每次通信都是由PC 机通过串口向智能控制单元发布命令,智能控制单元在接收到正确的命令后作出应答。
在Win32下,可以使用两种编程方式实现串口通信,其一是使用ActiveX控件,这种方法程序简单,但欠灵活。
其二是调用Windows的API函数,这种方法可以清楚地掌握串口通信的机制,并且自由灵活。
本文我们只介绍API串口通信部分。
串口的操作可以有两种操作方式:同步操作方式和重叠操作方式(又称为异步操作方式)。
同步操作时,API函数会阻塞直到操作完成以后才能返回(在多线程方式中,虽然不会阻塞主线程,但是仍然会阻塞监听线程);而重叠操作方式,API函数会立即返回,操作在后台进行,避免线程的阻塞。
无论那种操作方式,一般都通过四个步骤来完成:(1)打开串口(2)配置串口(3)读写串口(4)关闭串口(1)打开串口Win32系统把文件的概念进行了扩展。
无论是文件、通信设备、命名管道、邮件槽、磁盘、还是控制台,都是用API函数CreateFile来打开或创建的。
该函数的原型为:HANDLE CreateFile( LPCTSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDistribution,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile);lpFileName:将要打开的串口逻辑名,如“COM1”;dwDesiredAccess:指定串口访问的类型,可以是读取、写入或二者并列;dwShareMode:指定共享属性,由于串口不能共享,该参数必须置为0;lpSecurityAttributes:引用安全性属性结构,缺省值为NULL;dwCreationDistribution:创建标志,对串口操作该参数必须置为OPEN_EXISTING;dwFlagsAndAttributes:属性描述,用于指定该串口是否进行异步操作,该值为FILE_FLAG_OVERLAPPED,表示使用异步的I/O;该值为0,表示同步I/O操作;hTemplateFile:对串口而言该参数必须置为NULL;同步I/O方式打开串口的示例代码:HANDLE hCom; //全局变量,串口句柄hCom=CreateFile("COM1",//COM1口GENERIC_READ|GENERIC_WRITE, //允许读和写0, //独占方式NULL,OPEN_EXISTING, //打开而不是创建0, //同步方式NULL);if(hCom==(HANDLE)-1){AfxMessageBox("打开COM失败!");return FALSE;}return TRUE;重叠I/O打开串口的示例代码:HANDLE hCom; //全局变量,串口句柄hCom =CreateFile("COM1", //COM1口GENERIC_READ|GENERIC_WRITE, //允许读和写0, //独占方式NULL,OPEN_EXISTING, //打开而不是创建FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //重叠方式NULL);if(hCom ==INVALID_HANDLE_VALUE){AfxMessageBox("打开COM失败!");return FALSE;}return TRUE;(2)、配置串口在打开通讯设备句柄后,常常需要对串口进行一些初始化配置工作。
C#多线程实现异步接口
C#多线程实现异步接⼝异步接⼝的声明我们已经了解到,如果⼀个⽅法是异步的,那么这个⽅法的返回值类型是Task<T>,那么接⼝中该如何规定异步⽅法呢?⼀样的,如果接⼝中的⽅法是异步的,那么规定⽅法的返回值类型是Task<T>即可,看下⾯的代码:interface ITest{/// <summary>/// ⽅法的返回类型是Task<T>/// </summary>/// <returns></returns>Task<string> GetAsync();}注意:⽅法的前⾯不能添加async标注。
因为从语法上来讲,接⼝只能定义⾏为,不能定义实现,如果标注为async,就属于实现了。
我们在⽅法前⾯标注async,看看是什么效果:我们看到,⽅法直接就报错了。
⽽接⼝的实现类中的⽅法可以标注为async,也可以不标注为async,看下⾯的代码:/// <summary>/// 定义接⼝/// </summary>interface ITest{/// <summary>/// ⽅法的返回类型是Task<T>/// </summary>/// <returns></returns>///不能标注为asyncTask<string> GetAsync();}public class Test : ITest{/// <summary>/// ⽅法不标注为async 返回⼀个Task<string>类型/// </summary>/// <returns></returns>//public Task<string> GetAsync()//{// return Task.Run<string>(() =>// {// return "2";// });//}/// <summary>/// ⽅法标注为async 直接返回⼀个string类型/// </summary>/// <returns></returns>public async Task<string> GetAsync(){return "3";}}到此这篇关于C#多线程实现异步接⼝的⽂章就介绍到这了。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C++ 串口API 异步操作50
有谁能说下串口API异步操作的例子,最好有代码的。
如果是BCB的更好,谢谢啦,有些函数直接看的不是很懂。
一,我要同时向20个端口发送数据,句柄怎样才能控制好二,如果采用异步操作,怎样操作才最好,需要代码支持谢谢啦初始化:
//串行设备句柄;
HANDLE hComDev=0;
//串口打开标志;
BOOL bOpen=FALSE;
//线程同步事件句柄;
HANDLE hEvent=0;
DCB dcb;
COMMTIMEOUTS timeouts;
//设备已打开
if(bOpen) return FALSE;
//打开COM1
if((hComDev=CreateFile(“COM1”,GENERIC?READ|GENERIC?WRITE,0,N ULL,OPEN?EXISTING,FILE?ATTRIBUTE?NORMAL,NULL))==INVALID?HAN DLE?VALUE)
return FALSE;
//设置超时控制
SetCommTimeouts(hComDev,&timeouts);
//设置接收缓冲区和输出缓冲区的大小
SetupComm(hComDev,1024,512);
//获取缺省的DCB结构的值
GetCommState(hComDev,&dcb);
//设定波特率为9600 bps
dcb.BaudRate=CBR?9600;
//设定无奇偶校验
dcb.fParity=NOPARITY;
//设定数据位为8
dcb.ByteSize=8;
//设定一个停止位
dcb.StopBits=ONESTOPBIT;
//监视串口的错误和接收到字符两种事件SetCommMask(hComDev,EV?ERR|EV?RXCHAR); //设置串行设备控制参数
SetCommState(hComDev,&dcb);
//设备已打开
bOpen=TRUE;
//创建人工重设、未发信号的事件
hEvent=CreateEvent(NULL,FALSE,FALSE, “WatchEvent”);
//创建一个事件监视线程来监视串口事件
AfxBeginThread(CommWatchProc,pParam);
}
数据发送
数据发送利用WriteFile()函数实现。
对于同步I/O操作,它的最后一个参数可为NULL;而对异步I/O操作,它的最后一个参数必需是一个指向OVERLAPPED结构的指针,通过OVERLAPPED结构来获得当前的操作状态。
BOOL WriteComm(LPCVOID lpSndBuffer,DWORD dwBytesToWrite)
{
//lpSndBuffer为发送数据缓冲区指针,
dwBytesToWrite为将要发送的字节长度
//设备已打开
BOOL bWriteState;
//实际发送的字节数
DWORD dwBytesWritten;
//设备未打开
if(!bOpen) return FALSE;
bWriteState=WriteFile(hComDev,lpSndBuffer,dwBytesToWrite,&dwBytesWritten,NULL);
if(!bWriteState || dwBytesToWrite!=dwBytesWritten)
//发送失败
return FALSE;
else
//发送成功
return TRUE;
}
数据接收
接收数据的任务由ReadFile函数完成。
该函数从串口接收缓冲区中读取数据,读取数据前,先用ClearCommError函数获得接收缓冲区中的字节数。
接收数据时,同步和异步读取的差别同发送数据是一样的。
DWORD ReadComm(LPVOID lpInBuffer,DWORD dwBytesToRead)
{
//lpInBuffer为接收数据的缓冲区指针,dwBytesToRead为准备读取的数据长度(字节数)
//串行设备状态结构
COMSTAT ComStat;
DWORD dwBytesRead,dwErrorFlags;
//设备未打开
if(!bOpen) return 0;
//读取串行设备的当前状态
ClearCommError(hComDev,&dwErrorFlags,&ComStat);
//应该读取的数据长度
dwBytesRead=min(dwBytesToRead,ComStat.cbInQue);
if(dwBytesRead>0)
//读取数据
if(!ReadFile(hComDev,lpInBuffer,dwBytesRead,&dwBytesRead,NULL)) dwBytesRead=0;
return dwBytesRead;
}
事件监视线程
事件监视线程对串口事件进行监视,当监视的事件发生时,监视线程可将这个事件发送(SendMessage)或登记(PostMessage)到对事件进行处理的窗口类(由pParam指定)中。
UINT CommWatchProc(LPVOID pParam)
{
DWORD dwEventMask=0; //发生的事件;
while(bOpen)
{
//等待监视的事件发生
WaitCommEvent(hComDev, &dwEventMask,NULL);
if ((dwEventMask &EV?RXCHAR)==EV?RXCHAR)
……//接收到字符事件后,可以将此消息登记到由pParam有指定的窗口类中进行处理
if(dwEventMask &EV?ERR)==EV?ERROR)
……//发生错误时的处理
}
SetEvent(hEvent);
//发信号,指示监视线程结束
return 0;
}
关闭串行设备
在整个应用程序结束或不再使用串行设备时,应将串行设备关闭,包括取消事件监视,将设备打开标志bOpen置为FALSE以使事件监视线程结束,清除发
送/接收缓冲区和关闭设备句柄。
void CloseSynComm()
{
if(!bOpen) return;
//结束事件监视线程
bOpen=FALSE;
SetCommMask(hComDev,0);
//取消事件监视,此时监视线程中的WaitCommEvent将返回WaitForSingleObject(hEvent,INFINITE);
//等待监视线程结束
CloseHandle(hEvent); //关闭事件句柄
//停止发送和接收数据,并清除发送和接收缓冲区PurgeComm(hComDev,PURGE?TXABORT|
PURGE?RXABORT|PURGE?TXCLEAR|PURGE?RXCLEAR);
//关闭设备句柄
CloseHandle(hComDev);
}。