Win-API-03 串口读写
- 简 介
- 下 载
- 留 言
- 说 明
串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。串行接口 (Serial Interface) 是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
#include <stdio.h> #include <stdlib.h> #include <windows.h> HANDLE hComm; OVERLAPPED m_ov; COMSTAT comstat; DWORD m_dwCommEvents; //如果在调用CreateFile创建句柄时指 //定了FILE_FLAG_OVERLAPPED标志,那么调用ReadFile和WriteFile对该句柄进 //行的操作就应该是重叠的;如果未指定 //重叠标志,则读写操作应该是同步的 //在同步执行时,函数直到操作完成后才返回。这意味着同步执行时线程会被阻塞,从 //而导致效率下降。在重叠执行时,即使操作还未完成,这两个函数也会立即返回,费 //时的I/O操作在后台进行 bool openport(char *portname)//打开一个串口 { hComm = CreateFile(portname, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if (hComm == INVALID_HANDLE_VALUE) return FALSE; else return true; } bool setupdcb(int rate_arg) { DCB dcb; int rate= rate_arg; memset(&dcb,0,sizeof(dcb)); //在一段内存块中填充某个给定的值,是对较大的结构//体或数组进行清零操作的一种最快方法 if(!GetCommState(hComm,&dcb))//获取当前DCB配置 { return FALSE; } /* -------------------------------------------------------------------- */ // set DCB to configure the serial port dcb.DCBlength = sizeof(dcb); /* ---------- Serial Port Config ------- */ dcb.BaudRate = rate; dcb.Parity = NOPARITY; dcb.fParity = 0; dcb.StopBits = ONESTOPBIT; dcb.ByteSize = 8; dcb.fOutxCtsFlow = 0; dcb.fOutxDsrFlow = 0; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fDsrSensitivity = 0; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fOutX = 0; dcb.fInX = 0; /* ----------------- misc parameters ----- */ dcb.fErrorChar = 0; dcb.fBinary = 1; dcb.fNull = 0; dcb.fAbortOnError = 0; dcb.wReserved = 0; dcb.XonLim = 2; dcb.XoffLim = 4; dcb.XonChar = 0x13; dcb.XoffChar = 0x19; dcb.EvtChar = 0; /* -------------------------------------------------------------------- */ // set DCB if(!SetCommState(hComm,&dcb)) { return false; } else return true; } //在用readfile和writefile读写串行口时,需要考虑超时问题, 读写串口的超时有两 //种:间隔超时和总超时, 写操作只支持总超时,而读操作两种超时均支持, 如果所有 //写超时参数均为0,那么就不使用写超时。 bool setuptimeout(DWORD ReadInterval,DWORD ReadTotalMultiplier,DWORD ReadTotalconstant,DWORD WriteTotalMultiplier,DWORD WriteTotalconstant) { COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout=ReadInterval; //读间隔超时 timeouts.ReadTotalTimeoutConstant=ReadTotalconstant; //读时间系数 timeouts.ReadTotalTimeoutMultiplier=ReadTotalMultiplier; //读时间常量 timeouts.WriteTotalTimeoutConstant=WriteTotalconstant; // 写时间系数 timeouts.WriteTotalTimeoutMultiplier=WriteTotalMultiplier; //写时间常//量, 总超时的计算公式是:总超时=时间系数×要求读/写的字符数+时间常量 if(!SetCommTimeouts(hComm, &timeouts)) { return false; } else return true; } void ReceiveChar(){ BOOL bRead = TRUE; BOOL bResult = TRUE; DWORD dwError = 0; DWORD BytesRead = 0; char RXBuff; while(true){ bResult = ClearCommError(hComm, &dwError, &comstat); // 在使用ReadFile 函数进行读操作前,应先使用ClearCommError函数清除错误 if(comstat.cbInQue==0)// COMSTAT结构返回串口状态信息 //本文只用到了cbInQue成员变量,该成员变量的值代表输入缓冲区的字节数 continue; if(bRead){ bResult = ReadFile(hComm, // Handle to COMM port串口的句柄 &RXBuff,// RX Buffer Pointer// 读入的数据存储的地址,即读入的数据将存//储在以该指针的值为首地址的一片内存区 1,// Read one byte要读入的数据的字节数, &BytesRead, // Stores number of bytes read, 指向一个DWORD//数值,该数值返回读操作实际读入的字节数 &m_ov); // pointer to the m_ov structure// 重叠操作时,该参数指向一个OVERLAPPED结构,同步操作时,该参数为NULL printf("%c",RXBuff); if (!bResult){// 当ReadFile和WriteFile返回FALSE时,不一定就是操作失//败,线程应该调用GetLastError函数分析返回的结果 switch (dwError = GetLastError()){ case ERROR_IO_PENDING: bRead = FALSE; break; default:break; } }else{ bRead = TRUE; } } // close if (bRead) if (!bRead){ bRead = TRUE; bResult = GetOverlappedResult(hComm, // Handle to COMM port &m_ov, // Overlapped structure &BytesRead, // Stores number of bytes read TRUE); // Wait flag } } } BOOL WriteChar(BYTE* m_szWriteBuffer,DWORD m_nToSend){ BOOL bWrite = TRUE; BOOL bResult = TRUE; DWORD BytesSent = 0; HANDLE m_hWriteEvent; ResetEvent(m_hWriteEvent); if (bWrite){ m_ov.Offset = 0; m_ov.OffsetHigh = 0; // Clear buffer bResult = WriteFile(hComm, // Handle to COMM Port, 串口的句柄 m_szWriteBuffer, // Pointer to message buffer in calling finction // 即以该指针的值为首地址的nNumberOfBytesToWrite // 个字节的数据将要写入串口的发送数据缓冲区 m_nToSend, // Length of message to send, 要写入的数据的字节数 &BytesSent, // Where to store the number of bytes sent // 指向指向一个DWORD数值,该数值返回实际写入的字节数 &m_ov ); // Overlapped structure // 重叠操作时,该参数指向一个OVERLAPPED结构, // 同步操作时,该参数为NULL if (!bResult){ // 当ReadFile和WriteFile返回FALSE时,不一定就是操作失 //败,线程应该调用GetLastError函数分析返回的结果 DWORD dwError = GetLastError(); switch (dwError){ case ERROR_IO_PENDING: //GetLastError函数返回//ERROR_IO_PENDING。这说明重叠操作还未完成 // continue to GetOverlappedResults() BytesSent = 0; bWrite = FALSE; break; default:break; } } } // end if(bWrite) if (!bWrite){ bWrite = TRUE; bResult = GetOverlappedResult(hComm, // Handle to COMM port &m_ov, // Overlapped structure &BytesSent, // Stores number of bytes sent TRUE); // Wait flag // deal with the error code if (!bResult){ printf("GetOverlappedResults() in WriteFile()"); } } // end if (!bWrite) // Verify that the data size send equals what we tried to send if (BytesSent != m_nToSend){ printf("WARNING: WriteFile() error.. Bytes Sent: %d; Message Length: %d\n", BytesSent, strlen((char*)m_szWriteBuffer)); } return true; } void main(){ if(openport("com4")) printf("open comport success\n"); if(setupdcb(115200)) printf("setupDCB success\n"); if(setuptimeout(0,0,0,0,0)) //如果所有写超时参数均为0,那么就不使用写超时 printf("setuptimeout success\n"); PurgeComm(hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); // 在读写串口之前,还要用PurgeComm()函数清空缓冲区 //PURGE_TXABORT 中断所有写操作并立即返回,即使写操作还没有完成。 //PURGE_RXABORT 中断所有读操作并立即返回,即使读操作还没有完成。 //PURGE_TXCLEAR 清除输出缓冲区 //PURGE_RXCLEAR 清除输入缓冲区 //WriteChar("please send data now",20); printf("received data:\n"); ReceiveChar( ); system("pause"); } |