This is a simple example to connect a RS232 device. It supports following parameters:
- Com Port: COM1~COM11
- Baud Rate: 110, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800 and 921600
- Data Bit: 7 and 8
- Stop Bit: 1, 1.5 and 2
- Parity: no parity, odd, even, mark and space
- Flow Control: hardware, Xon/Xoff and none
// RS232_ConnectionDlg.cpp : implementation file
//
#include "stdafx.h"
#include "RS232_Connection.h"
#include "RS232_ConnectionDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
struct THREAD_INFO
{
CString csCMD;
//HandlerCallback hCMD; //for CALLBACK function
HWND hWnd;
}Thread_Info;
//---------------------------------------------------------------------------
UINT StartCOMThread(LPVOID param)
{
THREAD_INFO *Thread_Info = (THREAD_INFO*)param;
CRS232_ConnectionDlg *TheDlg = (CRS232_ConnectionDlg*) (Thread_Info->hWnd);
TheDlg->ComReceive(Thread_Info->csCMD);
return 0;
}
//---------------------------------------------------------------------------
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// Dialog Data
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CRS232_ConnectionDlg dialog
CRS232_ConnectionDlg::CRS232_ConnectionDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CRS232_ConnectionDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CRS232_ConnectionDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_COMBO_ComPort, m_ComPort);
DDX_Control(pDX, IDC_COMBO_BaudRate, m_BaudRate);
DDX_Control(pDX, IDC_COMBO_DataBit, m_DataBit);
DDX_Control(pDX, IDC_COMBO_StopBit, m_StopBit);
DDX_Control(pDX, IDC_COMBO_Parity, m_Parity);
DDX_Control(pDX, IDC_COMBO_FlowControl, m_FlowControl);
DDX_Control(pDX, IDC_CHECK_LineFeed, m_LineFeed);
DDX_Control(pDX, IDC_Echo, m_Echo);
DDX_Control(pDX, IDC_CHECK_Recv_LineFeed, m_RecvLineFeed);
DDX_Control(pDX, IDC_EDIT_SendMessage, m_SendMessage);
DDX_Control(pDX, IDC_LIST_SendRecvHistory, m_ListSendRecvHistory);
DDX_Control(pDX, IDC_CHECK_RecvDataAuto, m_RecvAuto);
DDX_Control(pDX, IDC_BUTTON_Recv, m_BtnRecv);
DDX_Control(pDX, IDC_STATIC_img, m_ConnectStatusImg);
DDX_Control(pDX, IDC_BUTTON_Connect, m_BtnConnect);
DDX_Control(pDX, IDC_BUTTON_Send, m_BtnSend);
}
BEGIN_MESSAGE_MAP(CRS232_ConnectionDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_Connect, &CRS232_ConnectionDlg::OnBnClickedButtonConnect)
ON_BN_CLICKED(IDC_BUTTON_Send, &CRS232_ConnectionDlg::OnBnClickedButtonSend)
ON_BN_CLICKED(IDC_BUTTON_Recv, &CRS232_ConnectionDlg::OnBnClickedButtonRecv)
END_MESSAGE_MAP()
// CRS232_ConnectionDlg message handlers
BOOL CRS232_ConnectionDlg::OnInitDialog()
{
CDialogEx::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)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
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
SetIcon(m_hIcon, FALSE); // Set small icon
//List Com Port
CString csPort;
for(int i = 1 ; i < 12 ; i++)
{
csPort.Format("COM%d", i);
m_ComPort.AddString(csPort);
}
m_ComPort.SetCurSel(0);
//List Baud Rate
m_BaudRate.AddString("110");
m_BaudRate.AddString("300");
m_BaudRate.AddString("1200");
m_BaudRate.AddString("2400");
m_BaudRate.AddString("4800");
m_BaudRate.AddString("9600");
m_BaudRate.AddString("19200");
m_BaudRate.AddString("38400");
m_BaudRate.AddString("57600");
m_BaudRate.AddString("115200");
m_BaudRate.AddString("230400");
m_BaudRate.AddString("460800");
m_BaudRate.AddString("921600");
m_BaudRate.SetCurSel(5);
//List Data Bit
m_DataBit.AddString("7");
m_DataBit.AddString("8");
m_DataBit.SetCurSel(0);
//List Stop Bit
m_StopBit.AddString("1");
m_StopBit.AddString("1.5");
m_StopBit.AddString("2");
m_StopBit.SetCurSel(0);
//List Parity
m_Parity.AddString("No parity");
m_Parity.AddString("Odd");
m_Parity.AddString("Even");
m_Parity.AddString("Mark");
m_Parity.AddString("Space");
m_Parity.SetCurSel(0);
//List Flow Control
m_FlowControl.AddString("Hardware");
m_FlowControl.AddString("Xon/Xoff");
m_FlowControl.AddString("None");
m_FlowControl.SetCurSel(0);
//Insert ListControl Column
m_ListSendRecvHistory.InsertColumn(0,"<->",LVCFMT_LEFT,40);
m_ListSendRecvHistory.InsertColumn(1,"Time",LVCFMT_LEFT,120);
m_ListSendRecvHistory.InsertColumn(2,"Message",LVCFMT_LEFT,240);
m_RecvAuto.SetCheck(true);
return TRUE; // return TRUE unless you set the focus to a control
}
void CRS232_ConnectionDlg::EnableCOMSetting(bool enable)
{
m_ComPort.EnableWindow(enable);
m_BaudRate.EnableWindow(enable);
m_DataBit.EnableWindow(enable);
m_StopBit.EnableWindow(enable);
m_Parity.EnableWindow(enable);
m_FlowControl.EnableWindow(enable);
m_LineFeed.EnableWindow(enable);
m_RecvLineFeed.EnableWindow(enable);
m_BtnSend.EnableWindow(!enable);
m_RecvAuto.EnableWindow(enable);
}
bool CRS232_ConnectionDlg::ComOpen(int iComNo, int iBaudRate, int iDataBit,
int iStopBit, int iParityCheck)
{
if(m_hComm != NULL)
ComClose();
iComNo++;
if(iComNo < 1 && iComNo > 10)
iComNo = 1;
switch(iBaudRate)
{
case 0:
iBaudRate = 110;
break;
case 1:
iBaudRate = 300;
break;
case 2:
iBaudRate = 1200;
break;
case 3:
iBaudRate = 2400;
break;
case 4:
iBaudRate = 4800;
break;
case 5:
iBaudRate = 9600;
break;
case 6:
iBaudRate = 19200;
break;
case 7:
iBaudRate = 38400;
break;
case 8:
iBaudRate = 57600;
break;
case 9:
iBaudRate = 115200;
break;
case 10:
iBaudRate = 230400;
break;
case 11:
iBaudRate = 460800;
break;
case 12:
iBaudRate = 921600;
break;
default:
iBaudRate = 9600;
break;
}
switch(iDataBit)
{
case 0:
iDataBit = 7;
break;
default:
iDataBit = 8;
break;
}
DCB PortDCB;
COMMTIMEOUTS CommTimeouts;
CString cs;
cs.Format("COM%d", iComNo);
// Open the serial port.
m_hComm = CreateFile(cs, // Pointer to the name of the port
GENERIC_READ | GENERIC_WRITE, // Access (read/write) mode
0, // Share mode
NULL, // Pointer to the security attribute
OPEN_EXISTING,// How to open the serial port
0, // Port attributes
NULL); // Handle to port with attribute
if(m_hComm == INVALID_HANDLE_VALUE)
{
MessageBox("Open com port fails.","Error",
MB_ICONERROR | MB_OK);
return FALSE;
}
PortDCB.DCBlength = sizeof (DCB);
// Get the default port setting information.
GetCommState (m_hComm, &PortDCB);
// Change the DCB structure settings.
PortDCB.BaudRate = iBaudRate; // Current baud
PortDCB.ByteSize = iDataBit; // Number of bits/bytes, 4-8
PortDCB.Parity = iParityCheck; // 0-4=no,odd,even,mark,space
PortDCB.StopBits = iStopBit; // 0,1,2 = 1, 1.5, 2
if(iParityCheck > 0)
PortDCB.fParity = TRUE; // Enable parity checking.
else
PortDCB.fParity = FALSE; // Disable parity checking.
PortDCB.fBinary = FALSE; // Binary mode; no EOF check
PortDCB.fOutxCtsFlow = FALSE; // No CTS output flow control
PortDCB.fOutxDsrFlow = FALSE; // No DSR output flow control
PortDCB.fDtrControl = DTR_CONTROL_DISABLE; // DTR flow control type
PortDCB.fDsrSensitivity = FALSE; // DSR sensitivity
PortDCB.fTXContinueOnXoff = FALSE; // XOFF continues Tx
PortDCB.fOutX = FALSE; // No XON/XOFF out flow control
PortDCB.fInX = FALSE; // No XON/XOFF in flow control
PortDCB.fErrorChar = FALSE; // Disable error replacement.
PortDCB.fNull = TRUE; // Disable null stripping.
PortDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;//RTS_CONTROL_DISABLE; // RTS flow control
PortDCB.fAbortOnError = FALSE; // Do not abort reads/writes on error.
// Configure the port according to the specifications of the DCB structure.
if (!SetCommState (m_hComm, &PortDCB))
{
MessageBox("Setting com DCB structure fails.","Error",
MB_ICONERROR | MB_OK);
ComClose();
return false;
}
// Retrieve the time-out parameters for all read and write operations on the port.
GetCommTimeouts(m_hComm, &CommTimeouts);
// Change the COMMTIMEOUTS structure settings.
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 10; // 10
CommTimeouts.WriteTotalTimeoutConstant = 1000; // 1000
// Set the time-out parameters for all read and write operations on the port.
if (!SetCommTimeouts(m_hComm, &CommTimeouts))
{
MessageBox("Setting com timeout parameters fails.","Error",
MB_ICONERROR | MB_OK);
ComClose();
return false;
}
EscapeCommFunction(m_hComm, SETDTR);
EscapeCommFunction(m_hComm, SETRTS);
ComClear();
return true;
}
bool CRS232_ConnectionDlg::IsComOpen()
{
if(m_hComm != NULL)
return true;
else
return false;
}
bool CRS232_ConnectionDlg::ComSend(char *buffer, int iSize)
{
unsigned long iLength = 0;
int iErrorCount=0;
bool status = true;
while(WriteFile(m_hComm, buffer, iSize, &iLength, NULL) == 0)
{
//retransmission
iErrorCount++;
if(iErrorCount>5)
{
status = false;
break;
}
Sleep(100);
}
return status;
}
//---------------------------------------------------------------------------
bool CRS232_ConnectionDlg::ComReceive(CString &recvData)
{
bool bResult;
while(IsComOpen())
{
unsigned long ulNumRead = 0;
char *buffer=new char[128];
memset(buffer,0,128);
bResult = ::ReadFile(m_hComm,buffer, 128, &ulNumRead, NULL);
if (!bResult && ulNumRead == 0)
bResult = false;
else
recvData.Format("%s",buffer);
delete [] buffer;
if(!bResult)
{
break;
}
Sleep(50);
}
return bResult;
}
//---------------------------------------------------------------------------
void CRS232_ConnectionDlg::ComClear()
{
PurgeComm(m_hComm, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);
}
//---------------------------------------------------------------------------
bool CRS232_ConnectionDlg::ComClose()
{
if(m_hComm == INVALID_HANDLE_VALUE || m_hComm == NULL)
{
m_hComm = NULL;
return true;
}
bool b = ::CloseHandle(m_hComm) == 0 ? false : true;
if(b)
m_hComm = NULL;
return b;
}
void CRS232_ConnectionDlg::OnBnClickedButtonConnect()
{
if(m_LineFeed.GetCheck())
{
//Line Feed LF \n
//Carriage Return CR \r
csLineFeed = "\n";
csCarrierReture = "\r";
}
else
{
csLineFeed = "";
csCarrierReture = "";
}
if(m_Echo.GetCheck())
{
bEcho = true;
}
else
bEcho = false;
if(m_RecvLineFeed.GetCheck())
{
csRecvLineFeed = "\n\r";
}
else
{
csRecvLineFeed = "";
}
//++++++++++Setting UI++++++++++
if(m_RecvAuto.GetCheck())
bAutoRecv = true;
else
bAutoRecv = false;
m_BtnRecv.ShowWindow(!bAutoRecv);
time_t tSysTime;
struct tm* ptm_time;
char bufTime[2048];
time(&tSysTime);
ptm_time = localtime(&tSysTime);
strftime(bufTime, sizeof(bufTime), "%Y/%m/%d %H:%M:%S\n", ptm_time);
m_ListSendRecvHistory.InsertItem(0,"<->");
//----------Setting UI----------
CString csBtnCaption;
m_BtnConnect.GetWindowTextA(csBtnCaption);
CBitmap ResultPic;
if(csBtnCaption == "Connect")
{
//++++++++++Connect to RS232++++++++++
bool status;
CString csMsg="";
status = ComOpen( m_ComPort.GetCurSel(), //ComNo
m_BaudRate.GetCurSel(), //BaudRate
m_DataBit.GetCurSel(), //DataBit
m_StopBit.GetCurSel(), //StopBit
m_Parity.GetCurSel() //ParityCheck
);
//----------Connect to RS232----------
if(status)
{
ResultPic.LoadBitmapA(IDB_BITMAP_CONNECT);
m_ConnectStatusImg.SetBitmap(HBITMAP(ResultPic));
m_BtnConnect.SetWindowTextA("Disconnect");
EnableCOMSetting(false);
m_ListSendRecvHistory.SetItemText(0,1,bufTime);
m_ListSendRecvHistory.SetItemText(0,2,"Connect");
}
else
{
m_ListSendRecvHistory.SetItemText(0,1,bufTime);
m_ListSendRecvHistory.SetItemText(0,2,"Connect Fail");
}
}
else if(csBtnCaption == "Disconnect")
{
//++++++++++Disconnect RS232++++++++++
bool status = ComClose();
//----------Disconnect RS232----------
if(status)
{
ResultPic.LoadBitmapA(IDB_BITMAP_DISCONNECT);
m_ConnectStatusImg.SetBitmap(HBITMAP(ResultPic));
m_BtnConnect.SetWindowTextA("Connect");
EnableCOMSetting(true);
m_ListSendRecvHistory.SetItemText(0,1,bufTime);
m_ListSendRecvHistory.SetItemText(0,2,"Disconnect");
}
else
{
m_ListSendRecvHistory.SetItemText(0,1,bufTime);
m_ListSendRecvHistory.SetItemText(0,2,"Disconnect Fail");
}
}
}
void CRS232_ConnectionDlg::OnBnClickedButtonSend()
{
CString csMessage;
time_t tSysTime;
struct tm* ptm_time;
char bufTime[2048];
time(&tSysTime);
ptm_time = localtime(&tSysTime);
strftime(bufTime, sizeof(bufTime), "%Y/%m/%d %H:%M:%S\n", ptm_time);
m_SendMessage.GetWindowTextA(csMessage);
m_ListSendRecvHistory.InsertItem(0," ->");
m_ListSendRecvHistory.SetItemText(0,1,bufTime);
m_ListSendRecvHistory.SetItemText(0,2,csMessage+csLineFeed+csCarrierReture);
if(m_RecvAuto.GetCheck())
bAutoRecv = true;
else
bAutoRecv = false;
m_BtnRecv.ShowWindow(!bAutoRecv);
}
void CRS232_ConnectionDlg::OnBnClickedButtonRecv()
{
if(m_hComm != NULL)
{
//Thread_Info.csCMD = csRecvMsg;
//Thread_Info.hCMD = AddMessage;
Thread_Info.hWnd = (HWND)theApp.m_hInstance;
AfxBeginThread(StartCOMThread, (LPVOID)&Thread_Info, THREAD_PRIORITY_NORMAL);
}
}
