damiaa 发表于 2024-6-2 21:36

【FireBeetle 2 ESP32 C6开发板】 6 modbus实验

<div class='showpostmsg'> 本帖最后由 damiaa 于 2024-6-3 12:27 编辑

<div><strong><span style="font-size:24px;">&nbsp;&nbsp;&nbsp;&nbsp; 【FireBeetle 2 ESP32 C6开发板】 6 modbus实验</span></strong></div>

<div>&nbsp;</div>

<div>&nbsp;</div>

<div>据说esp32c6有modbus库,那很好,虽然在stm32上也用过了。</div>

<div><span style="color:#27ae60;">下面来实验一下</span></div>

<div>&nbsp;</div>

<p><strong><span style="font-size:18px;">一、到处mb_master项目例程</span></strong></p>

<p><br />
</p>

<p><strong><span style="font-size:18px;">二、idf.py menuconfig修改</span></strong></p>

<p>&nbsp;</p>

<p><span style="font-size:16px;">dio=》QIO 80M速度烧写,4m flash</span><br />
<br />
修改它的consol为usb<br />
<br />
修改modbus的输出串口为串口0 tx 17 rx 16 rts因为我这里没用到就直接分配到3. 如果你是485通信你自己看着办。mosbus为RTU模式<br />
</p>

<p>&nbsp;</p>

<p><strong><span style="font-size:18px;">三、修改代码</span></strong></p>

<p><br />
这里改成串口模式,如果你是485就不改吧。我是用usb-ttl<br />
<br />
去掉这里两句,便于观察,否则填写线圈数据错了就报警退出了。<br />
</p>

<p>修改循环次数为</p>

<div style="color: #cccccc;background-color: #1f1f1f;white-space: pre">
<div>#define MASTER_MAX_RETRY 500 &nbsp;//30</div>
</div>

<p>&nbsp;</p>

<p><strong><span style="font-size:18px;">四、整体代码</span></strong></p>

