FreeModbus学习——eMBInit初始化

FreeModbus版本:1.6
在mb.c文件中
先看一下静态变量的定义

/* ----------------------- Static variables ---------------------------------*/static UCHAR    ucMBAddress;
static eMBMode  eMBCurrentMode;

ucMBAddress是从机地址,eMBCurrentMode是Modbus 的工作模式,如下:

    typedef enum
{MB_RTU,                     /*!< RTU transmission mode. */MB_ASCII,                   /*!< ASCII transmission mode. */MB_TCP                      /*!< TCP mode. */
} eMBMode;

我这里只使用RTU模式,在include/mbconfig.h文件中有一些宏定义,可以配置打开,我这里只打开了RTU使能。
在这里插入图片描述
eMBState 代表Modbus的工作状态,定义后赋值为STATE_NOT_INITIALIZED未初始化状态。

static enum
{STATE_ENABLED,STATE_DISABLED,STATE_NOT_INITIALIZED
} eMBState = STATE_NOT_INITIALIZED;

静态变量定义下面还有一些静态函数指针变量

/* Functions pointer which are initialized in eMBInit( ). Depending on the* mode (RTU or ASCII) the are set to the correct implementations.*/
static peMBFrameSend peMBFrameSendCur;
static pvMBFrameStart pvMBFrameStartCur;
static pvMBFrameStop pvMBFrameStopCur;
static peMBFrameReceive peMBFrameReceiveCur;
static pvMBFrameClose pvMBFrameCloseCur;

简单点讲,以static peMBFrameSend peMBFrameSendCur;为例,可以理解为定义了一个变量peMBFrameSendCur,而它的类型是peMBFrameSend 。
那么它是什么呢,是函数指针类型Functions pointer。
也就是说peMBFrameSendCur可以指向一个函数,可以把一个函数赋值给它(参数和返回值要保持一致)。

函数原型定义在mbframe.h文件中

/* ----------------------- Prototypes  0-------------------------------------*/
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 );

在mb.c文件中还定义了几个回调函数指针,这里只用到了前三个,分别是字节接收,发送空,定时器溢出回调函数。
刚开始时我一直不理解这个名字pxMBFrameCBByteReceived 该怎么个意思。
MB是Modbus,Frame是帧,CB是回调函数CallBack。

/* 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 );

下面看一下本篇主要学习的eMBInit,Modbus初始化,这里我只保留了RTU模式,其它两种模式都删除了。

/* ----------------------- Start implementation -----------------------------*/
eMBErrorCode
eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
{eMBErrorCode    eStatus = MB_ENOERR;/* check preconditions */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 > 0case 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;
#endifdefault:eStatus = MB_EINVAL;}if( eStatus == MB_ENOERR ){if( !xMBPortEventInit(  ) ){/* port dependent event module initalization failed. */eStatus = MB_EPORTERR;}else{eMBCurrentMode = eMode;eMBState = STATE_DISABLED;}}}return eStatus;
}

先看一下参数
eMBMode eMode, 工作模式,这里选择RTU
UCHAR ucSlaveAddress, 从机地址,UCHAR 类型,即unsigned char类型
UCHAR ucPort, 端口(这个不重要)
ULONG ulBaudRate, 波特率
eMBParity eParity,校验位:奇校验,偶校验,无校验

返回值为错误码,,错误码被协议栈的所有函数使用,这里初始化为无错误

