VC++串口通讯程序

本文详细介绍使用VC++进行串口编程的方法,包括串口的打开与关闭、设置缓冲区长度、配置串口属性等核心步骤。此外还介绍了不同读写数据的方式、超时设置、错误处理等内容。



   WIN95界面下的VC++串口通讯程序在WIN32下是不建议对端口进行操作的,在WIN32中所有的设备都被看成是文件,串行口也不例外也是作为文件来进行处理的。这是我的一份关于串口编程的读书笔记,对于使 用VC进行编程的同行应该有一定的帮助。 

1.打开串口: 

   在Window 95下串行口作为文件处理,使用文件操作对串行口进行处理。使用CreateFile()打开串口,CreateFile()将返回串口的句柄。 
   HANDLE CreateFile( 
   LPCTSTR lpFileName, // pointer to name of the file 
   DWORD dwDesiredAccess, // access (read-write) mode 
   DWORD dwShareMode, // share mode 
   LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes 
   DWORD dwCreationDistribution, // how to create 
   DWORD dwFlagsAndAttributes, // file attributes 
   HANDLE hTemplateFile // handle to file with attributes to copy 
   ); 
   lpFileName: 指明串口制备,例:COM1,COM2 
   dwDesiredAccess: 指明串口存取方式,例:GENERIC_READ|GENERIC_WRITE 
   dwShareMode: 指明串口共享方式 
   lpSecurityAttributes: 指明串口的安全属性结构,NULL为缺省安全属性 
   dwCreateionDistribution: 必须为OPEN_EXISTIN 
   dwFlagAndAttributes: 对串口唯一有意义的是FILE_FLAG_OVERLAPPED 
   hTemplateFile: 必须为NULL 

2.关闭串口: 

   CloseHandle(hCommDev); 

3.设置缓冲区长度: 

   BOOL SetupComm( 
   HANDLE hFile, // handle of communications device 
   DWORD dwInQueue, // size of input buffer 
   DWORD dwOutQueue // size of output buffer 
   ); 

