AFX_PMSG数据结构

博客主要介绍了AFX_PMSG数据结构,给出其定义,说明了AFX_MSG_CALL的作用及函数指针的限定情况。还阐述了用AFX_PMSG定义变量的使用规则,如只能用类的类方法赋值、只能在类内部使用等,同时说明了类名限定对类型作用域的影响。

AFX_PMSG数据结构
  定义: typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);
  
  void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);  //AFX_MSG_CALL定义为空,只为强调是MSG_CALL
  
  void (CCmdTarget::*AFX_PMSG)(void); //指定(限定)为ccmdTarget 的成员函数
  
  typedef void (*AFX_PMSG)(void);   //使用typedef定义函数指针类型: AFX_PMSG
  
  void (*afx_pmsg)(void);  //普通函数指针

//===========

typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);

AFX_PMSG pfunc; //用AFX_PMSG定义变量pfunc,则:

加上CCmdTarget::限定,则:(有无此限定导致了函数的调用约定不同,全局函数和类方法的约定是不同的)
1.定义的函数指针变量只能用该类的类方法赋值
2.只能在类内部使用
3.唯一的使用形式(this->*pfunc)();

同时,类名限定不会影响该类型的作用域,即:
1.类外部定义,为全局作用域(类外部或者内部,可直接定义变量,好比一般的自定义全局类型如struct)
2.类内部定义,作用域为类内部(外部仍可通过作用域解析符使用)

