2 Commits
Author SHA1 Message Date
stud126797 a591a87f9c Загрузил(а) файлы в '' 2023-06-23 05:42:04 +00:00
stud124688 b344a3564a Загрузил(а) файлы в '' 2023-06-21 13:20:11 +00:00
9 changed files with 501 additions and 670 deletions
+68
View File
@@ -0,0 +1,68 @@
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "device_ring_buffer.h"
#include "UART.h"
#define F_CPU 16000000
#define CONF_UART_BAUD 300
#define BAUD CONF_UART_BAUD
struct rb ring_buff_receive;
struct rb ring_buff_transmit;
inline void uart_initialize(void)
{
UCSR0B=0;
UCSR0C=0;
UCSR0B =(1<<RXEN0)|(1<<TXEN0); // Включаем приём и передачу по UART
UCSR0B |= (0<<UDRIE0); // Разрешаем или нет прерывание при очистке регистра данных
UCSR0B |= (0<<TXCIE0); // Разрешаем или нет прерывание при завершении передачи
UCSR0B |= (1<<RXCIE0); // Разрешаем или нет прерывание при приёме
UCSR0C = (1<<USBS0) | (3<<UCSZ00);
sei();
}
ISR(UART_RXC_vect)
{
register unsigned char received_data = UDR0;// Забираем принятые данные
rb_put(&ring_buff_receive, received_data);
}
// Функция отправки байта
void UART_Transmit(struct rb* _rb)
{
if (_rb->count > 0)
{
if (UCSR0A & (1 << UDRE0))
{
char data;
rb_get(&ring_buff_transmit, &data);
UDR0 = data;
}
}
}
struct rb* get_rb_receive(void)
{
return &ring_buff_receive;
}
struct rb* get_rb_transmit(void)
{
return &ring_buff_transmit;
}
/*int main(void) {
sei();
uart_initialize();
DDRD = 0xFF;
uint8_t buff[] = {0x48, 0x45, 0x4C, 0x4C, 0x4F, 0x21, 0x09};
UART_Transmit(buff);
while (1) {
UART_Transmit(buff);
}
}*/
+9
View File
@@ -0,0 +1,9 @@
#ifndef UART_H
#define UART_H
inline void uart_initialize(void);
void UART_Transmit(struct rb* _rb);
struct rb* get_rb_receive(void);
struct rb* get_rb_transmit(void);
#endif /*UART_H*/
-103
View File
@@ -1,103 +0,0 @@
#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;
}
-26
View File
@@ -1,26 +0,0 @@
#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*/
+39
View File
@@ -0,0 +1,39 @@
/*
* main.c
*
* Created: 18.06.2023 19:53:46
* Author: Lada Yuzhakova
*/
#include "UART.h"
#include "modbus.h"
#include "timer.h"
#include "device_adc.h"
#include "device_ring_buffer.h"
#include "gpio.h"
#include <avr/io.h>
int main(void)
{
// Èíèöèàëèçàöèè
adc_init();
uart_initialize();
modbus_init();
gpio_init();
rb_initialize(get_rb_receive());
rb_initialize(get_rb_transmit());
// Çàïóñêàåì òàéìåð
setup_timer();
while(1)
{
// Ôóíêöèÿ ïðèåìà ìîäáàñ-çàïðîñà
modbus_rtu();
// Ôóíêöèÿ ôîðìèðîâàíèÿ ìîäáàñ-îòâåòà
modbus_answer();
// Îòïðàâëÿòü îòâåò ïî óàðò
UART_Transmit(get_rb_transmit());
}
return 0;
}
+265 -357
View File
@@ -1,452 +1,360 @@
#include "modbus.h"
uint8_t state; #define On 1
uint8_t packet[SIZE_MODBUS_PAKET]; #define Off 0
uint8_t size_of_packet; #define Change_output 10
uint16_t crc_modbus; #define discrete_output_reading 11
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) 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)
{ {
size_of_packet = 0; register int j; // register - спецификатор, который предполагает, что доступ к объекту будет быстрым
crc_modbus = 0xFFFF; register unsigned int reg_crc = 0xFFFF; //объявление 16-битного регистра
state = 0; while (length--)
}
void range_in_range(uint8_t a, uint8_t b, uint8_t x, uint8_t y)
{ {
uint8_t c = a + b - 1; reg_crc ^= *data++; //каждый байт-исключение складывается по исключающему ИЛИ с текущим значением регистра контр суммы. После последнего 8 сдвига следующий байт складывается с текущей величиной регистра контр суммы и процесс сдвига повторяется повторно 8 раз
if (a >= x && a <= y) || (c >= x && c <= y) for (j = 0; j < 8; j++)
{ {
return 0; if (reg_crc & 0x01) //проверка младшего бита
{
reg_crc = (reg_crc >> 1) ^ 0xA001; //проверочный код на основе полинома. Результат всегда сдвигается в сторону младшего бита с заполнением нулем старшего бита. Если младший бит = 1, то производится искл ИЛИ содержимого регистра контр суммы и полиномиального числа
} }
else 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 1;
} }
} }
return 0;
// Функция приема 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();
} }
//РАБОТА С ДИСКРЕТНЫМИ ВХОДАМИ И ВЫВОДАМИ
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 else
Temp_1 &= ~(1 << NUMBER);
Masiv[Temp] = Temp_1;
}
else //выполняется, если нужно прочитать состояние бита
{ {
// Проверяем линейный буфер на переполнение if (Temp_1 & (1 << NUMBER))
if (size_of_packet == SIZE_MODBUS_PAKET) 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;
size_of_packet = 0; adres = ModbasRtu_Register_address(3); //адрес регистра, к которому обращается мастер
continue; if (adres > Number_) //проверка, что адрес не превышает допустимый
{
Error_modbasRtu(0x02); //недопустимый адрес
} }
else else
{ {
time = get_millis(); Number_bits = ModbasRtu_Register_address(5); //количество бит, которые нужно передать
packet[size_of_packet] = data; while (adres >= 8) //узнаем номер ячейки массива, с которой начнем считывать данные
size_of_packet++;
}
}
}
// Проверка временного интервала между символами
else
{ {
if ((get_millis() - time) > MAX_PAUSE) adres = adres - 8; //по завершению преобразования хранится бит, с которого нужно начинать считывание
Temp++; //номер байта в массиве к которому изначально происходит обращение
}
Data = Massiv[Temp]; //считываем данные
//считываем побитно и формируем данные для отправки
while (Number_bits > 0) //проверка, что все биты запроса переданы
{ {
// Превышен таймаут Number_bits--;
// Пакет закончился if (Data & (1 << adres))
packet_accepted = 1;
}
}
}
// Проверяем размер пакета
if (size_of_packet < 5)
{ {
size_of_packet = 0; Temp2 |= (1 << adres2);
crc_modbus = 0xFFFF; }
return; 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); //подсчитаем контрольную сумму для передачи данных
}
} }
// считаем контрольную сумму CRC и сравниваем с CRC в пакете //Чтение значений нескольких регистров хранения 0x03, Чтение значений нескольких регистров ввода 0x04
expected_crc = bytes_unification(size_of_packet - 2, size_of_packet - 1); void Read_analog_input(unsigned char* Massiv, register unsigned char Number_, unsigned char Vt)
crc_modbus = crc_chk(packet, size_of_packet - 3); //Vt - ввод или вывод
// проверка контрольной суммы CRC
if (crc_modbus != expected_crc)
{ {
size_of_packet = 0; volatile unsigned int address, Number_bits, Data;
crc_modbus = 0xFFFF; volatile unsigned char Adress = 4;
// формируем ошибку произошла невосполнимая ошибка address = ModbasRtu_Register_address(3); //адрес регистра, к которому обращается мастер
return; if (address > Number_) //проверка, что адрес не превышает допустимый
}
// проверка адреса устройства
else if (get_device_address() != packet[0])
{ {
size_of_packet = 0; Error_modbasRtu(0x02); //указанный в запросе адрес не существует
crc_modbus = 0xFFFF;
// формируем ошибку адреса
return;
} }
else else
{ {
// Расчленяем пакет Number_bits = ModbasRtu_Register_address(5); //количество байт, которые нужно передать (старший и младший)
state = 1; Data_Rx_ModbasRtu[2] = Number_bits * 2; //количество байт информащии, которые будут переданы
return; Adress = 3;
} while (Number_bits > 0)
}
}
// Функция отправки modbus-запроса в кольцевой буфер
void modbus_rtu_send(uint8_t answ_len)
{ {
size_of_packet = 0; if (Vt == 1) //определение, что считывать - вход или выход
// состояние отправки
if (state == 1)
{ {
// цикл отправки символов Data = Data_ModbasRtu_analog_input[address];
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 else
{ {
uint8_t value = 0; Data = Data_ModbasRtu_analog_Output[address];
while (number_of_registers_required > 0) }
{ address++;
switch (first_register_device) Massiv = &Data;
{ Data_Rx_ModbasRtu[Adress++] = Massiv[1]; //считываем старший байт
case COIL_1: Data_Rx_ModbasRtu[Adress++] = Massiv[0]; //считываем младший байт
value |= (gpio_read(PIN_COIL1)); Number_bits = Number_bits - 1;
break; }
case COIL_2: check_sum(Adress); //подсчитаем контрольную сумму для передачи данных
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++; //Запись одного регистра флагов 0x05
number_of_registers_required--; void Changing_Discrete_Output(void)
}
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)); register unsigned int address;
address = ModbasRtu_Register_address(3); //адрес регистра, к которому обращается мастер
if (address > 11) //проверка, что адрес не превышает допустимый [11 - НОМЕР ДИСКРЕТНОГО ВЫХОДА]
{
Error_modbasRtu(0x02);
} }
else else
{ {
uint8_t value = 0; if (Data_Rx_ModbasRtu[4] == 255)
while (number_of_registers_required > 0) _Bin_input_Output(address, On, Data_ModbasRtu_Binary_Output, Change_output);
{ else
switch (first_register_device) _Bin_input_Output(address, Off, Data_ModbasRtu_Binary_Output, Change_output);
{ }
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 ++; //Запись одного регистра хранения 0x06
number_of_registers_required--; void analog_output_recording(void)
}
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)); register int address;
address = ModbasRtu_Register_address(3);
if (address > 11) //[11 - НОМЕР АНАЛОГОВОГО ВЫХОДА]
{
Error_modbasRtu(0x02);
} }
else else
{ {
modbus_rtu_send(read_holding_registers(get_device_address(), get_device_address(), &modbus_answ)); Data_ModbasRtu_analog_Output[address] = ModbasRtu_Register_address(5); //данные, которые нужно записать
}
} }
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) //ОШИБКА
void Error_modbasRtu(volatile unsigned char Temp_Error)
{ {
modbus_rtu_send(modbus_err_answ(get_device_address(), packet[1], ILLEGAL_DATA_ADDRESS, &modbus_answ)); Data_Rx_ModbasRtu[1] |= (1 << 7);
Data_Rx_ModbasRtu[2] = Temp_Error; //код ошибки
check_sum(3); //подсчитаем контрольную сумму для передачи данных
} }
else
//ОТВЕТ КОНТРОЛЬНОЙ СУММЫ
void check_sum(register unsigned char Adress)
{ {
modbus_rtu_send(read_input_registers(get_device_address(), get_adc_value(), &modbus_answ)); 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;
} }
break;
case WRITE_SINGLE_COIL:
first_register_device = bytes_unification(2, 3);
if (range_in_range(first_register_device, 1, COIL_1, COIL_4)) //ФОРМИРУЕМ ДЕЙСТВИЕ И ОТВЕТ НА ПРИНЯТЫЕ КОМАНДЫ ИЛИ ФОРМИРУЕМ ОТВЕТ ОБ ОШИБКАХ
void modbasRtu_Answer()
{ {
modbus_rtu_send(modbus_err_answ(get_device_address(), packet[1], ILLEGAL_DATA_ADDRESS, &modbus_answ)); switch (Data_Rx_ModbasRtu[1])
}
else
{ {
uint8_t value = 0; case 1:
switch (first_register_device) //Modbus RTU чтение дискретного выхода 0x01
{ Reading_Discrete_Output(Data_ModbasRtu_Binary_Output, 11); //[11 - НОМЕР ДИСКРЕТНОГО ВЫХОДА]
case COIL_1:
value = gpio_write(PIN_COIL1, packet[4]);
break; break;
case COIL_2: case 2:
value = gpio_write(PIN_COIL2, packet[4]); //Modbus RTU чтение дискретного входа 0x02
Reading_Discrete_Output(Data_ModbasRtu_Binary_input, 11); //[11 - НОМЕР ДИСКРЕТНОГО ВХОДА]
break; break;
case COIL_3: case 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));
}
Read_analog_input(Data_ModbasRtu_analog_Output, 11, 0); //Modbus RTU на чтение аналогового выхода 0x03 [11 - НОМЕР АНАЛОГОВОГО ВЫХОДА]
break; break;
case WRITE_SINGLE_REGISTER: case 4:
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));
}
Read_analog_input(Data_ModbasRtu_analog_input, 11, 1); //Modbus RTU на чтение аналогового входа 0x04 [11 - НОМЕР АНАЛОГОВОГО ВХОДА]
break; 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: default:
modbus_rtu_send(modbus_err_answ(get_device_address(), packet[1], ILLEGAL_FUNCTION, &modbus_answ)); //команды не подерживаются
Error_modbasRtu(0x01); //принятый код функции не может быть обработан
break; break;
} }
} }
// Функция вычисления контрольной суммы CRC
uint16_t crc_chk(uint8_t *data, uint8_t length) //ПОДПРОГРАММЫ ДЛЯ ОБРАБОТКИ ЗНАЧЕНИЙ
//прочитать бит входов
char read_digital_inputs(volatile unsigned char Temp1)
{ {
register int16_t j; return _Bin_input_Output(Temp1, On, Data_ModbasRtu_Binary_input, discrete_output_reading); //считать состояние выхода из буферного массива
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) void change_digital_inputs(volatile unsigned char Temp1, volatile unsigned char Temp2)
{ {
return (packet[high] << 8) | packet[low]; _Bin_input_Output(Temp1, Temp2, Data_ModbasRtu_Binary_input, Change_output);
} }
// Коды функций (для формирования ответа) //прочитать бит выходов
char read_digital_Output(volatile unsigned char Temp1)
// Чтение данных с регистров флагов (функция с кодом 1)
uint8_t read_coils(uint8_t address, uint8_t value, uint8_t *modbus_answ)
{ {
modbus_answ[0] = address; // Адрес return _Bin_input_Output(Temp1, On, Data_ModbasRtu_Binary_Output, discrete_output_reading); //считать состояние выхода из буферного массива
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) void change_digital_Output(volatile unsigned char Temp1, volatile unsigned char Temp2)
{ {
modbus_answ[0] = address; // Адрес _Bin_input_Output(Temp1, Temp2, Data_ModbasRtu_Binary_Output, Change_output);
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) void change_analogue_Output(volatile unsigned char nomer, int Data)
{ {
modbus_answ[0] = address; // Адрес Data_ModbasRtu_analog_Output[nomer] = Data;
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) void change_analogue_input(volatile unsigned char nomer, int Data)
{ {
modbus_answ[0] = address; // Адрес Data_ModbasRtu_analog_input[nomer] = Data;
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) int read_analogue_Output(volatile unsigned char nomer)
{ {
modbus_answ[0] = address; // Адрес return Data_ModbasRtu_analog_Output[nomer];
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) int read_analogue_input(volatile unsigned char nomer)
{ {
modbus_answ[0] = address; // Адрес return Data_ModbasRtu_analog_input[nomer];
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) //(отправить по rb_put в кольцевой буфер ответ)
//выглядит как int rb_put(struct rb* _rb, char element)
void Data_Modbus_answer()
{ {
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;
} }
+20 -49
View File
@@ -1,54 +1,25 @@
#ifndef MODBUS_H #ifndef MODBUS_H
#define MODBUS_H #define MODBUS_H
#include "device_ring_buffer.h" int crc_chk(unsigned char* data, unsigned char length);
#include "device_adc.h" int ModbasRtu_Register_address(unsigned char Li);
#include "device_address.h" char Data_integrity();
#include "UART.h" char _Bin_input_Output(register unsigned char NUMBER, register unsigned char state, volatile unsigned char* Masiv, volatile unsigned char Sd);
#include "timer.h" void Reading_Discrete_Output(unsigned char* Massiv, register unsigned char Number_);
#include "gpio.h" void Read_analog_input(unsigned char* Massiv, register unsigned char Number_, unsigned char Vt);
#include <stdint.h> void Changing_Discrete_Output(void);
void analog_output_recording(void);
#define SIZE_MODBUS_PAKET (32) void Error_modbasRtu(volatile unsigned char Temp_Error);
#define MAX_PAUSE (4) void check_sum(register unsigned char Adress);
void modbasRtu_Answer();
// Объявление адреса Slave char read_digital_inputs(volatile unsigned char Temp1);
#define HOLDING_REGISTER_SLAVE_ADDRESS 100 void change_digital_inputs(volatile unsigned char Temp1, volatile unsigned char Temp2);
char read_digital_Output(volatile unsigned char Temp1);
// Объявление номеров Discrete Inputs void change_digital_Output(volatile unsigned char Temp1, volatile unsigned char Temp2);
#define DISCRETE_INPUTS_1 0x00 void change_analogue_Output(volatile unsigned char nomer, int Data);
#define DISCRETE_INPUTS_2 0x01 void change_analogue_input(volatile unsigned char nomer, int Data);
#define DISCRETE_INPUTS_3 0x02 int read_analogue_Output(volatile unsigned char nomer);
#define DISCRETE_INPUTS_4 0x03 int read_analogue_input(volatile unsigned char nomer);
// Объявление номеров 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*/ #endif /*MODBUS_H*/
-28
View File
@@ -1,28 +0,0 @@
#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;
}
-7
View File
@@ -1,7 +0,0 @@
#ifndef TIMER_H
#define TIMER_H
void setup_timer();
unsigned long get_millis();
#endif /*TIMER_H*/