程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 串口異步同步通訊

串口異步同步通訊

編輯:關於C語言


/*------+------+------+------+------+------+------+------+------+------+------+------ 
串口編程的一個實例 
  為了讓您更好地理解串口編程,下面我們分別編寫兩個例程(見附帶的源碼部分), 
    這兩個例程都實現了工控機與百特顯示儀表通過RS485接口進行的串口通信。其中 
    第一個例程采用同步串口操作,第二個例程采用異步串口操作。 
  我們只介紹軟件部分,RS485接口接線方法不作介紹,感興趣的讀者可以查閱相關資料。 
/*------+------+------+------+------+------+------+------+------+------+------+----*/
 
/*------+------+------+------+------+------+------+------+------+------+------+------+ 
    打開VC++6.0,新建基於對話框的工程RS485Comm,在主對話框窗口IDD_RS485COMM_DIALOG 
    上添加兩個按鈕,ID分別為IDC_SEND和IDC_RECEIVE,標題分別為“發送”和“接收”;添加一 
    個靜態文本框IDC_DISP,用於顯示串口接收到的內容。 
------+------+------+------+------+------+------+------+------+------+------+-------*/
 
//在RS485CommDlg.cpp文件中添加全局變量: 
 
HANDLE hCom;  //全局變量,串口句柄 
 
//在RS485CommDlg.cpp文件中的OnInitDialog()函數添加如下代碼: 
 
// TODO: Add extra initialization here 
hCom=CreateFile(    "COM1",                     //COM1口 
                    GENERIC_READ|GENERIC_WRITE, //允許讀和寫 
                    0,                          //獨占方式 
                    NULL, 
                    OPEN_EXISTING,              //打開而不是創建 
                    0,                          //同步方式 
                    NULL    ); 
if(hCom==(HANDLE)-1) 

    AfxMessageBox("打開COM失敗!"); 
    return FALSE; 

 
SetupComm(hCom,100,100); //輸入緩沖區和輸出緩沖區的大小都是1024 
 
COMMTIMEOUTS TimeOuts; 
 
//設定讀超時 
TimeOuts.ReadIntervalTimeout=MAXDWORD; 
TimeOuts.ReadTotalTimeoutMultiplier=0; 
TimeOuts.ReadTotalTimeoutConstant=0; 
 
//在讀一次輸入緩沖區的內容後讀操作就立即返回, 
//而不管是否讀入了要求的字符。 
 
//設定寫超時 
TimeOuts.WriteTotalTimeoutMultiplier=100; 
TimeOuts.WriteTotalTimeoutConstant=500; 
 
SetCommTimeouts(hCom,&TimeOuts);    //設置超時 
 
DCB dcb; 
GetCommState(hCom,&dcb); 
dcb.BaudRate=9600;                  //波特率為9600 
dcb.ByteSize=8;                     //每個字節有8位 
dcb.Parity=NOPARITY;                //無奇偶校驗位 
dcb.StopBits=TWOSTOPBITS;           //兩個停止位 
SetCommState(hCom,&dcb); 
 
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR); 
 
