一个印度人写的VC串口类CSerialCom(有串口基础介绍)

2024-02-17 04:32

本文主要是介绍一个印度人写的VC串口类CSerialCom(有串口基础介绍),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://www.vc-rs232.com/html/VC_SSCOM_Control/2011/0117/34.html

 

一个印度人写的VC串口类CSerialCom(有串口基础介绍)

软件介绍

  一个由印度人编写的VC串口类(也是一种VC串口控件),他还配合这个类写了VC 串口通信方面的一些基础知识,如怎么用VC打开串口,如何对串口进行配置,读串口、写串口等。

  这个类有点特别,它没有使用事件驱动原理,它是以查询方式工作的。

简介:  

  对没有接触过串口通信的VC程序员来说显得非常困难,很久以前我在 codeguru.com 上搜索过串口通信相关信息得到了非常大的帮助,从那时起能编写一个简单易用的VC 串口类是我的梦想。

  经过七个月在串口通信编程方面实践经验后,我编写了一个基于API实现的简单串口类,在介绍此串口类之前先介绍一下VC 串口通信方面的基础知识。

串口通信基础:

  串口通信每个字节的传输以串行的方式进行,传输时低位先被发送,一个“包”由“开始位”+“数据位”+“奇偶校验位”(不是必需)+“停止位” 组成。

  奇偶校验位是可选的,它用来进行错误检测,您可以在软件里设置是否启用奇偶校验,而且还可以选择启用哪种校验方式,如“奇”校验(ODD)或“偶”校验(EVEN)。

  PC机通过串口发送和接收数据的流程如下:

 1、

打开串口

 2、配置串口通信参数,如:波特率、校验方式、数据位数等
 3、设置通信超时时间
 4、写数据
 5、读数据
 6、关闭串口

用VC打开串口:

  打开串口可以用API函数 CreateFile() 来实现,打开串口有两种方式,分别为重叠I/O(OVERLAPPED)和非重叠(NON-OVERLAPPED)方式(其实这两种方式分别对应串口的异步和同步通信方式-VC串口通信技术网注)。CSerialCom 类工作于非重叠(NON-OVERLAPPED)模式(即同步通信模式),有关更多 OVERLAPPED NON-OVERLAPPED 方面的消息可查询MSDN。

串口配置:

  VC 串口通信程序编写最重要的课题就是如何利用 DCB 结构来配置串口,对 DCB 结构填充不正确是大多数人常反犯的毛病,通常串口通信程序编写好后出现这样那样的问题就是因为这个结构没有正确填充所致。在利用 CreateFile() 函数打开串口时就需要我们对串口的波特率、校验方式、数据位、停止位等进行配置。

设置超时时间:

  每次打开串口时都必须利用 COMMTIMEOUTS 结构设置超时时间,如果未设置此结构,通信将以默认或上次打开此串口时设置的超时时间为准。

写串口:

  WriteFile() 函数可实现这一功能,在执行这一动作之前必须先打开并配置好串口。

读串口:

  利用 ReadFile() 可实现这一功能,同样,在执行这一动作之前必须先打开并配置好串口。

关闭串口:

  不再使用已经打开的串口后必须关闭它以将此串口资源释放出来,这样其它程序才可能再使用此串口资源,外于非重叠I/O(NON-OVERLAPPED)模式下的串口在打开期间是不能被其它程序或同一程序内的其它线程访问的。使用 CloseHandle() 函数可以关闭串口, CloseHandle() 函数只有一个参数,它是由 CreateFile() 打开串口时返回的设置句柄。

