专注于Linux系统移植及应用开发
RSS
>
热门关键字:  s3c2410x  linux  u-boot  yaffs  weiyan
当前位置 :| 伟研科技>嵌入式文章>

WINCE 串口通信程序(1)

来源: 作者: 时间:2008-11-12 点击:

一、创建智能MFC应用程序
 打开vs2005,打开菜单“文件”“新建”“项目”,选中Visual C++智能设备,在右边的窗口选中MFC智能应用程序,输入项目名称,比如“Serial”。点击“确定”

点“下一步”
 
选中默认的Pocket PC 2003,点“下一步”

选中“基于对话框”选项,点击“完成”

二、程序解读
1、创建用户图形界面
在VS2005工作台上,切换到“资源视图”,双击Dialog文件夹的IDD_SERIAL_DIALOG对对话框进行编辑,请参照下图进行设定控件,相应的控件的属性如下:

 
 
“接收区”设置如下
 

  

请注意画红线的地方,只有这样设置才能正常的接收字符,否则edit control控件不会自动换行。ID设为IDC_REV
“发送区”设置如下:

 

把发送区的ID设为IDC_SEND,其它选项默认就行了
把“打开串口”、“关闭串口”、“发送按键”的ID分别设为IDC_OPEN_BUTTON、IDC_CLOSE_BUTTON、IDC_SEND_BUTTON,其它选项默认。

2、 添加代码
切换到“解决方案资源管理器”,在SerialDlg.h加入如下代码
添加与控件对应的变量
 CButton ButClose;   //对应“关闭串口”按键
 CButton ButOpen;    //对应“打开串口”按键
 CButton ButSend;    //对应“发送”按键
 CString  strSendEdit; //对应“发送区”的字符串变量

 

添加消息映射函数
afx_msg void OnOpenCom();  //响应“打开串口”按键
 afx_msg void OnCloseCom(); //响应“关闭串口”按键
 afx_msg void OnSend();     //响应“发送”按键
 afx_msg void OnDestroy();  //应用程序结束时调用

 

添加必要的结构体和函数
 DCB dcb;      /* 串口参数结构体*/
 HANDLE hComm;     /* 串口操作句柄*/
 HANDLE ExitThreadEvent;  /* 串口接收线程退出事件*/
 CString strRecDisp;   /* 接收区显示字符*/
 BOOL ClosePort(void);   /* 关闭串口*/
// 打开串口
 BOOL OpenPort(LPCTSTR Port, int BaudRate, int DataBits, int StopBits, int Parity);

 // 串口接收线程
 static DWORD ComRecvThread(LPVOID lparam);

 // 串口接收数据成功回调函数
 typedef void (CALLBACK *ONCOMMRECV)(CWnd* pWnd, char *buf, int buflen);
 static void CALLBACK OnComRecv(CWnd* pWnd, char *buf, int buflen);

 

至此,必要的数据成员和成员函数已经添加完毕,打开SerialDlg.cpp,编写实现代码
void CSerialDlg::DoDataExchange(CDataExchange* pDX)控件和相应变量的绑定,添加代码如下
CDialog::DoDataExchange(pDX);
 DDX_Control(pDX,IDC_CLOSE_BUTTON ,ButClose);
 DDX_Control(pDX,IDC_OPEN_BUTTON ,ButOpen);
 DDX_Control(pDX,IDC_SEND_BUTTON ,ButSend);
 DDX_Text(pDX,IDC_SEND ,strSendEdit);

 

添加消息处理程序
 ON_BN_CLICKED(IDC_OPEN_BUTTON, OnOpenCom)
 ON_BN_CLICKED(IDC_CLOSE_BUTTON, OnCloseCom)
 ON_BN_CLICKED(IDC_SEND_BUTTON, OnSend)
 ON_WM_DESTROY()

 

BOOL CSerialDlg::OnInitDialog()添加如下初始化代码
strRecDisp=_T("");                  /*接收字符串变量初始化*/
 CenterWindow(GetDesktopWindow());
 hComm = INVALID_HANDLE_VALUE;  /* 串口操作句柄无效*/
 ExitThreadEvent=NULL;               /* 关闭线程事件句柄无效*/
 ButClose.EnableWindow(FALSE);       /* "关闭串口"按键无效*/
 UpdateData(FALSE);                   /*把变量的值传给控件*/

 

添加打开串口函数代码BOOL CSerialDlg::OpenPort(LPCTSTR Port, int BaudRate, int DataBits, int StopBits, int Parity)
BOOL CSerialDlg::OpenPort(LPCTSTR Port, int BaudRate, int DataBits, int StopBits, int Parity)
{
 COMMTIMEOUTS CommTimeOuts;  //创建超时变量参数
DWORD error;                //获得错误代码
//打开串口
 hComm = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
 if(hComm == INVALID_HANDLE_VALUE)
 {
  error=GetLastError();
  MessageBox(_T("无法打开端口或端口已打开!请检查是否已被占用."));
  return FALSE;
 }
 GetCommState(hComm, &dcb);        /* 读取串口的DCB */
 dcb.BaudRate= BaudRate;                   /*设置波特率*/
 dcb.ByteSize = DataBits;                        /*设置数据位*/
 dcb.Parity= Parity;                             /*设置校验位*/
 dcb.StopBits= StopBits;                         /*设置停止位*/
 dcb.fParity= FALSE;      /* 禁止奇偶校验*/
 dcb.fBinary= TRUE;
 dcb.fOutX= 0;
 dcb.fInX= 0;
 //设置状态参数
 SetCommMask(hComm, EV_RXCHAR);     /* 串口事件:接收到一个字符*/ 
 SetupComm(hComm, 16384, 16384);     /* 设置接收与发送的缓冲区大小*/
    SetCommState(hComm, &dcb);
 BOOL isSucces=SetCommState(hComm, &dcb);/* 设置串口的DCB */
 if(!isSucces)     
 { 
  error=GetLastError();
  MessageBox(_T("无法按当前参数配置端口,请检查参数!"));
  ClosePort();
  return FALSE;
 }
 
 GetCommTimeouts(hComm, &CommTimeOuts);              /*获得超时参数*/ 
 //设置超时参数
 CommTimeOuts.ReadIntervalTimeout = 100;    /* 接收字符间最大时间间隔*/
 CommTimeOuts.ReadTotalTimeoutMultiplier = 1;  
 CommTimeOuts.ReadTotalTimeoutConstant = 100;  /* 读数据总超时常量*/
 CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
 CommTimeOuts.WriteTotalTimeoutConstant = 0;  
 if(!SetCommTimeouts(hComm, &CommTimeOuts))
 {
  MessageBox(_T("无法设置超时参数!"));
  ClosePort();
  return FALSE;
 }
 PurgeComm(hComm, PURGE_TXCLEAR | PURGE_RXCLEAR);  /* 清除收/发缓冲区*/
 return TRUE;  
}
添加关闭串口函数代码BOOL CSerialDlg::ClosePort(void)
BOOL CSerialDlg::ClosePort(void)
{
 if(hComm != INVALID_HANDLE_VALUE)
 {
  SetCommMask(hComm, 0); //通知线程退出
  PurgeComm(hComm, PURGE_TXCLEAR | PURGE_RXCLEAR); /* 清除收/发缓冲*/
  CloseHandle(hComm);        /* 关闭串口操作句柄*/
  hComm = INVALID_HANDLE_VALUE;
  return TRUE;
 }
 return FALSE;
}
实现回调函数void CALLBACK CSerialDlg::OnComRecv(CWnd* pWnd, char *buf, int buflen)
void CALLBACK CSerialDlg::OnComRecv(CWnd* pWnd, char *buf, int buflen)
{   
   CString tmp;
      CSerialDlg *pDlg = (CSerialDlg*)pWnd;
   CEdit *pRecvStrEdit = (CEdit*)pDlg->GetDlgItem(IDC_REV); //获取接收区指针
   for (int i = 0; i < buflen; i++, buf++)
 {
  tmp.Format(_T("%c"), *buf); /* 将字符转换为字符串*/
  pDlg->strRecDisp += tmp;
 }
 pRecvStrEdit->SetWindowText(pDlg->strRecDisp); /* 显示在窗口上*/
}
实现串口线程DWORD CSerialDlg::ComRecvThread(LPVOID lparam)
DWORD CSerialDlg::ComRecvThread(LPVOID lparam)
{
    DWORD dwLength;
 char *recvBuf = new char[1024];
 CSerialDlg *pDlg = (CSerialDlg*)lparam;

 while(TRUE)
 {  
  /* 等待线程退出事件*/
  if (WaitForSingleObject(pDlg->ExitThreadEvent, 0) == WAIT_OBJECT_0)
   break; 

  if (pDlg->hComm != INVALID_HANDLE_VALUE)
  {            /* 从串口读取数据*/
   BOOL fReadState = ReadFile(pDlg->hComm, recvBuf, 1024, &dwLength, NULL);
   if(!fReadState)
   {
    //MessageBox(_T("无法从串口读取数据!"));
   }
   else
   {
    if(dwLength != 0)
    OnComRecv(pDlg, recvBuf, dwLength-2);  /* 接收成功调用回调函数*/
   }
  }
 }  
 delete[] recvBuf;
 return 0;
}
下面是消息处理函数实现
“打开串口”消息处理
 void CSerialDlg::OnOpenCom()

 DWORD IDThread;
 HANDLE hRecvThread; 
 UpdateData(TRUE);                           /*把控件的值传给变量*/
 CString strPort =_T("COM1:");    /* 设置串口号*/
 DWORD baud  = 115200;                  /* 设置波特率*/
 DWORD databit   = 8;                         /* 设置数据位*/
 BYTE stopbit    = ONESTOPBIT;                /* 设置停止位*/
 BYTE parity  = NOPARITY;              /* 设置校验位*/
 BOOL ret = OpenPort(strPort, baud, databit, stopbit, parity); /* 打开串口*/
 if (ret == FALSE)
  return;
 ExitThreadEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* 创建串口接收线程退出事件*/
 hRecvThread = CreateThread(0, 0, ComRecvThread, this, 0, &IDThread);
 if (hRecvThread == NULL)
 {
  MessageBox(_T("创建接收线程失败!"));
  return;
 }
 CloseHandle(hRecvThread);
 ButOpen.EnableWindow(FALSE);     /* 打开端口按键禁止*/   
 ButClose.EnableWindow(TRUE);     /* 关闭端口按键使能*/ 
 MessageBox(_T("打开串口COM1成功!"));

 }