4.COMMPROP结构: 

   可使用GetCommProperties()取得COMMPROP结构,COMMPROP结构中记载了系统支持的各项设置。 
   typedef struct _COMMPROP { // cmmp 
   WORD wPacketLength; // packet size, in bytes 
   WORD wPacketVersion; // packet version 
   DWORD dwServiceMask; // services implemented 
   DWORD dwReserved1; // reserved 
   DWORD dwMaxTxQueue; // max Tx bufsize, in bytes 
   DWORD dwMaxRxQueue; // max Rx bufsize, in bytes 
   DWORD dwMaxBaud; // max baud rate, in bps 
   DWORD dwProvSubType; // specific provider type 
   DWORD dwProvCapabilities; // capabilities supported 
   DWORD dwSettableParams; // changeable parameters 
   DWORD dwSettableBaud; // allowable baud rates 
   WORD wSettableData; // allowable byte sizes 
   WORD wSettableStopParity; // stop bits/parity allowed 
   DWORD dwCurrentTxQueue; // Tx buffer size, in bytes 
   DWORD dwCurrentRxQueue; // Rx buffer size, in bytes 
   DWORD dwProvSpec1; // provider-specific data 
   DWORD dwProvSpec2; // provider-specific data 
   WCHAR wcProvChar[1]; // provider-specific data 
   } COMMPROP; 
   dwMaxBaud: 
   BAUD_075 75 bps 
   BAUD_110 110 bps 
   BAUD_134_5 134.5 bps 
   BAUD_150 150 bps 
   BAUD_300 300 bps 
   BAUD_600 600 bps 
   BAUD_1200 1200 bps 
   BAUD_1800 1800 bps 
   BAUD_2400 2400 bps 
   BAUD_4800 4800 bps 
   BAUD_7200 7200 bps 
   BAUD_9600 9600 bps 
   BAUD_14400 14400 bps 
   BAUD_19200 19200 bps 
   BAUD_38400 38400 bps 
   BAUD_56K 56K bps 
   BAUD_57600 57600 bps 
   BAUD_115200 115200 bps 
   BAUD_128K 128K bps 
   BAUD_USER Programmable baud rates available 
   dwProvSubType: 
   PST_FAX 传真设备 
   PST_LAT LAT协议 
   PST_MODEM 调制解调器设备 
   PST_NETWORK_BRIDGE 未指定的网桥 
   PST_PARALLELPORT 并口 
   PST_RS232 RS-232口 
   PST_RS422 RS-422口 
   PST_RS423 RS-432口 
   PST_RS449 RS-449口 
   PST_SCANNER 扫描仪设备 
   PST_TCPIP_TELNET TCP/IP Telnet协议 
   PST_UNSPECIFIED 未指定 
   PST_X25 X.25标准 
   dwProvCapabilities 
   PCF_16BITMODE 支持特殊的16位模式 
   PCF_DTRDSR 支持DTR(数据终端就绪)/DSR(数据设备就绪) 
   PCF_INTTIMEOUTS 支持区间超时 
   PCF_PARITY_CHECK 支持奇偶校验 
   PCF_RLSD 支持RLSD(接收线信号检测) 
   PCF_RTSCTS 支持RTS(请求发送)/CTS(清除发送) 
   PCF_SETXCHAR 支持可设置的XON/XOFF 
   PCF_SPECIALCHARS 支持特殊字符 
   PCF_TOTALTIMEOUTS 支持总(占用时间)超时 
   PCF_XONXOFF 支持XON/XOFF流控制 
   标准RS-232和WINDOW支持除PCF_16BITMODE和PCF_SPECIALCHAR外的所有功能 
   dwSettableParams 
   SP_BAUD 可配置波特率 
   SP_DATABITS 可配置数据位个数 
   SP_HANDSHAKING 可配置握手(流控制) 
   SP_PARITY 可配置奇偶校验模式 
   SP_PARITY_CHECK 可配置奇偶校验允许/禁止 
   SP_RLSD 可配置RLSD(接收信号检测) 
   SP_STOPBITS 可配置停止位个数 
   标准RS-232和WINDOW支持以上所有功能 
   wSettableData 
   DATABITS_5 5个数据位 
   DATABITS_6 6个数据位 
   DATABITS_7 7个数据位 
   DATABITS_8 8个数据位 
   DATABITS_16 16个数据位 
   DATABITS_16X 通过串行硬件线路的特殊宽度路径 
   WINDOWS 95支持16的所有设置 

5.DCB结构: 

   typedef struct _DCB {// dcb 
   DWORD DCBlength; // sizeof(DCB) 
   DWORD BaudRate; // current baud rate 
   指定当前的波特率 
   DWORD fBinary: 1; // binary mode, no EOF check 
   指定是否允许二进制模式, 
   WINDOWS 95中必须为TRUE 
   DWORD fParity: 1; // enable parity checking 
   指定奇偶校验是否允许 
   DWORD fOutxCtsFlow:1; // CTS output flow control 
   指定CTS是否用于检测发送控制。 
   当为TRUE是CTS为OFF,发送将被挂起。 
   DWORD fOutxDsrFlow:1; // DSR output flow control 
   指定CTS是否用于检测发送控制。 
   当为TRUE是CTS为OFF,发送将被挂起。 
   DWORD fDtrControl:2; // DTR flow control type 
   DTR_CONTROL_DISABLE值将DTR置为OFF, DTR_CONTROL_ENABLE值将DTR置为ON, DTR_CONTROL_HANDSHAKE允许DTR"握手",DWORD fDsrSensitivity:1; // DSR sensitivity 当该值为TRUE时DSR为OFF时接收的字节被忽略 
   DWORD fTXContinueOnXoff:1; // XOFF continues Tx 
   指定当接收缓冲区已满,并且驱动程序已经发 
   送出XoffChar字符时发送是否停止。 
   TRUE时,在接收缓冲区接收到缓冲区已满的字节XoffLim且驱动程序已经发送出XoffChar字符中止接收字节之后,发送继续进行。 
   FALSE时,在接收缓冲区接收到代表缓冲区已空的字节XonChar且驱动程序已经发送出恢复发送的XonChar之后,发送继续进行。 
   DWORD fOutX: 1; // XON/XOFF out flow control 
   TRUE时,接收到XoffChar之后便停止发送 
   接收到XonChar之后将重新开始 
   DWORD fInX: 1; // XON/XOFF in flow control 
   TRUE时,接收缓冲区接收到代表缓冲区满的XoffLim之后,XoffChar发送出去 
   接收缓冲区接收到代表缓冲区空的XonLim之后,XonChar发送出去 
   DWORD fErrorChar: 1; // enable error replacement 
   该值为TRUE且fParity为TRUE时,用ErrorChar 成员指定的字符代替奇偶校验错误的接收字符 
   DWORD fNull: 1; // enable null stripping 
   TRUE时,接收时去掉空(0值)字节 
   DWORD fRtsControl:2; // RTS flow control 
   RTS_CONTROL_DISABLE时,RTS置为OFF 
   RTS_CONTROL_ENABLE时, RTS置为ON 
   RTS_CONTROL_HANDSHAKE时, 
   当接收缓冲区小于半满时RTS为ON 
   当接收缓冲区超过四分之三满时RTS为OFF 
   RTS_CONTROL_TOGGLE时, 
   当接收缓冲区仍有剩余字节时RTS为ON ,否则缺省为OFF 
   DWORD fAbortOnError:1; // abort reads/writes on error 
   TRUE时,有错误发生时中止读和写操作 
   DWORD fDummy2:17; // reserved 
   未使用 
   WORD wReserved; // not currently used 
   未使用,必须为0 
   WORD XonLim; // transmit XON threshold 
   指定在XON字符发送这前接收缓冲区中可允许的最小字节数 
   WORD XoffLim; // transmit XOFF threshold 
   指定在XOFF字符发送这前接收缓冲区中可允许的最小字节数 
   BYTE ByteSize; // number of bits/byte, 4-8 
   指定端口当前使用的数据位 
   BYTE Parity; // 0-4=no,odd,even,mark,space 
   指定端口当前使用的奇偶校验方法,可能为: 
   EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY 
   BYTE StopBits; // 0,1,2 = 1, 1.5, 2 
   指定端口当前使用的停止位数,可能为: 
   ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS 
   char XonChar; // Tx and Rx XON character 
   指定用于发送和接收字符XON的值 
   char XoffChar; // Tx and Rx XOFF character 
   指定用于发送和接收字符XOFF值 
   char ErrorChar; // error replacement character 
   本字符用来代替接收到的奇偶校验发生错误时的值 
   char EofChar; // end of input character 
   当没有使用二进制模式时,本字符可用来指示数据的结束 
   char EvtChar; // received event character 
   当接收到此字符时,会产生一个事件 
   WORD wReserved1; // reserved; do not use 未使用 
   } DCB; 

6.改变端口设置 

   使用如下的两个方法 
   BOOL GetCommState(hComm,&dcb); 
   BOOL SetCommState(hComm,&dcb); 

7.改变普通设置 

   BuildCommDCB(szSettings,&DCB); 
   szSettings的格式:baud parity data stop 
   例: "baud=96 parity=n data=8 stop=1" 
   简写:"96,N,8,1" 
   szSettings 的有效值 
   baud: 
   11 or 110 = 110 bps 
   15 or 150 = 150 bps 
   30 or 300 = 300 bps 
   60 or 600 = 600 bps 
   12 or 1200 = 1200 bps 
   24 or 2400 = 2400 bps 
   48 or 4800 = 4800 bps 
   96 or 9600 = 9600 bps 
   19 or 19200= 19200bps 
   parity: 
   n=none 
   e=even 
   o=odd 
   m=mark 
   s=space 
   data: 
   5,6,7,8 
   StopBit 
   1,1.5,2 

8.COMMCONFIG结构: 

   typedef struct _COMM_CONFIG { 
   DWORD dwSize; 
   WORD wVersion; 
   WORD wReserved; 
   DCB dcb; 
   DWORD dwProviderSubType; 
   DWORD dwProviderOffset; 
   DWORD dwProviderSize; 
   WCHAR wcProviderData[1]; 
   } COMMCONFIG, *LPCOMMCONFIG; 
   可方便的使用BOOL CommConfigDialog( 
   LPTSTR lpszName, 
   HWND hWnd, 
   LPCOMMCONFIG lpCC); 
   来设置串行口。 

9.超时设置: 

   可通过COMMTIMEOUTS结构设置超时, 
   typedef struct _COMMTIMEOUTS { 
   DWORD ReadIntervalTimeout; 
   DWORD ReadTotalTimeoutMultiplier; 
   DWORD ReadTotalTimeoutConstant; 
   DWORD WriteTotalTimeoutMultiplier; 
   DWORD WriteTotalTimeoutConstant; 
   } COMMTIMEOUTS,*LPCOMMTIMEOUTS; 
   区间超时:(仅对从端口中读取数据有用)它指定在读取两个字符之间要经历的时间 
   总超时: 当读或写特定的字节数需要的总时间超过某一阈值时,超时触发. 
   超时公式: 
   ReadTotalTimeout = (ReadTotalTimeoutMultiplier * bytes_to_read) 
   + ReadToTaltimeoutConstant 
   WriteTotalTimeout = (WriteTotalTimeoutMuliplier * bytes_to_write) 
   + WritetoTotalTimeoutConstant 
   NOTE:在设置超时时参数0为无限等待,既无超时 
   参数MAXDWORD为立即返回 
   超时设置: 
   GetCommTimeouts(hComm,&timeouts); 
   SetCommTimeouts(hComm,&timeouts); 

10.查询方式读写数据 

 例程: 
   COMMTIMEOUTS to; 
   DWORD ReadThread(LPDWORD lpdwParam) 
   { 
   BYTE inbuff[100]; 
   DWORD nBytesRead; 
   if(!(cp.dwProvCapabilities&PCF_INTTIMEOUTS)) 
   return 1L; 
   memset(&to,0,sizeof(to)); 
   to.ReadIntervalTimeout = MAXDWORD; 
   SetCommTimeouts(hComm,&to); 
   while(bReading) 
   { 
   if(!ReadFile(hComm,inbuff,100,&nBytesRead,NULL)) 
   locProcessCommError(GetLastError()); 
   else 
   if(nBytesRead) 
   locProcessBytes(inbuff,nBytesRead); 
   } 
   PurgeComm(hComm,PURGE_RXCLEAR); 
   return 0L; 
   } 
   NOTE: 
   PurgeComm()是一个清除函数,它可以中止任何未决的后台读或写,并且可以冲掉I/O缓冲区. 
   BOOL PurgeComm(HANDLE hFile,DWORD dwFlags); 
   dwFlages的有效值: 
   PURGE_TXABORT: 中止后台写操作 
   PRUGE_RXABORT: 中止后台读操作 
   PRUGE_TXCLEAR: 清除发送缓冲区 
   PRUGE_RXCLEAR: 清除接收缓冲区 
  技巧: 
   可通过ClearCommError()来确定接收缓区中处于等待的字节数。 
   BOOL ClearCommError( 
   HANDLE hFile, // handle to communications device 
   LPDWORD lpErrors, // pointer to variable to receive error codes 
   LPCOMSTAT lpStat // pointer to buffer for communications status 
   ); 
   ClearCommError()将返回一个COMSTAT结构: 
   typedef struct _COMSTAT { // cst 
   DWORD fCtsHold : 1; // Tx waiting for CTS signal 
   DWORD fDsrHold : 1; // Tx waiting for DSR signal 
   DWORD fRlsdHold : 1; // Tx waiting for RLSD signal 
   DWORD fXoffHold : 1; // Tx waiting, XOFF char rec`d 
   DWORD fXoffSent : 1; // Tx waiting, XOFF char sent 
   DWORD fEof : 1; // EOF character sent 
   DWORD fTxim : 1; // character waiting for Tx 
   DWORD fReserved : 25; // reserved 
   DWORD cbInQue; // bytes in input buffer 
   DWORD cbOutQue; // bytes in output buffer 
   } COMSTAT, *LPCOMSTAT; 
   其中的cbInQue和cbOutQue中即为缓冲区字节。 