CSerialCom 串口类

  CSerialCom 类使用六个函数来实现上面提到的功能,它们分别是:

  1. BOOL CSerialCom::OpenPort(CString portname) 
  2. portname= "//./" + portname; 
  3. hComm = CreateFile(portname, 
  4.                       GENERIC_READ | GENERIC_WRITE, 
  5.                       0, 
  6.                       0, 
  7.                       OPEN_EXISTING, 
  8.                       0, 
  9.                       0); 
  10. if(hComm==INVALID_HANDLE_VALUE){ 
  11.     return false;} 
  12.     else
  13.     return true

  OpenPort()成员函数用来打开串口,它需要的参数只有一个,就是串口名,如“COM1”,“COM2” 。

  1. BOOL CSerialCom::ConfigurePort(DWORD BaudRate, BYTE ByteSize,  
  2.                                DWORD fParity, BYTE Parity, BYTE StopBits) 
  3.     if((m_bPortReady = GetCommState(hComm, &m_dcb))==0) 
  4.     { 
  5.         MessageBox("GetCommState Error","Error",MB_OK+MB_ICONERROR); 
  6.         CloseHandle(hComm); 
  7.         return false
  8.     } 
  9.      
  10.     m_dcb.BaudRate =BaudRate; 
  11.     m_dcb.ByteSize = ByteSize; 
  12.     m_dcb.Parity =Parity ; 
  13.     m_dcb.StopBits =StopBits; 
  14.     m_dcb.fBinary=TRUE; 
  15.     m_dcb.fDsrSensitivity=false
  16.     m_dcb.fParity=fParity; 
  17.     m_dcb.fOutX=false
  18.     m_dcb.fInX=false
  19.     m_dcb.fNull=false
  20.     m_dcb.fAbortOnError=TRUE; 
  21.     m_dcb.fOutxCtsFlow=FALSE; 
  22.     m_dcb.fOutxDsrFlow=false
  23.     m_dcb.fDtrControl=DTR_CONTROL_DISABLE; 
  24.     m_dcb.fDsrSensitivity=false
  25.     m_dcb.fRtsControl=RTS_CONTROL_DISABLE; 
  26.     m_dcb.fOutxCtsFlow=false
  27.     m_dcb.fOutxCtsFlow=false
  28.     m_bPortReady = SetCommState(hComm, &m_dcb); 
  29.     if(m_bPortReady ==0) 
  30.     { 
  31.         MessageBox("SetCommState Error","Error",MB_OK+MB_ICONERROR); 
  32.         CloseHandle(hComm); 
  33.         return false
  34.     } 
  35.     return true

  ConfigurePort() 函数对串口地配置,它所需参数如下所示:

  DWORD BaudRate

  DWORD BaudRate 用来描述串口通信使用的波特率,如此参数为 CBR_9600 时,波特率为9600bps,PC机支持的标准波特率有:CBR_110 ,CBR_300 ,CBR_600 ,CBR_1200,CBR_2400,CBR_4800,CBR_9600,CBR_14400, CBR_19200,CBR_38400,CBR_56000,CBR_57600,CBR_115200,CBR_128000,CBR_256000

  BYTE ByteSize

  此参数描述数据位位数,标准值为8或4。

  DWORD fParity

  奇偶校验开关,如果此参数为真(TRUE)则开启奇偶校验,为假(FALSE)则关闭奇偶校验。

  BYTE Parity

  校验方式,可选方式如下:

 

EVENPARITY

 MARKPARITY
 NOPARITY
 ODDPARITY
 SPACEPARITY

  BYTE StopBits

  停止位位数,可取值如下:

 

ONESTOPBIT

 ONE5STOPBITS
 TWOSTOPBITS

