串行通訊是目前計(jì)算機(jī)、通信和控制領(lǐng)域基本的通信方式。在CSDN的“嵌入式開(kāi)發(fā)/WINCE”社區(qū)中,經(jīng)常有人提問(wèn)該到哪找串口通訊例子,其實(shí)這個(gè)問(wèn)題我自己也問(wèn)過(guò)。:)而一般的回答是給你提供一個(gè)Pocket PC 2002的SDK例子程序。但到底SDK的程序和MFC的結(jié)構(gòu)有很大的不同,對(duì)于想用MFC編寫(xiě)通信程序的人來(lái)說(shuō)也不是很便利。
另一方面,由于Windows CE是一個(gè)基于Unicode的操作系統(tǒng),并且Windows CE不支持Windows下常用的串行通信重疊I/O方式(OVERLAPPED),因此編寫(xiě)Windows CE下的串口通訊類(lèi)有一些與桌面Windows不同的地方。
以下是我從SDK程序改寫(xiě)而來(lái)的MFC例子程序,希望能和致力于WINCE開(kāi)發(fā)的朋友多多交流,由于本人才疏學(xué)淺,程序中有許多不完善的地方,請(qǐng)大家指正。我的程序是基于“主動(dòng)發(fā)送請(qǐng)求,被動(dòng)接收響應(yīng)”的假設(shè),因此我只設(shè)置了一個(gè)接收數(shù)據(jù)的線(xiàn)程。
感謝“嵌入式開(kāi)發(fā)/WINCE”社區(qū)為我提供SDK例子的朋友,感謝CSDN上所有熱心的朋友,祝愿中國(guó)的軟硬件水平能早日擠身世界。
頭文件Serial.h
// Serial.h: interface for the CSerial class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_SERIAL_H__59575586_AAA9_4FEF_B2A7_E089553698EF__INCLUDED_)
#define AFX_SERIAL_H__59575586_AAA9_4FEF_B2A7_E089553698EF__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
DWORD WINAPI ReadPortThread(LPVOID lpvoid); //讀數(shù)據(jù)線(xiàn)程
class CSerial
{
public:
BOOL InitCommTimeouts(); //設(shè)置超時(shí)參數(shù)
BOOL InitDCB(); //配置串口
BOOL m_bConnected;
BOOL ClosePort(HANDLE hCommPort); //關(guān)閉串口
DWORD WritePort(TCHAR *buf,DWORD dwBytesToWrite); //寫(xiě)數(shù)據(jù)
BOOL OpenPort(LPTSTR lpszPortName); //打開(kāi)串口
CSerial();
HANDLE hReadThread;
virtual ~CSerial();
};
#endif // !defined(AFX_SERIAL_H__59575586_AAA9_4FEF_B2A7_E089553698EF__INCLUDED_)
源文件:Serial.cpp
// Serial.cpp: implementation of the CSerial class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Serial.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
HANDLE hPort;
CString strInChar;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSerial::CSerial()
{
}
CSerial::~CSerial()
{
if(hPort != INVALID_HANDLE_VALUE)
ClosePort(hPort);
}
BOOL CSerial::OpenPort(LPTSTR lpszPortName)
{
DWORD dwError,
dwThreadID;
if(hPort)
{
return FALSE;
}
//打開(kāi)串口
hPort = CreateFile (lpszPortName, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING,0, NULL);
//如果打開(kāi)端口出錯(cuò), 返回FALSE
if ( hPort == INVALID_HANDLE_VALUE )
{
//不能打開(kāi)端口
CString strError;
strError.Format(_T("Unable to open %s, Error No.=%d"),
lpszPortName, GetLastError());
MessageBox (NULL, strError, TEXT("Error"), MB_OK);
return FALSE;
}
//指定端口監(jiān)測(cè)的事件集
SetCommMask (hPort, EV_RXCHAR);
//分配設(shè)備緩沖區(qū)
SetupComm(hPort,512,512);
//初始化緩沖區(qū)中的信息
PurgeComm(hPort,PURGE_TXCLEAR|PURGE_RXCLEAR);
//配置串行端口
if(!InitDCB())
return FALSE;
//設(shè)置端口超時(shí)值
if(!InitCommTimeouts())
return FALSE;
//設(shè)置端口上指定信號(hào)的狀態(tài)
// SETDTR: 發(fā)送DTR (data-terminal-ready)信號(hào)
// SETRTS: 發(fā)送RTS (request-to-send)信號(hào)
EscapeCommFunction (hPort, SETDTR);
EscapeCommFunction (hPort, SETRTS);
//創(chuàng)建一個(gè)從串口讀取數(shù)據(jù)的線(xiàn)程
if (hReadThread = CreateThread (NULL, 0, ReadPortThread, 0, 0,
&dwThreadID))
{
}
else
{
//不能創(chuàng)建線(xiàn)程
MessageBox (NULL, TEXT("Unable to create the read thread"),
TEXT("Error"), MB_OK);
dwError = GetLastError ();
return FALSE;
}
m_bConnected=TRUE;
return TRUE;
}
DWORD CSerial::WritePort(TCHAR *buf,DWORD dwCharToWrite)
{
BOOL fWriteState;
DWORD dwBytesWritten;
//寫(xiě)入數(shù)據(jù)
fWriteState=WriteFile(hPort,buf,dwCharToWrite*sizeof(TCHAR),&dwBytesWritten,NULL);
if(!fWriteState)
{
//不能寫(xiě)數(shù)據(jù)
MessageBox(NULL,TEXT("Can't Write String to Comm"),TEXT("Error"),MB_OK);
dwBytesWritten=0;
}
return dwBytesWritten;
}
DWORD WINAPI ReadPortThread(LPVOID lpvoid)
{
BOOL fReadState;
DWORD dwCommModemStatus;
DWORD dwLength;
COMSTAT ComStat;
DWORD dwErrorFlags;
while (hPort != INVALID_HANDLE_VALUE)
{
//等待串口的事件發(fā)生
WaitCommEvent (hPort, &dwCommModemStatus, 0);
if (dwCommModemStatus & EV_RXCHAR)
{
ClearCommError(hPort,&dwErrorFlags,&ComStat);
//cbInQue返回在串行驅(qū)動(dòng)程序輸入隊(duì)列中的字符數(shù)
dwLength=ComStat.cbInQue;
if(dwLength>0)
{
//從串口讀取數(shù)據(jù)
TCHAR* buf=new TCHAR[256];
fReadState=ReadFile(hPort,buf,dwLength,&dwLength,NULL);
if(!fReadState)
{
//不能從串口讀取數(shù)據(jù)
MessageBox(NULL,TEXT("Error in read from serial port"),TEXT("Read Error"),MB_OK);
}
else
{
//把數(shù)據(jù)賦值給全局變量
strInChar=buf;
}
delete[] buf;
}
}
GetCommModemStatus (hPort, &dwCommModemStatus);
}
return 0;
}
BOOL CSerial::ClosePort(HANDLE hCommPort)
{
if (hCommPort != INVALID_HANDLE_VALUE)
{
//設(shè)置連接屬性為FALSE
m_bConnected=FALSE;
//結(jié)束線(xiàn)程中WaitCommEvent的等待
SetCommMask(hPort,0);
//阻塞至線(xiàn)程停止
if(hReadThread)
{
TerminateThread(hReadThread,0);
CloseHandle(hReadThread);
}
//清除端口上指定信號(hào)的狀態(tài)
EscapeCommFunction(hPort,CLRDTR);
EscapeCommFunction(hPort,CLRRTS);
//清除驅(qū)動(dòng)程序內(nèi)部的發(fā)送和接收隊(duì)列
PurgeComm(hPort,PURGE_TXCLEAR|PURGE_RXCLEAR);
//關(guān)閉串口
CloseHandle (hCommPort);
hCommPort = INVALID_HANDLE_VALUE;
return TRUE;
}
else
{
return TRUE;
}
}
BOOL CSerial::InitDCB()
{
DCB PortDCB;
DWORD dwError;
PortDCB.DCBlength = sizeof (DCB);
//得到端口的默認(rèn)設(shè)置信息
GetCommState (hPort, &PortDCB);
//改變DCB結(jié)構(gòu)設(shè)置
PortDCB.BaudRate = 19200; //波特率
PortDCB.fBinary = TRUE; //Win32不支持非二進(jìn)制串行傳輸模式,必須為T(mén)RUE
PortDCB.fParity = TRUE; //啟用奇偶校驗(yàn)
PortDCB.fOutxCtsFlow = TRUE; //串行端口的輸出由CTS線(xiàn)控制
PortDCB.fOutxDsrFlow = FALSE; //關(guān)閉串行端口的DSR流控制
PortDCB.fDtrControl = DTR_CONTROL_ENABLE; //啟用DTR線(xiàn)
PortDCB.fDsrSensitivity = FALSE; //如果設(shè)為T(mén)RUE將忽略任何輸入的字節(jié),除非DSR線(xiàn)被啟用
//PortDCB.fTXContinueOnXoff = TRUE; //當(dāng)為T(mén)RUE時(shí),如果接收緩沖區(qū)已滿(mǎn)且驅(qū)動(dòng)程序已傳送XOFF字符,將使驅(qū)動(dòng)程序停止傳輸字符
PortDCB.fTXContinueOnXoff = FALSE;
PortDCB.fOutX = FALSE; //設(shè)為T(mén)RUE指定XON/XOFF控制被用于控制串行輸出
PortDCB.fInX = FALSE; //設(shè)為T(mén)RUE指定XON/XOFF控制被用于控制串行輸入
PortDCB.fErrorChar = FALSE; //WINCE串行驅(qū)動(dòng)程序的默認(rèn)執(zhí)行將忽略這個(gè)字段
PortDCB.fNull = FALSE; //設(shè)為T(mén)RUE將使串行驅(qū)動(dòng)程序忽略收到的空字節(jié)
PortDCB.fRtsControl = RTS_CONTROL_ENABLE; //啟用RTS線(xiàn)
PortDCB.fAbortOnError = FALSE; //WINCE串行驅(qū)動(dòng)程序的默認(rèn)執(zhí)行將忽略這個(gè)字段
PortDCB.ByteSize = 8; //每字節(jié)的位數(shù)
PortDCB.Parity = NOPARITY; //無(wú)奇偶校驗(yàn)
PortDCB.StopBits = ONESTOPBIT; //每字節(jié)一位停止位
//根據(jù)DCB結(jié)構(gòu)配置端口
if (!SetCommState (hPort, &PortDCB))
{
//不能配置串行端口
MessageBox (NULL, TEXT("Unable to configure the serial port"),
TEXT("Error"), MB_OK);
dwError = GetLastError ();
return FALSE;
}
return TRUE;
}
BOOL CSerial::InitCommTimeouts()
{
COMMTIMEOUTS CommTimeouts;
DWORD dwError;
//得到超時(shí)參數(shù)
GetCommTimeouts (hPort, &CommTimeouts);
//改變COMMTIMEOUTS結(jié)構(gòu)設(shè)置
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 10;
CommTimeouts.WriteTotalTimeoutConstant = 1000;
//設(shè)置端口超時(shí)值
if (!SetCommTimeouts (hPort, &CommTimeouts))
{
//不能設(shè)置超時(shí)值
MessageBox (NULL, TEXT("Unable to set the time-out parameters"),
TEXT("Error"), MB_OK);
dwError = GetLastError ();
return FALSE;
}
return TRUE;
}
以上類(lèi)代碼在eMbedded Visual C++4.0和基于ARM9的三星S3C2410開(kāi)發(fā)板(運(yùn)行Windows CE.NET 4.1)上測(cè)試通過(guò)。
Windows CE下的串口通訊實(shí)例
更新時(shí)間: 2007-07-02 14:39:20來(lái)源: 粵嵌教育瀏覽量:852
粵嵌動(dòng)態(tài)
推薦閱讀
- ·粵嵌科技獲批特級(jí)技師/首席技師認(rèn)定資質(zhì),物聯(lián)網(wǎng)技能人才培養(yǎng)再添權(quán)威背書(shū)!!
- ·代碼空間優(yōu)化技巧(如使用查表法替代復(fù)雜計(jì)算)?
- ·如何減少中斷延遲?
- ·深化校企合作,共譜產(chǎn)教融合新篇章 —— 廣州航海學(xué)院與粵嵌科技開(kāi)展校企交流活動(dòng)
- ·校企聯(lián)動(dòng)促實(shí)踐!湖北工程學(xué)院 300 + 學(xué)子開(kāi)啟企業(yè)級(jí)實(shí)訓(xùn)之旅!!
- ·粵嵌科技31項(xiàng)命題入選中國(guó)國(guó)際大學(xué)生創(chuàng)新大賽(2025)產(chǎn)業(yè)賽道,誠(chéng)邀高校團(tuán)隊(duì)共創(chuàng)未來(lái)!
- ·在資源受限(如內(nèi)存不足)的設(shè)備中如何實(shí)現(xiàn)功能擴(kuò)展?
- ·廣東賽鉑安智能科技有限公司專(zhuān)場(chǎng)招聘會(huì)
- ·設(shè)計(jì)一個(gè)低功耗傳感器采集系統(tǒng),需考慮哪些因素?
- ·校企聯(lián)動(dòng)促實(shí)踐!湖北工程學(xué)院 300 + 學(xué)子開(kāi)啟企業(yè)級(jí)實(shí)訓(xùn)之旅!!