此篇博客将按照Freemodbus的运行流程,对各个函数进行解析(无主机RTU模式),

我将尽我所能解释的尽量清楚,如有错误或者语义模糊处还请在评论区指出,谢谢。

运行流程:freemodbus流程解析(原创)【百度文库】

文章目录

  • 1、eMBInit(...)
    • 1.1 定义函数返回值类型eMBErrorCode
    • 1.2 函数指针的定义
    • 1.3 eMBRTUInit(...)函数
      • 1.3.1 xMBPortSerialInit(...)
      • 1.3.1 xMBPortTimersInit(...)
    • 1.4 xMBPortEventInit( )函数
    • 1.5 小结
  • 2. eMBEnable()
    • 2.1 eMBRTUStart()函数
      • 2.1.1 vMBPortSerialEnable
      • 2.1.2 vMBPortTimersEnable( );
    • 2.2 小结

1、eMBInit(…)

首先我们来看mb.h里的说明注释

eMBErrorCode
eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity );

/* ----------------------- 函数原型------------------------------*/

  • \简要说明:初始化modbus协议栈

  • 该函数初始化ASCII或RTU模块,

  • 并调用porting layer的init函数来配置硬件部分。

  • 请注意,直到eMBEnable()被调用之前,

  • Receiver一直是禁用的,没有Modbus帧被处理。

  • \参数1:eMode      选择 ASCII or RTU 模式.

  • \参数2:ucSlaveAddress  从机地址

  • \参数3:ucPort       端口。例如windows上的COM1。这个值跟平台有关系,一些端口干脆忽略它。(我也忽略了,直接填0)

  • \参数4:ulBaudRate     波特率

  • \参数5:eParity       校验方式

  • \返回值:没错返回 MB_ENOERR.

  • 没错然后,该协议处于禁用状态,并准备通过调用eMBEnable()激活。

  • Otherwise one of the following error codes

  • is returned:

    • eMBErrorCode::MB_EINVAL 从机地址无效,有效的地址范围1 - 247
    • eMBErrorCode::MB_EPORTERR porting layer返回错误

小结:从上面可以看出eMBInit(…)函数就是做一些初始化的

eMBErrorCode点击跳转定义
eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
{
eMBErrorCode eStatus = MB_ENOERR;
if( ( ucSlaveAddress = = MB_ADDRESS_BROADCAST ) ||
( ucSlaveAddress < MB_ADDRESS_MIN ) || ( ucSlaveAddress > MB_ADDRESS_MAX ) )
{
eStatus = MB_EINVAL;
}
else
{
ucMBAddress = ucSlaveAddress;首先判断从机地址对不对
switch ( eMode )
{这里给函数指针赋值 ,根据不同的帧格式来执行不同的操作
#if MB_RTU_ENABLED > 0
case MB_RTU:点击跳转函数指针定义
pvMBFrameStartCur = eMBRTUStart;
pvMBFrameStopCur = eMBRTUStop;
peMBFrameSendCur = eMBRTUSend;
peMBFrameReceiveCur = eMBRTUReceive;
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
pxMBFrameCBByteReceived = xMBRTUReceiveFSM;
pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM;
pxMBPortCBTimerExpired = xMBRTUTimerT35Expired;
eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );
break;
点击跳转eMBRTUInit函数
#endif
#if MB_ASCII_ENABLED > 0
case MB_ASCII:
pvMBFrameStartCur = eMBASCIIStart;
pvMBFrameStopCur = eMBASCIIStop;
peMBFrameSendCur = eMBASCIISend;
peMBFrameReceiveCur = eMBASCIIReceive;
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
pxMBFrameCBByteReceived = xMBASCIIReceiveFSM;
pxMBFrameCBTransmitterEmpty = xMBASCIITransmitFSM;
pxMBPortCBTimerExpired = xMBASCIITimerT1SExpired;
eStatus = eMBASCIIInit( ucMBAddress, ucPort, ulBaudRate, eParity );
break;
#endif
default:
eStatus = MB_EINVAL;
}
/* port dependent event module initalization failed. */
if( eStatus == MB_ENOERR ) 如果前面的初始化没错,进行接下来的任务
{
if( !xMBPortEventInit( ) ) 注意,这里是!点击跳转xMBPortEventInit函数
{
eStatus = MB_EPORTERR; 端口事件模块初始化失败。
}
else
{
eMBCurrentMode = eMode;
eMBState = STATE_DISABLED;一切正常就会来到这里
}
}
}
return eStatus;
}

1.1 定义函数返回值类型eMBErrorCode

/*! \ingroup modbus* \brief Errorcodes used by all function in the protocol stack.*/
typedef enum
{MB_ENOERR,                  /*!< no error. */MB_ENOREG,                  /*!< illegal register address. */MB_EINVAL,                  /*!< illegal argument. */MB_EPORTERR,                /*!< porting layer error. */MB_ENORES,                  /*!< insufficient resources. */MB_EIO,                     /*!< I/O error. */MB_EILLSTATE,               /*!< protocol stack in illegal state. */MB_ETIMEDOUT                /*!< timeout error occurred. */
} eMBErrorCode;