备注:ConfigurePort() 函数是假定串口的流控制是由硬件来完成的,软件在收发数据过程中不检测CTS/RTS 和 Xon/Xoff 状态,您可以修改DCB结构来启用软件流控制。

  1. BOOL CSerialCom::SetCommunicationTimeouts(DWORD ReadIntervalTimeout,  
  2.                                           DWORD ReadTotalTimeoutMultiplier,  
  3.                                           DWORD ReadTotalTimeoutConstant,  
  4.                                           DWORD WriteTotalTimeoutMultiplier,  
  5.                                           DWORD WriteTotalTimeoutConstant) 
  6.     if((m_bPortReady = GetCommTimeouts (hComm, &m_CommTimeouts))==0) 
  7.         return false
  8.     m_CommTimeouts.ReadIntervalTimeout =ReadIntervalTimeout; 
  9.     m_CommTimeouts.ReadTotalTimeoutConstant =ReadTotalTimeoutConstant; 
  10.     m_CommTimeouts.ReadTotalTimeoutMultiplier =ReadTotalTimeoutMultiplier; 
  11.     m_CommTimeouts.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant; 
  12.     m_CommTimeouts.WriteTotalTimeoutMultiplier =WriteTotalTimeoutMultiplier; 
  13.     m_bPortReady = SetCommTimeouts (hComm, &m_CommTimeouts); 
  14.      
  15.     if(m_bPortReady ==0) 
  16.     { 
  17.         MessageBox("StCommTimeouts function failed"
  18.                    "Com Port Error",MB_OK+MB_ICONERROR); 
  19.         CloseHandle(hComm); 
  20.         return false
  21.     } 
  22.     return true
  23. }

  SetCommunicationTimeouts() 成员函数用来设置读/写超时时间,它所需参数如下:

  DWORD ReadIntervalTimeout

  设置读串口时,收到两个字符的最大时间间隔,单位为毫秒。在执行ReadFile() 期间,一但收到两个字符的时间间隔超过这一设定值,ReadFile()立即返回。如果这一参数设置为零,则表明这一特性未启用。

  ReadTotalTimeoutConstant

  常量,用来计算读操作总超时时间。每个读操作过程中,这个参数被加到ReadTotalTimeoutMultiplier。如果ReadTotalTimeoutMultiplierReadTotalTimeoutConstant两个参数都为零则表明总超时计算功能没有启用。

  ReadTotalTimeoutMultiplier

  用来保存读操作总超时时间的

  WriteTotalTimeoutConstant

  常量,用来计算写操作总超时时间。与ReadTotalTimeoutConstant差不多。

  WriteTotalTimeoutMultiplier

  用来保存写操作总超时时间的,如果WriteTotalTimeoutMultiplierWriteTotalTimeoutConstant两参数均为零,表明写操作总超时时间特性不被启用。

  例如,您需要传送一块数据包,设定了写操作超时时间为500ms(每个字符间发送时间最大间隔),您可以用设置超时成员函数来设定,内容为:SetCommunicationTimeouts(0,500,0,0,0);如果设置成功,函数返回真,否则返回假。

  1. BOOL CSerialCom::WriteByte(BYTE bybyte) 
  2.     iBytesWritten=0; 
  3.     if(WriteFile(hComm,&bybyte,1,&iBytesWritten,NULL)==0) 
  4.         return false
  5.     else  
  6.         return true
  7. }

  WriteByte() 成员函数用来向串口写数据。

  1. BOOL CSerialCom::ReadByte(BYTE &resp) 
  2.     BYTE rx; 
  3.     resp=0; 
  4.     DWORD dwBytesTransferred=0; 
  5.     if (ReadFile (hComm, &rx, 1, &dwBytesTransferred, 0)) 
  6.     { 
  7.         if (dwBytesTransferred == 1) 
  8.         { 
  9.             resp=rx; 
  10.             return true
  11.          } 
  12.     } 
  13.     return false
  14. }

  

ReadByte() 成员函数实现读串口功能,如果您知道有数据发送来了,可能使用 ReadByte() 来读取数据,如果不知道何时有数据发送过来,可以周期性调用此函数,当没收到数据超过超时时间后, ReadByte() 自动返回。在实际应用中,通信双方可能会以某种协议进行的,此时一般有表明通信数据包结束的标志,如3964协议的结束符是‘ETX’,您可能通过它来判断是否传输结束。

  1. void CSerialCom::ClosePort() 
  2. CloseHandle(hComm); 
  3. return

 

  ClosePort() 成员函数用来关闭一个已经打开的串口。

如何使用CSerialCom类

  使用CSerialCom类前的准备工作:

 1、

