1.串行接口是采用串行通信方式的扩展接口,将数据一位一位地顺序传送。

2.基本概念

(1) RS232电平和TTL电平
电平信号是用信号线电平减去参考线电平得到的电压差,这个电压差决定了传输值是1还是0。在电平信号中多少V代表1,多少V代表0是不固定的,取决于点评标准。例如:RS232电平中-15V ~ -3V表示1,+3V ~ +15V代表0;TTL电平中+5V表示1,0V表示0。
不管哪种电平都是为了在传输线上表示1和0,区别在于适用的环境和条件不同。RS232电平适合干扰大、距离远的情况,一般传输距离小于15米,用于工业上;TTL电平适合距离近且干扰小的情况,一般用在电路板内部的两个芯片之间。对于编程来说,RS232电平传输和TTL电平传输是没有差异的。TTL电平和RS232电平混接是不可以的。
(2) 波特率指的是串口通信的速率,也就是串口通信时每秒钟可以传输多少个二进制位。串口通信的波特率不能随意设定,而应该是在一些值中去选择。一般最常见的波特率是9600或115300(低端单片机如51常用9600,高端单片机和嵌入式SOC常用115200)。
波特率不能随意指定,主要是因为:通信双方必须事先设定相同的波特率才能成功通信,如果发送方和接收方按照不同的波特率通信根本收不到,因此波特率最好是常用的9600或者115200。
(3) 串口通信时,收发是一个周期一个周期进行的,每个周期传输n个二进制位。这一个周期就叫做一个通信单元,一个通信单元由:起始位 + 数据位 + 奇偶校验位 + 停止位组成。

串口通信时因为是异步通信,所以通信双方必须事先约定好通信参数,这些通信参数包括:波特率、数据位、校验位、停止位。

3.在Win32位的windows系统中,有两种编程方式实现串口通信:

(1) 使用ActiveX控件,这种方法程序简单,但欠灵活。

(2) 调用Win32API函数,这种方法可以清楚的掌握串口通信机制,并且自由灵活。

4.串口的操作可以有两种操作方式:

(1) 同步操作方式

同步操作时,API函数会阻塞直到操作完成以后才能返回(在多线程方式中,虽然不会阻塞主线程,但是仍然会阻塞监听线程)。

(2) 重叠操作方式 (又称为异步操作方式)

重叠操作方式,API函数会立即返回,操作在后台进行,避免线程的阻塞。

5.操作步骤

(1) 打开串口

Win32系统把文件的概念进行了扩展。无论是文件、通信设备、命名管道、邮件槽、磁盘还是控制台,都是用API函数CreateFile来打开或创建的。

HANDLE CreateFile (LPCTSTR lpFileName,        //  串口逻辑名,如"COM1"或"\\\\.\\COM10"

DWORD dwDesiredAccess,            //  串口访问类型,可以是读取、写入或者两者并列

DWORD dwShareMode,        //  共享属性,由于串口不能共享,该参数必须为0

LPSECURITY_ATTRIBUTES lpSecurityAttributes,    //  引用安全性树形结构,缺省值为NULL

DWORD dwCreationDistribution,        //  创建标志,该参数必须设置为OPEN_EXISTING

DWORD dwFlagsAndAttributes,         //  属性描述,指定串口是否进行异步操作: FILE_FLAG_OVERLAPPED,异步的I/O;0,同步I/O操作

HANDLE hTemplateFile        //  对于串口而言该参数必须为NULL

);