//分別雙擊IDC_SEND按鈕和IDC_RECEIVE按鈕,添加兩個按鈕的響應函數: 
void CRS485CommDlg::OnSend()  

    /*------+------+------+------+------+------+------+------+------- 
    |   TODO: Add your control notification handler code here       | 
    |   在此需要簡單介紹百特公司XMA5000的通訊協議:                   | 
    |   該儀表RS485通訊采用主機廣播方式通訊。                       | 
    |   串行半雙工,幀11位,1個起始位(0),8個數據位,2個停止位(1)  | 
    |   如:讀儀表顯示的瞬時值,主機發送:DC1 AAA BB ETX         | 
    |   其中:DC1是標准ASCII碼的一個控制符號,碼值為11H(十進制的17)   | 
    |   在XMA5000的通訊協議中,DC1表示讀瞬時值                        | 
    |   AAA是從機地址碼,也就是XMA5000顯示儀表的通訊地址           | 
    |   BB為通道號,讀瞬時值時該值為01                               | 
    |   ETX也是標准ASCII碼的一個控制符號,碼值為03H                 | 
    |   在XMA5000的通訊協議中,ETX表示主機結束符                   | 
    ------+------+------+------+------+------+------+------+------+*/
    char lpOutBuffer[7]; 
    memset(lpOutBuffer,''\0'',7);   //前7個字節先清零 
    lpOutBuffer[0]=''\x11'';        //發送緩沖區的第1個字節為DC1 
    lpOutBuffer[1]=''0'';           //第2個字節為字符0(30H) 
    lpOutBuffer[2]=''0'';           //第3個字節為字符0(30H) 
    lpOutBuffer[3]=''1'';           // 第4個字節為字符1(31H) 
    lpOutBuffer[4]=''0'';           //第5個字節為字符0(30H) 
    lpOutBuffer[5]=''1'';           //第6個字節為字符1(31H) 
    lpOutBuffer[6]=''\x03'';        //第7個字節為字符ETX 
     
    //從該段代碼可以看出,儀表的通訊地址為001  
    DWORD dwBytesWrite=7; 
    COMSTAT ComStat; 
    DWORD dwErrorFlags; 
    BOOL bWriteStat; 
    ClearCommError(hCom,&dwErrorFlags,&ComStat); 
    bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL); 
    if(!bWriteStat) 
    { 
        AfxMessageBox("寫串口失敗!"); 
    } 
 

 
void CRS485CommDlg::OnReceive()  

    // TODO: Add your control notification handler code here 
    char str[100]; 
    memset(str,''\0'',100); 
    DWORD wCount=100;       //讀取的字節數 
    BOOL bReadStat; 
    bReadStat=ReadFile(hCom,str,wCount,&wCount,NULL); 
    if(!bReadStat) 
        AfxMessageBox("讀串口失敗!"); 
    PurgeComm(hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); 
    m_disp=str; 
    UpdateData(FALSE); 
  

 
//您可以觀察返回的字符串,其中有和儀表顯示值相同的部分,您可以進行相應的字符串操作取出儀表的顯示值。 
//打開ClassWizard,為靜態文本框IDC_DISP添加CString類型變量m_disp,同時添加WM_CLOSE的相應函數: 
 
void CRS485CommDlg::OnClose()  

 // TODO: Add your message handler code here and/or call default 
    CloseHandle(hCom);  //程序退出時關閉串口 
    CDialog::OnClose(); 

 
 
//-------------------------------------------------------------------------------------------------- 
//-------------------------------------------------------------------------------------------------- 
 
 
//程序的相應部分已經在代碼內部作了詳細介紹。連接好硬件部分,編譯運行程序,細心體會串口同步操作部分。 
//例程2 
 
/*------+------+------+------+------+------+------+------+------+------+------+------+------+------- 
    打開VC++6.0,新建基於對話框的工程RS485Comm,在主對話框窗口IDD_RS485COMM_DIALOG上添加兩個按鈕, 
    ID分別為IDC_SEND和IDC_RECEIVE,標題分別為“發送”和“接收”;添加一個靜態文本框IDC_DISP,用於顯示 
    串口接收到的內容。在RS485CommDlg.cpp文件中添加全局變量: 
/*------+------+------+------+------+------+------+------+------+------+------+------+------+------*/
 
HANDLE hCom; //全局變量, 
 
//串口句柄在RS485CommDlg.cpp文件中的OnInitDialog()函數添加如下代碼: 
 
hCom=CreateFile(    "COM1",                                     //COM1口 
                    GENERIC_READ|GENERIC_WRITE,                 //允許讀和寫 
                    0,                                          //獨占方式 
                    NULL, 
                    OPEN_EXISTING,                              //打開而不是創建 
                    FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //重疊方式 
                    NULL    ); 
if(hCom==(HANDLE)-1) 

    AfxMessageBox("打開COM失敗!"); 
    return FALSE; 

 
SetupComm(hCom,100,100); //輸入緩沖區和輸出緩沖區的大小都是100 
 
COMMTIMEOUTS TimeOuts; 
//設定讀超時 
TimeOuts.ReadIntervalTimeout=MAXDWORD; 
TimeOuts.ReadTotalTimeoutMultiplier=0; 
TimeOuts.ReadTotalTimeoutConstant=0; 
//在讀一次輸入緩沖區的內容後讀操作就立即返回, 
//而不管是否讀入了要求的字符。 
 
