深入浅出VC 串口编程之基于Win32API(2)

转自 http://www.west263.com/info/html/chengxusheji/C-C--/20080410/60910_3.html

对话框上控件对应的资源文件(.RC)中的内容如下:

BEGIN
 EDITTEXT IDC_RECV_EDIT,28,119,256,46,ES_AUTOHSCROLL
 GROUPBOX "发送数据",IDC_STATIC,19,15,282,70
 GROUPBOX "接收数据",IDC_STATIC,19,100,282,80
 EDITTEXT IDC_SEND_EDIT,29,33,214,39,ES_AUTOHSCROLL
 PUSHBUTTON "清除",IDC_CLEAR_BUTTON,248,33,50,14
 PUSHBUTTON "发送",IDC_SEND_BUTTON,248,55,50,14
END
  而整个对话框的消息映射(描述了消息及其对应的行为)如下:

BEGIN_MESSAGE_MAP(CSerialPortAPIDlg, CDialog)
//{{AFX_MSG_MAP(CSerialPortAPIDlg)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 ON_BN_CLICKED(IDC_CLEAR_BUTTON, OnClearButton)
 ON_BN_CLICKED(IDC_SEND_BUTTON, OnSendButton)
 ON_MESSAGE(COM_RECVDATA, OnRecvData)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
  我们为IDC_SEND_EDIT和IDC_RECV_EDIT编辑框控件分别添加了一个CString变量m_recv和m_send,下面的代码描述了这一行为:

class CSerialPortAPIDlg : public CDialog
{
 // Construction
 public:
  CSerialPortAPIDlg(CWnd* pParent = NULL); // standard constructor

  // Dialog Data
  //{{AFX_DATA(CSerialPortAPIDlg)
   enum { IDD = IDD_SERIALPORTAPI_DIALOG };
   CString m_recv; //IDC_RECV_EDIT控件对应的变量
   CString m_send; //IDC_SEND_EDIT控件对应的变量
  //}}AFX_DATA

  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(CSerialPortAPIDlg)
 protected:
  virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
 //}}AFX_VIRTUAL

 // Implementation
 protected:
  BOOL OpenSerialPort1();
  HICON m_hIcon;

  // Generated message map functions
  //{{AFX_MSG(CSerialPortAPIDlg)
   virtual BOOL OnInitDialog();

 

afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
   afx_msg void OnPaint();
   afx_msg HCURSOR OnQueryDragIcon();
   afx_msg void OnClearButton();
   afx_msg void OnSendButton();
   afx_msg void OnRecvData(WPARAM wParam, LPARAM lParam);
  //}}AFX_MSG
  DECLARE_MESSAGE_MAP()
};

CSerialPortAPIDlg::CSerialPortAPIDlg(CWnd* pParent /*=NULL*/)
: CDialog(CSerialPortAPIDlg::IDD, pParent)
{
 //{{AFX_DATA_INIT(CSerialPortAPIDlg)
  //在构造函数中初始化变量
  m_recv = _T(""); //在构造函数中初始化变量
  m_send = _T("");
 //}}AFX_DATA_INIT
 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

//建立编辑框控件和变量之间的映射
void CSerialPortAPIDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CSerialPortAPIDlg)
  DDX_Text(pDX, IDC_RECV_EDIT, m_recv);
  DDX_Text(pDX, IDC_SEND_EDIT, m_send);
 //}}AFX_DATA_MAP
}
  在对话框的OnInitDialog()函数中,我们启动窗口监听线程并将主窗口句柄传递给线程控制函数:

BOOL CSerialPortAPIDlg::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
 SetIcon(m_hIcon, FALSE); // Set small icon

 // TODO: Add extra initialization here
 //启动串口监视线程
 DWORD threadID;
 hCommThread = ::CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0,
     (LPTHREAD_START_ROUTINE)SerialPort1ThreadProcess, 
 AfxGetMainWnd()->m_hWnd, 0, &threadID);
 if (hCommThread == NULL)
 {
  ::AfxMessageBox("创建串口1处理线程失败");
  ::PostQuitMessage(0);
 }
 return TRUE; // return TRUE unless you set the focus to a control
}

//"清除"按钮函数
void CSerialPortAPIDlg::OnClearButton() 
{
 // TODO: Add your control notification handler code here
 m_send = "";
 UpdateData(false);
}

//发送数据函数("发送"按钮函数)
void CSerialPortAPIDlg::OnSendButton() 
{
 // TODO: Add your control notification handler code here
 UpdateData(true);
 DWORD wCount = 0;
 WriteFile(hCom, m_send, m_send.GetLength(), &wCount, NULL);//发送数据
}

//接收数据后(通过监听线程发来的用户自定义消息)显示
void CSerialPortAPIDlg::OnRecvData(WPARAM wParam, LPARAM lParam)
{
 CString recvStr((char *)wParam);
 m_recv = recvStr;
 UpdateData(false);
}

  在工程中添加SerialPortControl.h和SerialPortControl.cpp两个文件,前者声明串口控制的接口函数及外部全局变量,后者实现串口接口函数及串口监听线程控制函数。

  SerialPortControl.h文件

#ifndef _SERIAL_PORT_CONTROL_H
#define _SERIAL_PORT_CONTROL_H

#define COM_RECVDATA WM_USER 1000//自定义消息

extern HANDLE hCom; //全局变量,串口句柄
extern HANDLE hCommThread; //全局变量,串口线程
//串口监视线程控制函数
extern DWORD WINAPI SerialPort1ThreadProcess(HWND hWnd);
//打开并设置PC串口1(COM1)
extern BOOL OpenSerialPort1();

#endif
SerialPortControl.cpp文件
#include "StdAfx.h"
#include "SerialPortControl.h"

HANDLE hCom; //全局变量,串口句柄
HANDLE hCommThread; //全局变量,串口线程

BOOL OpenSerialPort1()
{
 //打开并设置COM1
 hCom=CreateFile("COM1", GENERIC_READ|GENERIC_WRITE, 0,NULL , OPEN_EXISTING, 0, NULL);
 if (hCom==(HANDLE)-1)
 {
  AfxMessageBox("打开COM1失败");
  return false;
 }
 else
 {
  DCB wdcb;
  GetCommState (hCom, &wdcb);
  wdcb.BaudRate=9600;//波特率:9600,其他:不变
  SetCommState (hCom, &wdcb);
  PurgeComm(hCom, PURGE_TXCLEAR);
 }
 return true;
}

//以一个线程不同监控串口行接收的数据
DWORD WINAPI SerialPort1ThreadProcess( HWND hWnd//主窗口句柄)
{
 char str[101];
 DWORD wCount; //读取的字节数
 while(1)
 {
  ReadFile(hCom,str, 100, &wCount, NULL);
  if(wCount > 0) //收到数据
  {
   str[wCount] = '\0';
   ::PostMessage(hWnd, COM_RECVDATA, (unsigned int) str, wCount); 
   //发送消息给对话框主窗口,以进行接收内容的显示
  }
 }
 return TRUE;
}

posted @   曦花  阅读(270)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示