[ESP32]:基于esp-modbus实现serial主机

[ESP32]:基于esp-modbus实现serial主机

开发环境

  • esp idf 5.1
  • esp-modbus 1.0.13

使用如下指令添加组件,或者访问esp-modbus

idf.py add-dependency "espressif/esp-modbus^1.0.13"

Device parameters

对于master而言,需要理解的主要是device parameters,下面是一个parameters的例子

enum
{
    CID_INPUT = 0,
    CID_COIL,
    CID_HOLDING,
};

const mb_parameter_descriptor_t device_parameters[] = {
    {CID_INPUT, (const char *)("INPUT"), (const char *)(""), 1, MB_PARAM_INPUT, 0x00, 5,
     INPUT_OFFSET(input_value1), PARAM_TYPE_U16, sizeof(uint16_t), OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
    {CID_COIL, (const char *)("COIL"), (const char *)(""), 1, MB_PARAM_COIL, 0x00, 16,
     COIL_OFFSET(coil_value1), PARAM_TYPE_U8, sizeof(uint8_t), OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
    {CID_HOLDING, (const char *)("HOLDING"), (const char *)(""), 1, MB_PARAM_HOLDING, 0x00, 5,
     HOLDING_OFFSET(holding_value1), PARAM_TYPE_U16, sizeof(uint16_t), OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
};

可以看到,我们这边分别定义了输入寄存器、线圈与保持寄存器,其中,关于mb_parameter_descriptor_t的定义如下:

typedef struct {
    uint16_t            cid;                /*!< Characteristic cid */
    const char*         param_key;          /*!< The key (name) of the parameter */
    const char*         param_units;        /*!< The physical units of the parameter */
    uint8_t             mb_slave_addr;      /*!< Slave address of device in the Modbus segment */
    mb_param_type_t     mb_param_type;      /*!< Type of modbus parameter */
    uint16_t            mb_reg_start;       /*!< This is the Modbus register address. This is the 0 based value. */
    uint16_t            mb_size;            /*!< Size of mb parameter in registers */
    uint16_t            param_offset;       /*!< Parameter name (OFFSET in the parameter structure) */
    mb_descr_type_t     param_type;         /*!< Float, U8, U16, U32, ASCII, etc. */
    mb_descr_size_t     param_size;         /*!< Number of bytes in the parameter. */
    mb_parameter_opt_t  param_opts;         /*!< Parameter options used to check limits and etc. */
    mb_param_perms_t    access;             /*!< Access permissions based on mode */
} mb_parameter_descriptor_t;

其中:

  • mb_size: 是你要读取的数量
    • CID_INPUT这个parameters里,5就是要读取5个输入寄存器
    • CID_COIL这个parameters里,16就是要读取16个线圈,注意,每一个线圈只有1个位
  • param_size:是每一个数据的字节数
    • CID_INPUT里,每一个数据的大小为2个字节,同时数据保存的类型也是uint16_t
    • CID_COIL里,每一个数据的大小为1个字节,就是sizeof(uint8_t),但是我们上面写的是16个线圈,所以读取数据的时候要写两个uint8_t来存放结果

master读取

对于读取,只需要选择好device parameters里的cid即可,下面是一个读取线圈的例子

esp_err_t modbus_master_read_coil_reg()
{
    esp_err_t err = mbc_master_get_cid_info(CID_COIL, &param_descriptor);
    if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL))
    {
        void *temp_data_ptr = master_get_param_data(param_descriptor);
        assert(temp_data_ptr);
        uint8_t type = 0;
        uint8_t value[2] = {0};
        err = mbc_master_get_parameter(CID_COIL, (char *)param_descriptor->param_key, (uint8_t *)&value, &type);
        if (err == ESP_OK)
        {
            ESP_LOGI(TAG, "Coil: %d %d", (*(uint8_t *)&value[0]), *(uint8_t *)&value[1]);
        }
    }
    return err;
}

我们在刚才的device parameters里定义了要读16个线圈,返回的数据每一个是uint8_t,所以需要两个uint8_t的数据,所以我这里写一个数组。

实验效果如下:

在这里插入图片描述

在这里插入图片描述

127就是10000001

读取保持寄存与线圈的代码都差不多:

/**
 * @brief mdobus read input reg
 *
 * @return esp_err_t
 */
esp_err_t modbus_master_read_input_reg()
{
    esp_err_t err = mbc_master_get_cid_info(CID_INPUT, &param_descriptor);
    if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL))
    {
        void *temp_data_ptr = master_get_param_data(param_descriptor);
        assert(temp_data_ptr);
        uint8_t type = 0;
        uint16_t value[5] = {0};
        err = mbc_master_get_parameter(CID_INPUT, (char *)param_descriptor->param_key, (uint8_t *)&value, &type);
        if (err == ESP_OK)
        {
            ESP_LOGI(TAG, "Input: %d %d %d %d %d", value[0], value[1], value[2], value[3], value[4]);
        }
    }

    return err;
}

