S 串列埠程式設計 詳解3 串列埠的初始化、開啟/關閉
阿新 • • 發佈:2019-01-07
串列埠程式設計 詳解3 串列埠的初始化
程式開啟串列埠,採用兩種方法:
1、程式啟動,呼叫OnInitDialog( )函式,開啟串列埠,預設串列埠號為COM1,如果COM1不存在或被佔用,就給出提示(其實,我覺得在OnInitDialog( )函式中開啟串列埠不大好)
BOOL CSCOMMDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE);//獲得系統選單
if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon 程式顯示時,左上角就會顯示定義了的圖示,生成的EXE程式也顯示了這個圖示SetIcon(m_hIcon, FALSE); // Set small icon在程式執行的時候,當用Alt+TAB時,會顯示定義的這個圖示,要不不顯示 // TODO: Add extra initialization here //下面初始化串列埠的 串列埠號 波特率 奇偶校驗 資料位 停止位 m_bOpenPort=FALSE; m_nCom=1; m_nBaud=115200; m_cParity='N'; m_nDatabits=8; m_nStopbits=1; m_dwCommEvents=EV_RXCHAR||EV_RXFLAG;//串列埠事件 CString strStatus; if(m_Port.InitPort(this,m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits,m_dwCommEvents,512))//這句是串列埠的初始化 會在串列埠的開啟和關閉中進行分析 { m_Port.StartMonitoring(); //啟動檢測輔助執行緒 m_ctrlIconOpenoff.SetIcon(m_hIconRed); //開啟串列埠成功 設定ICON圖示 為ON strStatus.Format("STATUS: COM %d OPENED, %d, %c, %d, %d",m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits); //當前的狀態 埠號 奇偶 資料位 停止位 m_ctrlOpenPort.SetWindowText("關閉串列埠"); m_bOpenPort=TRUE; } else { AfxMessageBox("沒有發現該串列埠或 已被佔用"); m_ctrlIconOpenoff.SetIcon(m_hIconOff); //開啟串列埠失敗 設定ICON圖示 為OFF m_bOpenPort=FALSE; } m_ctrlPortStatus.SetWindowText(strStatus); m_ctrlStopDisp.SetWindowText("停止顯示"); //埠的初始化 m_ctrlPort.SetCurSel(0); m_ctrlPort.GetWindowText(m_strPort); //波特率的初始化 m_ctrlBaud.InsertString(0,_T("4800")); m_ctrlBaud.InsertString(1,_T("14400")); m_ctrlBaud.InsertString(2,_T("19200")); m_ctrlBaud.InsertString(3,_T("38400")); m_ctrlBaud.InsertString(4,_T("56000")); m_ctrlBaud.InsertString(5,_T("57600")); m_ctrlBaud.InsertString(6,_T("115200")); // m_ctrlBaud.InsertString(7,_T("128000")); // m_ctrlBaud.InsertString(8,_T("256000")); m_ctrlBaud.SetCurSel(6); m_ctrlBaud.GetWindowText(m_strBaud); //校驗初始化 m_ctrlPartity.SetCurSel(0); m_ctrlPartity.GetWindowText(m_strPartity); //資料位初始化 m_ctrlDatabits.SetCurSel(0); m_ctrlDatabits.GetWindowText(m_strDatabits); //停止位 m_ctrlStopbits.SetCurSel(0); m_ctrlStopbits.GetWindowText(m_strStopbits); return TRUE; // return TRUE unless you set the focus to a control }
程式碼分析:
串列埠的開啟:(m_Port.InitPort(this,m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits,m_dwCommEvents,512)
以及m_Port.StartMonitoring(); //啟動檢測輔助執行緒
當然這裡第一次用到ICON控制元件和COMBOX控制元件的知識
如:m_ctrlIconOpenoff.SetIcon(m_hIconRed);
m_ctrlBaud.InsertString(6,_T("115200"));
m_ctrlBaud.SetCurSel(6);
m_ctrlBaud.GetWindowText(m_strBaud); //獲取當前控制元件框內的值到m_strBaud
2、開啟/關閉串列埠(IDC_BUTTON_OPENPORT新增響應函式)
//開啟/關閉串列埠
void CSCOMMDlg::OnButtonOpenport()
{
if(m_bOpenPort)//串列埠先是開啟的,現在點選按鈕進行關閉
{
if(m_ctrlAutoSend.GetCheck())
{
m_bOpenPort=!m_bOpenPort;
AfxMessageBox("請先關掉自動傳送");
return;
}
m_ctrlOpenPort.SetWindowText("開啟串列埠");
m_Port.ClosePort();//關閉串列埠
m_ctrlPortStatus.SetWindowText("STATUS: COM Port Close");
m_ctrlIconOpenoff.SetIcon(m_hIconOff);
m_bOpenPort=FALSE;
}
else//開啟串列埠
{
m_ctrlOpenPort.SetWindowText("關閉串列埠");
CString strStatus;
// BOOL InitPort(CWnd* pPortOwner, UINT portnr = 1, UINT baud = 19200, \
char parity = 'N', UINT databits = 8, UINT stopbits = 1, DWORD dwCommEvents = EV_RXCHAR, UINT writebuffersize = 1024);
if(m_Port.InitPort(this,m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits,m_dwCommEvents,512))
{
m_Port.StartMonitoring();
m_ctrlIconOpenoff.SetIcon(m_hIconRed);
strStatus.Format("STATUS: COM %d OPENED, %d, %c, %d, %d",m_nCom,m_nBaud,m_cParity,m_nDatabits,m_nStopbits);
//當前的狀態 埠號 奇偶 資料位 停止位
m_bOpenPort=TRUE;
}
else
{
AfxMessageBox("沒有發現該串列埠或 已被佔用");
m_ctrlIconOpenoff.SetIcon(m_hIconOff);
m_bOpenPort=FALSE;
}
m_ctrlPortStatus.SetWindowText(strStatus);
}
}
程式碼分析:現在我們得看InitPort( )裡邊都是些什麼。
//SerialPort.cpp
// Initialize the port. This can be port 1 to 4.
BOOL CSerialPort::InitPort(CWnd* pPortOwner, // the owner (CWnd) of the port (receives message)
UINT portnr, // portnumber (1..4)
UINT baud, // baudrate
char parity, // parity
UINT databits, // databits
UINT stopbits, // stopbits
DWORD dwCommEvents, // EV_RXCHAR, EV_CTS etc
UINT writebuffersize) // size to the writebuffer
{
// assert(portnr > 0 && portnr < 5);
assert(portnr > 0 && portnr < 20);
assert(pPortOwner != NULL);
// if the thread is alive: Kill
if (m_bThreadAlive)
{
do
{
SetEvent(m_hShutdownEvent);
} while (m_bThreadAlive);
TRACE("Thread ended/n");
}
// create events
if (m_ov.hEvent != NULL)
ResetEvent(m_ov.hEvent);
m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hWriteEvent != NULL)
ResetEvent(m_hWriteEvent);
m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hShutdownEvent != NULL)
ResetEvent(m_hShutdownEvent);
m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// initialize the event objects
m_hEventArray[0] = m_hShutdownEvent; // highest priority
m_hEventArray[1] = m_ov.hEvent;
m_hEventArray[2] = m_hWriteEvent;
// initialize critical section
InitializeCriticalSection(&m_csCommunicationSync);
// set buffersize for writing and save the owner
m_pOwner = pPortOwner;
if (m_szWriteBuffer != NULL)
delete [] m_szWriteBuffer;
m_szWriteBuffer = new char[writebuffersize];
m_nPortNr = portnr;
m_nWriteBufferSize = writebuffersize;
m_dwCommEvents = dwCommEvents;
BOOL bResult = FALSE;
char *szPort = new char[50];
char *szBaud = new char[50];
// now it critical!
EnterCriticalSection(&m_csCommunicationSync);
// if the port is already opened: close it
if (m_hComm != NULL)
{
CloseHandle(m_hComm);
m_hComm = NULL;
}
// prepare port strings
sprintf(szPort, "COM%d", portnr);
sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);
// get a handle to the port
m_hComm = CreateFile(szPort, // communication port string (COMX)
GENERIC_READ | GENERIC_WRITE, // read/write types
0, // comm devices must be opened with exclusive access
NULL, // no security attributes
OPEN_EXISTING, // comm devices must use OPEN_EXISTING
FILE_FLAG_OVERLAPPED, // Async I/O
0); // template must be 0 for comm devices
if (m_hComm == INVALID_HANDLE_VALUE)
{
// port not found
delete [] szPort;
delete [] szBaud;
return FALSE;
}
// set the timeout values
m_CommTimeouts.ReadIntervalTimeout = 1000;
m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;
m_CommTimeouts.ReadTotalTimeoutConstant = 1000;
m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;
m_CommTimeouts.WriteTotalTimeoutConstant = 1000;
// configure
if (SetCommTimeouts(m_hComm, &m_CommTimeouts))
{
if (SetCommMask(m_hComm, dwCommEvents))
{
if (GetCommState(m_hComm, &m_dcb))
{
m_dcb.EvtChar = 'q';
m_dcb.fRtsControl = RTS_CONTROL_ENABLE; // set RTS bit high!
if (BuildCommDCB(szBaud, &m_dcb))
{
if (SetCommState(m_hComm, &m_dcb))
; // normal operation... continue
else
ProcessErrorMessage("SetCommState()");
}
else
ProcessErrorMessage("BuildCommDCB()");
}
else
ProcessErrorMessage("GetCommState()");
}
else
ProcessErrorMessage("SetCommMask()");
}
else
ProcessErrorMessage("SetCommTimeouts()");
delete [] szPort;
delete [] szBaud;
// flush the port
PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
// release critical section
LeaveCriticalSection(&m_csCommunicationSync);
TRACE("Initialisation for communicationport %d completed./nUse Startmonitor to communicate./n", portnr);
return TRUE;
}
啟動檢測輔助執行緒m_Port.StartMonitoring();
//SerialPort.cpp
// start comm watching
BOOL CSerialPort::StartMonitoring()
{
if (!(m_Thread = AfxBeginThread(CommThread, this)))
return FALSE;
TRACE("Thread started/n");
return TRUE;
}
使用者介面執行緒和工作者執行緒都是由AfxBeginThread建立的。現在,考察該函式:MFC提供了兩個過載版的AfxBeginThread.下面只說工作者執行緒工作者執行緒的AfxBeginThread的原型如下:
CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,
LPVOID lParam,int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);//用於建立工作者執行緒 返回值: 一個指向新執行緒的執行緒物件的指標 pfnThreadProc : 執行緒的入口函式,宣告一定要如下: UINT MyThreadFunction(LPVOID pParam),不能設定為NULL; pParam : 傳遞入執行緒的引數,注意它的型別為:LPVOID,所以我們可以傳遞一個結構體入執行緒. 程式關閉後要關閉串列埠並釋放所佔用的資源。在CSCOMMDlg新增WM_DISTROY訊息響應函式OnDestroy( ).該函式即將撤銷時呼叫。
void CSCOMMDlg::OnDestroy()
{
CDialog::OnDestroy();
m_ctrlAutoSend.SetCheck(0);//強行關閉自動傳送
KillTimer(1);
KillTimer(4);
m_Port.ClosePort();//關閉串列埠
m_strReceiveData.Empty();//清空接收資料字串
}
其實,要是自己來說設計程式的話,可能就不會考慮到這麼全面的(建立後得撤銷)
從上面可以看到一個串列埠開啟、撤銷程式碼都有啊