/******************************************************************* *******函數功能:打開串口設備鏈接 *******函數名稱:OpenComm *******輸入參數:無 *******輸出參數:無 *******返 回 值:TRUE -- 打開串口成功 FALSE -- 打開窗口失敗 *******************************************************************/ BOOL CSerial::OpenComm( OPEN_COMM_PARA openCommPara) { if (m_bOpened) { return FALSE; } char szPort[15] = {0}; char szComParams[50] = {0}; DCB dcb; wsprintf( szPort, "\\\\.\\COM%d", openCommPara.comPort); m_hIDComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );// if( m_hIDComDev == NULL ) return( FALSE ); memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) ); memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) ); COMMTIMEOUTS CommTimeOuts; CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF; CommTimeOuts.ReadTotalTimeoutMultiplier = 0; CommTimeOuts.ReadTotalTimeoutConstant = 0; CommTimeOuts.WriteTotalTimeoutMultiplier = 0; CommTimeOuts.WriteTotalTimeoutConstant = 5000; SetCommTimeouts( m_hIDComDev, &CommTimeOuts ); m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); GetCommState(m_hIDComDev,&dcb); dcb.DCBlength = sizeof(DCB); dcb.BaudRate = openCommPara.nBaud; dcb.ByteSize = openCommPara.nBit; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fDtrControl = DTR_CONTROL_DISABLE; if( !SetCommState( m_hIDComDev, &dcb ) || !SetupComm( m_hIDComDev, 10000, 10000 )
|| m_OverlappedRead.hEvent == NULL || m_OverlappedWrite.hEvent == NULL ) { DWORD dwError = GetLastError(); if( m_OverlappedRead.hEvent != NULL ) CloseHandle( m_OverlappedRead.hEvent ); if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent ); CloseHandle( m_hIDComDev ); return( FALSE ); } m_bOpened = TRUE; return(TRUE); }
2、win32下對文件的概念進行了擴展,無論是文件、通信設備、命名管道、郵槽、磁盤還是控制台都是用API函數CreateFile打開或者創建。
HANDLE CreateFile( LPCTSTR lpFileName, //串口號,支持CString,Fomat轉換進來 DWORD dwDesiredAccess, //訪問模式(寫 / 讀),一般設為:GENERIC_READ | GENERIC_WRITE DWORD dwShareMode, //共享屬性,一般設為0 LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全屬性的指針 ,一般設為:NULL DWORD dwCreationDispostion , //如何創建,必須設為:OPEN_EXISTING DWORD dwFlagsAndAttributes, //文件屬性,一般設為:FILE_FLAG_OVERLAPPED(允許對文件進行重疊操作) | FILE_ATTRIBUTE_NORMAL(默認屬性)
HANDLE hTemplateFile //用於復制文件句柄,對於串口而言必須設為NULL );
使用同步方式打開的代碼:
HANDLE hCOM; hCOM=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
if(hCOM==(HANDLE)-1) { MessageBox("打開COM失敗!"); return FALSE; } return TRUE;
使用重疊方式(非阻塞式)打開串口的方法:
HANDLE hCOM; hCOM=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED);
if(hCOM==INVALID_HANDLE_VALUE) { MessageBox("打開COM失敗!"); return FALSE; } return TRUE;
一般采用CreateFile打開串口之后,調用GetCommState函數來獲取串口的初始配置,要修改串口的配置,應該先修改DCB結構,然后再調用SetCommState函數設置串口。
BOOL GetCommState ( HANDLE hFile, // 通訊設備的句柄 LPDCB lpDCB // 設備控制塊,指向一個DCB結構的指針 ); BOOL SetCommState( HANDLE hFile, //通訊設備的句柄 LPDCB lpDCB //設備控制塊,指向一個DCB結構的指針 );
除了在BCD中的設置外,程序一般還需要設置I/O緩沖區的大小和超時,Windows用I/O緩沖區來緩存串口輸入和輸出的數據。如果通信的速率較高,應該設置較大的緩沖區。調用SetupComm函數可以設置串行口的輸入和輸出緩沖區的大小。
BOOL SetupComm( HANDLE hFile, DWORD dwInQueue,//設置輸入緩沖區的大小(字節數) DWORD dwOutQueue//設置輸出緩沖區的大小 );
在用ReadFile和WriteFile讀寫串口時,需要考慮超時問題。超時的作用是在指定的時間內沒有讀入或發送指定數量的字符,ReadFile和WriteFile的操作依然會結束。要查詢當前的超時設置應調用GetCommTimeout函數,該函數會填充一個COMMTIMEOUTS結構,調用SetCommTimeout可以用某一個COMMTIMEOUTS結構的內容來設置超時。讀寫串口的超時包括間隔超時和總超時,間隔超時是指在接收時兩個字符之間的最大時延,總超時是指讀寫操作總共話費的最大時間。寫操作只支持總超時,讀操作支持兩種超時。
typedefstruct _COMMTIMEOUTS { DWORD ReadIntervalTimeout; //讀間隔超時 DWORD ReadTotalTimeoutMultiplier; //讀時間系數 DWORD ReadTotalTimeoutConstant; //讀時間常數 DWORD WriteTotalTimeoutMultiplier; //寫時間系數 DWORD WriteTotalTimeoutConstant; //寫時間常量 } COMMTIMEOUTS,*LPCOMMTIMEOUTS;
簡單定義示范:
COMMTIMEOUTS CommTimeOuts; //創建一個實例 CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;//讀取間隔一直讀取 CommTimeOuts.ReadTotalTimeoutMultiplier = 0;//讀時間系數 CommTimeOuts.ReadTotalTimeoutConstant = 0;//讀時間常數 CommTimeOuts.WriteTotalTimeoutMultiplier = 0;//寫時間系數 CommTimeOuts.WriteTotalTimeoutConstant = 5000;//寫時間常量
COMMTIMEOUTS結構的成員都以毫秒為單位,總超時的計算方式是:
總超時=時間系數*要求讀/寫的字符數+時間常量
4、串口的讀寫采用ReadFile和WriteFile函數,其同步還是異步都由CreateFile函數決定,如果在CreateFile創建句柄時制定了FILE_FLAG_OVERLAPPED標志,就調用ReadFile和WriteFile函數是重疊的,如果未指定重疊標志,則讀寫操作應該是同步的。如果操作成功,這兩個函數都返回TRUE,當都返回FALSE時也不一定就是失敗的,應該調用GetLastError函數分析返回的結果,如果返回值是ERROR_IO_PENDING,說明重疊操作未完成。
5、串行通信傳輸方式分為信號傳輸方式和線路傳輸方式兩類。信號傳輸方式是按信號原樣傳輸的基波傳輸或是利用原信號調制成高頻載波的載波傳輸;線路傳輸方式是指通信雙方設備的線路可以選擇單工、半雙工、全雙工和多雙工傳輸。
2、RS232,RS485等均采用信號傳輸方式,這種方式實現簡單,但是通信距離有限制。遠距離傳輸時一般采用Modem,通過Modem可以將原信號調制成高頻的模擬信號,然后通過電話網絡,進行遠距離通信。線路傳輸方式一般分成單工、半雙工和全雙工、多工四種方式,其中半雙工采用一條傳輸線,全雙工采用兩根線可以同時對發,多工傳輸方式采用復用技術將一個信道划分為若干個頻帶或時間片,從而使多路信號同時共享信道,這就是多工傳輸方式。使用復用器和集中器可以降低成本,提高通信網的傳輸效率。
3、在高級通信控制程序中一般采用循環冗余代碼CRC校驗以自動糾錯方式發送。
4、波特率:1波特=1bit/s,波特率是衡量通信線路基本電信號發送率的一種量度,它僅僅是電學上的度量單位,不是信息的度量單位,代表通信線路上的電脈沖速率
5、發送器在發送時鍾的有效沿(下降沿)作用下將移位寄存器的數據按位移位串行輸出,在接收數據時,接收器在接收時鍾的有效沿(上升沿)作用下對接收數據按位采樣,發送/接收時鍾頻率=1/16/64*發送/接收波特率。
6、串行傳輸協議一般有兩類:異步通信和同步通信。異步傳輸格式也成為起止式異步協議,特點是通信雙方以一個字符作為數據傳輸單位,且發送方傳送字符的間隔時間是不定的。在傳輸一個字符時總是以起始位開始,以停止位結束。起始位恆為0,長度1,停止位恆為1,長度1、1.5、2可選,起始位和停止位及其中間內容稱為一幀。
7、異步傳輸的錯誤檢測:接收方能檢測到的錯誤一般有:奇偶錯、超越錯(也成為溢出錯)和幀格式錯(因為時鍾不匹配或者不穩定未能按照協議裝配成一個完整的字符幀等)。
8、面向字符的同步傳輸協議:SYN控制字,是同步字符,每一幀開始都有SYN,加一個SYN的稱為單同步,加兩個SYN的稱為雙同步,同步字符的作用是為了聯絡。SOH是序始字符,它表示標題的開始,標題中包括源地址、目標地址和路由指示等信息。STX是文始字符,標志着傳送的正文的開始,數據塊是被傳送的正文內容,由多個字符組成。數據塊后面是ETB組終字符或ETX文終字符,在對很長的文段分段發送時每個分數據塊后面用組終字符ETB,最后一個分數據塊后面用文終字符ETX。在幀的最后是校驗碼,它對從SOH開始直到ETX或ETB字段進行校驗。面向字符的傳輸有未解決的問題,需要在數據字符前加轉義字符DLE,這樣的實現比較麻煩,所以出現了面向比特的同步傳輸協議。
9、面向比特的同步傳輸協議:又稱為二進制同步傳輸,協議包括三種:同步數據鏈路控制規程SDLC;高級數據鏈路控制規程HDLC;先進數據通信規程ADCCP。
10、SDLC/HDLC協議規定所有信息傳輸必須以一個標志符開始,且以同一個標識符結束。這個標識符是01111110,稱為標志場。所有的信息都是以幀的形式發送的,而標志字符提供了每一幀的邊界,接收端可以通過搜索01111110確定幀的開始和結束。
11、常用的通信標准:一是計算機與外設之間的物理接口標准,屬於七層模型中的物理層。二是按接口標准設置計算機與外設之間進行串行通信的接口電路。
DCE:數據通信設備,該設備和其與通信網絡的連接構成了網絡終端的用戶網絡接口。它提供了到網絡的一條物理連接、轉發業務量,並且提供了一個用於同步DCE設備和DTE設備之間數據傳輸的時鍾信號。調制解調器和接口卡都是DCE設備的例子。:
標准指出DTE應該擁有一個插頭(針輸出)DCE擁有一個插座(孔輸出)。
DTE和DCE之間的連接直連即可,兩台DTE之間的連接需要用到硬件握手信號。
二、RS-423A(1.2),RS-422A(1.2),RS-485(1.2-1.5)。RS-423A采用差分非平衡傳輸,RS-422A采用差分平衡傳輸,用兩根信號線,RS-485采用差分平衡傳輸,並擴展了RS-422A的功能,在RS-422A中只允許電路有一個發送器,而RS-485標准允許電路中有多個發送器。他們的主要區別在於RS-485只能工作在半雙工方式,RS-422A卻可以工作在全雙工方式。
三、USB接口標准。USB通用串行總線,是一種應用於PC領域的接口技術,在工業領域太麻煩--!!
12、握手處理:在半雙工方式下的握手信號可以通過硬件握手處理或軟件握手處理兩種方式完成。其中硬件握手處理即使用專門的導線來作為握手聯絡信號,握手信號和數據信號不在同一條線路上流通;軟件握手處理不使用專門的握手導線,而是與數據信號一起在同一條導線上傳輸,它通過在數據線上傳送特定的字符來作為握手的專用信號。
RS-232C支持硬件握手和軟件握手。硬件握手使用DTR/DCR/RTS/CTS四個信號,DTE設備通過TxD向DCE設備發送數據的條件是:DTR/DCR/RTS/CTS四個信號引腳電壓必須都為正電壓。
一、DTE和DCE的區別,若連接兩個DTE,必須要將2號線和3號線交叉連接;
二、決不能帶電拔插串口。在連接和拔下串口時,一定要保證至少有一端是不帶電的,否則容易燒壞計算機或設備中的串口通信芯片。
17、使用MSComm控件的OnComm事件中接收數據:
voidCTTYDlg::OnOnCommMscomm1() { // TODO: 在此處添加控件通知處理程序代碼 VARIANT input1; BYTE rxdata[2048],aa1; long len1,k; COleSafeArray safearray1; CString strDis; switch(mycomm.GetCommEvent()) { case2: input1=mycomm.GetInput(); safearray1=input1; len1=safearray1.GetOneDimSize(); for(k=0;k<len1;k++) { safearray1.GetElement(&k,rxdata+k); } for(k=0;k<len1;k++) { if(rxdata[k]==13) { m_edit.SetSel(100000,100000); m_edit.ReplaceSel("\15\12"); UpdateData(FALSE); } else { if(rxdata[k]<=126&& rxdata[k]>=32) { strDis+=rxdata[k]; m_edit.SetSel(100000,100000); m_edit.ReplaceSel(strDis); strDis=""; UpdateData(FALSE); } } } } }
在類聲明中添加:
classCMainFrame:publicCFrameWnd { protected: CMSComm mycomm;//聲明類對象 afx_msg voidOnCommMscomm();//聲明響應函數 DECLARE_EVENTSINK_MAP();//聲明事件引用宏 }
在cpp中添加:
BEGIN_EVENTSINK_MAP(CMainFrame,CFrameWnd) ON_EVENT(CMainFrame,myID,1,OnCommMscomm,VTS_NONE) END_EVENTSINK_MAP()
在主框架類成員函數OnCreate函數中添加代碼:
intCMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { DWORD style=WS_VISIBLE|WS_CHILD; if(!myComm.Create(NULL,style,CRect(0,0,0,0),this,myID)) { Afx~~~ } }
添加OnCommMscomm成員函數,實現對控件事件的響應。
voidCMainFrame::OnCommMscomm() { //事件響應代碼 }