HANDLE hCom = CreateFile("COM3", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

(2) 配置串口

1> DCB结构:

在打开通讯设备句柄后,需要对串口进行一些初始化配置工作。通过DCB结构来进行,DCB结构包含了波特率、数据位数、奇偶校验和停止位数等信息。在查询或配置串口的属性时,都要用DCB结构来作为缓冲区。在调用CreateFile打开串口后,可以调用GetCommState函数来获取串口的初始配置,若修改串口的配置,应该先修改DCB结构,然后再调用SetCommState函数设置串口。

BOOL GetCommState(

HANDLE hFile,            //  通信设备句柄

LPDCB lpDCB             //  指向一个设备控制块(DCB结构)的指针

);

BOOL SetCommState(

HANDLE hFile,            //  通信设备句柄

LPDCB lpDCB             //  指向一个设备控制块(DCB结构)的指针

);

2> I/O缓冲区

Windows用I/O缓冲区来暂存串口输入和输出的数据。如果通信的速率较高,则应该设置较大的缓冲区。调用SetupComm函数可以设置串行口的输入和输出缓冲区的大小

BOOL SetupComm(

HANDLE hFile,                      //  通信设备句柄

DWORD dwInQueue,           //  输入缓冲区的大小 (字节数)

DWORD dwOutQueue        //  输出缓冲区的大小 (字节数)

);

3> 超时问题

在使用ReadFile和WriteFile读写串行口时,需要考虑超时问题。超时的作用是在指定的时间内没有读入或发送指定数量的字符,ReadFile或WriteFile的操作仍然会结束。要查询当前的超时设置应调用GetCommTimeouts函数,该函数会填充一个COMMTIMEOUT结构。调用SetCommTimeouts可以用某一个COMMTIMEOUTS结构的内容来设置超时。

BOOL GetCommTimeouts(

HANDLE hFile,

LPCOMMTIMEOUTS lpCommTimeouts

);

BOOL SetCommTimeouts(

HANDLE hFIle,

LPCOMMTIMEOUTS lpCommTimeouts

);

读写串口的超时有两种:

间隔超时:在接收时两个字符之间的最大时延。

总超时:指读写操作总共花费的最大时间。

写操作只支持总超时,而读操作两种超时均支持。

typedef struct _COMMTIMEOUTS{

DWORD ReadIntervalTimeout;                    //  读间隔超时

DWORD ReadTotalTimeoutMultiplier;        //  读时间系数

DWORD ReadTotalTimeoutConstant;         //  读时间常量

DWORD WriteTotalTimeoutMultiplier;       //  写时间系数

DWORD WriteTotalTimeoutConstant;        //  写时间常量

}COMTIMEOUTS, *LPCOMMTIMEOUTS;

COMMTIMEOUTS结构的成员都以毫秒为单位。

总超时计算公式:总超时 = 时间系数  X  要求读/写的字符数  +  时间常量

如果所有写超时参数均为0,那么就不使用写超时。如果ReadIntervalTimeout为0,那么就不适用读间隔超时。如果ReadTotalTimeoutMultiplier和ReadTotalConstant都为0,则不适用读总超时。如果读间隔超时被设置成MAXDWORD并且读时间系数和读时间常量都为0,那么在读一次输入缓冲区的内容后读操作就立即返回,而不管是否读入了要求的字符。

在用重叠方式读写串口时,虽然ReadFile和WriteFile在完成操作以前就可能返回,但超时仍然是起作用的。在这种情况下,超时规定的是操作的完成时间,而不是ReadFile和WriteFile的返回时间。

在读写串口之前,还要用PurgeComm()函数情况缓冲区

BOOL PurgeComm(

HANDLE hFile,                    //  通信设备句柄

DWORD dwFlags                //  需要完成的操作

);

参数dwFlags指定要完成的操作,可以是下列值的组合:

PURGE_TXABORT    中断所有写操作并立即返回,即使写操作还没有完成

PURGE_RXABORT    中断所有读操作并立即返回,即使读操作还没有完成

PURGE_TXCLEAR     清除输出缓冲区

PURGE_RXCLEAR     清除输入缓冲区

(3) 读写串口

BOOL ReadFile(

HANDLE hFIle,        //  通信设备句柄

LPVOID lpBuffer,        //  读入的数据存储的地址,即读入的数据将存储在以该指针的值为首地址的一片内存区

DWORD nNumberOfBytesToRead,        //  要读入的数据的字节数

LPDWORD lpNumberOfBytesRead,        //  指向一个DWORD数值,该数值返回读操作实际读入的字节数

LPOVERLAPPED lpOverlapped        //  重叠操作时,该参数指向一个OVERLAPPED结构,同步操作时,该参数为NULL

);

BOOL WriteFile(

HANDLE hFile,        //  通信设备句柄

LPCVOID lpBuffer,        //  写入的数据存储的地址,即以该指针的值为首地址的nNumberOfBytesToWrite个字节的数据将要写入串口的发送数据缓冲区

DWORD nNumberOfBytesToWrite,        //  要写入的数据的字节数

LPDWORD lpNumberOfBytesWritten,        //  指向一个DWORD数值,该数值返回实际写入的字节数

LPOVERLAPPED lpOverlapped        //  重叠操作时,该参数指向一个OVERLAPPED结构,同步操作时,该参数为NULL

);

在用ReadFile和WriteFile读写串口时,既可以同步执行,也可以重叠执行。在同步执行时,函数直到操作完成后才返回。这意味着同步执行时线程会被阻塞,从而导致效率下降。在重叠执行时,即使操作还未完成,这两个函数也会立即返回,费时的I/O操作在后台进行。

ReadFile和WriteFile函数是同步还是异步由CreateFile函数决定,如果在调用CreateFile创建句柄时指定了FILE_FLAG_OVERLAPPED标志,那么调用ReadFile和WriteFile对该句柄进行的操作就应该是重叠的;如果未指定重叠标志,则读写操作应该是同步的。ReadFile和WriteFile函数的同步或者异步应该和CreateFile函数相一致。

ReadFile函数只要在串口输入缓冲区中读入指定数量的字符,就算完成操作。而WriteFile函数不但要把指定数量的字符拷入到输出缓冲区,而且要等这些字符从串行口送出去后才算完成操作。如果操作成功,这两个函数都返回TRUE。需要注意的是,当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,线程应该调用GetLastError函数分析返回的结果。例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,而且GetLastError函数返回ERROR_IO_PENDING。这说明重叠操作还未完成。

(4) 关闭串口

void CloseHandle(HANDLE hFIle);        //  关闭通信设备句柄

Windows串口编程相关推荐

  1. Windows串口编程:使用非标准波特率

    文章目录 前言 1. 创建一个对话框 2. Windows下使用非标准波特率 2.1获取串口号 2.2 获取设置的非标波特率 2.3 打开串口 前言 我们在使用USB转串口设备进行通讯时候,常用的标准 ...

  2. windows 串口编程 c语言,windows下C语言版串口发送程序(基于VS2017)

    #include "tchar.h" #include int main() { /*****************************打开串口*************** ...

  3. windows API 串口编程参考

    *************************************************** 更多精彩,欢迎进入:http://shop115376623.taobao.com ****** ...

  4. 串口编程 - windows如何枚举串口|获取活跃串口号

    串口编程 - windows如何枚举串口|获取活跃串口号 如需转载请标明出处:http://blog.csdn.net/itas109 QQ技术交流群:129518033 文章目录 串口编程 - wi ...

  5. windows中Python串口编程(一)

    在windows中,使用python进行串口编程需要安装一个Serial模块 pyserial: 下载地址:https://pypi.python.org/pypi/pyserial 下载完成后得到一 ...

  6. Wince C++串口编程

    C# 串口操作系列:http://blog.csdn.net/wuyazhe/article/category/695097 在windows程序设计与开发过程中,特别是涉及到开发嵌入式软硬件系统时, ...

  7. VirtualBox Ubuntu虚拟机串口编程

    VirtualBox Ubuntu虚拟机串口编程 此文适用于Ubuntu虚拟机实现串口通信,可以在虚拟机上运行程序,直接将windows下的串口映射到虚拟机上即可.在网上找了半天,没有找到合适的教程, ...

  8. 用户方式中线程的同步——Windows核心编程学习手札之八

    用户方式中线程的同步 --Windows核心编程学习手札之八 系统中所有线程都必须拥有对各种系统资源的访问权,这些资源包括内存堆栈.串口.文件.窗口和许多其他资源.如果一个线程需要独占对资源的访问权, ...

  9. CSerialPort多线程串口编程工具详解

    1.前言 既然有了MSComm这种简单粗暴的控件,为什么还需要CSerialPort类?这是因为与前者相比,这个类在程序的发布上不需要加入其他的文件,而且CSerialPort提供给我们的函数都是开放 ...

最新文章

  1. 万万没想到,我居然在机器人大会遇到了这些奇葩物种
  2. zabbix聚合图形创建脚本
  3. webpack 入口文件 php,webpack,jsx_webpack jsx 找不到入口文件,webpack,jsx - phpStudy
  4. 指针学习笔记(更新中)
  5. Nmap Windows 版本时区显示乱码
  6. 「服务端」node服务的监控预警系统架构
  7. transpose公式_EXCEL转置你是用公式还是选择性粘贴?
  8. Exception in thread main java.lang.NoClassDefFoundError
  9. Linux学习总结(28)——Linux主机加固
  10. linux查看图片的拍摄时间,ImageMagick 的一些高级图片查看技巧 | Linux 中国
  11. 声智科技陈孝良:没有好的语音数据收集,语音识别和交互不可能做好
  12. 【渝粤教育】电大中专建筑力学 (2)作业 题库
  13. ARMA 模型的参数估计 —— 增广最小二乘法
  14. 2009年考研数学一解析pdf
  15. Cadence PSpice 补充1:脉冲信号源的详细介绍与使用方法图文演示
  16. 海外网红营销是战略还是战术?从“PDCA循环”层面规划营销
  17. 餐厅点菜c语言程序代码,餐馆点菜系统C语言源代码.pdf
  18. 鬼故事之中学异事(01)
  19. MSDN无法打开的解决办法
  20. 我不想安于当前的限度,以达到所谓的幸福,回顾下2020年的我

热门文章

  1. Redis学习(StringHash)
  2. java hive建表_java jdbc 操作 hive 建表 load 数据
  3. Device ID 和Android ID的区别
  4. Burp 扩展武器库
  5. Google Chrome组策略配置白名单
  6. 万用表排查焊接线路(小白)
  7. 黄金分割寻优算法(0.618法)的Matlab实现
  8. 大厂技术博客汇总/美团/腾讯/网易/百度/头条
  9. OFDM循环前缀及其作用(矩阵视角解释)
  10. 3d激光SLAM:LIO-SAM框架---位姿融合输出