/**
 * @brief modbus read holding reg
 *
 * @return esp_err_t
 */
esp_err_t modbus_master_read_holding_reg()
{
    esp_err_t err = mbc_master_get_cid_info(CID_HOLDING, &param_descriptor);
    if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL))
    {
        void *temp_data_ptr = master_get_param_data(param_descriptor);
        assert(temp_data_ptr);
        uint8_t type = 0;
        uint16_t value[5] = {0};
        err = mbc_master_get_parameter(CID_HOLDING, (char *)param_descriptor->param_key, (uint8_t *)&value, &type);
        if (err == ESP_OK)
        {
            ESP_LOGI(TAG, "Holding: %d %d %d %d %d", value[0], value[1], value[2], value[3], value[4]);
        }
    }

    return err;
}

完整代码参考:项目代码

Ref

modbus协议

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

五、Yocto集成QT5(基于Raspberrypi 4B)

Yocto集成QT5 本篇文章为基于raspberrypi 4B单板的yocto实战系列的第五篇文章&#xff1a; 一、yocto 编译raspberrypi 4B并启动 二、yocto 集成ros2(基于raspberrypi 4B) 三、Yocto创建自定义的layer和image 四、Yocto创建静态IP和VLAN 本章节实操代码请查看github仓库&…

CVAE——生成0-9数字图像(Pytorch+mnist)

1、简介 CVAE&#xff08;Conditional Variational Autoencoder&#xff0c;条件变分自编码器&#xff09;是一种变分自编码器&#xff08;VAE&#xff09;的变体&#xff0c;用于生成有条件的数据。在传统的变分自编码器中&#xff0c;生成的数据是完全由潜在变量决定的&…

GridLayoutManager 中的一些坑

前言 如果GridLayoutManager使用item的布局都是wrap_cotent 那么会在布局更改时会出现一些出人意料的情况。&#xff08;本文完全不具备可读性和说教性&#xff0c;仅为博主方便查找问题&#xff09; 布局item: <!--layout_item.xml--> <?xml version"1.0&qu…

论文阅读: Visual Attention Network

Motivation 自注意力机制在2D自然图像领域面临3个挑战&#xff1a; 视二维图像为一维序列。对于高分辨率图像&#xff0c;二次复杂度消耗太大。只捕捉空间适应性&#xff0c;忽略通道适应性。 Contribution 设计了 Large Kernel attention(LKA)&#xff0c;包含卷积和自注意…

SpringBoot整合knife4J 3.0.3

Knife4j的前身是swagger-bootstrap-ui,前身swagger-bootstrap-ui是一个纯swagger-ui的ui皮肤项目。项目正式更名为knife4j,取名knife4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍,更名也是希望把她做成一个为Swagger接口文档服务的通用性解决方案,不仅仅只是专注于前端Ui…

受益于边缘计算的三个关键应用

边缘计算和 5G 网络正在改变物联网&#xff0c;增强跨多个领域的广泛应用的功能&#xff0c;并催生大量新兴应用。我们通过研究三个突出的用例来说明边缘计算的强大功能。 工业4.0智能工厂 工业 4.0 为制造商提供了基于灵活的工业环境提高生产力和盈利能力的愿景&#xff0c;…

5.vector容器的使用

文章目录 vector容器1.构造函数代码工程运行结果 2.赋值代码工程运行结果 3.容量和大小代码工程运行结果 4.插入和删除代码工程运行结果 5.数据存取工程代码运行结果 6.互换容器代码工程运行结果 7.预留空间代码工程运行结果 vector容器 1.构造函数 /*1.默认构造-无参构造*/ …

STM32 can通信部分函数注释

相关截图: CAN模式初始化函数:u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode) //CAN初始化 //tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq //tbs2:时间段2的时间单元. 范围:CAN_BS2_1tq~CAN_BS2_8tq; //tbs1:时间段1的时间单元. 范围:CAN_BS…

IO流c++

IO流类库 输入输出流 #include <iostream> using namespace std;class InCount { public:InCount(int a 0, int b 0){c1 a;c2 b;}void show(void){cout << "c1" << c1 << "\t" << "c2" << c2 << …

