Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ЛР2 Саляхов

.docx
Скачиваний:
0
Добавлен:
25.06.2025
Размер:
247.26 Кб
Скачать

ФГБОУ ВО

Уфимский университет науки и технологий

Кафедра ВТиЗИ

Отчёт

Лабораторной работе №2

по дисциплине "Сети и телекоммуникации"

«Разработка коммуникационного ПО для физического интерфейса RS-485 и изучение промышленного протокола MODBUS»

Выполнили:

ст. гр. ИВТ-429Б

Саляхов А.Ф.

Хамидуллин А.Р.

Пономарева А.А.

Проверил:

Атарская Е.А.

Уфа 2024

Цель работы: Целью работы является практическое изучение интерфейса физического уровня RS-485 и протокола обмена данными Modbus, а также получение навыков разработки и использования ПО для обмена данными с периферийным устройством.

Ход работы:

  1. Создать виртуальные порты COM5 и COM6:

Виртуальные последовательные порты можно создать с помощью программы Virtual Serial Ports Emulator (VSPE):

  1. Протестировать приложение обмена текстовыми данными server и client

  1. Модернизировать клиент и сервер так, чтобы можно было осуществлять отсылку 3 целочисленных значений и 3 вещественных чисел.

  1. Разработать программу циклического опроса одного регистра источника с адресом 25 в формате RTU.

  1. Разработать программу циклического опроса 16 регистров источника в формате RTU.

Текст программ:

Сервер:

#include <stdio.h>

#ifndef _MSC_VER

#include <unistd.h>

#endif

#include <string.h>

#include <stdlib.h>

#include <errno.h>

#include <modbus/modbus.h>

//==============================================================================

// float == int32 == char[4]

union ParsedFloat

{

float value;

__int32 integer;

unsigned char byteArray[4];

struct ieee_t

{

unsigned int mantissa : 23;

unsigned int exponenta : 8;

unsigned int sign : 1;

} ieee;

};

//==============================================================================

// Печать представления числа с плавающей точкой в виде набора байт

// в шестандцатиричном формате

void printParsedFloatToHex(ParsedFloat &parsedFloat)

{

printf("Float number: dec = %f, hex = ", parsedFloat.value);

for (int i = 3; i > -1; i--)

printf("0x%02X ", parsedFloat.byteArray[i]);

printf("\n");

}

//==============================================================================

// ПРИМЕР

// Пример прямого и обратного преобразования вещественного числа в двоичное

// представление

void convertFloatNumbers(int numEx)

{

printf("Example %d: Parse float number s*m*2^e\n", numEx);

ParsedFloat ft;

ft.value = 123.123;

// Прямое

printf("Float number = %f\n", ft.value);

printf("s_16 = %x\ts_10 = %u\n", ft.ieee.sign, ft.ieee.sign);

printf("e_16 = %x\te_10 = %u\n", ft.ieee.exponenta, ft.ieee.exponenta);

printf("m_16 = %x\tm_10 = %u\n", ft.ieee.mantissa, ft.ieee.mantissa);

// Печать числа в виде октетов в 16 ричном представлении

printParsedFloatToHex(ft);

}

int main(void)

{

//Prepare a Modbus mapping with 30 holding registers

//(plus no output coil, one input coil and two input registers)

//This will also automatically set the value of each register to 0

modbus_mapping_t *mapping = modbus_mapping_new(0, 1, 30, 2);

if (!mapping) {

fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno));

exit(1);

}

mapping->tab_registers[10] = 123;

mapping->tab_registers[11] = 456;

mapping->tab_registers[12] = 789;

ParsedFloat ft1, ft2, ft3;

ft1.value = 123.123;

ft2.value = 456.456;

ft3.value = 789.789;

for(int j=0; j<4; j++)

{

mapping->tab_registers[13+j] = ft1.byteArray[0+j];

}

for(int j=0; j<4; j++)

{

mapping->tab_registers[17+j] = ft2.byteArray[0+j];

}

for(int j=0; j<4; j++)

{

mapping->tab_registers[21+j] = ft3.byteArray[0+j];

}

modbus_t *ctx = modbus_new_rtu("COM5", 9600, 'N', 8, 1);

if (!ctx) {

fprintf(stderr, "Failed to create the context: %s\n", modbus_strerror(errno));

exit(1);

}

//Set the Modbus address of this slave (to 3)

modbus_set_slave(ctx, 3);