1.2 函数指针的定义

//eMBInit( )要初始化的函数指针. 根据模式(RTU or ASCII)来赋予不同的函数地址 定义在里面static peMBFrameSend peMBFrameSendCur;
static pvMBFrameStart pvMBFrameStartCur;
static pvMBFrameStop pvMBFrameStopCur;
static peMBFrameReceive peMBFrameReceiveCur;
static pvMBFrameClose pvMBFrameCloseCur;/* Callback functions required by the porting layer. They are called when* an external event has happend which includes a timeout or the reception* or transmission of a character.*/
BOOL( *pxMBFrameCBByteReceived ) ( void );//函数指针
BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );//函数指针
BOOL( *pxMBPortCBTimerExpired ) ( void );//函数指针BOOL( *pxMBFrameCBReceiveFSMCur ) ( void );//函数指针
BOOL( *pxMBFrameCBTransmitFSMCur ) ( void );//函数指针/*********************************mbframe.h*************************************/
//定义了函数指针
typedef void    ( *pvMBFrameStart ) ( void );typedef void    ( *pvMBFrameStop ) ( void );typedef eMBErrorCode( *peMBFrameReceive ) ( UCHAR * pucRcvAddress,UCHAR ** pucFrame,USHORT * pusLength );typedef eMBErrorCode( *peMBFrameSend ) ( UCHAR slaveAddress,const UCHAR * pucFrame,USHORT usLength );typedef void( *pvMBFrameClose ) ( void );

函数指针详情参考【】

1.3 eMBRTUInit(…)函数

在mbrtu.c中。此函数完成的时对于串口和传输数据要用的定时器的初始化,同时这下面调用的这两个函数也是在移植Freemodbus协议到不同的板子的过程中必须要进行修改的部分。

/* ----------------------- Start implementation -----------------------------*/
eMBErrorCode
eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
{eMBErrorCode    eStatus = MB_ENOERR;ULONG           usTimerT35_50us;( void )ucSlaveAddress;ENTER_CRITICAL_SECTION(  );/* Modbus RTU uses 8 Databits. */if( xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity ) != TRUE ){eStatus = MB_EPORTERR;}else{/* If baudrate > 19200 then we should use the fixed timer values* t35 = 1750us. Otherwise t35 must be 3.5 times the character time.*/if( ulBaudRate > 19200 ){usTimerT35_50us = 35;       /* 1800us. */}else{/* The timer reload value for a character is given by:** ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )*             = 11 * Ticks_per_1s / Baudrate*             = 220000 / Baudrate* The reload for t3.5 is 1.5 times this value and similary* for t3.5.*/usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );}if( xMBPortTimersInit( ( USHORT ) usTimerT35_50us ) != TRUE ){eStatus = MB_EPORTERR;}}EXIT_CRITICAL_SECTION(  );return eStatus;
}

1.3.1 xMBPortSerialInit(…)

1.3.1 xMBPortTimersInit(…)

这关这两个函数的详细介绍请看【】
关于modbus协议数据传输间隔3.5T的详细解释请看【】

1.4 xMBPortEventInit( )函数

BOOL
xMBPortEventInit( void )
{xEventInQueue = FALSE;return TRUE;
}

1.5 小结

做为在main()调用的第一个初始化函数,具体功能可总结为如下

eMBInit(RTU,从机地址,端口,波特率,校验方式)
{
  验证从机地址是否正确
  设置RTU模式并对函数指针进行映射
  调用eMBRTUInit( 从机地址, 端口, 波特率, 校验)
  {
     初始化串口xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity )
     初始化定时器xMBPortTimersInit( ( USHORT ) usTimerT35_50us )
  }
  初始化事件函数xMBPortEventInit( )
}


2. eMBEnable()

首先我们来看mb.h里的说明注释

eMBErrorCode    eMBEnable( void );
  • 简要说明:使能Modbus协议栈.
  • 此函数启动处理消息帧
  • 只有协议栈在disabled状态下才可以enable
  • 返回值:如果协议栈现在处于enabled状态,则返回 MB_ENOERR.
  •     如果不在 disabled state 则返回 MB_EILLSTATE.
    */

eMBErrorCode
eMBEnable( void )
{eMBErrorCode    eStatus = MB_ENOERR;if( eMBState == STATE_DISABLED ) //先前一定要是 Disbaled状态{/* Activate the protocol stack. */pvMBFrameStartCur(  );//  pvMBFrameStartCur = eMBRTUStart;函数指针 ,不太懂eMBState = STATE_ENABLED;}else{eStatus = MB_EILLSTATE;}return eStatus;
}

函数指针赋值过了,直接调用

2.1 eMBRTUStart()函数

void
eMBRTUStart( void )
{ENTER_CRITICAL_SECTION(  );/* Initially the receiver is in the state STATE_RX_INIT. we start* the timer and if no character is received within t3.5 we change* to STATE_RX_IDLE. This makes sure that we delay startup of the* modbus protocol stack until the bus is free.*/eRcvState = STATE_RX_INIT;vMBPortSerialEnable( TRUE, FALSE );vMBPortTimersEnable(  );EXIT_CRITICAL_SECTION(  );
}

