Page 1 of 1

Read multiple registers in modbus RTU

Posted: Thu May 16, 2024 12:47 pm
by manas_frinso
I am reading 4 registers in Modbus and am successful in receiving the values but I am only being able to print the first 2 register values

Please help.

Code: Select all

#include "modbus_master.h"

static const char *TAG = "MASTER_TEST";








float flow_valu = 0;



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

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("active_energy"), STR(" "), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 01127, 4,
		INPUT_OFFSET(data_block1), PARAM_TYPE_FLOAT, 8, OPTS( 0, 0, 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[0]));

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

// User operation function to read slave values
void master_operation_func(void *arg)
{

    ESP_ERROR_CHECK(master_init());

	esp_err_t err = ESP_OK;
	uint64_t value = 0;
	const mb_parameter_descriptor_t* param_descriptor = NULL;

	while(1)
	{
		if (is_waiting == false){
			//            ESP_LOGI(TAG, "Start modbus test...");
			// Read all found characteristics from slave(s)
			for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < 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, &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;
					err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
							(uint8_t*)&value, &type);
					if (err == ESP_OK) {
						//use custom conversion, givin conversion are just for example , use : https://www.scadacore.com/tools/programming-calculators/online-hex-converter/ (for hex convrersions)

						if(param_descriptor->cid == 0){
							                             ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %08lX read successful.",
							                                         param_descriptor->cid,
							                                         (char*)param_descriptor->param_key,
							                                         (char*)param_descriptor->param_units,
							                                         value);
						}
					} else {
//						ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
//								param_descriptor->cid,
//								(char*)param_descriptor->param_key,
//								(int)err,
//								(char*)esp_err_to_name(err));
					}
					vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls
				}
			}
			vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS); //
		}  else {
			//            ESP_LOGI(TAG, "Waiting for MQTT to initiate\n");
			vTaskDelay(1000 / portTICK_PERIOD_MS);
		}
	}
}

// Modbus master initialization
esp_err_t master_init(void)
{
	// Initialize and start Modbus controller
	mb_communication_info_t comm = {
			.port = 2,
#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, &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).",
			(uint32_t)err);
	err = mbc_master_setup((void*)&comm);
	MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
			"mb controller setup fail, returns(0x%x).",
			(uint32_t)err);

	// Set UART pin numbers
	err = uart_set_pin(2, 17, 16, 33, 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).", (uint32_t)err);

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

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

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

Re: Read multiple registers in modbus RTU

Posted: Mon May 27, 2024 9:35 am
by ESP_alisitsyn
@manas_frinso,

The latest esp-modbus supports extended types and also allows to configure the array of the values with the same type.
For example it is possible to configure the array of float type in the data dictionary and the stack will pack the incoming data to this contiguous array. Then you can use the for example the EACH_ITEM() https://github.com/espressif/esp-modbus ... er.c#L257 to access each element in the array and do required action.

Please see the links below.

https://docs.espressif.com/projects/esp ... of-mapping
https://github.com/espressif/esp-modbus ... ter.c#L161

Let me know if you have any troubles.