diplom/научка/code/pwm_motor_control/Modbus/Modbus.h
2025-05-09 21:26:59 +03:00

420 lines
19 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************MODBUS*************************************
Данный файл содержит объявления базовых функции и дефайны для реализации
MODBUS.
Данный файл необходимо подключить в rs_message.h. После подключать rs_message.h
к основному проекту.
***************************************************************************/
#ifndef __MODBUS_H_
#define __MODBUS_H_
#include "stm32f4xx_hal.h"
#include "modbus_data.h"
#include "settings.h" // for modbus settings
/////////////////////////////////////////////////////////////////////
//////////////////////////---SETTINGS---/////////////////////////////
////----------DEFINES FOR MODBUS SETTING--------------
//#define MODBUS_UART_NUMB 3 // number of used uart
//#define MODBUS_SPEED 115200
//#define MODBUS_GPIOX GPIOB
//#define MODBUS_GPIO_PIN_RX GPIO_PIN_11
//#define MODBUS_GPIO_PIN_TX GPIO_PIN_10
///* accord to this define sets define USED_MB_UART = USARTx */
//#define MODBUS_TIM_NUMB 7 // number of used uart
//#define MODBUS_TIM_AHB_FREQ 72
///* accord to this define sets define USED_MB_TIM = TIMx */
///* defines for modbus behaviour */
//#define MODBUS_DEVICE_ID 1 // number of used uart
//#define MODBUS_MAX_TIMEOUT 5000 // is ms
//// custom define for size of receive message
////--------------------------------------------------
//---------------MODBUS DEVICE DATA-----------------
/* EXTERN REGISTERS/COILS */
extern uint16_t sine_log[R_SINE_LOG_QNT]; // start from 0x0000
extern uint16_t pwm_log[R_PWM_LOG_QNT]; // start from 500 (0x1F4)
extern uint16_t cnt_log[R_CNT_LOG_QNT]; // start from 100 (0x3E8)
extern uint16_t time_log[R_TIME_LOG_QNT]; // start from 1500 (0x5DC)
extern uint16_t pwm_ctrl[R_PWM_CTRL_QNT]; // start from 2000 (0x7D0)
extern uint16_t log_ctrl[R_LOG_CTRL_QNT]; // start from 2008 (0x7D0)
extern uint16_t uart_ctrl[R_UART_CTRL_QNT];
extern uint16_t coils_regs[C_CTRL_COILS_QNT]; // start from 0x0001 (16th bit)
//--------------------------------------------------
//////////////////////////---SETTINGS---/////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////---USER MESSAGE DEFINES---//////////////////////
//-------------DEFINES FOR STRUCTURE----------------
/* defines for structure of modbus message */
#define MbAddr_SIZE 1 // size of (MbAddr)
#define Func_Code_SIZE 1 // size of (Func_Code)
#define Addr_SIZE 2 // size of (Addr)
#define Qnt_SIZE 2 // size of (Qnt)
#define ByteCnt_SIZE 1 // size of (ByteCnt)
#define DATA_SIZE 125 // maximum number of data: DWORD (NOT MESSAGE SIZE)
#define CRC_SIZE 2 // size of (MB_CRC) in bytes
/* size of info */
#define INFO_SIZE_MAX (MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE+ByteCnt_SIZE)
/* size of first part of message that will be received
first receive info part of message, than defines size of rest message*/
#define RX_FIRST_PART_SIZE INFO_SIZE_MAX
/* size of buffer: max size of whole message */
#define MSG_SIZE_MAX (INFO_SIZE_MAX + DATA_SIZE*2 + CRC_SIZE) // max possible size of message
/* Structure for modbus exception codes */
typedef enum //MB_ExceptionTypeDef
{
// reading
NO_ERRORS = 0x00, // no errors
ILLEGAL_FUNCTION = 0x01, // function cannot be processed
ILLEGAL_DATA_ADDRESS = 0x02, // data at this address is not available
ILLEGAL_DATA_VALUE = 0x03, // uncorrect data value (quantity too big and cannot be returned or value for coil is incorrect)
SLAVE_DEVICE_FAILURE = 0x04, // idk
ACKNOWLEDGE = 0x05, // idk
SLAVE_DEVICE_BUSY = 0x06, // idk
MEMORY_PARITY_ERROR = 0x08, // idk
}MB_ExceptionTypeDef;
/* Structure for modbus func codes */
typedef enum //MB_FunctonTypeDef
{
// reading
MB_R_COILS = 0x01,
MB_R_DISC_IN = 0x02,
MB_R_IN_REGS = 0x03,
MB_R_HOLD_REGS = 0x04,
// writting
MB_W_COIL = 0x05,
MB_W_IN_REG = 0x06,
MB_W_COILS = 0x0F,
MB_W_IN_REGS = 0x10,
}MB_FunctonTypeDef;
#define ERR_VALUES_START 0x80U // from this value starts error func codes
/* Structure for modbus messsage */
typedef struct // RS_MsgTypeDef
{
uint8_t MbAddr;
MB_FunctonTypeDef Func_Code;
uint16_t Addr;
uint16_t Qnt;
uint8_t ByteCnt;
uint16_t DATA[DATA_SIZE];
MB_ExceptionTypeDef Except_Code;
uint16_t MB_CRC;
}RS_MsgTypeDef;
//--------------------------------------------------
/////////////////////---USER MESSAGE DEFINES---//////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////---GENERAL MODBUS STUFF---//////////////////////
/* Structure for coils operation */
typedef enum
{
// READ_COIL,
SET_COIL,
RESET_COIL,
TOOGLE_COIL,
}MB_CoilsOpTypeDef;
//------------DEFINES FOR PROCESS DATA--------------
/**
* @brief Calc dividing including remainder
* @param _val_ - делимое.
* @param _div_ - делитель.
* @note Если результат деления без остатка: он возвращается как есть
Если с остатком - округляется вверх
*/
//#define Divide_Up(_val_, _div_) (((_val_)%(_div_))? (_val_)/(_div_)+1 : (_val_)/_div_) /* через тернарный оператор */
#define Divide_Up(_val_, _div_) ((_val_ - 1) / _div_) + 1 /* через мат выражение */
/**
* @brief Swap between Little Endian and Big Endian
* @param v - Переменная для свапа.
* @return v (new) - Свапнутая переменная.
* @note Переключения между двумя типами хранения слова: HI-LO байты и LO-HI байты.
*/
#define ByteSwap16(v) (((v&0xFF00) >> (8)) | ((v&0x00FF) << (8)))
//--------------------------------------------------
//-----------DEFINES FOR ACCESS TO DATA-------------
/**
* @brief Macros to set pointer to 16-bit array
* @param _arr_ - массив слов (16-бит).
*/
#define MB_Set_Arr16_Ptr(_arr_) ((uint16_t*)(&(_arr_)))
/**
* @brief Macros to set pointer to register
* @param _parr_ - массив регистров.
* @param _addr_ - Номер регистра (его индекс) от начала массива _arr_.
*/
#define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_))
/**
* @brief Macros to set pointer to a certain register that contains certain coil
* @param _parr_ - массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
* @note Пояснение выражений
* (_coil_/16) - get index (address shift) of register that contain certain coil
* (16*(_coil_/16) - how many coils we need to skip. e.g. (16*30/16) - skip 16 coils from first register
* _coil_-(16*(_coil_/16)) - shift to certain coil in certain register
* e.g. Coil(30) gets in register[1] (30/16 = 1) coil №14 (30 - (16*30/16) = 30 - 16 = 14)
*
* Visual explanation:
* xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
* |register[0]----| |register[1]----|
* |skip this------| |get this-------|
* |shift to 14 bit|
*/
#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16))
#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) ))
/**
* @brief Read Coil at its local address.
* @param _parr_ - массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
* @return uint16_t - Возвращает запрошенный коил на 0м бите.
*
* @note Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Read_Coil_Local(_parr_, _coil_) (( *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) & MB_Set_Coil_Mask(_coil_) ) >> (_coil_))
/**
* @brief Set Coil at its local address.
* @param _parr_ - указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
*
* @note Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Set_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) |= MB_Set_Coil_Mask(_coil_)
/**
* @brief Reset Coil at its local address.
* @param _parr_ - указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
*
* @note Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Reset_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) &= ~(MB_Set_Coil_Mask(_coil_))
/**
* @brief Set Coil at its local address.
* @param _parr_ - указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
*
* @note Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Toogle_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ^= MB_Set_Coil_Mask(_coil_)
//--------------------------------------------------
//------------------OTHER DEFINES-------------------
// create hadnles and settings for uart, tim, rs with _modbus_ name
#define CONCAT(a,b) a##b
#define Create_MODBUS_Handles(_modbus_) \
UART_SettingsTypeDef CONCAT(_modbus_, _suart); \
UART_HandleTypeDef CONCAT(_modbus_, _huart); \
TIM_SettingsTypeDef CONCAT(_modbus_, _stim); \
TIM_HandleTypeDef CONCAT(_modbus_, _htim); \
RS_HandleTypeDef CONCAT(h, _modbus_)
//--------------------------------------------------
///////////////////---MODBUS & MESSAGE DEFINES---////////////////////
/////////////////////////////////////////////////////////////////////
////////////////////---FUNCTIONS FOR USER---/////////////////////////
/**
* @brief First set up of MODBUS.
* @note Первый инит модбас. Заполняет структуры и инициализирует таймер и юарт для общения по модбас.
* Скважность ШИМ меняется по закону синусоиды, каждый канал генерирует свой полупериод синуса (от -1 до 0 И от 0 до 1)
* ШИМ генерируется на одном канале.
* @note This called from main
*/
void MODBUS_FirstInit(void);
/**
* @brief Set or Reset Coil at its global address.
* @param Addr - адрес коила.
* @param WriteVal - Что записать в коил: 0 или 1.
* @return ExceptionCode - Код исключения если коила по адресу не существует, и NO_ERRORS если все ок.
*
* @note Позволяет обратиться к любому коилу по его глобальному адрессу.
Вне зависимости от того как коилы размещены в памяти.
*/
MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal);
/**
* @brief Read Coil at its global address.
* @param Addr - адрес коила.
* @param Exception - Указатель на переменную для кода исключения, в случа неудачи при чтении.
* @return uint16_t - Возвращает весь регистр с маской на запрошенном коиле.
*
* @note Позволяет обратиться к любому коилу по его глобальному адрессу.
Вне зависимости от того как коилы размещены в памяти.
*/
uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
////////////////////---FUNCTIONS FOR USER---/////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////---PROCESS MODBUS COMMAND FUNCTIONS---//////////////////
/**
* @brief Check is address valid for certain array.
* @param Addr - начальный адресс.
* @param Qnt - количество запрашиваемых элементов.
* @param R_ARR_ADDR - начальный адресс массива R_ARR.
* @param R_ARR_NUMB - количество элементов в массиве R_ARR.
* @return ExceptionCode - ILLEGAL DATA ADRESS если адресс недействителен, и NO_ERRORS если все ок.
*
* @note Позволяет определить, брать ли данные по адрессу Addr из массива R_ARR.
* Если адресс Addr находится в диапазоне адрессов массива R_ARR, то возвращаем NO_ERROR.
* Если адресс Addr находится за пределами адрессов массива R_ARR - ILLEGAL_DATA_ADDRESSю.
*/
MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB);
/**
* @brief Define Address Origin for Input/Holding Registers
* @param pRegs - указатель на указатель регистров.
* @param Addr - адрес начального регистра.
* @param Qnt - количество запрашиваемых регистров.
* @param WriteFlag - флаг регистр нужны для чтения или записи.
* @return ExceptionCode - Код исключения если есть, и NO_ERRORS если нет.
*
* @note Определение адреса начального регистра.
* @note WriteFlag пока не используется.
*/
MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t WriteFlag);
/**
* @brief Define Address Origin for coils
* @param pCoils - указатель на указатель коилов.
* @param Addr - адресс начального коила.
* @param Qnt - количество запрашиваемых коилов.
* @param start_shift - указатель на переменную содержащую сдвиг внутри регистра для начального коила.
* @param WriteFlag - флаг коилы нужны для чтения или записи.
* @return ExceptionCode - Код исключения если есть, и NO_ERRORS если нет.
*
* @note Определение адреса начального регистра запрашиваемых коилов.
* @note WriteFlag используется для определния регистров GPIO: ODR или IDR.
*/
MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag);
/**
* @brief Proccess command Read Coils (01 - 0x01).
* @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды.
* @note Обработка команды Read Coils.
*/
uint8_t MB_Read_Coils(RS_MsgTypeDef *modbus_msg);
/**
* @brief Proccess command Read Holding Registers (03 - 0x03).
* @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды.
* @note Обработка команды Read Holding Registers.
*/
uint8_t MB_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg);
/**
* @brief Proccess command Write Single Coils (05 - 0x05).
* @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды.
* @note Обработка команды Write Single Coils.
*/
uint8_t MB_Write_Single_Coil(RS_MsgTypeDef *modbus_msg);
/**
* @brief Proccess command Write Multiple Coils (15 - 0x0F).
* @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды.
* @note Обработка команды Write Multiple Coils.
*/
uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg);
/**
* @brief Proccess command Write Multiple Register (16 - 0x10).
* @param modbus_msg - указатель на структуру собщения modbus.
* @return fMessageHandled - статус о результате обработки комманды.
* @note Обработка команды Write Multiple Register.
*/
uint8_t MB_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
/////////////---PROCESS MODBUS COMMAND FUNCTIONS---//////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////---CALC DEFINES---//////////////////////////
/* set USART_TypeDef for choosen numb of usart */
#if (MODBUS_UART_NUMB == 1)
#define USED_MODBUS_UART USART1
#define USE_USART1
#elif (MODBUS_UART_NUMB == 2)
#define USED_MODBUS_UART USART2
#define USE_USART2
#elif (MODBUS_UART_NUMB == 3)
#define USED_MODBUS_UART USART3
#define USE_USART3
#elif (MODBUS_UART_NUMB == 4)
#define USED_MODBUS_UART UART4
#define USE_UART4
#elif (MODBUS_UART_NUMB == 5)
#define USED_MODBUS_UART UART5
#define USE_UART6
#elif (MODBUS_UART_NUMB == 6)
#define USED_MODBUS_UART USART6
#define USE_USART6
#endif
#if (MODBUS_TIM_NUMB == 1)
#define USED_MODBUS_TIM TIM1
#define USE_TIM1
#elif (MODBUS_TIM_NUMB == 2)
#define USED_MODBUS_TIM TIM2
#define USE_TIM2
#elif (MODBUS_TIM_NUMB == 3)
#define USED_MODBUS_TIM TIM3
#define USE_TIM3
#elif (MODBUS_TIM_NUMB == 4)
#define USED_MODBUS_TIM TIM4
#define USE_TIM4
#elif (MODBUS_TIM_NUMB == 5)
#define USED_MODBUS_TIM TIM5
#define USE_TIM5
#elif (MODBUS_TIM_NUMB == 6)
#define USED_MODBUS_TIM TIM6
#define USE_TIM6
#elif (MODBUS_TIM_NUMB == 7)
#define USED_MODBUS_TIM TIM7
#define USE_TIM7
#elif (MODBUS_TIM_NUMB == 8)
#define USED_MODBUS_TIM TIM8
#define USE_TIM8
#elif (MODBUS_TIM_NUMB == 9)
#define USED_MODBUS_TIM TIM9
#define USE_TIM9
#elif (MODBUS_TIM_NUMB == 10)
#define USED_MODBUS_TIM TIM10
#define USE_TIM10
#elif (MODBUS_TIM_NUMB == 11)
#define USED_MODBUS_TIM TIM11
#define USE_TIM11
#elif (MODBUS_TIM_NUMB == 12)
#define USED_MODBUS_TIM TIM12
#define USE_TIM12
#elif (MODBUS_TIM_NUMB == 13)
#define USED_MODBUS_TIM TIM13
#define USE_TIM13
#elif (MODBUS_TIM_NUMB == 14)
#define USED_MODBUS_TIM TIM14
#define USE_TIM14
#endif
#endif //__MODBUS_H_