2.1.1 vMBPortSerialEnable

详情请看【】

2.1.2 vMBPortTimersEnable( );

详情请看【】

2.2 小结

eMBErrorCode
eMBEnable( void )
{

  判断状态为进制,则调用eMBRTUStart()
  {
    状态设为RX初始化
    启动串口接收功能
    使能定时器
  }
  状态设置为使能
}

未完待续

【STM32】Freemodbus流程解析函数解析详细相关推荐

  1. Flowable 快速入门教程:Flowable 入门开发案例,结合流程设计器详细讲解

    Flowable 快速入门教程:Flowable 入门开发案例,结合流程设计器详细讲解 前言 流程设计器集成 整体流程图 流程节点说明 第一审核人节点:实际设置审核人 配置信息 说明 第二审核人:参数 ...

  2. 【SemiDrive源码分析】【X9芯片启动流程】30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一)

    [SemiDrive源码分析][X9芯片启动流程]30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一) 一.Android Kernel 启动流程分析 ...

  3. busybox启动流程简单解析:从init到shell login

    https://www.cnblogs.com/arnoldlu/p/10868354.html busybox启动流程简单解析:从init到shell login 关键词:kernel_init() ...

  4. python流程控制语句-Python中流程控制语句的详细介绍

    除了刚才介绍的while语句之外,Python也从其他语言借鉴了其他流程控制语句,并做了相应改变.Python中流程控制语句的详细介绍 4.1 ifStatements 或许最广为人知的语句就是if语 ...

  5. Git使用流程及技巧 - 详细教程

    Git使用流程及技巧 - 详细教程 前言 1. 技巧 1.1. 基础技巧 1.2. 提升SSH传输速度 1.3. 解决Git Bash命令行的中文乱码问题 1.3.1. 情况1:内部资源乱码 1.3. ...

  6. 爬虫的基本原理:网络爬虫、爬虫基本流程、解析方式、保存数据

    爬虫的基本原理:网络爬虫.爬虫基本流程.解析方式 网络爬虫(Web crawler),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本,它们被广泛用于互联网搜索引擎或其他类似网站,可以自动采集 ...

  7. Godaddy域名A记录解析详细教程

    Godaddy域名A记录解析详细教程 1.先开的Godaddy.com,然后在网页顶部进行登录.如图1: 2.登陆过后,点击导航条最右边的:My Account 如图2: 3.这时点击左栏的:Doma ...

  8. (一)Ubuntu安装详细教程(从镜像制作到NVIDIA驱动安装全流程)——超详细的图文教程

    Ubuntu安装详细教程(从下载镜像到安装NVIDIA驱动) 1.下载镜像文件 2.制作硬盘镜像 2.1 安装UltraISO并打开ISO文件 2.2 制作硬盘镜像 2.3 检查是否成功 3.划分磁盘 ...

  9. Python语音机器人控制STM32开发流程

    一:Python语音机器人控制STM32开发流程 1. 上位机的开发用到的工具: 1.1. Python3.9 1.2. Pycahrm社区版 2. 上位机开发用到的模块: import sys # ...

最新文章

  1. 王建春计算机应用基础,计算机应用基础(本)教学指南.pdf
  2. STM32 基础系列教程 48 – CJSON
  3. CentOS 7 中firewall-cmd命令
  4. 使用maven下载jar包,使用ant打包。yqxt项目的安装。
  5. Linux以下基于TCP多线程聊天室(client)
  6. 这可能是国内首款5G手机了!中兴AXON 10 Pro 5G上市定档
  7. 开篇、食堂管理评价系统(Android)
  8. 元胞自动机(又称细胞自动机)
  9. 【Java】NIO 仿照zookeeper 写的 nio客户端
  10. Android下载安装Apk
  11. 环洋市场分析-2021年全球MICC电缆行业调研及趋势分析报告
  12. postgresql去除首尾空格
  13. Denoise Autoencoder
  14. 汇编指令中 Rd Rm Rn Ra 的 具体含义 ?
  15. narwal机器人_省时省心才见真章!Narwal云鲸J1智能扫拖机器人国内上市
  16. Linux中nvme驱动详解
  17. QT报错:error: invalid use of incomplete type ‘class QDebug‘ qDebug()<<“gemo:“
  18. ps切图详解以及上传至蓝湖
  19. #一日一图#《秋的味道》
  20. 关键词短语生成的无监督方法01——综述

热门文章

  1. 代理模式(静态代理、jdk动态代理、CGLib动态代理)
  2. 装载问题-分支限界法(队列式分支限界法,优先队列式分支限界法)
  3. Redis五种数据类型
  4. 学术前沿篇 | 盗梦空间或将成真?新研究——REM睡眠期间实验者和做梦者之间的实时对话
  5. 深入学习JavaScript
  6. jmeter的安装及下载配置
  7. 在SQL server中如何定时自动执行存储过程
  8. 功能测试用例设计方法、有那些,一一举例
  9. android ui 扁平化,android 自定义标签的使用,实现扁平化UI设计
  10. 静态时序分析—时钟偏斜(Clock Skew:Global Skew与Local Skew)