//設定寫超時 
TimeOuts.WriteTotalTimeoutMultiplier=100; 
TimeOuts.WriteTotalTimeoutConstant=500; 
SetCommTimeouts(hCom,&TimeOuts);        //設置超時 
 
DCB dcb; 
GetCommState(hCom,&dcb); 
dcb.BaudRate=9600;                      //波特率為9600 
dcb.ByteSize=8;                         //每個字節有8位 
dcb.Parity=NOPARITY;                    //無奇偶校驗位 
dcb.StopBits=TWOSTOPBITS;               //兩個停止位 
SetCommState(hCom,&dcb); 
 
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR); 
  
//分別雙擊IDC_SEND按鈕和IDC_RECEIVE按鈕,添加兩個按鈕的響應函數: 
 
void CRS485CommDlg::OnSend()  

    // TODO: Add your control notification handler code here 
    OVERLAPPED m_osWrite; 
    memset(&m_osWrite,0,sizeof(OVERLAPPED)); 
    m_osWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); 
 
    char lpOutBuffer[7]; 
    memset(lpOutBuffer,''\0'',7); 
    lpOutBuffer[0]=''\x11''; 
    lpOutBuffer[1]=''0''; 
    lpOutBuffer[2]=''0''; 
    lpOutBuffer[3]=''1''; 
    lpOutBuffer[4]=''0''; 
    lpOutBuffer[5]=''1''; 
    lpOutBuffer[6]=''\x03''; 
 
    DWORD dwBytesWrite=7; 
    COMSTAT ComStat; 
    DWORD dwErrorFlags; 
    BOOL bWriteStat; 
    ClearCommError(hCom,&dwErrorFlags,&ComStat); 
    bWriteStat=WriteFile(hCom,lpOutBuffer, 
    dwBytesWrite,& dwBytesWrite,&m_osWrite); 
 
    if(!bWriteStat) 
    { 
        if(GetLastError()==ERROR_IO_PENDING) 
        { 
            WaitForSingleObject(m_osWrite.hEvent,1000); 
        } 
    } 
 

 
void CRS485CommDlg::OnReceive()  

    // TODO: Add your control notification handler code here 
    OVERLAPPED m_osRead; 
    memset(&m_osRead,0,sizeof(OVERLAPPED)); 
    m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); 
 
    COMSTAT ComStat; 
    DWORD dwErrorFlags; 
 
    char str[100]; 
    memset(str,''\0'',100); 
    DWORD dwBytesRead=100;//讀取的字節數 
    BOOL bReadStat; 
 
    ClearCommError(hCom,&dwErrorFlags,&ComStat); 
    dwBytesRead=min(dwBytesRead, (DWORD)ComStat.cbInQue); 
    bReadStat=ReadFile(hCom,str, 
    dwBytesRead,&dwBytesRead,&m_osRead); 
    if(!bReadStat) 
    { 
        if(GetLastError()==ERROR_IO_PENDING)    //GetLastError()函數返回ERROR_IO_PENDING,表明串口正在進行讀操作 
        { 
            WaitForSingleObject(m_osRead.hEvent,2000); 
            //使用WaitForSingleObject函數等待,直到讀操作完成或延時已達到2秒鐘 
            //當串口讀操作進行完畢後,m_osRead的hEvent事件會變為有信號 
        } 

 
    PurgeComm(hCom, PURGE_TXABORT| 
    PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); 
    m_disp=str; 
    UpdateData(FALSE); 

 
//打開ClassWizard,為靜態文本框IDC_DISP添加CString類型變量m_disp,同時添加WM_CLOSE的相應函數: 
 
void CRS485CommDlg::OnClose()  

    // TODO: Add your message handler code here and/or call default 
    CloseHandle(hCom);      //程序退出時關閉串口 
    CDialog::OnClose(); 

 
 
//您可以仔細對照這兩個例程,細心體會串口同步操作和異步操作的區別。

作者“情っ㈠顆欲枯旳草丶ゞ”

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved