RTT-笔记-freeModbus组件

1 获取组件代码

  • 直接通过env中


    image.png
  • github下载

2 导入

通过env导入将自动添加文件,组件代码在RTT\components\net\freemodbus\modbus目录下,可以直接使用,而通过git下载的代码需要手动加入,首先进入FreeModbus_Slave-Master-RTT-STM32-1.1\FreeModbus目录,modbus文件夹是协议相关文件,port文件夹是移植相关文件。还需要在rtconfig中添加配置

#define RT_USING_MODBUS
#define RT_MODBUS_MASTER_RTU  //这里使用的是RTU

3 移植

目前使用stm32f103,无需移植,之后更新补充该章节

3.1定时器

不同波特率定时时间计算:
1.freemodbus一帧的结束是通过串口3.5位传输的时间来判断的,当串口的波特率大于19200时超时时间是固定为1750us,当串口通信的波特率小于等于19200时,就有一个计算公式,用来计算超时时间。
2.串口可以设置成以下模式
起始位1bit + 数据位8bit + 停止位1bit
起始位1bit + 数据位8bit + 停止位2bit
起始位1bit + 数据位8bit + 校验位1bit + 停止位1bit
起始位1bit + 数据位8bit + 校验位1bit + 停止位2bit
位数10 11 12 ,取中间值11
3.5位时间的计算:1位传输时间是 1/BaudRate(s),1字节就是 11* 1/BaudRate(s) ,定时器溢出时间3.511 1/BaudRate(s),转成整数运算711 1/BaudRate2(s)
定时配置是50us计一次数,假设为X次,则得出计算公式50
X(us) = 711 1/BaudRate2(s),推出X = 7220000UL/BaudRate 2,将X设置到定时器的计数值,将定时器配置成50us计数一次,x50us就会溢出中断。

这里说明一下在定时器初始化中超时时间计算的代码

(50 * usT35TimeOut50us) / (1000 * 1000 / RT_TICK_PER_SECOND) + 1

其中usT35TimeOut50us变量由函数传入,是由波特率计算出的超时时间,单位是us,转化成ms,除以1000,然后再转化成街拍数,乘上 RT_TICK_PER_SECOND/1000,最后的+1是为了至少大于超时时间,因为前面转化小数被去掉了的。
这里要注意一下是,如果RT_TICK_PER_SECOND最好是调高一些,例程中给的是10000。

4 使用

4.1 运行协议栈

需要建立一个线程,下列例子是参考的例程代码

#define thread_ModbusMasterPoll_Prio         9
static rt_uint8_t thread_ModbusMasterPoll_stack[512];
struct rt_thread thread_ModbusMasterPoll;

void thread_entry_ModbusMasterPoll(void* parameter)
{
    eMBMasterInit(MB_RTU, 3, 115200,  MB_PAR_EVEN);
    eMBMasterEnable();
    while (1)
    {
        eMBMasterPoll();
        rt_thread_delay(1);
    }
}

int main()
{
        rt_thread_init(&thread_ModbusMasterPoll, "MBMasterPoll",
            thread_entry_ModbusMasterPoll, RT_NULL, thread_ModbusMasterPoll_stack,
            sizeof(thread_ModbusMasterPoll_stack), thread_ModbusMasterPoll_Prio,5);
        rt_thread_startup(&thread_ModbusMasterPoll);
}

4.2 读写

4.2.1 freemodebus功能字说明

image.png

4.2.2 读写API

函数均返回eMBMasterReqErrCode 类型数据,当返回值等于MB_MRE_NO_ERR时则表示操作失败

功能 保持寄存器API函数
单写 eMBMasterReqWriteHoldingRegister( 从机地址,寄存器地址,无符号16位数据,超时时间);
多写 eMBMasterReqWriteMultipleHoldingRegister(从机地址,寄存器地址,写寄存器数,数据首地址,超时时间)
多读 eMBMasterReqReadHoldingRegister(从机地址,寄存器地址,读取数量,超时时间)
读写 eMBMasterReqReadWriteMultipleHoldingRegister(从机地址,读寄存器地址,读寄存器数量,写数据首地址,写寄存器地址,写寄存器数量,超时时间)
功能 输入寄存器API函数
多读 eMBMasterReqReadInputRegister(从机地址,读寄存器地址,读寄存器数量,超时时间)
功能 线圈API函数
单写 eMBMasterReqWriteCoil(从机地址,写线圈地址,写线圈数量,超时时间)
多写 eMBMasterReqWriteMultipleCoils(从机地址,写线圈起始地址,写线圈数量,写数据首地址,超时时间)
多读 eMBMasterReqReadCoils(从机地址,读线圈地址,读线圈数量,超时时间)
功能 离散输入API函数
多读 eMBMasterReqReadDiscreteInputs(从机地址,读离散输入地址,读离散输入数量,超时时间)

