From 8be941b2b22b0545a2637a17b4a771cdedf9b2e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BD=D0=B0=D1=81=D1=82=D0=B0=D1=81=D0=B8=D1=8F=20?=
 =?UTF-8?q?=D0=A1=D0=B0=D0=BB=D0=B0=D0=BD=D0=B3=D0=B8=D0=BD=D0=B0?=
 <stud126792@vyatsu.ru>
Date: Tue, 20 Jun 2023 14:16:30 +0000
Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=B8?=
 =?UTF-8?q?=D0=BB(=D0=B0)=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D0=B2=20''?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 gpio.c   | 103 +++++++
 gpio.h   |  26 ++
 modbus.c | 812 +++++++++++++++++++++++++++++++------------------------
 modbus.h |  79 ++++--
 timer.c  |  28 ++
 5 files changed, 663 insertions(+), 385 deletions(-)
 create mode 100644 gpio.c
 create mode 100644 gpio.h
 create mode 100644 timer.c

diff --git a/gpio.c b/gpio.c
new file mode 100644
index 0000000..1d45ef4
--- /dev/null
+++ b/gpio.c
@@ -0,0 +1,103 @@
+#include "device_ring_buffer.h"
+#include "device_adc.h"
+#include "device_address.h"
+#include "UART.h"
+#include "modbus.h"
+#include "timer.h"
+#include "gpio.h"
+
+
+//�������������
+void gpio_init(void)
+{
+	//��������� ����� pin_coils � ����� ������ - 1
+	DDRD |= (1 � PIN_COIL1);
+	DDRD |= (1 � PIN_COIL2);
+	DDRD |= (1 � PIN_COIL3);
+	DDRD |= (1 � PIN_COIL4);
+	
+	//��������� ����� pin_discrete_inputs � ����� ����� - 0
+	DDRB &= ~(1 � PIN_DISCRETE_INPUT_1);
+	DDRB &= ~(1 � PIN_DISCRETE_INPUT_2);
+	DDRB &= ~(1 � PIN_DISCRETE_INPUT_3);
+	DDRB &= ~(1 � PIN_DISCRETE_INPUT_4);
+}
+
+//������
+uint8_t gpio_read(uint8_t pin)
+{
+	switch (pin)
+	{
+	//������ pin_coils
+	case PIN_COIL1:
+		return (PIND & (1 � PIN_COIL1)) � PIN_COIL1; // ������ �������� �� ���� � ����� ������ �� ����� ����
+	case PIN_COIL2:
+		return (PIND & (1 � PIN_COIL2)) � PIN_COIL2;
+	case PIN_COIL3:
+		return (PIND & (1 � PIN_COIL3)) � PIN_COIL3;
+	case PIN_COIL4:
+		return (PIND & (1 � PIN_COIL4)) � PIN_COIL4;
+
+	//������ pin_discrete_inputs
+	case PIN_DISCRETE_INPUT_1:
+		return (PINB & (1 � PIN_DISCRETE_INPUT_1)) � PIN_DISCRETE_INPUT_1;
+	case PIN_DISCRETE_INPUT_2:
+		return (PINB & (1 � PIN_DISCRETE_INPUT_2)) � PIN_DISCRETE_INPUT_2;
+	case PIN_DISCRETE_INPUT_3:
+		return (PINB & (1 � PIN_DISCRETE_INPUT_3)) � PIN_DISCRETE_INPUT_3;
+	case PIN_DISCRETE_INPUT_4:
+		return (PINB & (1 � PIN_DISCRETE_INPUT_4)) � PIN_DISCRETE_INPUT_4;
+
+	default:
+		return 0;
+	}
+}
+
+//������
+void gpio_write(uint8_t pin, uint8_t value)
+{
+	switch (pin)
+	{
+	case PIN_COIL1:
+		if (value != 0x0000)
+		{
+			PORTD |= (1 � PIN_COIL1);
+		}
+		else
+		{
+			PORTD &= ~(1 � PIN_COIL1);
+		}
+		break;
+	case PIN_COIL2:
+		if (value != 0x0000)
+		{
+			PORTD |= (1 � PIN_COIL2);
+		}
+		else
+		{
+			PORTD &= ~(1 � PIN_COIL2);
+		}
+		break;
+	case PIN_COIL3:
+		if (value != 0x0000)
+		{
+			PORTD |= (1 � PIN_COIL3);
+		}
+		else
+		{
+			PORTD &= ~(1 � PIN_COIL3);
+		}
+		break;
+	case PIN_COIL4:
+		if (value != 0x0000)
+		{
+			PORTD |= (1 � PIN_COIL4);
+		}
+		else
+		{
+			PORTD &= ~(1 � PIN_COIL4);
+		}
+		break;
+	default:
+		break;
+}
\ No newline at end of file
diff --git a/gpio.h b/gpio.h
new file mode 100644
index 0000000..94c3c1c
--- /dev/null
+++ b/gpio.h
@@ -0,0 +1,26 @@
+#ifndef GPIO_H
+#define GPIO_H
+
+#include "device_ring_buffer.h"
+#include "device_adc.h"
+#include "device_address.h"
+#include "UART.h"
+#include "modbus.h"
+#include "timer.h"
+
+#define PIN_COIL1 PD4
+#define PIN_COIL2 PD5
+#define PIN_COIL3 PD6
+#define PIN_COIL4 PD7
+
+#define PIN_DISCRETE_INPUT_1 PB0
+#define PIN_DISCRETE_INPUT_2 PB1
+#define PIN_DISCRETE_INPUT_3 PB2
+#define PIN_DISCRETE_INPUT_4 PB3
+
+void gpio_init(void);
+uint8_t gpio_read(uint8_t pin);
+void gpio_write(uint8_t pin, uint8_t value);
+
+
+#endif /*GPIO_H*/
diff --git a/modbus.c b/modbus.c
index 9830fa8..07059b4 100644
--- a/modbus.c
+++ b/modbus.c
@@ -1,360 +1,452 @@
-
-#define On 1
-#define Off 0
-#define Change_output 10
-#define discrete_output_reading 11
-
-
-volatile unsigned char Data_Rx_ModbasRtu[30];//������ �������� ������
-volatile unsigned char quantity_Data_ModbasRtu; //���������� �������� ������
-//Volatile � �������� ����� ������ C/C++, ������� ����������� ���������� � ���, ��� �������� ���������� ����� �������� ����� � ��� ���������� �� ����� �������������� ��� ����������
-volatile unsigned int Data_ModbasRtu_analog_input[1]; //������ �� ���������� ����� [1 - ����� ����������� �����]
-volatile unsigned int Data_ModbasRtu_analog_Output[1]; //������ �� ���������� ������ [1 - ����� ����������� ������]
-volatile unsigned char Data_ModbasRtu_Binary_input[(1/8)+1]; //������ �� ���������� ����� [1 - ����� ����������� �����]
-volatile unsigned char Data_ModbasRtu_Binary_Output[(1/8)+1]; //������ �� ���������� ������ [1 - ����� ����������� ������]
-
-
-//������� ������ � ���������� ������(Data_Rx_ModbasRtu)
-//�������� ��� int rb_get(struct rb* _rb, char *element)
-Data_Rx_ModbasRtu = rb_get(&, 1);
-
-
-//����������� �����(+)
-int crc_chk(unsigned char* data, unsigned char length)
-{
-	register int j; // register - ������������, ������� ������������, ��� ������ � ������� ����� �������
-	register unsigned int reg_crc = 0xFFFF; //���������� 16-������� ��������
-	while (length--)
-	{
-		reg_crc ^= *data++; //������ ����-���������� ������������ �� ������������ ��� � ������� ��������� �������� ����� �����. ����� ���������� 8 ������ ��������� ���� ������������ � ������� ��������� �������� ����� ����� � ������� ������ ����������� �������� 8 ���
-		for (j = 0; j < 8; j++)
-		{
-			if (reg_crc & 0x01) //�������� �������� ����
-			{
-				reg_crc = (reg_crc >> 1) ^ 0xA001; //����������� ��� �� ������ ��������. ��������� ������ ���������� � ������� �������� ���� � ����������� ����� �������� ����. ���� ������� ��� = 1, �� ������������ ���� ��� ����������� �������� ����� ����� � ��������������� �����
-			}
-			else
-			{
-				reg_crc = reg_crc >> 1; //���� ������� ��� = 0, ���� ��� �� ��������
-			}
-		}
-	}
-	return reg_crc; //������� �������� ��������� ���������� ����� �����
-}
-
-
-//����������� ���� ����(�������� � ��������)
-int ModbasRtu_Register_address(unsigned char Li)
-//Hi - ������� ����
-//Li - �������
-{
-	register char Hi = Li - 1;
-	return  Data_Rx_ModbasRtu[Hi] * 256 + Data_Rx_ModbasRtu[Li]; //��������� ����� �������� � �������� �����
-}
-
-//�����
-int Modbus_addr()
-{
-	volatile unsigned int adres;
-	adres = ModbasRtu_Register_address(1);
-}
-
-//�������� ����������� ����� � ���������� ������� ������
-char Data_integrity()
-{
-	register unsigned int Temp_2;
-	register unsigned char Temp_3;
-	quantity_Data_ModbasRtu = quantity_Data_ModbasRtu - 2; //������� ����������� ����� �� �������
-	Temp_2 = crc_chk(Data_Rx_ModbasRtu, quantity_Data_ModbasRtu); //��������� ����������� �����
-	Temp_3 = Temp_2; //�������� ������� ���� � ����������� �����
-	if (Data_Rx_ModbasRtu[quantity_Data_ModbasRtu] == Temp_3) //���������� � ������� ������� ���� � ����������� ������
-	{
-		quantity_Data_ModbasRtu++; //����� ������ �����������
-		Temp_3 = (Temp_2 >> 8); //����� �� 8 ���
-		if (Data_Rx_ModbasRtu[quantity_Data_ModbasRtu] == Temp_3) //������� 
-		{
-			return 1;
-		}
-	}
-	return 0;
-}
-
-
-//������ � ����������� ������� � ��������
-char _Bin_input_Output(register unsigned char NUMBER, register unsigned char state, volatile unsigned char* Masiv, volatile unsigned char Sd)
-{
-	volatile unsigned char Temp = 0, Temp_1 = 0;
-	while (NUMBER >= 8)
-	{
-		NUMBER = NUMBER - 8;
-		Temp++; //����������, � ����� �������� ����� �������� ���� ��������� ���
-	}
-	Temp_1 = Masiv[Temp];
-	if (Sd == 10) //�����������, ���� ����� �������� ���
-	{
-		if (state == On)
-			Temp_1 |= (1 << NUMBER);
-		else
-			Temp_1 &= ~(1 << NUMBER);
-		Masiv[Temp] = Temp_1;
-	}
-	else //�����������, ���� ����� ��������� ��������� ����
-	{
-		if (Temp_1 & (1 << NUMBER))
-			NUMBER = 1;
-		else
-			NUMBER = 0;
-	}
-	return NUMBER; //���������� ��������� ������������ ����
-}
-
-
-//���� ������� :
-
-//������ �������� ���������� ��������� ������ 0x01, ������ �������� ���������� ���������� ������ 0x02
-void Reading_Discrete_Output(unsigned char* Massiv, register unsigned char Number_)
-{
-	volatile unsigned int adres, Number_bits;
-	register unsigned char Temp = 0, Data, Temp2 = 0, adres2 = 0, Temp3 = 2;
-	adres = ModbasRtu_Register_address(3); //����� ��������, � �������� ���������� ������
-	if (adres > Number_) //��������, ��� ����� �� ��������� ����������
-	{
-		Error_modbasRtu(0x02); //������������ �����
-	}
-	else
-	{
-		Number_bits = ModbasRtu_Register_address(5); //���������� ���, ������� ����� ��������
-		while (adres >= 8) //������ ����� ������ �������, � ������� ������ ��������� ������
-		{
-			adres = adres - 8; //�� ���������� �������������� �������� ���, � �������� ����� �������� ����������
-			Temp++; //����� ����� � ������� � �������� ���������� ���������� ���������
-		}
-		Data = Massiv[Temp]; //��������� ������
-		//��������� ������� � ��������� ������ ��� ��������
-		while (Number_bits > 0) //��������, ��� ��� ���� ������� ��������
-		{
-			Number_bits--;
-			if (Data & (1 << adres))
-			{
-				Temp2 |= (1 << adres2);
-			}
-			adres2++;
-			adres++;
-			if (adres2 == 8)
-			{
-				adres2 = 0;
-				Temp3++;
-				Data_Rx_ModbasRtu[Temp3] = Temp2;
-				Temp2 = 0;
-			}
-			if (adres == 8)
-			{
-				adres = 0;
-				Temp++;
-				Data = Massiv[Temp]; //��������� ������
-			}
-		}
-		if (adres2 > 0)
-		{
-			Temp3++;
-			Data_Rx_ModbasRtu[Temp3] = Temp2;
-		}
-		Data_Rx_ModbasRtu[2] = Temp3 - 2; //���������� ���������� ���� (��� ����� ������ � ���� �������)
-		Temp3++;
-		check_sum(Temp3); //���������� ����������� ����� ��� �������� ������
-	}
-}
-
-//������ �������� ���������� ��������� �������� 0x03, ������ �������� ���������� ��������� ����� 0x04
-void Read_analog_input(unsigned char* Massiv, register unsigned char Number_, unsigned char Vt)
-//Vt - ���� ��� �����
-{
-	volatile unsigned int address, Number_bits, Data;
-	volatile unsigned  char Adress = 4;
-	address = ModbasRtu_Register_address(3); //����� ��������, � �������� ���������� ������
-	if (address > Number_) //��������, ��� ����� �� ��������� ����������
-	{
-		Error_modbasRtu(0x02); //��������� � ������� ����� �� ����������
-	}
-	else
-	{
-		Number_bits = ModbasRtu_Register_address(5); //���������� ����, ������� ����� �������� (������� � �������)
-		Data_Rx_ModbasRtu[2] = Number_bits * 2; //���������� ���� ����������, ������� ����� ��������
-		Adress = 3;
-		while (Number_bits > 0)
-		{
-			if (Vt == 1) //�����������, ��� ��������� - ���� ��� �����
-			{
-				Data = Data_ModbasRtu_analog_input[address];
-			}
-			else
-			{
-				Data = Data_ModbasRtu_analog_Output[address];
-			}
-			address++;
-			Massiv = &Data;
-			Data_Rx_ModbasRtu[Adress++] = Massiv[1]; //��������� ������� ����
-			Data_Rx_ModbasRtu[Adress++] = Massiv[0]; //��������� ������� ����
-			Number_bits = Number_bits - 1;
-		}
-		check_sum(Adress); //���������� ����������� ����� ��� �������� ������
-	}
-}
-
-//������ ������ �������� ������ 0x05
-void Changing_Discrete_Output(void)
-{
-	register unsigned int address;
-	address = ModbasRtu_Register_address(3); //����� ��������, � �������� ���������� ������
-	if (address > 11) //��������, ��� ����� �� ��������� ���������� [11 - ����� ����������� ������]
-	{
-		Error_modbasRtu(0x02);
-	}
-	else
-	{
-		if (Data_Rx_ModbasRtu[4] == 255)
-			_Bin_input_Output(address, On, Data_ModbasRtu_Binary_Output, Change_output);
-		else
-			_Bin_input_Output(address, Off, Data_ModbasRtu_Binary_Output, Change_output);
-	}
-}
-
-//������ ������ �������� �������� 0x06
-void analog_output_recording(void)
-{
-	register int address;
-	address = ModbasRtu_Register_address(3);
-	if (address > 11) //[11 - ����� ����������� ������]
-	{
-		Error_modbasRtu(0x02);
-	}
-	else
-	{
-		Data_ModbasRtu_analog_Output[address] = ModbasRtu_Register_address(5); //������, ������� ����� ��������
-	}
-}
-
-
-//������
-void Error_modbasRtu(volatile unsigned char Temp_Error)
-{
-	Data_Rx_ModbasRtu[1] |= (1 << 7);
-	Data_Rx_ModbasRtu[2] = Temp_Error; //��� ������
-	check_sum(3); //���������� ����������� ����� ��� �������� ������
-}
-
-
-//����� ����������� �����
-void check_sum(register unsigned char Adress)
-{
-	register unsigned int RC;
-	RC = crc_chk(Data_Rx_ModbasRtu, Adress); //��������� ����������� �����
-	Data_Rx_ModbasRtu[Adress] = RC; //������� ���� ����������� �����
-	Adress++;
-	Data_Rx_ModbasRtu[Adress] = RC >> 8; //������� ���� ����������� �����
-	quantity_Data_ModbasRtu = Adress;
-}
-
-
-//��������� �������� � ����� �� �������� ������� ��� ��������� ����� �� �������
-void modbasRtu_Answer()
-{
-	switch (Data_Rx_ModbasRtu[1])
-	{
-	case 1:
-		//Modbus RTU ������ ����������� ������ 0x01
-		Reading_Discrete_Output(Data_ModbasRtu_Binary_Output, 11); //[11 - ����� ����������� ������]
-		break;
-	case 2:
-		//Modbus RTU ������ ����������� ����� 0x02
-		Reading_Discrete_Output(Data_ModbasRtu_Binary_input, 11); //[11 - ����� ����������� �����]
-		break;
-	case 3:
-
-		Read_analog_input(Data_ModbasRtu_analog_Output, 11, 0); //Modbus RTU �� ������ ����������� ������ 0x03 [11 - ����� ����������� ������]
-		break;
-	case 4:
-
-		Read_analog_input(Data_ModbasRtu_analog_input, 11, 1); //Modbus RTU �� ������ ����������� ����� 0x04 [11 - ����� ����������� �����]
-		break;
-	case 5:
-		//Modbus RTU �� ������ ����������� ������ 0x05
-		Changing_Discrete_Output();
-		break;
-	case 6:
-		//Modbus RTU �� ������ ����������� ������ 0x06
-		analog_output_recording();
-		break;
-	case 15:
-		//Modbus RTU �� ������ ���������� ���������� ������� 0x0F
-		asm("nop"); //������� ���������, ������� ������������ ������ �� ������
-		//break;
-	case 16:
-		//Modbus RTU �� ������ ���������� ���������� ������� 0x10
-		asm("nop");
-		//break;
-	default:
-		//������� �� �������������
-		Error_modbasRtu(0x01); //�������� ��� ������� �� ����� ���� ���������
-		break;
-	}
-}
-
-
-//������������ ��� ��������� ��������
-
-//��������� ��� ������
-char read_digital_inputs(volatile unsigned char Temp1)
-{
-	return _Bin_input_Output(Temp1, On, Data_ModbasRtu_Binary_input, discrete_output_reading); //������� ��������� ������ �� ��������� �������
-}
-
-//�������� ��� ������
-void change_digital_inputs(volatile unsigned char Temp1, volatile unsigned char Temp2)
-{
-	_Bin_input_Output(Temp1, Temp2, Data_ModbasRtu_Binary_input, Change_output);
-}
-
-//��������� ��� �������
-char read_digital_Output(volatile unsigned char Temp1)
-{
-	return _Bin_input_Output(Temp1, On, Data_ModbasRtu_Binary_Output, discrete_output_reading); //������� ��������� ������ �� ��������� �������
-}
-
-//�������� ��� �������
-void change_digital_Output(volatile unsigned char Temp1, volatile unsigned char Temp2)
-{
-	_Bin_input_Output(Temp1, Temp2, Data_ModbasRtu_Binary_Output, Change_output);
-}
-
-//�������� �������� ���������� �������
-void change_analogue_Output(volatile unsigned char nomer, int Data)
-{
-	Data_ModbasRtu_analog_Output[nomer] = Data;
-}
-
-//�������� �������� ���������� ������
-void change_analogue_input(volatile unsigned char nomer, int Data)
-{
-	Data_ModbasRtu_analog_input[nomer] = Data;
-}
-
-//������� �������� ���������� �������
-int read_analogue_Output(volatile unsigned char nomer)
-{
-	return Data_ModbasRtu_analog_Output[nomer];
-}
-
-//������� �������� ���������� �������
-int read_analogue_input(volatile unsigned char nomer)
-{
-	return Data_ModbasRtu_analog_input[nomer];
-}
-
-
-//(��������� �� rb_put � ��������� ����� �����)
-//�������� ��� int rb_put(struct rb* _rb, char element)
-void Data_Modbus_answer()
-{
-
-}
\ No newline at end of file
+#include "modbus.h"
+
+uint8_t state;
+uint8_t packet[SIZE_MODBUS_PAKET];
+uint8_t size_of_packet;
+uint16_t crc_modbus;
+uint16_t first_register_device;
+uint16_t number_of_registers_required;
+uint16_t crc_answ;
+uint8_t modbus_answ[SIZE_MODBUS_PAKET];
+uint16_t expected_crc;
+unsigned long time;
+uint8_t packet_accepted;
+uint16_t last_possible_register;
+
+uint16_t crc_chk(uint8_t *data, uint8_t length);
+uint16_t bytes_unification(uint8_t high, uint8_t low);
+uint8_t read_coils(uint8_t address, uint8_t value, uint8_t *modbus_answ);
+uint8_t read_discrete_inputs(uint8_t address, uint8_t value, uint8_t *modbus_answ);
+uint8_t read_holding_registers(uint8_t address, uint8_t value, uint8_t *modbus_answ);
+uint8_t read_input_registers(uint8_t address, uint8_t value, uint8_t *modbus_answ);
+uint8_t write_single_coil(uint8_t address, uint16_t coil_addr, int on, uint8_t *modbus_answ);
+uint8_t write_single_register(uint8_t address, uint16_t register_addr, uint16_t new_value, uint8_t *modbus_answ);
+uint8_t write_multiple_coils(uint8_t address, uint16_t first_coil_addr, uint16_t recorded_num, uint8_t *modbus_answ);
+uint8_t write_multiple_registers(uint8_t address, uint16_t first_register_addr, uint16_t recorded_num, uint8_t *modbus_answ);
+uint8_t modbus_err_answ(uint8_t address, uint8_t func_code, uint8_t err_code, uint8_t *modbus_answ);
+void modbus_rtu_send(uint8_t answ_len);
+
+void modbus_init(void)
+{
+    size_of_packet = 0;
+    crc_modbus = 0xFFFF;
+    state = 0;
+}
+
+void range_in_range(uint8_t a, uint8_t b, uint8_t x, uint8_t y)
+{
+	uint8_t c = a + b - 1;
+	if (a >= x && a <= y) || (c >= x && c <= y)
+	{
+		return 0;
+	}
+	else
+	{
+		return 1;
+	}
+}
+
+// Функция приема modbus-запроса RTU
+void modbus_rtu(void)
+{
+    // состояние приема
+    if (state == 0)
+    {
+        uint8_t data;
+        // Размер пакета 0
+        size_of_packet = 0;
+        // Записываем время начала приема пакета
+        time = get_millis();
+        // Пакет не принят
+        packet_accepted = 0;
+
+        // Цикл приема символов
+        while (!packet_accepted)
+        {
+            // Читаем символ из входящего кольцевого буфера
+            // Кольцевой буфер не пуст
+            if (count_elements(get_rb_receive()) > 0)
+            {
+                // Читаем символ из кольцевого буфера
+                rb_get(get_rb_receive(), &data);
+                if (size_of_packet == 0)
+                {
+                    // Пришел новый пакет
+                    packet[0] = data;
+                    size_of_packet = 1;
+                    time = get_millis();
+                }
+                    
+                else
+                {
+                    // Проверяем линейный буфер на переполнение
+                    if (size_of_packet == SIZE_MODBUS_PAKET)
+                    {
+                        // Буфер переполнился
+                        // Ждем новый пакет
+                        size_of_packet = 0;
+                        continue;
+                    }
+                    else
+                    {
+                        time = get_millis();
+                        packet[size_of_packet] = data;
+                        size_of_packet++;
+                    }
+                }
+            }
+            // Проверка временного интервала между символами
+            else
+            {
+                if ((get_millis() - time) > MAX_PAUSE)
+                {
+                    // Превышен таймаут
+                    // Пакет закончился
+                    packet_accepted = 1;
+                }
+            }
+        }
+        // Проверяем размер пакета
+        if (size_of_packet < 5)
+        {
+            size_of_packet = 0;
+            crc_modbus = 0xFFFF;
+            return;
+        }
+
+        // считаем контрольную сумму CRC и сравниваем с CRC в пакете
+        expected_crc = bytes_unification(size_of_packet - 2, size_of_packet - 1);
+        crc_modbus = crc_chk(packet, size_of_packet - 3);
+        // проверка контрольной суммы CRC
+        if (crc_modbus != expected_crc)
+        {
+            size_of_packet = 0;
+            crc_modbus = 0xFFFF;
+            // формируем ошибку произошла невосполнимая ошибка
+            return;
+        }
+        // проверка адреса устройства
+        else if (get_device_address() != packet[0])
+        {
+            size_of_packet = 0;
+            crc_modbus = 0xFFFF;
+            // формируем ошибку адреса
+            return;
+        }
+        else
+        {
+            // Расчленяем пакет
+            state = 1;
+            return;
+        }
+    }
+}
+
+// Функция отправки modbus-запроса в кольцевой буфер
+void modbus_rtu_send(uint8_t answ_len)
+{
+    size_of_packet = 0;
+    // состояние отправки
+    if (state == 1)
+    {
+        // цикл отправки символов
+        while (state == 1)
+        {
+            // Отправка всех байт в кольцевой буфер
+            rb_put(get_rb_transmit(), modbus_answ[size_of_packet]);
+
+            // смещаем указатель
+            size_of_packet++;
+            if (size_of_packet == answ_len)
+            {
+                state = 0;
+                size_of_packet = 0;
+                crc_modbus = 0xFFFF;
+                return;
+            }
+        }
+    }
+}
+
+// Функция формирования modbus-ответа RTU
+void modbus_answer()
+{
+    switch (packet[1])
+    {
+    case READ_COILS:
+        first_register_device = bytes_unification(2, 3);
+        number_of_registers_required = bytes_unification(4, 5);
+
+        if (range_in_range(first_register_device, number_of_registers_required, COIL_1, COIL_4) && number_of_registers_required > 0)
+		{
+			modbus_rtu_send(modbus_err_answ(get_device_address(), packet[1], ILLEGAL_DATA_ADDRESS, &modbus_answ));
+		}
+        else
+        {
+            uint8_t value = 0;
+            while (number_of_registers_required > 0)
+            {
+                switch (first_register_device)
+                {
+                case COIL_1:
+                    value |= (gpio_read(PIN_COIL1));
+                    break;
+                case COIL_2:
+                    value |= (gpio_read(PIN_COIL2));
+                    break;
+                case COIL_3:
+                    value |= (gpio_read(PIN_COIL3));
+                    break;
+                case COIL_4:
+                    value |= (gpio_read(PIN_COIL4));
+                    break;
+                }
+
+                first_register_device++;
+                number_of_registers_required--;
+            }
+            modbus_rtu_send(read_coils(get_device_address(), value, &modbus_answ));
+        }
+
+        break;
+    case READ_DISCRETE_INPUTS:
+        first_register_device = bytes_unification(2, 3);
+        number_of_registers_required = bytes_unification(4, 5);
+
+        if (range_in_range(first_register_device, number_of_registers_required, DISCRETE_INPUTS_1, DISCRETE_INPUTS_4) && number_of_registers_required > 0)
+		{
+			modbus_rtu_send(modbus_err_answ(get_device_address(), packet[1], ILLEGAL_DATA_ADDRESS, &modbus_answ));
+		}
+        else
+        {
+            uint8_t value = 0;
+            while (number_of_registers_required > 0)
+            {
+                switch (first_register_device)
+                {
+                case DISCRETE_INPUTS_1:
+                    value |= (gpio_read(PIN_DISCRETE_INPUT_1));
+                    break;
+                case DISCRETE_INPUTS_2:
+                    value |= (gpio_read(PIN_DISCRETE_INPUT_2));
+                    break;
+                case DISCRETE_INPUTS_3:
+                    value |= (gpio_read(PIN_DISCRETE_INPUT_3));
+                    break;
+                case DISCRETE_INPUTS_4:
+                    value |= (gpio_read(PIN_DISCRETE_INPUT_4));
+                    break;
+                }
+
+                first_register_device ++;
+                number_of_registers_required--;
+            }
+            modbus_rtu_send(read_discrete_inputs(get_device_address(), value, &modbus_answ));
+        }
+
+        break;
+    case READ_HOLDING_REGISTERS:
+        first_register_device = bytes_unification(2, 3);
+        number_of_registers_required = bytes_unification(4, 5);
+
+        if (first_register_device != HOLDING_REGISTER_SLAVE_ADDRESS || number_of_registers_required != 1)
+		{
+			modbus_rtu_send(modbus_err_answ(get_device_address(), packet[1], ILLEGAL_DATA_ADDRESS, &modbus_answ));
+		}
+        else
+        {
+            modbus_rtu_send(read_holding_registers(get_device_address(), get_device_address(), &modbus_answ));
+        }
+
+        break;
+    case READ_INPUT_REGISTERS:
+        first_register_device = bytes_unification(2, 3);
+        number_of_registers_required = bytes_unification(4, 5);
+
+        if (first_register_device != INPUT_REGISTERS || number_of_registers_required != 1)
+		{
+			modbus_rtu_send(modbus_err_answ(get_device_address(), packet[1], ILLEGAL_DATA_ADDRESS, &modbus_answ));
+		}
+        else
+        {
+            modbus_rtu_send(read_input_registers(get_device_address(), get_adc_value(), &modbus_answ));
+        }
+
+        break;
+    case WRITE_SINGLE_COIL:
+        first_register_device = bytes_unification(2, 3);
+
+        if (range_in_range(first_register_device, 1, COIL_1, COIL_4))
+		{
+			modbus_rtu_send(modbus_err_answ(get_device_address(), packet[1], ILLEGAL_DATA_ADDRESS, &modbus_answ));
+		}
+        else
+        {
+            uint8_t value = 0;
+			switch (first_register_device)
+			{
+			case COIL_1:
+				value = gpio_write(PIN_COIL1, packet[4]);
+				break;
+			case COIL_2:
+				value = gpio_write(PIN_COIL2, packet[4]);
+				break;
+			case COIL_3:
+				value = gpio_write(PIN_COIL3, packet[4]);
+				break;
+			case COIL_4:
+				value = gpio_write(PIN_COIL4, packet[4]);
+				break;
+			}
+
+            modbus_rtu_send(write_single_coil(get_device_address(), first_register_device, GPIORead(first_register_device), &modbus_answ));
+        }
+
+        break;
+    case WRITE_SINGLE_REGISTER:
+        first_register_device = bytes_unification(2, 3);
+
+        if (first_register_device != HOLDING_REGISTER_SLAVE_ADDRESS)
+		{
+			modbus_rtu_send(modbus_err_answ(get_device_address(), packet[1], ILLEGAL_DATA_ADDRESS, &modbus_answ));
+		}
+        else
+        {
+            write_device_address(bytes_unification(4, 5));
+
+            modbus_rtu_send(write_single_register(get_device_address(), first_register_device, get_device_address(), &modbus_answ));
+        }
+
+        break;
+    default:
+        modbus_rtu_send(modbus_err_answ(get_device_address(), packet[1], ILLEGAL_FUNCTION, &modbus_answ));
+        break;
+    }
+}
+
+// Функция вычисления контрольной суммы CRC
+uint16_t crc_chk(uint8_t *data, uint8_t length)
+{
+    register int16_t j;
+    register uint16_t reg_crc = 0xFFFF;
+    while (length--)
+    {
+        reg_crc ^= *data++;
+        for (j = 0; j < 8; j++)
+        {
+            if (reg_crc & 0x01)
+            {
+                reg_crc = (reg_crc >> 1) ^ 0xA001;
+            }
+            else
+            {
+                reg_crc = reg_crc >> 1;
+            }
+        }
+    }
+    return reg_crc;
+}
+
+// Функция объединения двух байт (старшего и младшего)
+uint16_t bytes_unification(uint8_t high, uint8_t low)
+{
+    return (packet[high] << 8) | packet[low];
+}
+
+// Коды функций (для формирования ответа)
+
+// Чтение данных с регистров флагов (функция с кодом 1)
+uint8_t read_coils(uint8_t address, uint8_t value, uint8_t *modbus_answ)
+{
+    modbus_answ[0] = address;                // Адрес
+    modbus_answ[1] = 0x01;                   // Код функции
+    modbus_answ[2] = 0x01;                   // Кол-во передаваемых байт
+    modbus_answ[3] = value;                  // Данные
+    crc_answ = crc_chk(modbus_answ, 4);      // Подсчет контрольной суммы
+    modbus_answ[4] = crc_answ & 0xFF;        // Первый байт контрольной суммы
+    modbus_answ[5] = (crc_answ >> 8) & 0xFF; // Второй байт контрольной суммы
+    return 6;
+}
+
+// Чтение данных с дискретных входов (функция с кодом 2)
+uint8_t read_discrete_inputs(uint8_t address, uint8_t value, uint8_t *modbus_answ)
+{
+    modbus_answ[0] = address;                // Адрес
+    modbus_answ[1] = 0x02;                   // Код функции
+    modbus_answ[2] = 0x01;                   // Кол-во передаваемых байт
+    modbus_answ[3] = value;                  // Данные
+    crc_answ = crc_chk(modbus_answ, 4);      // Подсчет контрольной суммы
+    modbus_answ[4] = crc_answ & 0xFF;        // Первый байт контрольной суммы
+    modbus_answ[5] = (crc_answ >> 8) & 0xFF; // Второй байт контрольной суммы
+    return 6;
+}
+
+// Чтение данных с регистров хранения (функция с кодом 3)
+uint8_t read_holding_registers(uint8_t address, uint16_t value, uint8_t *modbus_answ)
+{
+    modbus_answ[0] = address;                // Адрес
+    modbus_answ[1] = 0x03;                   // Код функции
+    modbus_answ[2] = 0x01;                   // Кол-во передаваемых байт
+    modbus_answ[3] = value;                  // Первый байт данных
+    modbus_answ[4] = value >> 8;             // Второй байт данных
+    crc_answ = crc_chk(modbus_answ, 5);      // Подсчет контрольной суммы
+    modbus_answ[5] = crc_answ & 0xFF;        // Первый байт контрольной суммы
+    modbus_answ[6] = (crc_answ >> 8) & 0xFF; // Второй байт контрольной суммы
+    return 7;
+}
+
+// Чтение данных с регистров ввода (функция с кодом 4)
+uint8_t read_input_registers(uint8_t address, uint16_t value, uint8_t *modbus_answ)
+{
+    modbus_answ[0] = address;                // Адрес
+    modbus_answ[1] = 0x04;                   // Код функции
+    modbus_answ[2] = 0x01;                   // Кол-во передаваемых байт
+    modbus_answ[3] = value;                  // Первый байт данных
+    modbus_answ[4] = value >> 8;             // Второй байт данных
+    crc_answ = crc_chk(modbus_answ, 5);      // Подсчет контрольной суммы
+    modbus_answ[5] = crc_answ & 0xFF;        // Первый байт контрольной суммы
+    modbus_answ[6] = (crc_answ >> 8) & 0xFF; // Второй байт контрольной суммы
+    return 7;
+}
+
+// Запись данных в регистр флагов (функция с кодом 5)
+uint8_t write_single_coil(uint8_t address, uint16_t coil_addr, int on, uint8_t *modbus_answ)
+{
+    modbus_answ[0] = address;                 // Адрес
+    modbus_answ[1] = 0x05;                    // Код функции
+    modbus_answ[2] = (coil_addr >> 8) & 0xFF; // Старший байт адреса
+    modbus_answ[3] = coil_addr & 0xFF;        // Младший байт адреса
+    modbus_answ[4] = on ? 0xFF : 0x00;        // Значение, которое нужно записать
+    modbus_answ[5] = 0x00;
+    crc_answ = crc_chk(modbus_answ, 6);      // Подсчет контрольной суммы
+    modbus_answ[6] = crc_answ & 0xFF;        // Первый байт контрольной суммы
+    modbus_answ[7] = (crc_answ >> 8) & 0xFF; // Второй байт контрольной суммы
+    return 8;
+}
+
+// Запись данных в регистр (функция с кодом 6)
+uint8_t write_single_register(uint8_t address, uint16_t register_addr, uint16_t new_value, uint8_t *modbus_answ)
+{
+    modbus_answ[0] = address;                     // Адрес
+    modbus_answ[1] = 0x06;                        // Код функции
+    modbus_answ[2] = (register_addr >> 8) & 0xFF; // Старший байт адреса
+    modbus_answ[3] = register_addr & 0xFF;        // Младший байт адреса
+    modbus_answ[4] = (new_value >> 8) & 0xFF;     // Старший байт значения
+    modbus_answ[5] = new_value & 0xFF;            // Младший байт значения
+    crc_answ = crc_chk(modbus_answ, 6);           // Подсчет контрольной суммы
+    modbus_answ[6] = crc_answ & 0xFF;             // Первый байт контрольной суммы
+    modbus_answ[7] = (crc_answ >> 8) & 0xFF;      // Второй байт контрольной суммы
+    return 8;
+}
+
+// Сообщение об ошибке
+uint8_t modbus_err_answ(uint8_t address, uint8_t func_code, uint8_t err_code, uint8_t *modbus_answ)
+{
+    modbus_answ[0] = address;                // Адрес
+    modbus_answ[1] = 0x80 + func_code;       // Код функции + ошибка
+    modbus_answ[2] = err_code;               // Код ошибки
+    crc_answ = crc_chk(modbus_answ, 3);      // Подсчет контрольной суммы
+    modbus_answ[3] = crc_answ & 0xFF;        // Первый байт контрольной суммы
+    modbus_answ[4] = (crc_answ >> 8) & 0xFF; // Второй байт контрольной суммы
+    return 5;
+}
diff --git a/modbus.h b/modbus.h
index a172a4b..9d46628 100644
--- a/modbus.h
+++ b/modbus.h
@@ -1,25 +1,54 @@
-
-#ifndef MODBUS_H
-#define MODBUS_H
-
-int crc_chk(unsigned char* data, unsigned char length);
-int ModbasRtu_Register_address(unsigned char Li);
-char Data_integrity();
-char _Bin_input_Output(register unsigned char NUMBER, register unsigned char state, volatile unsigned char* Masiv, volatile unsigned char Sd);
-void Reading_Discrete_Output(unsigned char* Massiv, register unsigned char Number_);
-void Read_analog_input(unsigned char* Massiv, register unsigned char Number_, unsigned char Vt);
-void Changing_Discrete_Output(void);
-void analog_output_recording(void);
-void Error_modbasRtu(volatile unsigned char Temp_Error);
-void check_sum(register unsigned char Adress);
-void modbasRtu_Answer();
-char read_digital_inputs(volatile unsigned char Temp1);
-void change_digital_inputs(volatile unsigned char Temp1, volatile unsigned char Temp2);
-char read_digital_Output(volatile unsigned char Temp1);
-void change_digital_Output(volatile unsigned char Temp1, volatile unsigned char Temp2);
-void change_analogue_Output(volatile unsigned char nomer, int Data);
-void change_analogue_input(volatile unsigned char nomer, int Data);
-int read_analogue_Output(volatile unsigned char nomer);
-int read_analogue_input(volatile unsigned char nomer);
-
-#endif /*MODBUS_H*/
+#ifndef MODBUS_H
+#define MODBUS_H
+
+#include "device_ring_buffer.h"
+#include "device_adc.h"
+#include "device_address.h"
+#include "UART.h"
+#include "timer.h"
+#include "gpio.h"
+#include <stdint.h>
+
+#define SIZE_MODBUS_PAKET (32)
+#define MAX_PAUSE (4)
+
+// Объявление адреса Slave
+#define HOLDING_REGISTER_SLAVE_ADDRESS 100
+
+// Объявление номеров Discrete Inputs
+#define DISCRETE_INPUTS_1 0x00
+#define DISCRETE_INPUTS_2 0x01
+#define DISCRETE_INPUTS_3 0x02
+#define DISCRETE_INPUTS_4 0x03
+
+// Объявление номеров Coil
+#define COIL_1 0x00
+#define COIL_2 0x01
+#define COIL_3 0x02
+#define COIL_4 0x03
+
+// Объявление номеров Input Registers
+#define INPUT_REGISTERS 0x00
+
+// Объявление кодов функций
+#define READ_COILS 1
+#define READ_DISCRETE_INPUTS 2
+#define READ_HOLDING_REGISTERS 3
+#define READ_INPUT_REGISTERS 4
+#define WRITE_SINGLE_COIL 5
+#define WRITE_SINGLE_REGISTER 6
+#define WRITE_MULTIPLE_COILS 15
+#define WRITE_MULTIPLE_REGISTER 16
+
+//Объявление кодов ошибок
+#define ILLEGAL_FUNCTION 1
+#define ILLEGAL_DATA_ADDRESS 2
+#define SLAVE_DEVICE_FAILURE 4
+
+uint8_t size_of_packet;
+
+void modbus_init(void);
+void modbus_rtu (void);
+void modbus_answer(void);
+
+#endif /*MODBUS_H*/
\ No newline at end of file
diff --git a/timer.c b/timer.c
new file mode 100644
index 0000000..8f62920
--- /dev/null
+++ b/timer.c
@@ -0,0 +1,28 @@
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+static unsigned long millis = 0;
+
+void setup_timer()
+{
+    // Включаем режим СТС
+    TCCR0A = (1 << WGM01);
+    // Устанавливаем счетчик с предделителем 64
+    TCCR0B = (1 << CS01) | (1 << CS00);
+    // Устанавливаем значение сравнения для 1 мс
+    OCR0A = 250;
+    // Разрешаем прерывание по совпадению
+    TIMSK0 = (1 << OCIE0A);
+    // Разрешаем все прерывания
+    sei();
+}
+
+unsigned long get_millis()
+{
+    return millis;
+}
+
+ISR(TIMER0_COMPA_vect)
+{
+    ++millis;
+}
\ No newline at end of file