#pragma once #include "SerialPort.h" // 自定义消息 #define WM_COMM_ERR (WM_USER + 100) class CPCMFCDlg : public CDialogEx { public: CPCMFCDlg(CWnd* pParent = nullptr) noexcept; #ifdef AFX_DESIGN_TIME enum { IDD = IDD_PCMFC_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); virtual BOOL OnInitDialog(); HICON m_hIcon; // 消息映射 DECLARE_MESSAGE_MAP() public: // 控件变量 CComboBox m_cbPort; CComboBox m_cbBaud; CComboBox m_cbParity; CComboBox m_cbData; CComboBox m_cbStop; // 状态列表控件 CListBox m_listStatus; CString m_strTime1; CString m_strTime2; CString m_strTime3; // 串口相关 CSerialPort m_SerialPort; BOOL m_bConnected; // 定时器 UINT_PTR m_nTimerID; // 功能函数 BOOL ValidateTimeFormat(CString strTime) noexcept; void SendFeedCommand(); void OpenSerialPort(); void CloseSerialPort(); void AddStatusMessage(CString message); // 控件事件处理 afx_msg void OnBnClickedButtonOpen(); afx_msg void OnBnClickedButtonClose(); afx_msg void OnBnClickedButtonNowfeed(); afx_msg void OnBnClickedButtonTimefeed(); afx_msg void OnTimer(UINT_PTR nIDEvent); afx_msg LRESULT OnCommErr(WPARAM wParam, LPARAM lParam); // 以下函数保持空实现 afx_msg void OnCbnSelchangeComboPort() noexcept {} afx_msg void OnCbnSelchangeComboBaud() noexcept {} afx_msg void OnCbnSelchangeComboParity() noexcept {} afx_msg void OnCbnSelchangeComboData() noexcept {} afx_msg void OnCbnSelchangeComboStop() noexcept {} afx_msg void OnEnChangeEditTime1() noexcept {} afx_msg void OnEnChangeEditTime2() noexcept {} afx_msg void OnEnChangeEditTime3() noexcept {} }; #include "pch.h" #include "framework.h" #include "PCMFC.h" #include "PCMFCDlg.h" #include "afxdialogex.h" #include <ctime> #ifdef _DEBUG #define new DEBUG_NEW #endif CPCMFCDlg::CPCMFCDlg(CWnd* pParent) noexcept : CDialogEx(IDD_PCMFC_DIALOG, pParent), m_strTime1(_T("08:00")), m_strTime2(_T("12:00")), m_strTime3(_T("18:00")), m_bConnected(FALSE), m_nTimerID(0) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CPCMFCDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_COMBO_PORT, m_cbPort); DDX_Control(pDX, IDC_COMBO_BAUD, m_cbBaud); DDX_Control(pDX, IDC_COMBO_PARITY, m_cbParity); DDX_Control(pDX, IDC_COMBO_DATA, m_cbData); DDX_Control(pDX, IDC_COMBO_STOP, m_cbStop); DDX_Control(pDX, IDC_LIST, m_listStatus); DDX_Text(pDX, IDC_EDIT_TIME1, m_strTime1); DDX_Text(pDX, IDC_EDIT_TIME2, m_strTime2); DDX_Text(pDX, IDC_EDIT_TIME3, m_strTime3); } BEGIN_MESSAGE_MAP(CPCMFCDlg, CDialogEx) ON_BN_CLICKED(IDC_BUTTON_OPEN, &CPCMFCDlg::OnBnClickedButtonOpen) ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CPCMFCDlg::OnBnClickedButtonClose) ON_BN_CLICKED(IDC_BUTTON_NOWFEED, &CPCMFCDlg::OnBnClickedButtonNowfeed) ON_BN_CLICKED(IDC_BUTTON_TIMEFEED, &CPCMFCDlg::OnBnClickedButtonTimefeed) ON_WM_TIMER() ON_MESSAGE(WM_COMM_ERR, &CPCMFCDlg::OnCommErr) END_MESSAGE_MAP() void CPCMFCDlg::AddStatusMessage(CString message) { const CTime currentTime = CTime::GetCurrentTime(); CString timestamp = currentTime.Format(_T("[%H:%M:%S] ")); m_listStatus.AddString(timestamp + message); const int count = m_listStatus.GetCount(); if (count > 0) { m_listStatus.SetCurSel(count - 1); } } BOOL CPCMFCDlg::OnInitDialog() { CDialogEx::OnInitDialog(); SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE); // 初始化串口列表 for (int i = 1; i <= 16; ++i) { CString port; port.Format(_T("COM%d"), i); m_cbPort.AddString(port); } m_cbPort.SetCurSel(0); // 初始化波特率 m_cbBaud.AddString(_T("1200")); m_cbBaud.AddString(_T("2400")); m_cbBaud.AddString(_T("4800")); m_cbBaud.AddString(_T("9600")); m_cbBaud.AddString(_T("19200")); m_cbBaud.AddString(_T("38400")); m_cbBaud.AddString(_T("57600")); m_cbBaud.AddString(_T("115200")); m_cbBaud.SetCurSel(3); // 9600 // 初始化校验位 m_cbParity.AddString(_T("None")); m_cbParity.AddString(_T("Odd")); m_cbParity.AddString(_T("Even")); m_cbParity.SetCurSel(0); // 初始化数据位 m_cbData.AddString(_T("5")); m_cbData.AddString(_T("6")); m_cbData.AddString(_T("7")); m_cbData.AddString(_T("8")); m_cbData.SetCurSel(3); // 8 // 初始化停止位 m_cbStop.AddString(_T("1")); m_cbStop.AddString(_T("1.5")); m_cbStop.AddString(_T("2")); m_cbStop.SetCurSel(0); // 1 AddStatusMessage(_T("系统启动完成")); AddStatusMessage(_T("请设置串口参数并打开连接")); return TRUE; } LRESULT CPCMFCDlg::OnCommErr(WPARAM wParam, LPARAM lParam) { CString* pMsg = (CString*)wParam; if (pMsg) { AddStatusMessage(*pMsg); delete pMsg; } return 0; } void CPCMFCDlg::OpenSerialPort() { if (m_bConnected) { AddStatusMessage(_T("串口已连接,无需重复打开")); return; } CString strPort, strBaud; m_cbPort.GetWindowText(strPort); m_cbBaud.GetWindowText(strBaud); // 配置串口参数 const int baudRate = _ttoi(strBaud); const int parity = m_cbParity.GetCurSel(); const int dataBits = m_cbData.GetCurSel() + 5; const int stopBits = m_cbStop.GetCurSel(); if (m_SerialPort.InitPort(this, strPort, baudRate, parity, dataBits, stopBits)) { if (m_SerialPort.OpenListenThread()) { m_bConnected = TRUE; AddStatusMessage(_T("串口打开成功: ") + strPort + _T(" @") + strBaud); } else { m_SerialPort.ClosePort(); AddStatusMessage(_T("无法启动监听线程")); } } else { AddStatusMessage(_T("串口打开失败: ") + strPort); } } void CPCMFCDlg::CloseSerialPort() { if (m_bConnected) { m_SerialPort.ClosePort(); m_SerialPort.CloseListenThread(); m_bConnected = FALSE; AddStatusMessage(_T("串口已关闭")); } } void CPCMFCDlg::SendFeedCommand() { if (!m_bConnected) { AddStatusMessage(_T("错误: 串口未连接")); return; } BYTE cmd[] = { 0xAA, 0x01, 0x55 }; if (m_SerialPort.WriteToPort(cmd, sizeof(cmd))) { AddStatusMessage(_T("喂食指令已发送")); } else { AddStatusMessage(_T("错误: 指令发送失败")); } } BOOL CPCMFCDlg::ValidateTimeFormat(CString strTime) noexcept { if (strTime.GetLength() != 5) return FALSE; if (strTime[2] != _T(':')) return FALSE; const int hour = _ttoi(strTime.Left(2)); const int min = _ttoi(strTime.Mid(3)); return (hour >= 0 && hour < 24 && min >= 0 && min < 60); } void CPCMFCDlg::OnBnClickedButtonOpen() { AddStatusMessage(_T("尝试打开串口...")); OpenSerialPort(); } void CPCMFCDlg::OnBnClickedButtonClose() { AddStatusMessage(_T("关闭串口")); CloseSerialPort(); } void CPCMFCDlg::OnBnClickedButtonNowfeed() { AddStatusMessage(_T("执行立即投喂")); SendFeedCommand(); } void CPCMFCDlg::OnBnClickedButtonTimefeed() { UpdateData(TRUE); if (!ValidateTimeFormat(m_strTime1) || !ValidateTimeFormat(m_strTime2) || !ValidateTimeFormat(m_strTime3)) { AddStatusMessage(_T("错误: 时间格式无效 (使用 HH:MM 格式)")); return; } if (m_nTimerID) { KillTimer(m_nTimerID); AddStatusMessage(_T("定时喂食已停止")); } m_nTimerID = SetTimer(1, 30000, NULL); // 30秒检查一次 CString msg; msg.Format(_T("定时喂食已启动: %s, %s, %s"), (LPCTSTR)m_strTime1, (LPCTSTR)m_strTime2, (LPCTSTR)m_strTime3); AddStatusMessage(msg); } void CPCMFCDlg::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == 1) { const CTime currentTime = CTime::GetCurrentTime(); CString strCurrent = currentTime.Format(_T("%H:%M")); if (strCurrent == m_strTime1) { AddStatusMessage(_T("到达定时喂食时间1: ") + m_strTime1); SendFeedCommand(); } else if (strCurrent == m_strTime2) { AddStatusMessage(_T("到达定时喂食时间2: ") + m_strTime2); SendFeedCommand(); } else if (strCurrent == m_strTime3) { AddStatusMessage(_T("到达定时喂食时间3: ") + m_strTime3); SendFeedCommand(); } } CDialogEx::OnTimer(nIDEvent); } 这是一个基于stm32f103c6单片机以及pc端来实现智能宠物投喂的系统,现在stm32f103c6的PA1连接串口的RXD,PA2连接TXD,PB0和PB1用来控制电机的转动,请你根据上述代码给出修改之后的.h和.cpp代码以及要烧录到单片机里面的keil代码。方便我直接复制。
最新发布
06-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值