复制SerialCom.h 和 SerialCom.cpp两个文件到工程所在目录

 2、在VC工程中导入这两个文件
 3、加入#include "SerialCom.h"句代码到程序适当位置
 4、创建CSerialCom类的一个实例

  现在就可以调用CSerialCom类成员函数来进行串口通信了,操作流程如下:

  1. // 打开串口。 需要检查函数返回值来判断串口是否正确打开
  2. port.OpenPort( );  
  3. // 配置串口。需要检查函数返回值来判断否正确配置
  4. port.ConfigurePort( );   
  5. // 设置超时时间。需要检查函数返回值来判断否正确配置
  6. port.SetCommunicationTimeouts( );  
  7.       
  8. // 写串口,由于一次只能写一个字节,一般需要多次调用此函数才能将需要发送的字符串发送完
  9. port.WriteByte();  
  10.      
  11. // 读串口,由于一次只能读一个字节,一般需要多次调用此函数才能将需要读取的字符串读完
  12. port.ReadByte( );  
  13. // 关闭串口
  14. port.ClosePort();  

 

这篇关于一个印度人写的VC串口类CSerialCom(有串口基础介绍)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/716683

相关文章

Android Mainline基础简介

《AndroidMainline基础简介》AndroidMainline是通过模块化更新Android核心组件的框架,可能提高安全性,本文给大家介绍AndroidMainline基础简介,感兴趣的朋... 目录关键要点什么是 android Mainline?Android Mainline 的工作原理关键

Pytest多环境切换的常见方法介绍

《Pytest多环境切换的常见方法介绍》Pytest作为自动化测试的主力框架,如何实现本地、测试、预发、生产环境的灵活切换,本文总结了通过pytest框架实现自由环境切换的几种方法,大家可以根据需要进... 目录1.pytest-base-url2.hooks函数3.yml和fixture结论你是否也遇到过

mysql的基础语句和外键查询及其语句详解(推荐)

《mysql的基础语句和外键查询及其语句详解(推荐)》:本文主要介绍mysql的基础语句和外键查询及其语句详解(推荐),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录一、mysql 基础语句1. 数据库操作 创建数据库2. 表操作 创建表3. CRUD 操作二、外键

Python基础语法中defaultdict的使用小结

《Python基础语法中defaultdict的使用小结》Python的defaultdict是collections模块中提供的一种特殊的字典类型,它与普通的字典(dict)有着相似的功能,本文主要... 目录示例1示例2python的defaultdict是collections模块中提供的一种特殊的字

Python基础文件操作方法超详细讲解(详解版)

《Python基础文件操作方法超详细讲解(详解版)》文件就是操作系统为用户或应用程序提供的一个读写硬盘的虚拟单位,文件的核心操作就是读和写,:本文主要介绍Python基础文件操作方法超详细讲解的相... 目录一、文件操作1. 文件打开与关闭1.1 打开文件1.2 关闭文件2. 访问模式及说明二、文件读写1.

C#基础之委托详解(Delegate)

《C#基础之委托详解(Delegate)》:本文主要介绍C#基础之委托(Delegate),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 委托定义2. 委托实例化3. 多播委托(Multicast Delegates)4. 委托的用途事件处理回调函数LINQ

MySQL中慢SQL优化的不同方式介绍

《MySQL中慢SQL优化的不同方式介绍》慢SQL的优化,主要从两个方面考虑,SQL语句本身的优化,以及数据库设计的优化,下面小编就来给大家介绍一下有哪些方式可以优化慢SQL吧... 目录避免不必要的列分页优化索引优化JOIN 的优化排序优化UNION 优化慢 SQL 的优化,主要从两个方面考虑,SQL 语

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

Python实现html转png的完美方案介绍

《Python实现html转png的完美方案介绍》这篇文章主要为大家详细介绍了如何使用Python实现html转png功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 1.增强稳定性与错误处理建议使用三层异常捕获结构:try: with sync_playwright(

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir