c语言串口通讯过程?

Python019

c语言串口通讯过程?,第1张

分接收端和发送端。

接收端:

1·打开com1端口

fd=fopen("/dev/ttys0",方式)

2·取得当前串口值,保存到结构体变量oldtio

tcgetattr(fd,&oldtio)

3·串口结构体变量newtio清0.

bzero(&newtio,sizeof(newtio))

4·设置串口参数

主要设置比特率、是否忽略奇偶校验错误,启用正规模式等等。

接收端

1·打开com端口

2·取得当前串口值

3·串口结构体变量清0

4·设置串口参数。

基本方法是使用CreateFile来建立一个串口文件,然后用overlap的方式进行读写

#define SERAIL_PORT_BUF_MAX (1024*8)

typedef HRESULT (*PFN_CMD_PARSE_DATA)(HANDLE hParseApp, LPCSTR szRspCmd, int nCmdLen)

class CUsbSrvApp// : public CWinApp

{

public:

CUsbSrvApp()

~CUsbSrvApp()

BOOL OnSendData(const char *szBuf, int nLen)// 发送数据

int ComConnect(CString strPort)// 连接COM口

HANDLE OpenComPort(CString strPort, int nBaudRate, int nDataBits, int nStopBits, int nParity, int nFlowCtrlType)// 打开串口

void Close()// 关闭串口

HANDLE m_hCom

BOOL m_bConnected

OVERLAPPED m_OverlappedRead

OVERLAPPED m_OverlappedWrite

CWinThread *m_pThread

PFN_CMD_PARSE_DATA m_pRspCmdFunc// 用来处理接受数据的CALLBACK

HANDLE m_hParseApp

}

CUsbSrvApp::CUsbSrvApp()

{

// TODO: add construction code here,

// Place all significant initialization in InitInstance

m_bConnected = false

m_hCom = NULL

m_pRspCmdFunc = NULL

}

CUsbSrvApp::~CUsbSrvApp()

{

}

//打开串口通信,并返回串口句柄

HANDLE CUsbSrvApp::OpenComPort(CString strPortName,

int nBaudRate,

int nDataBits,

int nStopBits,

int nParity,

int nFlowCtrlType)

{

DCB dcb

COMMTIMEOUTS CommTimeOuts

COMMCONFIG ComConfig

HANDLE hComPort

CString strPort

strPort.Format("\\\\.\\%s",strPortName)// COM口的文件名应该是 \\.\COMXX

//打开窗口其实就是创建一个文件

hComPort = CreateFile(strPort,

GENERIC_READ | GENERIC_WRITE,

FILE_SHARE_READ | FILE_SHARE_WRITE,

NULL,

OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,

NULL)

if (INVALID_HANDLE_VALUE == hComPort)

return INVALID_HANDLE_VALUE

// 设置一些COM口通讯参数和OVERLAP

CommTimeOuts.ReadIntervalTimeout = -1

CommTimeOuts.ReadTotalTimeoutConstant = 0

CommTimeOuts.ReadTotalTimeoutMultiplier = 0

CommTimeOuts.WriteTotalTimeoutConstant = 0

CommTimeOuts.WriteTotalTimeoutMultiplier = 0x1388

SetCommTimeouts( m_hCom, &CommTimeOuts )

SetDefaultCommConfig(strPortName, &ComConfig, sizeof(COMMCONFIG))

GetCommState(m_hCom, &dcb )

dcb.BaudRate = nBaudRate

dcb.ByteSize = nDataBits

dcb.StopBits = nStopBits

dcb.fParity = (NOPARITY != nParity)

dcb.Parity = nParity

//set the receive char

dcb.EvtChar = 0x0D

switch(nFlowCtrlType)

{

case 0: //no flow control

break

case 1://HARD_FLOW_CTRL:

dcb.fOutxCtsFlow = TRUE

dcb.fOutxDsrFlow = TRUE

dcb.fDtrControl = DTR_CONTROL_DISABLE

dcb.fDsrSensitivity = TRUE

dcb.fRtsControl = RTS_CONTROL_TOGGLE

break

case 2://SOFT_FLOW_CTRL:

dcb.fOutX = TRUE

dcb.fInX = TRUE

break

}

BuildCommDCB(_T("baud=115200 parity=N data=8 stop=1"),&dcb)

SetCommState(hComPort, &dcb )

SetCommMask(hComPort, 0)

SetCommMask(hComPort, EV_RXCHAR|EV_CTS|EV_DSR|EV_RLSD|EV_RING)

SetupComm( hComPort, SERAIL_PORT_BUF_MAX,SERAIL_PORT_BUF_MAX)

//clear read and write buffer

PurgeComm( hComPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR )

return hComPort

}

void CUsbSrvApp::Close()

{

if(m_bConnected)

{

m_bConnected = false

CloseHandle(m_hCom)

m_hCom = NULL

}

}

// 这个线程是监视串口数据,一旦有数据则读取并调用CALLBACK通知客户端

UINT ReceiveComData(LPVOID pParam)

{

CUsbSrvApp *pUsbSrv = (CUsbSrvApp *)pParam

HANDLE hComPort = pUsbSrv->m_hCom

DWORD dwEvtMask=0

DWORD dwErrorFlags

SetCommMask( hComPort, EV_RXCHAR)

OVERLAPPED osRead

osRead.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL)

DWORD dwTransfer = 0

while(pUsbSrv->m_bConnected)

{

if( !WaitCommEvent( hComPort, &dwEvtMask,&osRead))

{

if( GetLastError()== ERROR_IO_PENDING)

{

WaitForSingleObject(osRead.hEvent, INFINITE)

if(dwEvtMask&EV_RXCHAR==EV_RXCHAR)

{

COMSTAT ComStat={0}

DWORD dwReadLen = 0

DWORD dwBytesRead = 0

DWORD dwTotalLen = 0

ClearCommError(hComPort, &dwErrorFlags, &ComStat )

dwTotalLen = ComStat.cbInQue

dwReadLen = (SERAIL_PORT_BUF_MAX >dwTotalLen)?dwTotalLen:SERAIL_PORT_BUF_MAX

BYTE *pBuf = new BYTE[dwTotalLen+1]

memset(pBuf, 0 , dwTotalLen+1)

DWORD nReadBufLen=0

while(dwTotalLen>0)

{

if(FALSE == ReadFile( hComPort, pBuf+nReadBufLen,dwReadLen, &dwBytesRead,&pUsbSrv->m_OverlappedRead))

{

if(GetLastError() == ERROR_IO_PENDING)

{

GetOverlappedResult(hComPort,&osRead, &dwTransfer, TRUE )

}

break

}

nReadBufLen +=dwBytesRead

dwTotalLen -=dwBytesRead

dwReadLen -= dwBytesRead

dwReadLen = (SERAIL_PORT_BUF_MAX>dwReadLen)?dwReadLen:SERAIL_PORT_BUF_MAX

}

if(pUsbSrv->m_pRspCmdFunc!=NULL&&nReadBufLen!=0)

{

pUsbSrv->m_pRspCmdFunc(pUsbSrv->m_hParseApp, (char*)pBuf,nReadBufLen)

}

delete pBuf

ClearCommError(hComPort, &dwErrorFlags, &ComStat )

int len =0//= m_retList.GetSize()

}//endif if(dwEvtMask&EV_RXCHAR==EV_RXCHAR)

}//endif if( GetLastError()== ERROR_IO_PENDING)

}//endif if( !WaitCommEvent( hComPort, &dwEvtMask,&o))

else

{

if(GetLastError() == ERROR_IO_PENDING) {

GetOverlappedResult(hComPort, &osRead, &dwTransfer, TRUE )// sleep thread

}

}

Sleep(1)

} //endwhile while(m_bConnected)

return 0

}

int CUsbSrvApp::ComConnect(CString strPort)

{

int nBaudRate = 115200

int nDataBits = 8

int nStopBits = 1

int nParity = 0

int nFlowCtrl = 1

if (NULL != m_hCom || m_bConnected)

{

return 0

}

m_hCom = OpenComPort(strPort,nBaudRate,nDataBits,nStopBits,nParity,nFlowCtrl)

if( INVALID_HANDLE_VALUE == m_hCom)

{

m_hCom = NULL

return 0

}

memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) )

memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) )

m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL )

m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL )

m_pThread = AfxBeginThread( ReceiveComData,(void*)this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED ,NULL )

if( NULL == m_pThread )

{

CloseHandle( m_hCom )

m_hCom = NULL

return FALSE

}

else

{

m_bConnected = TRUE

m_pThread->ResumeThread( )

}

return TRUE

}

int CUsbSrvApp::OnSendData(const char *szBuf, int nLen)

{

BOOL bWriteStat

BOOL bWrite = TRUE

DWORD dwBytesWrite = 0

DWORD dwBytesWritten = 0

int dwByteswrittenTotal = 0

if (NULL == m_hCom)

return 0

int nSentTimes=0

while(dwByteswrittenTotal<nLen&&nSentTimes<10)

{

nSentTimes++

dwBytesWrite = nLen-dwByteswrittenTotal

bWriteStat = WriteFile( m_hCom, szBuf+dwByteswrittenTotal, dwBytesWrite, &dwBytesWritten, &m_OverlappedWrite )

if( !bWriteStat)

{

if ( GetLastError() == ERROR_IO_PENDING )

{

dwBytesWritten = 0

bWrite = FALSE

}

}

if (!bWrite)

{

bWrite = TRUE

bWriteStat = GetOverlappedResult(m_hCom, // Handle to COMM port

&m_OverlappedWrite, // Overlapped structure

&dwBytesWritten, // Stores number of bytes sent

TRUE)// Wait flag

//deal with the error code

}

dwByteswrittenTotal += dwBytesWritten

}

if(dwByteswrittenTotal<nLen)

return 0

else

return 1

}

windows下对串口的操作可以通过WindowsAPI进行,也可以通过Linux下的read什么的直接操作,但是这种情况需要了解电路结构,比较麻烦,第三种有第三方提供的库,但是大多数针对C++,所以可能比较难找到顺手的第三方库.那么,接下来就见要介绍一下串口通信用WindowsAPI通信的方式.我们会发现,在文件名的位置填上"comX" X表示com口号,超过十的com口号需要另外的书写方式,这里不说了,因为网上一抓一大把,接下来,我们要对串口进行一系列的明确设置,这里就用到了一个结构体DCB结构,是专门用来描述一个com口的工作方式的,由于次结构体有28个成员,非常多,而且大部分的设置都是全世界通用的,所以,我们偷个懒,在打开一个com口之后,建立DCB结构体,接下来调用一个函数GetCommState用这个函数把现在com口的数据都写到DCB里,这样,比较通用的com口设置就已经弄好了,我们一般情况下只需要改一下DCB的波特率就好了,改好后马上用SetCommState把刚改好的结构体再写回去,这样串口就设置好了,现在还有点麻烦,串口设置好了,我们要它干什么呢?废话,读写数据呗,嘟~~~~~~可不能用fwrite和fread因为这个com口句柄不是文件句柄,是内核句柄,要用ReadFile和WriteFile来进行读写,又出麻烦了,我们怎么知道单片机什么时候发数据过来,就算我们知道,计算机什么时候知道啊?所以,一般的情况下,用ReadFile一直在哪检查,又是麻烦,通常情况下,一个com口的ReadFile设置是阻塞函数,影响编程啊!!!!!!怎么办,很简单,你不阻塞吗,打通你呗,我们再建立里一个结构体COMMTIMEOUTS这个结构体描述里一个com口的相关超时设置,我们用GetCommTimeouts把数据读回来,具体的设置方法在网上也有,但是要注意,有一个MAXDWORD用它来设置读间隔超时设置就可以使ReadFile向kbhit()函数一样完全非阻塞了.经过一些列的设置,事实上,现在已经可以通信了,要是有人觉得缓存不舒服,用SetupComm函数来重设缓存大小,对于传输速度比较快的通信,要把缓存设置的大些.