“关闭串口”消息处理
void CSerialDlg::OnCloseCom()
 {
   if (ExitThreadEvent != NULL)
 {
  SetEvent(ExitThreadEvent);     /* 通知线程退出*/
  Sleep(1000);
  CloseHandle(ExitThreadEvent);
  ExitThreadEvent = NULL;
 }

 ButOpen.EnableWindow(TRUE);      /* 打开端口按键禁止*/   
 ButClose.EnableWindow(FALSE);      /* 关闭端口按键使能*/ 
 ClosePort();                                
}
“发送”消息处理
void CSerialDlg::OnSend()
 {
 DWORD dwactlen;
     char *recvBuf = new char[1024];
 if (hComm == INVALID_HANDLE_VALUE)
 {
  MessageBox(_T("串口未打开!"));
  return;
 }
 UpdateData(TRUE);
 int len = strSendEdit.GetLength();     /* 取得输入字符串长度*/
 char *psendbuf = new char[len];

 for(int i = 0; i < len;i++)
  psendbuf[i] = (char)strSendEdit.GetAt(i);   /* 转换为单字节字符*/

 WriteFile(hComm, psendbuf, len, &dwactlen, NULL);  /* 从串口发送数据*/

 delete[] psendbuf;
 }
 程序结束调用的函数
 void CSerialDlg::OnDestroy()
 {
    CDialog::OnDestroy();
 
 if (ExitThreadEvent != NULL)
 {
  SetEvent(ExitThreadEvent);    /* 通知串口接收线程退出*/
  Sleep(1000);
  CloseHandle(ExitThreadEvent);    /* 关闭接收线程退出事件句柄*/
  ExitThreadEvent = NULL;
 }
 ClosePort();         /* 关闭串口*/

 }

联系我们