深入浅出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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现