例如

//执行
if(MB_MRE_NO_ERR == eMBMasterReqReadHoldingRegister(1,3,1,1))
//则串口输出 01 03 00 03 00 01 74 0A 

函数的超时时间是等待发送的时间,并不是发送完成等待应答的时间,单位是毫秒

4.2.3 读数据存储

由user_mb_app_m.c和user_mb_app.c来管理,数据被分类保存在数组中。

从机默认使用 一维数组 作为缓存区数据结构,主机可以存储所有网内从机的数据,所以主机采用 二维数组 对所有从机节点数据进行存储。二维数组的列号代表寄存器、线圈及离散量地址,行号代表从机节点ID,但需要做减一处理,例如usMRegHoldBuf[2][1]代表从机ID为 3,保持寄存器地址为 1 的从机数据。
文件中的函数是协议内部使用,并不是用来读buffer的,也就如果需要读buffer数据,可以先这么处理:
读从机地址为1.寄存器地址为3的数据

extern USHORT   usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];
rt_kprintf("Receive success  reg %d",usMRegHoldBuf[0][3]);

4.3 使用例程

//main.c
#include 
#include "user_mb_app.h"


#define thread_ModbusMasterPoll_Prio         9
#define thread_MDtest_Prio                       10

static rt_uint8_t thread_ModbusMasterPoll_stack[512];
static rt_uint8_t thread_MDtest_stack[512];

struct rt_thread thread_ModbusMasterPoll;
struct rt_thread thread_MDtest;


void thread_entry_ModbusMasterPoll(void* parameter)
{
    eMBMasterInit(MB_RTU, 3, 115200,  MB_PAR_EVEN);
    eMBMasterEnable();
    while (1)
    {
        eMBMasterPoll();
        rt_thread_delay(1);
    }
}



USHORT  usModbusUserData[10]={1,2,3,4,5,6,7,8,9,0};
UCHAR temp[2];

void mbMasterThreadEntry(void * para)
{
      rt_thread_mdelay(5000);
    while (1)
    {
       // if(MB_MRE_NO_ERR == eMBMasterReqReadInputRegister(1, 3, 2, 1)) //这里的超时时等待获取信号量的时间 01 04 00 03 00 02 81 CB 
             // if(MB_MRE_NO_ERR == eMBMasterReqWriteHoldingRegister(1,3,usModbusUserData[0],1)) // 01 06 00 03 00 01 B8 0A 
              if(MB_MRE_NO_ERR == eMBMasterReqReadHoldingRegister(1,3,1,1))
        {               
                        //eMBMasterRegHoldingCB(temp,3,1,MB_REG_READ);
                        //rt_kprintf("Receive success  reg 3= %d\n",((uint16_t)temp[0])<<8 + temp[1]    );
                        extern USHORT   usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];
                        rt_kprintf("Receive success  reg %d",usMRegHoldBuf[0][3]);                      
        }
        else
        {
            rt_kprintf(" poll failed\n");
        }
        rt_thread_mdelay(10000);
                 
    }

}


int main(void)
{
    /* user app entry */
        rt_thread_init(&thread_ModbusMasterPoll, "MBMasterPoll",
            thread_entry_ModbusMasterPoll, RT_NULL, thread_ModbusMasterPoll_stack,
            sizeof(thread_ModbusMasterPoll_stack), thread_ModbusMasterPoll_Prio,5);
        rt_thread_startup(&thread_ModbusMasterPoll);
    
        rt_thread_init(&thread_MDtest, "MBtest",
            mbMasterThreadEntry, RT_NULL, thread_MDtest_stack,
            sizeof(thread_MDtest_stack), thread_MDtest_Prio,5);
        rt_thread_startup(&thread_MDtest);

            
    return 0;
}

5 参考

https://blog.csdn.net/weixin_42867108/article/details/82227635
https://github.com/armink/FreeModbus_Slave-Master-RTT-STM32
https://blog.csdn.net/byxdaz/article/details/77979114

6 附件

度盘(nfjc)

你可能感兴趣的:(RTT-笔记-freeModbus组件)