串口编程学习报告
引言:
串口是计算机上非常通用设备通信的协议,串行接口可以接收来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接收的串行数据流转换为并行数据字符供给CPU的器件,在日常生活中应用广泛,因此有必要对串口进行深入学习,首先谈到需要了解的硬件和软件方面的知识,然后可以整体的了解从硬件到软件数据收发的过程.
一.硬件部分
1、串口通信是一位一位的传输的,但是计算机处理数据是并行数据,所以当数据由计算机送至数据发送器时,首先用移位寄存器把串行数据转换为并行数据才能送入计算机处理。RS232C是用正负电压表示逻辑状态与TTL高低电压表示逻辑状态的规定不一样在这里就需要硬件部分有ETA与TTL电平转换电路这样才能和计算机和TTL的器件连接,并且下位机还需要有可编程的串口芯片这样可以通过编程控制我们需要达到的成效.
2、串口要遵守串口之间的协议,在物理方面就要求有相同的波特率来控制数据的发送速度,因此需要有波特率发生器. 具体的要多大的波特率可以根据需求通过控制寄存器来控制发生的波特率
3、根据同步/异步方式,有时要要求上位机与下位机时间同步,需要一个授时器授时.
4、每个下位机都有它自己的地址,这时当上位机要寻找这个下位机时就需要寻找它的地址,这里要一个地址译码器。
5、对于数据流的控件,可以是硬件流控制(RTC/CTS DTR/CTS等)也可以是软件流控制(XON/XOFF),不过现在大多都是用软件控制。
6、普遍情况下电脑都有一个RS232的串口,所以我们一般都采用RS232串口线,通常情况下无论使用的是九针的还是二十五针的只要接通2,3针就可以进行简单的收发数据测试DB-25,DB-9接口如下图。
7、串口都有一定的存贮功能,这些可以由下位机单片机上的RAM,移位寄存器或其它的外部存贮来实现的.
二.软件部分
WINDOWS API已经提供给我们通用接口方法程序,只要在适当的时候调用就可以完成自己想要的功能,在写一个串口程序中(打开/关闭,配置,读写)需要如下的API提供的方法:
1、打开串口:
Win32系统把文件的概念进行了扩展,无论是文件、通信设备、命名管道、邮件槽、磁盘、还是控制台,都是用API函数CreateFile来打开或创建的。该函数的原型为:
private static extern int CreateFile(
string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDistribution,
int dwFlagsAndAttributes,
int hTemplateFile);
lpFileName:将要打开的串口逻辑名,如“COM1”; dwDesiredAccess:指定串口访问的类型,可以是读取、写入或二者并列;
dwShareMode:指定共享属性,由于串口不能共享,该参数必须置为0;
lpSecurityAttributes:引用安全性属性结构,缺省值为NULL; dwCreationDistribution:创建标志,对串口操作该参数必须置为OPEN_EXISTING;
dwFlagsAndAttributes:属性描述,用于指定该串口是否进行异步操作,该值为FILE_FLAG_OVERLAPPED,表示使用异步的I/O;该值为0,表示同步I/O操作;
hTemplateFile:对串口而言该参数必须置为NULL;
2、关闭串口:
利用API函数关闭串口非常简单,只需使用CreateFile函数返回的句柄作为参数调用CloseHandle即可:
BOOL CloseHandle(
Int hObject; //handle to object to close
);
3、配置串口:
(1)缓冲区大小设置:打开串口后,可以对I/O口的缓冲区的大小进行设置,虽然Windows用I/O缓冲区来暂存串口输入和输出的数据。如果通信的速率较高,则应该设置较大的缓冲区。调用SetupComm函数可以设置串行口的输入和输出缓冲区的大小。
BOOL SetupComm(
Int hFile, // 通信设备的句柄
Int dwInQueue, // 输入缓冲区的大小(字节数)
Int dwOutQueue // 输出缓冲区的大小(字节数)
);
(2)超时设置:在用ReadFile和WriteFile读写串行口时,需要考虑超时问题。超时的作用是在指定的时间内没有读入或发送指定数量的字符,ReadFile或WriteFile的操作仍然会结束。要查询当前的超时设置应调用GetCommTimeouts函数,该函数会填充一个COMMTIMEOUTS结构。调用SetCommTimeouts可以用某个COMMTIMEOUTS结构的内容来设置超时。
读写串口的超时有两种情况:间隔超时和总超时。间隔超时是指在接收时两个字符之间的最大时延。总超时是指读写操作总共花费的最大时间。写操作只支持总超时,而读操作两种超时均支持。用COMMTIMEOUTS结构可以规定读写操作的超时。
COMMTIMEOUTS结构的定义为:
typedef struct _COMMTIMEOUTS {
int ReadIntervalTimeout; //读间隔超时
int ReadTotalTimeoutMultiplier; //读时间系数
int ReadTotalTimeoutConstant; //读时间常量
int WriteTotalTimeoutMultiplier; // 写时间系数
int WriteTotalTimeoutConstant; //写时间常量
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
COMMTIMEOUTS结构的成员都以毫秒为单位。总超时的计算公式是:
总超时=时间系数×要求读/写的字符数+时间常量
如果所有写超时参数均为0,那么就不使用写超时。如果ReadIntervalTimeout为0,那么就不使用读间隔超时。如果ReadTotalTimeoutMultiplier 和 ReadTotalTimeoutConstant 都为0,则不使用读总超时。如果读间隔超时被设置成MAXDWORD并且读时间系数和读时间常量都为0,那么在读一次输入缓冲区的内容后读操作就立即返回,而不管是否读入了要求的字符。
(3)对串口的一些属性配置我们会用到DCB, DCB结构包含了诸如波特率、数据位数、奇偶校验和停止位数等信息。在查询或配置串口的属性时,都要用DCB结构来作为缓冲区一般用CreateFile打开串口后,可以调用GetCommState函数来获取串口的初始配置。要修改串口的配置,应该先修改DCB结构,然后再调用SetCommState函数设置串口:
BOOL GetCommState(
Int hFile, //标识通讯端口的句柄
RefDCB lpDCB //指向一个设备控制块(DCB结构)的指针
);
SetCommState函数设置COM口的设备控制块:
BOOL SetCommState(
int hFile,
refDCB lpDCB
);
我们用到的DCB部分结构如下:
typedef struct _DCB{