当前位置: 首页 > article >正文

MODBUS规约的秘密之五-----如何用C++编写MODBUS规约

根据之前的几篇MODBUS规约介绍,我们发现MODBUS规约是比较简单的一个规约,
在这里插入图片描述
如上图,我们可以看到MODBUS_RTU和MODBUS_TCP之间有共同的部分,因此可以考虑用C++中的继承方式。将上图中的红框部分用一个基类来实现,串口方式和网络方式分别继承自此基类。这样就可以同时实现即支持MODBUS_RTU又支持MODBUS_TCP,相当于将MODBUS分成了应用层和链路层。使用共同的应用层代码维护也比较方便。

基类可以这样写:

class CModbusS
{
public:
    CModbusS();
protected:
    BOOL IsTerminated();
private:
    BOOL m_bIsTerminated;
    CSync sync_Tag;
    bool ProcessSOE();
    bool ProcessYX();
    CSync m_Sync_Event; // 事件队列用互斥
    void AddToEventQueue(TYxValue &signalValue,TSignalAddress &SignalAddr);
    // 读取事件,一次一条
    BOOL ReadEventQuent(TYxValue &signalValue,TSignalAddress &SignalAddr);
    list<TYXData> m_lSOE; // 遥信事件队列
    list<TYXData>::iterator m_itrEventPos;
    BOOL EventQueueEmpty();
    void ActEvent(); // 确认已经发送的事件
public:
    //CModbusS();
    //~CModbusS();
    // 前两个参数,报文和报文实际长度,offset实际报文开始
    // 报文主要用于显示,偏移用于实际解析报文,对于TCP,偏移为7个字节,对于串口,偏移为1个字节,实际都从处理功能码开始
    int AnalyseDiagram(LPBYTE szDiag,int len,int offset=7);
    virtual int WriteTele(LPBYTE szDiag, WORD length)=0;
    void SetStopTag(BOOL bFlag);
    virtual void MainControlS();
    void InitSignalParam();
    virtual void * LinkLayerMain()=0;
    WORD CreateExceptionDiag(LPBYTE szDiag,BYTE btExCode);
};

这个类中主要实现就是分析报文函数AnalyseDiagram,处理都是从功能码开始的,之所以传入全部报文,还是为了打印显示报文用。处理报文不处理报文头和校验码,只处理串口模式和网络模式中的共同部分。
报文报文中需要调用的处理遥信等函数放到了私有函数中。

MainControlS为应用层主处理函数,LinkLayerMain为链路层处理函数,定义为纯虚函数,需要继承实现。

发送报文函数WriteTele也定义为纯虚函数,需要继承实现,基类只负责将需要发送的应用层报文传入,由继承类来增加头尾并进行具体发送。

class CMODBUSSCOM: public CModbusS{
    int WriteTele(LPBYTE szDiag, WORD length);
    void * LinkLayerMain();
    CSerial m_Comm;
    WORD suMod_buildCRC16(
            unsigned char *puchMsg,                /* message to calculate CRC upon */
            unsigned short usDataLen               /* quantity of bytes in message  */
    );
};

以上为MODBUS_RTU的继承实现,主要实现发送函数WriteTele和链路层函数。suMod_buildCRC16这个为计算校验码函数,网上和文档中都有很多具体实现。

class CMODBUSSTCP : public CModbusS{
public:
    CMODBUSSTCP();
    CConnection  *m_conn;
    string m_strCurIP; // 当前连接件的IP
private:

    CNetworking m_myNet;
    void StopListen();
    bool StartListen();
    void CheckConn();
    BYTE m_btSendBuf[SEND_BUF_LEN]; // 发送缓冲


    int WriteTele(LPBYTE szDiag, WORD length);

    void * LinkLayerMain();

};

以上为MODBUS_TCP的继承类定义。同样只需要实现发送函数和链路层函数。由于这里展示是从规约,因此有启动监听和停止监听函数。主规约是类似的,用TCP的连接函数即可。

if(g_ModbussParam.bMODBUSTCP)
            g_ModbussParam.pModbus = new CMODBUSSTCP();
   else
            g_ModbussParam.pModbus = new CMODBUSSCOM();

在main函数中,根据读取配置文件,判断是MODBUS_TCP,还是MODBUS_RTU来实例化不同的类。其中的 pModbus 指针定义如下:
CModbusS *pModbus; // modbus实例

最后创建两个线程,
一个应用层线程,应用线程可以和主线程在一起,也可以单独开一个线程
void * AppThread (void * lparam)
{
CModbusS * pModbuss = (CModbusS*)(lparam);
pModbuss->SetStopTag(FALSE);
pModbuss->MainControlS();
return 0;
}
一个链路层线程
void ProcessModbusSLinkThread(void pParam)
{
CModbusS
pModbusLink = reinterpret_cast <CModbusS
> (pParam);
return pModbusLink->LinkLayerMain();
}


http://www.kler.cn/a/411291.html

相关文章:

  • Mongo数据库 --- Mongo Pipeline
  • D80【 python 接口自动化学习】- python基础之HTTP
  • pikachu文件上传漏洞通关详解
  • Vue实训---5-路由搭建
  • ctfshow单身杯2024wp
  • 远程控制软件:探究云计算和人工智能的融合
  • 基于物联网技术的智能家居安全监控体系构建
  • 利用HTML5和CSS来实现一个漂亮的表格样式
  • Spring Boot——统一功能处理
  • Rust学习笔记_01——基础
  • 新能源汽车充电插口类型识别-YOLO标记,可识别Type1,ccs2的充电标准
  • 【机器学习】如何使用Python的Scikit-learn库实现机器学习模型,并对数据进行预处理和特征缩放以提高模型性能?
  • 【青牛科技】D1117 1.0A低压差线性稳压电路芯片介绍,可保证了输出电压精度控制在±1.5%的范围内
  • 【论文复现】融入模糊规则的宽度神经网络结构
  • 【笔记】轻型民用无人驾驶航空器安全操控
  • 51单片机从入门到精通:理论与实践指南入门篇(二)
  • C语言数据结构——详细讲解《栈》
  • 【docker集群应用】Docker常用命令
  • ubuntu 连不上网 桌面 右上角没有网络图标 Ubuntu复制后虚拟网络失效问题
  • Error executing a python function in exec_func_python() autogenerated
  • C++ 二叉搜索树(Binary Search Tree, BST)深度解析与全面指南:从基础概念到高级应用、算法优化及实战案例
  • 基于DVB-T的COFDM+16QAM+LDPC图传通信系统matlab仿真,包括载波同步,定时同步,信道估计
  • Unity中动态生成贴图并保存成png图片实现
  • SAR ADC系列15:基于Vcm-Base的开关切换策略
  • 二叉树的层次遍历
  • web组态可视化编辑器