11.同步I/O读写数据 

   COMMTIOMOUTS to; 
   DWORD ReadThread(LPDWORD lpdwParam) 
   { 
   BYTE inbuff[100]; 
   DWORD nByteRead,dwErrorMask,nToRead; 
   COMSTAT comstat; 
   if(!cp.dwProvCapabilities&PCF_TOTALTIMEOUTS) 
   return 1L; 
   memset(&to,0,sizeof(to)); 
   to.ReadTotalTimeoutMultiplier = 5; 
   to.ReadTotalTimeoutConstant = 50; 
   SetCommTimeouts(hComm,&to); 
   while(bReading) 
   { 
   ClearCommError(hComm,&dwErrorMask,&comstat); 
   if(dwErrorMask) 
   locProcessCommError(dwErrorMask); 
   if(comstat.cbInQue >100) 
   nToRead = 100; 
   else 
   nToRead = comstat.cbInQue; 
   if(nToRead == 0) 
   continue; 
   if(!ReadFile(hComm,inbuff,nToRead,&nBytesRead,NULL)) 
   locProcessCommError(GetLastError()); 
   else 
   if(nBytesRead) 
   locProcessBytes(inbuff,nBytesRead); 
   } 
   return 0L; 
   } 

12.异步I/O读写数据 

   当CreateFile()中的fdwAttrsAndFlags参数为FILE_FLAG_OVERLAPPEN时, 端口是为异步I/O打开的,此时可以在ReadFile的最后一个参数中指定一个OVERLAPPED结构,使数据的读操作在后台进行。WINDOWS 95包括了异步I/O的许多变种。 
   typedef struct _OVERLAPPED { 
   DWORD Internal; 
   DWORD InternalHigh; 
   DWORD Offset; 
   DWORD OffsetHigh; 
   HANDLE hEvent; 
   } OVERLAPPED; 
   对于串行口仅hEvent成员有效,其于成员必须为0。 
   例程: 
   COMMTIMEOUTS to; 
   ... 
   DWORD ReadThread((LPDWORD lpdwParam) 
   { 
   BYTE inbuff[100]; 
   DWORD nRytesRead,endtime,lrc; 
   static OVERLAPPED o; 
   if(!cp.dwProvCapabilities & PCF_TOTALTIMEOUTS) 
   return 1L; 
   memset(&to,0,sizeof(to)); 
   to.ReadTotalTimeoutMultiplier = 5; 
   to.ReadTotalTimeoutConstant = 1000; 
   SetCommTimeouts(hComm,&to); 
   o.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); 
   while(bReading) 
   { 
   if(!ReadFile(hComm,inbuff,10,&nBytesRead,&o)) 
   { 
   nBytesRead = 0; 
   if(lrc=GetLastError() == ERROR_IO_PENDING) 
   { 
   endtime = GetTickCount() + 1000; 
   while(!GetOverlappedResult(hComm,&o,&nBytesRead,FALSE)) 
   if(GetTickCount() > endtime) break; 
   } 
   if(nBytesRead) locProcessBytes(inbuff,nBytesRead); 
   } 
   else 
   { 
   if(nBytesRead) locProcessBytes(inbuff,nBytesRead); 
   ResetEvent(o.hEvent); 
   } 
   } 
   PurgeComm(hComm,PURGE_RXCLEAR); 
   return 0L; 
   } 
   这一例程是对一开始读缓冲区就读到所需的字节时的处理: 
   while(bReading) 
   { 
   if(!ReadFile(hComm,inbuff,10,&nBytesRead,&o)) 
   { 
   if((lrc=GetLastError()) ==ERROR_IO_PENDING) 
   { 
   if(GetOverlappedResult(hComm,&o,&nBytesRead,TRUE)) 
   { 
   if(nBytesRead) 
   locProcessBytesa(inbuff,nBytesRead); 
   } 
   else 
   locProcessCommError(GetLastError()); 
   } 
   else 
   locProcessCommError(GetLastError)); 
   } 
   else 
   if(nBytesRead) locProcessBytes(inbuff,nBytesRead); 
   ResetEvent(o.hEvent); 
   } 

