@@ -1,360 +1,452 @@
# include "modbus.h"
# define On 1
# define Off 0
# define Change_output 10
# define discrete_output_reading 11
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 ) ;
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 )
void modbus_init ( void )
{
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 ; //регистр хранения конечного результата контр суммы
size_of_packet = 0 ;
crc_modbus = 0xFFFF ;
state = 0 ;
}
//ОБЪЕДИНЕНИЕ ДВУХ БАЙТ(старшего и младшего)
int ModbasRtu_Register_address ( unsigned char Li )
//Hi - старший байт
//Li - младший
void range_in_range ( uint8_t a , uint8_t b , uint8_t x , uint8_t y )
{
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 ) //сравнимаем с таблицы старший байт с контрольной суммой
uint8_t c = a + b - 1 ;
if ( a > = x & & a < = y ) | | ( c > = x & & c < = y )
{
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 ) ; //недопустимый адрес
return 0 ;
}
else
{
Number_bits = ModbasRtu_Register_address ( 5 ) ; //количество бит, которые нужно передать
while ( adres > = 8 ) //узнаем номер ячейки массива, с которой начнем считывать данные
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 )
{
adres = adres - 8 ; //по завершению преобразования хранится бит, с которого нужно начинать считывание
Temp + + ; //номер байта в массиве к которому изначально происходит обращение
modbus_rtu_send ( modbus_err_answ ( get_device_address ( ) , packet [ 1 ] , ILLEGAL_DATA_ADDRESS , & modbus_answ ) ) ;
}
Data = Massiv [ Temp ] ; //считываем данные
//считываем побитно и формируем данные для отправки
while ( Number_bits > 0 ) //проверка, что все биты запроса переданы
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 )
{
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 ] ; //считываем данные
}
modbus_rtu_send ( modbus_err_answ ( get_device_address ( ) , packet [ 1 ] , ILLEGAL_DATA_ADDRESS , & modbus_answ ) ) ;
}
if ( adres2 > 0 )
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 )
{
Temp3 + + ;
Data_Rx_ModbasRtu [ Temp3 ] = Temp2 ;
modbus_rtu_send ( modbus_err_answ ( get_device_address ( ) , packet [ 1 ] , ILLEGAL_DATA_ADDRESS , & modbus_answ ) ) ;
}
Data_Rx_ModbasRtu [ 2 ] = Temp3 - 2 ; //количество переданных байт (без учета адреса и кода команды)
Temp3 + + ;
check_sum ( Temp3 ) ; //подсчитаем контрольную сумму для передачи данных
}
}
else
{
modbus_rtu_send ( read_holding_registers ( get_device_address ( ) , get_device_address ( ) , & modbus_answ ) ) ;
}
//Чтение значений нескольких регистров хранения 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 )
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 )
{
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 ;
modbus_rtu_send ( modbus_err_answ ( get_device_address ( ) , packet [ 1 ] , ILLEGAL_DATA_ADDRESS , & modbus_answ ) ) ;
}
check_sum ( Adress ) ; //подсчитаем контрольную сумму для передачи данных
}
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 ;
}
}
//Запись одного регистра флагов 0x05
void Changing_Discrete_Output ( void )
// Функция вычисления контрольной суммы CRC
uint16_t crc_chk ( uint8_t * data , uint8_t length )
{
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 ) ;
}
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 ;
}
//Запись одного регистра хранения 0x06
void analog_output_recording ( void )
// Функция объединения двух байт (старшего и младшего)
uint16_t bytes_unification ( uint8_t high , uint8_t low )
{
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 ) ; //данные, которые нужно записать
}
return ( packet [ high ] < < 8 ) | packet [ low ] ;
}
// Коды функций (для формирования ответа)
//ОШИБКА
void Error_modbasRtu ( volatile unsigned char Temp_Error )
// Чтение данных с регистров флагов (функция с кодом 1)
uint8_t read_coils ( uint8_t address , uint8_t value , uint8_t * modbus_answ )
{
Data_Rx_ModbasRtu [ 1 ] | = ( 1 < < 7 ) ;
Data_Rx_ModbasRtu [ 2 ] = Temp_Error ; //к од ошибк и
check_sum ( 3 ) ; //подсчитаем контрольную сумму для передачи данных
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 ;
}
//ОТВЕТ КОНТРОЛЬНОЙ СУММЫ
void check_sum ( register unsigned char Adress )
// Чтение данных с дискретных входов (функция с кодом 2)
uint8_t read_discrete_inputs ( uint8_t address , uint8_t value , uint8_t * 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 ;
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 ;
}
//ФОРМИРУЕМ ДЕЙСТВИЕ И ОТВЕТ НА ПРИНЯТЫЕ КОМАНДЫ ИЛИ ФОРМИРУЕМ ОТВЕТ ОБ ОШИБКАХ
void modbasRtu_Answer ( )
// Чтение данных с регистров хранения (функция с кодом 3)
uint8_t read_holding_registers ( uint8_t address , uint16_t value , uint8_t * modbus_answ )
{
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 ;
}
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 ;
}
//ПОДПРОГРАММЫ ДЛЯ ОБРАБОТКИ ЗНАЧЕНИЙ
//прочитать бит входов
char read_digital_inputs ( volatile unsigned char Temp1 )
// Чтение данных с регистров ввода (функция с кодом 4)
uint8_t read_input_registers ( uint8_t address , uint16_t value , uint8_t * modbus_answ )
{
return _Bin_input_Output ( Temp1 , On , Data_ModbasRtu_Binary_input , discrete_output_reading ) ; //считать состояние выхода из буферного массива
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 ;
}
//изменить бит входов
void change_digital_inputs ( volatile unsigned char Temp1 , volatile unsigned char Temp2 )
// Запись данных в регистр флагов (функция с кодом 5)
uint8_t write_single_coil ( uint8_t address , uint16_t coil_addr , int on , uint8_t * modbus_answ )
{
_Bin_input_Output ( Temp1 , Temp2 , Data_ModbasRtu_Binary_input , Change_output ) ;
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 ;
}
//прочитать бит выходов
char read_digital_Output ( volatile unsigned char Temp1 )
// Запись данных в регистр (функция с кодом 6)
uint8_t write_single_register ( uint8_t address , uint16_t register_addr , uint16_t new_value , uint8_t * modbus_answ )
{
return _Bin_input_Output ( Temp1 , On , Data_ModbasRtu_Binary_Output , discrete_output_reading ) ; //считать состояние выхода из буферного массива
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 ;
}
//изменить бит выходов
void change_digital_Output ( volatile unsigned char Temp1 , volatile unsigned char Temp2 )
// Сообщение об ошибке
uint8_t modbus_err_answ ( uint8_t address , uint8_t func_code , uint8_t err_code , uint8_t * modbus_answ )
{
_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 ( )
{
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 ;
}