/*! \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;

先检查传进来的从机地址是否符合要求,
① 不是广播地址0
② 满足在1到147之间

满足要求,则将这个从机地址赋值给我们的静态变量ucMBAddress,从此我们的从机地址就确定了。
在这里插入图片描述

然后将前面提到的函数指针都给赋值(不赋值都为空),这些函数都定义在mbrtc.c文件中
在这里插入图片描述

然后调用函数eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );进行RTU初始化。

/* ----------------------- 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;
}

在调用xMBPortSerialInit进行串口初始化,这个函数在portserial.c文件中,这个函数是留给用户自己实现的,就是初始化函数,实际上串口初始化放在外面自己初始化也可以,反正只要初始化了就行。比如使用cubeMX生成的MX_USART2_UART_Init();

下一步是初始化定时器。
因为T3.5字符原则嘛,就是两帧之间间隔3.5个字符的时间长度,字符时间长度当然跟波特率有关系啦。
If baudrate > 19200 时给固定时间间隔 t35 = 1750us.
当If baudrate ≤ 19200us时TimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
这个公式怎么来的呢
令波特率为Baud ,传输一位要的时间为: bitTime = 1000 / Baud ms
传输1个字符,要传11位: charTime = 11 * bitTime = 11 * ( 1000 / Baud ) ms
那么传输 3.5 字符: T3.5 = 3.5 * charTime = 3.5 * 11 * ( 1000 / Baud ) ms
换成整数:T3.5 = ( 7 * 11 * 10^6 ) / ( 2 * Baud ) us
50us的个数:Period = T3.5 / 50 = ( 7 * 220000 ) / ( 2 * Baud )

定时器初始化,我这里使用的是STM32H743,TIM 240MHz,
所以设置Prescaler = 11999;,这样一个时基就是12000/240000000 = 1/20000 = 1/20ms = 1000/20 us = 50us。
Period = usTim1Timerout50us - 1;
所以自动重装载值设为 50us 的个数即可。

BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{TIM_MasterConfigTypeDef sMasterConfig = {0};htim7.Instance = TIM7;htim7.Init.Prescaler = 11999;htim7.Init.CounterMode = TIM_COUNTERMODE_UP;htim7.Init.Period = usTim1Timerout50us - 1;htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim7) != HAL_OK){return FALSE;}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig) != HAL_OK){return FALSE;}return TRUE;
}

我们继续回到eMBInit函数
eMBRTUInit初始化完成之后,调用xMBPortEventInit初始化,然后把当前模式赋值为RTU,协议栈状态由未初始化变未使能。
在这里插入图片描述

eStatus为本函数内状态,其值为返回的错误码。
eMBState为协议栈状态,其值为:未初始化,未使能,使能。
二者不要搞混。

好了初始化结束。
流程:
eMBInit →
赋值从机地址 →
赋值函数指针 →
eMBRTUInit(→xMBPortSerialInit →xMBPortTimersInit→) →
xMBPortEventInit →
eMBState = STATE_DISABLED;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/50500.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ 八股(2)

1.函数调用的参数是以什么顺序压栈的&#xff0c;为什么&#xff1f; 从右向左压栈的。因为C, C支持可变参函数。 可变参函数就是参数个数可变的函数&#xff0c;如printf()就是可变参函数 void func(int a,...){} 2.有一个函数 在main函数中通过&#xff1a;string s fun…

焦化超低排放解决方案

在环保政策日益严苛与可持续发展理念深入人心的当下&#xff0c;朗观视觉小编认为焦化行业作为传统重工业的重要组成部分&#xff0c;正经历着一场前所未有的绿色变革。其中&#xff0c;“焦化超低排放”不仅是对环境保护的积极响应&#xff0c;更是行业转型升级、实现高质量发…

【开发问题记录】启动某个微服务时无法连接到seata(seata启动或配置异常)

问题记录 一、问题描述1.1 问题复现1.1.1 将Linux中的部分微服务启动1.1.2 在本地启动当时出错的服务 1.2 解决思路1.2.1 Nacos中seata相关的信息1.2.2 Linux中seata相关的信息 二、问题解决2.1 seata的配置错误2.1.1 Nacos中seata的配置问题2.1.2 命名空间问题的发现 2.2 网络…

wpf基础

在 WPF (Windows Presentation Foundation) 中&#xff0c;Style 是一种强大的资源&#xff0c;允许你定义一组属性值&#xff0c;这些值可以被多个控件实例共享。使用 Style 可以减少重复的 XAML 代码&#xff0c;并且使得 UI 的一致性和可维护性得到提高。 以下是一些 Style…

IP地址专用SSL/https证书——10分钟签发

一般常用的SSL证书多为域名型SSL证书&#xff0c;即需要提供准确的域名。如果不能提供域名&#xff0c;只能提供IP地址&#xff0c;则需要一种特殊的SSL证书——IP地址证书。下面是IP地址证书的申请教程 IP地址专用SSL证书获取链接https://www.joyssl.com/certificate/select/…

vscode+git解决远程分支合并冲突

1&#xff09;远程分支和远程分支不复杂情况合并 例如readme的冲突 可直接在github上解决 删到只剩下 #supergenius002 合并冲突测试1/合并测试冲突1合并测试冲突2/合并测试冲突2就行 《《《/》》》也要删掉 2&#xff09;但如果是复杂的冲突&#xff0c;让我们回到vscod…

SpringMVC源码解析(二):请求执行流程

SpringMVC源码系列文章 SpringMVC源码解析(一)&#xff1a;web容器启动流程 SpringMVC源码解析(二)&#xff1a;请求执行流程 目录 前言DispatcherServlet入口一、获取HandlerExcutionChain(包括Handler)1、获取Handler1.1、通过request获取查找路径1.2、通过查找路径获取Han…

c++修炼之路之STL_map,set

目录 一&#xff1a;序列式容器与键值对 二&#xff1a;set与multiset 三&#xff1a;map与multimap 接下来的日子会顺顺利利&#xff0c;万事胜意&#xff0c;生活明朗-----------林辞忧 一&#xff1a;序列式容器与键值对 1.在初阶阶段&#xff0c;我们已经接触过S…

Vue基础2

1.监视属性 先推荐大家安装第一个vscode常用插件 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>天气案例_监视简写</title><!-- 引入Vue --><script type"text/javascript"…

Linux操作系统常用命令总结

1、网络配置查看 要想知道网络的配置状态&#xff0c;我们可以使用ifconfig 或者 ip命令来查看。 这两个命令功能都差不多&#xff0c;不过它们属于不同的软件包&#xff0c;ifconfig属于net-tools软件包&#xff0c;ip属于iproute2软件包&#xff0c;通过查资料&#xff0c;…

【全栈实战】大模型自学:从入门到实战打怪升级,20W字总结(二)

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本栏讲解【全栈实战】大模型自学&#xff1a;从入门到实战打怪升级。 &#x1f514;专栏持续更新&#xff0c;适合人群&#xff1a;本科生、研究生、大模型爱好者&#xff0c;期…

【通俗理解】涌现现象与神经网络——从结构到智能的飞跃

【通俗理解】涌现现象与神经网络——从结构到智能的飞跃 涌现现象的类比 你可以把涌现现象比作一个“魔法锅”&#xff0c;锅里的各种原料&#xff08;内在结构和相互作用&#xff09;在特定的条件下相互作用&#xff0c;最终“熬制”出令人惊叹的“魔法汤”&#xff08;整体性…

【Qwen2微调实战】LLaMA-Factory框架对Qwen2-7B模型的微调实践

系列篇章&#x1f4a5; No.文章1【Qwen部署实战】探索Qwen-7B-Chat&#xff1a;阿里云大型语言模型的对话实践2【Qwen2部署实战】Qwen2初体验&#xff1a;用Transformers打造智能聊天机器人3【Qwen2部署实战】探索Qwen2-7B&#xff1a;通过FastApi框架实现API的部署与调用4【Q…

无线融合,智能协同:ECWAN打造物联网高效协同网络

关键词&#xff1a;资产管理、ECWAN、无线混合组网、用电监测、用电计量、广域基站、计量插座、边缘协同 在当今快速发展的物联网领域&#xff0c;每天都有数以亿计的设备互相通信&#xff0c;形成庞大而复杂的网络生态。在这样的背景下&#xff0c;ECWAN技术以其灵活、高效和智…

Biorhythms(牛客)

由题意可以知 CRT模板即可 #include<iostream> using namespace std; typedef long long ll; const int N19; ll a[N],b[N],m[N],invm[N]; ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x1,y0;return a;}ll dexgcd(b,a%b,y,x);y-a/b*x;return d; } void solve(){for…

《动手做科研 》| 03. 如何阅读人工智能研究论文

地址链接:《动手做科研》03. 如何阅读人工智能研究论文 导读: 在刚迈入科研时&#xff0c;人人都说读论文很重要&#xff0c;但是很少有人能完整地教你应该如何读论文。论文不仅揭示了行业的最新进展和趋势&#xff0c;而且为我们提供了改进技术和解决复杂问题的思路。然而&…

《学会 SpringBoot · 参数校验》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

经纬恒润天津研发中心实验室荣获CNAS权威认证

近日&#xff0c;经纬恒润天津研发中心实验室成功通过中国合格评定国家认可委员会(CNAS)的严格扩项评审&#xff0c;正式被授予CNAS认可证书。此次认证&#xff0c;是经纬恒润实验室在原有CNAS实验室基础上&#xff0c;再添天津研发中心这一重要检测阵地&#xff0c;是对经纬恒…

重生奇迹MU自由选择个性大师之路

自由选择大师技能 每一个大师职业都拥有三条大师技能树&#xff0c;每一条大师技能树对职业加强的侧重点各不相同。玩家可以根据自己喜欢专一选择&#xff0c;一条路走到底&#xff1b;当然也可以同时兼修两条或者三条技能树&#xff0c;做到雨露均沾。每一种选择都没有绝对的…

【linux】Linux中环境变量相关操作的详细教程及实战案例

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…