13.事件驱I/O读写: 

   GetCommMask(hComm,&dwMask) 
   Windows 95报告给应用程序的事件由此方法返回。 
   SetCommMasl(hComm,&dwMask) 
   添加或修改Windows 95所报告的事件列表。 
   事件掩码如下: 
   EV_BREAK 检测到输入为止 
   EV_CTS CTS(清除发送)信号改变状态 
   EV_DSR DSR(数据设置就绪)信号改变状态 
   EV_ERR 发生了线路状态错误. 
   线路状态错误为: 
   CE_FRAME(帧错误) 
   CE_OVERRUN(接收缓冲区超限) 
   CE_RXPARITY(奇偶校验错误) 
   EV_RING 检测到振铃 
   EV_RLSD RLSD(接收线路信号检测)信号改变状态 
   EV_EXCHAR 接收到一个字符,并放入输入缓冲区 
   EV_RXFLAG 接收到事件字符(DCB成员的EvtChar成员),度放入输入缓冲区 
   EV_TXEMPTY 输出缓冲区中最后一个字符发送出去 
   在用SetCommMask指定了有用的事件后,应用程序可调用WaitCommEvent()来等待事件发生. 
   BOOL WaitCommEvent( 
   HANDLE hFile, // handle of communications device 
   LPDWORD lpEvtMask, // address of variable for event that occurred 
   LPOVERLAPPED lpOverlapped, // address of overlapped structure 
   ); 
   此方法可以以同步或异步方式操作 
   例程: 
   COMMTIMEOUTS to; 
   ... 
   DWORD ReadTherad(LPDWORD lpdwParam) 
   { 
   BYTE binbuff[100]; 
   DWORD nBytesRead,dwEvent,dwError; 
   COMSTAT cs; 
   SetCommMask(hComm,EV_RXHAR); 
   while(bReading) 
   { 
   if(WaitCommEvent(hComm,&dwEvent,NULL)) 
   { 
   ClearCommError(hComm,&dwError,&cs); 
   if((dwEvent&EV_RXCHAR)&&cs.cbInQue) 
   { 
   if(!ReadFile(hComm,inbuff,cs.cbInQue,&nBytesRead,NULL) 
   locProcessCommError(GetLastError()); 
   } 
   else 
   { 
   if(nByteRead) 
   locProcessBytes(inbuff,nBytesRead); 
   } 
   else 
   locProcessCommError(GetLastError()); 
   } 
   PurgeComm(hComm,PURGE_RXCLEAR); 
   return 0L; 
   } 
   NOTE: SetCommMask(hComm,0)可使WaitCommEvent()中止. 
   可使用GetCommmodemStatus()方法,例程: 
   if(cp.dwProvCapabilities&PCF_RTSCTS) 
   { 
   SetCommMask(hComm,EV_CTS); 
   WaitCommEvent(hComm,&dwMask,NULL); 
   if(dwMask&EV_CTS) 
   { 
   GetCommModemStatus(hComm,&dwStatus) 
   if(dwStatus&MS_CTS_ON) /* CTS stransition OFF-ON */ 
   else /* CTS stransition ON-OFF */ 
   } 
   } 
   MS_CTS_ON CTS为ON 
   MS_DSR_ON DSR为ON 
   MS_RING_ON RING为ON 
   MS_ELSD_ON RLSD为ON 

14.错误 

   当发生错误时应用方法ClearCommError(hComm,&dwErrorMask,&constat)得到错误掩码。 
   CE_BREAK 中止条件 
   CE_FRAME 帧错误 
   CW_IOE 一般I/O错误,常伴有更为详细的错误标志 
   CE_MODE 不支持请求的模式 
   CE_OVERRUN 缓冲区超限下一个字符将丢失 
   CE_RXOVER 接收缓冲区超限 
   CE_RXPARITY 奇偶校验错误 
   CE_TXFULL 发送缓冲区满 
   CE_DNS 没有选择并行设备 
   CE_PTO 并行设备发生超时 
   CE_OOP 并行设备缺纸 

15.控制命令 

   EscapeCommFunction()可将硬件信号置ON或OFF,模拟XON或XOFF 

  BOOL EscapeCommFunction( 
   HANDLE hFile, // handle to communications device 
   DWORD dwFunc // extended function to perform 
   ); 
   dwFunc的有效值(可用’|’同时使用多个值) 
   CLRDTR DTR置OFF 
   CLRRTS RTS置OFF 
   SETDTR STR置ON 
   SETRTS TRS置ON 
   SETXOFF 模拟XOFF字符的接收 
   SETXON 模拟XON字符的接收 
   SETBREAK 在发送中产生一个中止 
   CLRBREAK 在发送中清除中止  
 


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值