if (modbus_connect(ctx) == -1) {

fprintf(stderr, "Unable to connect: %s\n", modbus_strerror(errno));

modbus_free(ctx);

exit(1);

}

uint8_t req[MODBUS_RTU_MAX_ADU_LENGTH];// request buffer

int len;// length of the request/response

int n = 1;

while(1) {

len = modbus_receive(ctx, req);

if (len == -1) break;

len = modbus_reply(ctx, req, len, mapping);

if (len == -1) break;

mapping->tab_registers[25] = n;

n++;

}

printf("Exit the loop: %s\n", modbus_strerror(errno));

modbus_mapping_free(mapping);

modbus_close(ctx);

modbus_free(ctx);

return 0;

}

Клиент:

#include <stdio.h>

#ifndef _MSC_VER

#include <unistd.h>

#endif

#include <stdlib.h>

#include <errno.h>

#include <modbus/modbus.h>

#include <iostream>

union ParsedFloat

{

float value;

__int32 integer;

unsigned char byteArray[4];

struct ieee_t

{

unsigned int mantissa : 23;

unsigned int exponenta : 8;

unsigned int sign : 1;

} ieee;

};

void printParsedFloatToHex(ParsedFloat &parsedFloat)

{

printf("Float number: dec = %f, hex = ", parsedFloat.value);

for (int i = 3; i > -1; i--)

printf("0x%02X ", parsedFloat.byteArray[i]);

printf("\n");

}

#if defined(_WIN32)

#define close closesocket

#endif

int main(void)

{

//Create a new RTU context with proper serial parameters (in this example,

//device name /dev/ttyS0, baud rate 9600, no parity bit, 8 data bits, 1 stop bit)

modbus_t *ctx = modbus_new_rtu("COM6", 9600, 'N', 8, 1);

if (!ctx) {

fprintf(stderr, "Failed to create the context: %s\n", modbus_strerror(errno));

exit(1);

}

if (modbus_connect(ctx) == -1) {

fprintf(stderr, "Unable to connect: %s\n", modbus_strerror(errno));

modbus_free(ctx);

exit(1);

}

//Set the Modbus address of the remote slave (to 3)

modbus_set_slave(ctx, 3);

uint16_t reg[5];// will store read registers values

//Read 5 holding registers starting from address 10

int num = modbus_read_registers(ctx, 10, 3, reg);

if (num != 3) {// number of read registers is not the one expected

fprintf(stderr, "Failed to read: %s\n", modbus_strerror(errno));

}

for (int j=0; j<3; j++)

{

printf("\n%d\n", reg[j]);

}

ParsedFloat ft1, ft2, ft3;

int num1 = modbus_read_registers(ctx, 13, 4, reg);

if (num1 != 4) {// number of read registers is not the one expected

fprintf(stderr, "Failed to read: %s\n", modbus_strerror(errno));

}

for (int j=0; j<4; j++)

{

ft1.byteArray[j] = reg[j];

}

printf("\n%f", ft1.value);

int num2 = modbus_read_registers(ctx, 17, 4, reg);

if (num2 != 4) {// number of read registers is not the one expected

fprintf(stderr, "Failed to read: %s\n", modbus_strerror(errno));

}

for (int j=0; j<4; j++)

{

ft2.byteArray[j] = reg[j];

}

printf("\n\n%f", ft2.value);

int num3 = modbus_read_registers(ctx, 21, 4, reg);

if (num3 != 4) {// number of read registers is not the one expected

fprintf(stderr, "Failed to read: %s\n", modbus_strerror(errno));

}

for (int j=0; j<4; j++)

{

ft3.byteArray[j] = reg[j];

}

printf("\n\n%f\n", ft3.value);

while(true)

{

modbus_read_registers(ctx, 25, 1, reg);

std::cout << "\n" << "Register 25: " << reg[0] << "\n\n";

uint16_t tab_reg[16] = {0};

int ret = modbus_read_registers(ctx, 0, 16, tab_reg);

if (ret == -1) {

std::cerr << "Read error: " << modbus_strerror(errno) << "\n";

break;

}

for (int i = 0; i < ret; i++) {

std::cout << "Register " << i << ": " << tab_reg[i] << "\n";

}

sleep(1);

}

modbus_close(ctx);

modbus_free(ctx);

return 0;

}

Вывод: Мы изучили интерфейс физического уровня RS-485 и протокол обмена данными Modbus, а также получили навыки разработки и использования ПО для обмена данными с периферийным устройством.

Соседние файлы в предмете Сети и Телекоммуникации