Бета добавление новых кодов исключения
Улучшение механики ответа с задержкой, когда время ответа определяется пользователем, а не в прерывании сразу
This commit is contained in:
@@ -72,15 +72,17 @@ first receive info part of message, than defines size of rest message*/
|
|||||||
*/
|
*/
|
||||||
typedef enum //MB_ExceptionTypeDef
|
typedef enum //MB_ExceptionTypeDef
|
||||||
{
|
{
|
||||||
// reading
|
/* Регулярные коды ошибок, которые определены конкретной программой */
|
||||||
ET_NO_ERRORS = 0x00, ///< no errors
|
ET_NO_ERRORS = 0x00, ///< no errors
|
||||||
ET_ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан
|
ET_ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан
|
||||||
ET_ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен
|
ET_ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен
|
||||||
ET_ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной
|
ET_ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной
|
||||||
ET_SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие
|
ET_SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие
|
||||||
// ET_ACKNOWLEDGE = 0x05, ///< idk
|
|
||||||
// ET_SLAVE_DEVICE_BUSY = 0x06, ///< idk
|
/* Специальные коды ошибок, которые определены конкретной программой */
|
||||||
// ET_MEMORY_PARITY_ERROR = 0x08, ///< idk
|
ET_ACKNOWLEDGE = 0x05, ///< Устройство приняло запрос, но на обработку требуется время. Нужно чтобы не было Timeout ошибки
|
||||||
|
ET_SLAVE_DEVICE_BUSY = 0x06, ///< Устройство занято обработкой комманды
|
||||||
|
ET_MEMORY_PARITY_ERROR = 0x08, ///< Ошибка внешней памяти
|
||||||
}MB_ExceptionTypeDef;
|
}MB_ExceptionTypeDef;
|
||||||
|
|
||||||
#define FC_ERR_VALUES_START 0x80U ///< from this value starts error func codes
|
#define FC_ERR_VALUES_START 0x80U ///< from this value starts error func codes
|
||||||
|
|||||||
@@ -21,6 +21,10 @@
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Ответить позже, не в прерывании */
|
||||||
|
HAL_StatusTypeDef MB_Slave_ResponseLater(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode);
|
||||||
|
/* Ответить на запрос */
|
||||||
|
HAL_StatusTypeDef MB_Slave_SendResponse(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode, MB_ExceptionTypeDef error);
|
||||||
/* Ответ на сообщение в режиме слейва */
|
/* Ответ на сообщение в режиме слейва */
|
||||||
RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
|
RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
|
||||||
/* Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart) */
|
/* Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart) */
|
||||||
|
|||||||
@@ -211,11 +211,13 @@ typedef struct
|
|||||||
unsigned TX_Done:1; ///< 1 - Передача закончена, 0 - Передача еще в процессе или не инициализирована
|
unsigned TX_Done:1; ///< 1 - Передача закончена, 0 - Передача еще в процессе или не инициализирована
|
||||||
|
|
||||||
// Выставление следующие флагов определяет пользователь
|
// Выставление следующие флагов определяет пользователь
|
||||||
unsigned RX_Continue:1; ///< 0 - Продолжить принимать, 0 - Начать прием сначала
|
unsigned RX_Continue:1; ///< 1 - Продолжить принимать, 0 - Начать прием сначала
|
||||||
unsigned MessageHandled:1; ///< 1 - Обработка запроса успешна, 0 - Обработка запроса в процессе или ошибка
|
unsigned MessageHandled:1; ///< 1 - Обработка запроса успешна, 0 - Обработка запроса в процессе или ошибка
|
||||||
unsigned EchoResponse:1; ///< 1 - Ответить эхом, 0 - Ответить своим сообщением
|
unsigned EchoResponse:1; ///< 1 - Ответить эхом, 0 - Ответить своим сообщением
|
||||||
unsigned DeferredResponse:1; ///< 1 - Не начинать передачу в IT, 0 - Ответить в прерывании
|
unsigned DataUpdated:1; ///< 1 - Данные были обновлены:
|
||||||
unsigned DataUpdated:1; ///< 1 - Данные были обновлены
|
unsigned DeviceBusy:1; ///< 1 - Устройство занято (важно! не rs а именно устрройство)
|
||||||
|
unsigned DeferredResponse:8; ///< >0 - Не начинать передачу в IT, 0 - Ответить в прерывании
|
||||||
|
|
||||||
}RS_FlagsTypeDef;
|
}RS_FlagsTypeDef;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
49
README.md
49
README.md
@@ -56,16 +56,15 @@ ProjectRoot/
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 3. **Настройте конфигурацию** под ваш проект:
|
### 3. **Настройте конфигурацию** под ваш проект:
|
||||||
#### 3.1. Настройка периферии
|
#### 3.1. Настройка периферии
|
||||||
|
|
||||||
- **UART**: Настройте в режиме Asynchronous, нужная скорость (9600, 19200, etc), 8N1
|
- **UART**: Настройте в режиме Asynchronous, нужная скорость (9600, 19200, etc), 8N1
|
||||||
- **TIM**: Настройте таймер для генерации прерываний (например, 1ms tick)
|
- **TIM**: Настройте таймер для генерации прерываний (например, 1ms tick)
|
||||||
- **Включите прерывания** для UART и TIM
|
- **Включите прерывания** для UART и TIM
|
||||||
|
|
||||||
#### 3.2. Подключение обработчиков прерываний
|
#### 3.2. Подключение обработчиков прерываний
|
||||||
|
|
||||||
Подключите обработчики прерываний **UART** и **TIM** в свои IRQ обработчики ***вместо*** HAL-обработчиков:
|
|
||||||
|
|
||||||
|
Подключите обработчики прерываний **UART** и **TIM** в свои IRQ обработчики ***вместо*** HAL-обработчиков:
|
||||||
```c
|
```c
|
||||||
#include "modbus.h"
|
#include "modbus.h"
|
||||||
|
|
||||||
@@ -83,15 +82,21 @@ void TIMx_IRQHandler(void)
|
|||||||
HAL_TIM_IRQHandler(&htim);
|
HAL_TIM_IRQHandler(&htim);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### 3.3. В `modbus_config.h` укажите параметры устройства
|
#### 3.3. В `modbus_config.h` укажите параметры устройства
|
||||||
|
|
||||||
#### 3.4. Инициализация в коде
|
#### 3.4. Инициализация в коде
|
||||||
|
|
||||||
Чтобы настроить Slave-режим `main()` после инициализации HAL:
|
Чтобы настроить Slave-режим `main()` после инициализации HAL:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#include "modbus.h"
|
#include "modbus.h"
|
||||||
|
|
||||||
|
// TxEnable: 1 - передача, 0 - прием
|
||||||
|
void SetTxDirectionFunc(int TxEnable)
|
||||||
|
{
|
||||||
|
HAL_GPIO_WritePin(SCIDE1_GPIO_Port, SCIDE1_Pin, !TxEnable);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
// Инициализация HAL
|
// Инициализация HAL
|
||||||
@@ -102,7 +107,7 @@ int main(void)
|
|||||||
MX_TIM3_Init();
|
MX_TIM3_Init();
|
||||||
|
|
||||||
// Инициализация Modbus
|
// Инициализация Modbus
|
||||||
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim, SetTxDirectionFunc);
|
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim, &SetTxDirectionFunc);
|
||||||
MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
|
MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
|
||||||
|
|
||||||
// Запуск приема Modbus
|
// Запуск приема Modbus
|
||||||
@@ -114,13 +119,13 @@ int main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Чтобы настроить Master-режим `main()` после инициализации HAL:
|
Чтобы настроить Master-режим `main()` после инициализации HAL:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#include "modbus.h"
|
#include "modbus.h"
|
||||||
|
|
||||||
// Инициализация Modbus
|
// Инициализация Modbus
|
||||||
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim, SetTxDirectionFunc);
|
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim, &SetTxDirectionFunc);
|
||||||
MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
|
MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
|
||||||
|
|
||||||
|
|
||||||
@@ -170,11 +175,11 @@ int main(void)
|
|||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### 3.5. Настройка карты данных (только для режима Slave)
|
#### 3.5. Настройка карты данных (только для режима Slave)
|
||||||
|
|
||||||
В `modbus_data.h` настройте регистры и coils под ваше устройство:
|
В `modbus_data.h` настройте регистры и coils под ваше устройство:
|
||||||
|
|
||||||
**Input Registers (только чтение)**
|
**Input Registers (только чтение)**
|
||||||
```c
|
```c
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -187,7 +192,7 @@ typedef struct
|
|||||||
#define R_INPUT_ADDR 0 // Начальный адрес Input регистров
|
#define R_INPUT_ADDR 0 // Начальный адрес Input регистров
|
||||||
#define R_INPUT_QNT 4 // Количество Input регистров
|
#define R_INPUT_QNT 4 // Количество Input регистров
|
||||||
```
|
```
|
||||||
**Holding Registers (чтение/запись)**
|
**Holding Registers (чтение/запись)**
|
||||||
```c
|
```c
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -199,7 +204,7 @@ typedef struct
|
|||||||
#define R_HOLDING_ADDR 0 // Начальный адрес Holding регистров
|
#define R_HOLDING_ADDR 0 // Начальный адрес Holding регистров
|
||||||
#define R_HOLDING_QNT 3 // Количество Holding регистров
|
#define R_HOLDING_QNT 3 // Количество Holding регистров
|
||||||
```
|
```
|
||||||
**Coils (1-битные)**
|
**Coils (1-битные)**
|
||||||
```c
|
```c
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -213,9 +218,9 @@ typedef struct
|
|||||||
#define C_COILS_ADDR 0 // Начальный адрес Coils
|
#define C_COILS_ADDR 0 // Начальный адрес Coils
|
||||||
#define C_COILS_QNT 4 // Количество Coils
|
#define C_COILS_QNT 4 // Количество Coils
|
||||||
```
|
```
|
||||||
#### 3.6. Доступ к данным в коде
|
#### 3.6. Доступ к данным в коде
|
||||||
|
|
||||||
В режиме **слейва** есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля
|
В режиме **слейва** есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля
|
||||||
```c
|
```c
|
||||||
// Чтение входных регистров
|
// Чтение входных регистров
|
||||||
uint16_t temp = MB_DATA.InRegs.Temperature;
|
uint16_t temp = MB_DATA.InRegs.Temperature;
|
||||||
@@ -232,7 +237,7 @@ if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) {
|
|||||||
// Pump включен
|
// Pump включен
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
В режиме **мастера** есть функции для получения информации из ответа `MB_RespGet_...()`
|
В режиме **мастера** есть функции для получения информации из ответа `MB_RespGet_...()`
|
||||||
```c
|
```c
|
||||||
// Чтение регистров: Получить запрошенные регистры
|
// Чтение регистров: Получить запрошенные регистры
|
||||||
uint16_t value;
|
uint16_t value;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
Файл содержит реализацию функций для работы Modbus в режиме слейва.
|
Файл содержит реализацию функций для работы Modbus в режиме слейва.
|
||||||
|
|
||||||
@section slave Функции и макросы
|
@section slave Функции и макросы
|
||||||
|
- MB_Slave_ResponseLater() — Выставить флаг на ответ вне прерывания
|
||||||
|
- MB_Slave_SendResponse() — Ответить на запрос
|
||||||
|
|
||||||
- MB_Slave_Response() — Ответ на запрос
|
- MB_Slave_Response() — Ответ на запрос
|
||||||
- MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва.
|
- MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва.
|
||||||
@@ -15,6 +17,66 @@
|
|||||||
#include "modbus.h"
|
#include "modbus.h"
|
||||||
|
|
||||||
#ifdef MODBUS_ENABLE_SLAVE
|
#ifdef MODBUS_ENABLE_SLAVE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ответить позже, не в прерывании.
|
||||||
|
* @param hmodbus Указатель на хендлер RS.
|
||||||
|
* @param ResponseCode Код запроса на который надо ответить.
|
||||||
|
* @return HAL Status.
|
||||||
|
* @details Отменяет ответ в прерывании на запрос.
|
||||||
|
Используется вместе с @ref MB_Slave_SendResponse
|
||||||
|
*/
|
||||||
|
HAL_StatusTypeDef MB_Slave_ResponseLater(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode)
|
||||||
|
{
|
||||||
|
hmodbus->f.DeferredResponse = ResponseCode;
|
||||||
|
|
||||||
|
return HAL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ответить на запрос.
|
||||||
|
* @param hmodbus Указатель на хендлер RS.
|
||||||
|
* @param ResponseCode Код запроса на который надо ответить.
|
||||||
|
* @param error Тип ошибки или её отсутствия в ответе.
|
||||||
|
* @return HAL Status.
|
||||||
|
* @details Ответить на запрос вне прерывания.
|
||||||
|
Используется вместе с @ref MB_Slave_ResponseLater
|
||||||
|
*/
|
||||||
|
HAL_StatusTypeDef MB_Slave_SendResponse(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode, MB_ExceptionTypeDef error)
|
||||||
|
{
|
||||||
|
RS_StatusTypeDef MB_RES = 0;
|
||||||
|
if(hmodbus->f.DeferredResponse == ResponseCode)
|
||||||
|
{
|
||||||
|
hmodbus->f.DeferredResponse = 0;
|
||||||
|
switch(error)
|
||||||
|
{
|
||||||
|
case ET_NO_ERRORS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ET_ACKNOWLEDGE:
|
||||||
|
MB_Diagnostics_SlaveNAKCnt();
|
||||||
|
break;
|
||||||
|
case ET_SLAVE_DEVICE_BUSY:
|
||||||
|
MB_Diagnostics_SlaveBusyCnt();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(error != ET_NO_ERRORS)
|
||||||
|
{
|
||||||
|
MB_Diagnostics_ExceptionErrorCnt();
|
||||||
|
TrackerCnt_Warn(hmodbus->rs_err);
|
||||||
|
hmodbus->pMessagePtr->FuncCode |= FC_ERR_VALUES_START;
|
||||||
|
hmodbus->pMessagePtr->Except_Code = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
hmodbus->RS_STATUS = RS_Handle_Transmit_Start(hmodbus, hmodbus->pMessagePtr);
|
||||||
|
}
|
||||||
|
return HAL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Ответ на сообщение в режиме слейва.
|
* @brief Ответ на сообщение в режиме слейва.
|
||||||
* @param hmodbus Указатель на хендлер RS.
|
* @param hmodbus Указатель на хендлер RS.
|
||||||
@@ -115,8 +177,7 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
|
|||||||
/* unknown func code */
|
/* unknown func code */
|
||||||
default:
|
default:
|
||||||
modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
|
modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Проверяем режим устройства - если Listen Only, не обрабатываем команды
|
// Проверяем режим устройства - если Listen Only, не обрабатываем команды
|
||||||
if (MB_GetDeviceMode() == MODBUS_LISTEN_ONLY_MODE)
|
if (MB_GetDeviceMode() == MODBUS_LISTEN_ONLY_MODE)
|
||||||
@@ -152,8 +213,8 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RS_Handle_Receive_Start(hmodbus, modbus_msg);
|
// RS_Handle_Receive_Start(hmodbus, modbus_msg);
|
||||||
hmodbus->f.DeferredResponse = 0;
|
// hmodbus->f.DeferredResponse = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hmodbus->RS_STATUS = MB_RES;
|
hmodbus->RS_STATUS = MB_RES;
|
||||||
@@ -173,7 +234,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
|
|||||||
{
|
{
|
||||||
int ind = 0; // ind for modbus-uart buffer
|
int ind = 0; // ind for modbus-uart buffer
|
||||||
|
|
||||||
if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need
|
if(hmodbus->f.EchoResponse && (modbus_msg->Except_Code == ET_NO_ERRORS)) // if echo response need
|
||||||
ind = hmodbus->RS_Message_Size;
|
ind = hmodbus->RS_Message_Size;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user