串口(COM接口):串行接口(Serial Interface) 是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信。
计算机(上面的串口) <-> (开发板或其他设备上面的)串口
分别对应着的概念是:
DCE数据发送方串口A<-> DTE数据接收方串口B。A打算发送数据到B中
A设置RTS(Request To Send),表示:请求发送(数据到对方)
正常情况下,数据接收方,B不忙的时候,即不是busy的状态,则:B去设置对应的CTS(Clear To Send):表示OK,对方可以发送数据了
发送者A,可以直接发送数据给B,B也可以去接受数据,处理收到的数据;偶尔特殊的时候,B处于忙的状态,即busy,比如忙着处理上次发送的数据,所以没空理会你这次还要发的数据:那么此时B不去设置对应的CTS,表示自己忙,来不及处理你将要发送的数据,数据发送者A,就继续检测CTS,直到(数据接受者B,忙清了自己手上的活,有空接受数据了,然后)CTS被接受者B去设置对应的CTS,表示可以接受数据了,然后A才去发送数据给B。
DTR/DSR主要是用来做:建立链接,在数据发送和接受之前,先要建立A和B的连接。这时候,才用到DTR/DSR。
在串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据
串口通信的四个步骤:
CreateFile打开串口,无论是文件、通信设备、命名管道、邮件槽、磁盘、还是控制台,都是用API函数CreateFile来打开或创建的。
HANDLECreateFileA(
LPCSTR lpFileName, // 文件名
DWORD dwDesiredAccess, // 对文件或设备的请求访问
DWORD dwShareMode, //共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, //安全属性,
DWORD dwCreationDisposition, //创作倾向
DWORD dwFlagsAndAttributes,//标志和属性
HANDLE hTemplateFile //模板文件
);
GetCommState函数来获取串口的初始配置。需要通过一个DCB结构来进行。DCB结构包含了诸如波特率、数据位数、奇偶校验和停止位数等信息。在查询或配置串口的属性时,都要用DCB结构来作为缓冲区。要修改串口的配置,应该先修改DCB结构。
BOOL GetCommState(
HANDLE hFile, //标识通讯端口的句柄
LPDCB lpDCB //指向一个设备控制块(DCB结构)的指针
);
程序片段如下:
由SetCommState函数设置COM口的设备控制块:
BOOL SetCommState( HANDLE hFile, LPDCB lpDCB );
调用SetupComm函数可以设置串行口的输入和输出缓冲区的大小。如果通信的速率较高,则应该设置较大的缓冲区
使用ReadFile和WriteFile读写串口。
BOOLReadFile(
HANDLEhFile, // handle to file
LPVOIDlpBuffer, // data buffer
DWORD nNumberOfBytesToRead, // number of bytesto read
LPDWORD lpNumberOfBytesRead, // number of bytesread
LPOVERLAPPED lpOverlapped // overlapped buffer
);
BOOLWriteFile(
HANDLE hFile, //句柄
LPVOID lpBuffer, //数据缓冲区指针
DWORD nNumberOfBytesToRead, //写入的字节数
LPDWORD lpNumberOfBytesRead, //用于保存实际写入的字节数的存储区域 LPOVERLAPPED lpOverlapped //OVERAPPED结构体指针,一般取NULL
);
调用CloseHandle,使用CreateFile函数返回的句柄作为参数。
CloseHandle(m_hCom);
可以用 GetCommMask() 和 SetCommMask() 来获取或设定目前设定的通讯事件。 WaitCommEvent发出一个状态检查。
(1) BOOL GetCommMask(
HANDLE hFile, //标识通信端口的句柄
LPDWORDlpEvtMask //获取通信事件的指针
);
GetCommMask(m_hCom, &dwMask);
(2) BOOL SetCommMask(
HANDLE hFile, //标识通信端口的句柄
DWORD dwEvtMask //能够使能的通信事件
);
(3) BOOL WINAPI WaitCommEvent(
HANDLE hFile, //标识通信端口的句柄
LPDWORD lpEvtMask, //获取通信事件的指针
LPOVERLAPPED lpOverlapped //异步结构,用来保存异步操作结果。
);
WaitCommEvent(m_hCom,&dwMask, &os)
串口上可能发生的事件:
EV_BREAK |
收到BREAK信号 |
EV_CTS |
CTS(clear to send)线路发生变化 |
EV_DSR |
DST(Data Set Ready)线路发生变化 |
EV_ERR |
线路状态错误,包括了CE_FRAME / CE_OVERRUN / CE_RXPARITY 3种错误 |
EV_RING |
检测到振铃信号 |
EV_RLSD |
CD(Carrier Detect)线路信号发生变化 |
EV_RXCHAR |
输入缓冲区中已收到数据,即接收到一个字节并放入输入缓冲区 |
EV_RXFLAG |
使用SetCommState()函数设置的DCB结构中的等待字符已被传入输入缓冲区中 |
EV_TXEMPTY |
输出缓冲区中的数据已被完全送出 |
举例来说,可以用 SetCommMask() 设定事件为EV_RXCHAR, 那么在呼叫 WaitCommEvent() 时, 它会等到有字符可供读取时才会返回, 那么在它返回之后, 可以检查一下 lpEvtMask 中是否 set 了 EV_RXCHAR, 如果是的话就可以用 ReadFile() 去读取. 这样的话, 可以避免掉某些情形之下, 需要做polling 所引起效率不彰的问题.
Win32 中提供了EscapeCommFunction() 发送扩展COMM函数允许对几个硬件讯号做控制。参数如下表:
CLRDTR |
让 DTR OFF |
CLRRTS |
让 RTS OFF |
SETDTR |
让 DTR ON |
SETRTS |
让 RTS ON |
SETXOFF |
"仿真" 接收到 XOFF 字符 |
SETXON |
"仿真" 接收到 XON 字符 |
SETBREAK |
和 SetCommBreak() 的意思相同 |
CLRBREAK |
和 ClearCommBreak() 的意思相同 |
BOOLEscapeCommFunction(
HANDLE hFile, //标识通信端口的句柄
DWORD dwFunc //要执行的扩展函数
);
EscapeCommFunction(m_hCom, CLRDTR);
ClearCommError函数也提供通信状态用来表明为什么传输被停止。
BOOLClearCommError(
HANDLE hFile, //标识通信端口的句柄
LPDWORD lpErrors, //接收错误类型的指针
LPCOMSTAT lpStat //返回状态信息的指针
);
ClearCommError(hComm,&dwErrors, &comStat);
SetCommTimeouts函数用于为端口指定通信超时。调用GetCommTimeouts函数可以得到端口目前的超时。
BOOLSetCommTimeouts(
HANDLE hFile, //标识通信端口的句柄
LPCOMMTIMEOUTS lpCommTimeouts //指向超时值的指针
);
BOOLGetCommTimeouts(
HANDLE hFile, //标识通信端口的句柄
LPCOMMTIMEOUTS lpCommTimeouts //指向超时值的指针
);
GetCommTimeouts(m_hCom,&TimeOut);