PHP三种方式读取RSA密钥加解密、签名验签完整教程

目录 第一步、生成公私钥 第二步、三种方式读取RSA密钥 第1种&#xff1a;公私钥弄成一行&#xff0c;必须一行没有空格和换行 第2种&#xff1a;直接复制生成公私钥 第3种;复制密钥存储为.pem文件后缀 第三步、RSA加解密 第四步、RSA签名以及验证签名 第五步、封装完整…

Linux的开发工具(二):编译器gcc/g++与Linux项目自动化构建工具-Makefile

Linux的编译器-gcc/g 基本概念&#xff1a;gcc是专门用来编译c语言的&#xff0c;g可以编译c或c语言 问题一&#xff1a;gcc有时候为什么不能编译带有for循环的c语言源文件&#xff1f; 答&#xff1a;gcc版本过低会不支持for循环等c99标准下的内容 解决方式&#xff1a;gcc…

手搓 Docker Image Creator(DIC)工具(02):预备知识

此节主要简单介绍一下 Docker、Dockerfile 的基本概念&#xff0c;Dockerfile 对的基本语法&#xff0c;Windows 和 macOS 下 Docker 桌面的安装&#xff0c;Docker 镜像的创建和运行测试等。 1 关于 Docker Docker 是一个开源的应用容器引擎&#xff0c;它允许开发者打包应用…

Open3D(C++) 基于随机抽样与特征值法的点云平面稳健拟合方法

目录 一、算法原理1、论文概述2、参考文献二、代码实现三、结果展示四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的GPT爬虫。 一、算法原理 1、论文概述 针对点云数据含有异常值且传统拟合方法拟合结果不理想的情…

《自动机理论、语言和计算导论》阅读笔记:p115-p138

《自动机理论、语言和计算导论》学习第 6 天&#xff0c;p115-p138 总结&#xff0c;总计 24 页。 一、技术总结 1.associativity and comutativity (1)commutativity(交换性): Commutativity is the property of an operator that says we can switch the order of its ope…

Acwing-3418 杨辉三角形

关于杨辉三角形的一些规律&#xff08;更详细地去看参考&#xff09;&#xff1a; 下面这些图都来自其他人所做图片 因为杨辉三角形是对称的&#xff0c;并且与二项式有关&#xff1a; 将左半部分(左半部分的编号肯定比右半部分小&#xff0c;不考虑右半部分&#xff09;一个斜…

如何区分相对路径 与 绝对路径?

在网页中有很多需要使用我们URL路径的场景&#xff0c;包括a标签的href、link标签的href、script标签的src、imag标签的src、form中的action、ajax请求的url等等等等。它们都可以使用相对路径和绝对路径来引入文件&#xff0c;那么&#xff0c;我们如何区分相对路径与绝对路径呢…

MATLAB | 绘图复刻(十六) | 弦图2.1.0版本更新——弦末端弧形块颜色单独设置

Hey, 本人自主开发的弦图绘制工具迎来2.1.0版本了&#xff1a;起因是有粉丝问我前两天发布的文章中这张图咋画&#xff1a; 我本来一想我开发的工具画弦图还是很简单的哇&#xff08;下面文章中有基本用法&#xff09; https://slandarer.blog.csdn.net/article/details/126458…

Vue tree自定义滚动条位置

贴一张效果图&#xff0c;我的效果不方便贴出来 实现支持&#xff1a; 1、懒加载 2、普通加载 下面贴关键思想&#xff1a; document有一个获取element元素的方法。 let element document.getElementById(tree); let arr document.querySelectorAll(".nodelModel&quo…

编曲知识15:重复段落编写 尾奏编写 家庭工作室搭建 硬件设备使用常识

15 重复段落编写 尾奏编写 家庭工作室搭建 硬件设备使用常识小鹅通-专注内容付费的技术服务商https://app8epdhy0u9502.pc.xiaoe-tech.com/live_pc/l_6602a586e4b0694cc051476b?course_id=course_2XLKtQnQx9GrQHac7OPmHD9tqbv 重复段落设计 第二段落指代间奏过后的段落 第二…

uniapp 小程序发布体验版 http://198.18.0.1:7001 不在以下 request 合法域名列表中(踩坑记录二)

问题一&#xff1a; 小程序发布体验版时出现报错信息&#xff1a; http://198.18.0.1:7001 不在以下 request 合法域名列表中无法连接uniCloud本地调试服务&#xff0c;请检查当前客户端是否与主机在同一局域网下 解决方案&#xff1a; 请务必在HBuilderX内使用【发行】菜单打…