<pre>
<code class="language-cpp">/*
* SPDX-FileCopyrightText: 2016-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "string.h"
#include "esp_log.h"
#include "modbus_params.h"// for modbus parameters structures
#include "mbcontroller.h"
#include "sdkconfig.h"

#define MB_PORT_NUM   (CONFIG_MB_UART_PORT_NUM)   // Number of UART port used for Modbus connection
#define MB_DEV_SPEED    (CONFIG_MB_UART_BAUD_RATE)// The communication speed of the UART

// Note: Some pins on target chip cannot be assigned for UART communication.
// See UART documentation for selected board and target to configure pins using Kconfig.

// The number of parameters that intended to be used in the particular control process
#define MASTER_MAX_CIDS num_device_parameters

// Number of reading of parameters from slave
#define MASTER_MAX_RETRY 500//30

// Timeout to update cid over Modbus
#define UPDATE_CIDS_TIMEOUT_MS          (500)
#define UPDATE_CIDS_TIMEOUT_TICS      (UPDATE_CIDS_TIMEOUT_MS / portTICK_PERIOD_MS)

// Timeout between polls
#define POLL_TIMEOUT_MS               (1)
#define POLL_TIMEOUT_TICS               (POLL_TIMEOUT_MS / portTICK_PERIOD_MS)

// The macro to get offset for parameter in the appropriate structure
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
#define COIL_OFFSET(field) ((uint16_t)(offsetof(coil_reg_params_t, field) + 1))
// Discrete offset macro
#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1))

#define STR(fieldname) ((const char*)( fieldname ))
// Options can be used as bit masks or parameter limits
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }

static const char *TAG = "MASTER_TEST";

// Enumeration of modbus device addresses accessed by master device
enum {
    MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here)
};

// Enumeration of all supported CIDs for device (used in parameter definition table)
enum {
    CID_INP_DATA_0 = 0,
    CID_HOLD_DATA_0,
    CID_INP_DATA_1,
    CID_HOLD_DATA_1,
    CID_INP_DATA_2,
    CID_HOLD_DATA_2,
    CID_HOLD_TEST_REG,
    CID_RELAY_P1,
    CID_RELAY_P2,
    CID_DISCR_P1,
    CID_COUNT
};

// Example Data (Object) Dictionary for Modbus parameters:
// The CID field in the table must be unique.
// Modbus Slave Addr field defines slave address of the device with correspond parameter.
// Modbus Reg Type - Type of Modbus register area (Holding register, Input Register and such).
// Reg Start field defines the start Modbus register number and Reg Size defines the number of registers for the characteristic accordingly.
// The Instance Offset defines offset in the appropriate parameter structure that will be used as instance to save parameter value.
// Data Type, Data Size specify type of the characteristic and its data size.
// Parameter Options field specifies the options that can be used to process parameter value (limits or masks).
// Access Mode - can be used to implement custom options for processing of characteristic (Read/Write restrictions, factory mode values and etc).
const mb_parameter_descriptor_t device_parameters[] = {
    // { CID, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode}
    { CID_INP_DATA_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0, 2,
            INPUT_OFFSET(input_data0), PARAM_TYPE_FLOAT, 4, OPTS( -10, 10, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
    { CID_HOLD_DATA_0, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2,
            HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
    { CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 2,
            INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
    { CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 2,
            HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
    { CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 4, 2,
            INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
    { CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 2,
            HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
    { CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 10, 58,
            HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, 116, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
    { CID_RELAY_P1, STR("RelayP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 2, 6,
            COIL_OFFSET(coils_port0), PARAM_TYPE_U8, 1, OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
    { CID_RELAY_P2, STR("RelayP2"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 10, 6,
            COIL_OFFSET(coils_port1), PARAM_TYPE_U8, 1, OPTS( 0x55, 0x2A, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
    { CID_DISCR_P1, STR("DiscreteInpP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_DISCRETE, 2, 7,
            DISCR_OFFSET(discrete_input_port1), PARAM_TYPE_U8, 1, OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER }
};

// Calculate number of parameters in the table
const uint16_t num_device_parameters = (sizeof(device_parameters)/sizeof(device_parameters));

// The function to get pointer to parameter storage (instance) according to parameter description table
static void* master_get_param_data(const mb_parameter_descriptor_t* param_descriptor)
{
    assert(param_descriptor != NULL);
    void* instance_ptr = NULL;
    if (param_descriptor-&gt;param_offset != 0) {
       switch(param_descriptor-&gt;mb_param_type)
       {
         case MB_PARAM_HOLDING:
               instance_ptr = ((void*)&amp;holding_reg_params + param_descriptor-&gt;param_offset - 1);
               break;
         case MB_PARAM_INPUT:
               instance_ptr = ((void*)&amp;input_reg_params + param_descriptor-&gt;param_offset - 1);
               break;
         case MB_PARAM_COIL:
               instance_ptr = ((void*)&amp;coil_reg_params + param_descriptor-&gt;param_offset - 1);
               break;
         case MB_PARAM_DISCRETE:
               instance_ptr = ((void*)&amp;discrete_reg_params + param_descriptor-&gt;param_offset - 1);
               break;
         default:
               instance_ptr = NULL;
               break;
       }
    } else {
      ESP_LOGE(TAG, "Wrong parameter offset for CID #%u", (unsigned)param_descriptor-&gt;cid);
      assert(instance_ptr != NULL);
    }
    return instance_ptr;
}

// User operation function to read slave values and check alarm
static void master_operation_func(void *arg)
{
    esp_err_t err = ESP_OK;
    float value = 0;
    bool alarm_state = false;
    const mb_parameter_descriptor_t* param_descriptor = NULL;

    ESP_LOGI(TAG, "Start modbus test...");

    for(uint16_t retry = 0; retry &lt;= MASTER_MAX_RETRY &amp;&amp; (!alarm_state); retry++) {
      // Read all found characteristics from slave(s)
      for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) &amp;&amp; cid &lt; MASTER_MAX_CIDS; cid++)
      {
            // Get data from parameters description table
            // and use this information to fill the characteristics description table
            // and having all required fields in just one table
            err = mbc_master_get_cid_info(cid, &amp;param_descriptor);
            if ((err != ESP_ERR_NOT_FOUND) &amp;&amp; (param_descriptor != NULL)) {
                void* temp_data_ptr = master_get_param_data(param_descriptor);
                assert(temp_data_ptr);
                uint8_t type = 0;
                if ((param_descriptor-&gt;param_type == PARAM_TYPE_ASCII) &amp;&amp;
                        (param_descriptor-&gt;cid == CID_HOLD_TEST_REG)) {
                   // Check for long array of registers of type PARAM_TYPE_ASCII
                  err = mbc_master_get_parameter(cid, (char*)param_descriptor-&gt;param_key,
                                                    (uint8_t*)temp_data_ptr, &amp;type);
                  if (err == ESP_OK) {
                        ESP_LOGI(TAG, "Characteristic #%u %s (%s) value = (0x%" PRIx32 ") read successful.",
                                        param_descriptor-&gt;cid,
                                        param_descriptor-&gt;param_key,
                                        param_descriptor-&gt;param_units,
                                        *(uint32_t*)temp_data_ptr);
                        // Initialize data of test array and write to slave
                        if (*(uint32_t*)temp_data_ptr != 0xAAAAAAAA) {
                            memset((void*)temp_data_ptr, 0xAA, param_descriptor-&gt;param_size);
                            *(uint32_t*)temp_data_ptr = 0xAAAAAAAA;
                            err = mbc_master_set_parameter(cid, (char*)param_descriptor-&gt;param_key,
                                                            (uint8_t*)temp_data_ptr, &amp;type);
                            if (err == ESP_OK) {
                              ESP_LOGI(TAG, "Characteristic #%u %s (%s) value = (0x%" PRIx32 "), write successful.",
                                                param_descriptor-&gt;cid,
                                                param_descriptor-&gt;param_key,
                                                param_descriptor-&gt;param_units,
                                                *(uint32_t*)temp_data_ptr);
                            } else {
                              ESP_LOGE(TAG, "Characteristic #%u (%s) write fail, err = 0x%x (%s).",
                                                param_descriptor-&gt;cid,
                                                param_descriptor-&gt;param_key,
                                                (int)err,
                                                (char*)esp_err_to_name(err));
                            }
                        }
                  } else {
                        ESP_LOGE(TAG, "Characteristic #%u (%s) read fail, err = 0x%x (%s).",
                                        param_descriptor-&gt;cid,
                                        param_descriptor-&gt;param_key,
                                        (int)err,
                                        (char*)esp_err_to_name(err));
                  }
                } else {
                  err = mbc_master_get_parameter(cid, (char*)param_descriptor-&gt;param_key,
                                                      (uint8_t*)temp_data_ptr, &amp;type);
                  if (err == ESP_OK) {
                        if ((param_descriptor-&gt;mb_param_type == MB_PARAM_HOLDING) ||
                            (param_descriptor-&gt;mb_param_type == MB_PARAM_INPUT)) {
                            value = *(float*)temp_data_ptr;
                            ESP_LOGI(TAG, "Characteristic #%u %s (%s) value = %f (0x%" PRIx32 ") read successful.",
                                          param_descriptor-&gt;cid,
                                          param_descriptor-&gt;param_key,
                                          param_descriptor-&gt;param_units,
                                          value,
                                          *(uint32_t*)temp_data_ptr);
                            if (((value &gt; param_descriptor-&gt;param_opts.max) ||
                              (value &lt; param_descriptor-&gt;param_opts.min))) {
                                    alarm_state = true;
                                    break;
                            }
                        } else {
                            uint8_t state = *(uint8_t*)temp_data_ptr;
                            const char* rw_str = (state &amp; param_descriptor-&gt;param_opts.opt1) ? "ON" : "OFF";
                            if ((state &amp; param_descriptor-&gt;param_opts.opt2) == param_descriptor-&gt;param_opts.opt2) {
                              ESP_LOGI(TAG, "Characteristic #%u %s (%s) value = %s (0x%" PRIx8 ") read successful.",
                                                param_descriptor-&gt;cid,
                                                param_descriptor-&gt;param_key,
                                                param_descriptor-&gt;param_units,
                                                (const char*)rw_str,
                                                *(uint8_t*)temp_data_ptr);
                            } else {
                              ESP_LOGE(TAG, "Characteristic #%u %s (%s) value = %s (0x%" PRIx8 "), unexpected value.",
                                                param_descriptor-&gt;cid,
                                                param_descriptor-&gt;param_key,
                                                param_descriptor-&gt;param_units,
                                                (const char*)rw_str,
                                                *(uint8_t*)temp_data_ptr);
                     //         alarm_state = true;
                              break;
                            }
                            if (state &amp; param_descriptor-&gt;param_opts.opt1) {
                     //         alarm_state = true;
                              break;
                            }
                        }
                  } else {
                        ESP_LOGE(TAG, "Characteristic #%u (%s) read fail, err = 0x%x (%s).",
                                        param_descriptor-&gt;cid,
                                        param_descriptor-&gt;param_key,
                                        (int)err,
                                        (char*)esp_err_to_name(err));
                  }
                }
                vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls
            }
      }
      vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS*10);
    }

    if (alarm_state) {
      ESP_LOGI(TAG, "Alarm triggered by cid #%u.", param_descriptor-&gt;cid);
    } else {
      ESP_LOGE(TAG, "Alarm is not triggered after %u retries.", MASTER_MAX_RETRY);
    }
    ESP_LOGI(TAG, "Destroy master...");
    ESP_ERROR_CHECK(mbc_master_destroy());
}

// Modbus master initialization
static esp_err_t master_init(void)
{
    // Initialize and start Modbus controller
    mb_communication_info_t comm = {
            .port = MB_PORT_NUM,
#if CONFIG_MB_COMM_MODE_ASCII
            .mode = MB_MODE_ASCII,
#elif CONFIG_MB_COMM_MODE_RTU
            .mode = MB_MODE_RTU,
#endif
            .baudrate = MB_DEV_SPEED,
            .parity = MB_PARITY_NONE
    };
    void* master_handler = NULL;

    esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &amp;master_handler);
    MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
                              "mb controller initialization fail.");
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
                            "mb controller initialization fail, returns(0x%x).", (int)err);
    err = mbc_master_setup((void*)&amp;comm);
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
                            "mb controller setup fail, returns(0x%x).", (int)err);

    // Set UART pin numbers
    //err = uart_set_pin(MB_PORT_NUM, CONFIG_MB_UART_TXD, CONFIG_MB_UART_RXD,
    //                        CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE);
    err = uart_set_pin(MB_PORT_NUM, CONFIG_MB_UART_TXD, CONFIG_MB_UART_RXD,
                              UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
      "mb serial set pin failure, uart_set_pin() returned (0x%x).", (int)err);

    err = mbc_master_start();
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
                            "mb controller start fail, returned (0x%x).", (int)err);

    // Set driver mode to Half Duplex
    //err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
    err = uart_set_mode(MB_PORT_NUM, UART_MODE_UART);
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
            "mb serial set mode failure, uart_set_mode() returned (0x%x).", (int)err);

    vTaskDelay(5);
    err = mbc_master_set_descriptor(&amp;device_parameters, num_device_parameters);
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
                              "mb controller set descriptor fail, returns(0x%x).", (int)err);
    ESP_LOGI(TAG, "Modbus master stack initialized...");
    return err;
}

void app_main(void)
{
    // Initialization of device peripheral and objects
    ESP_ERROR_CHECK(master_init());
    vTaskDelay(10);

    master_operation_func(NULL);
}
</code></pre>

<p><strong><span style="font-size:18px;">五、编译烧写。</span></strong><br />
Idf.py -p COM73 flash</p>

<p>&nbsp;</p>

<p><strong><span style="font-size:18px;">六、准备modbus slave和串口工具MobaXterm_Personal进行调试</span></strong></p>

<p><br />
配置如下:记得前面两个是2个单元一个浮点的数据,填写数据不要超过 范围,具体可以看代码。<br />
线圈(左下)可以实时修改看打印结果,右边的那个是个数据单元区,打开就可以。<br />
</p>

<p>&nbsp;</p>

<p>实验实验结果:</p>

<div></div>

<div>b85bf7ac4d4de39700ab5700808ed9f2<br />
&nbsp;</div>

<div>&nbsp;</div>

<div>谢谢</div>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

小鳄鱼_A 发表于 2024-6-3 15:37

正准备用这个, 就看到了你的贴子

damiaa 发表于 2024-6-3 20:53

小鳄鱼_A 发表于 2024-6-3 15:37
正准备用这个, 就看到了你的贴子

<p>感谢支持 。</p>

<p>这个还可以。有啥问题可以直接问。用这个做过些项目,略懂一二。</p>
页: [1]
查看完整版本: 【FireBeetle 2 ESP32 C6开发板】 6 modbus实验