diff --git a/Arduino_Modbus.ino b/Arduino_Modbus.ino index 233dacf..e03dfb6 100644 --- a/Arduino_Modbus.ino +++ b/Arduino_Modbus.ino @@ -1,9 +1,13 @@ #include "rs_message.h" +#include "FreeRTOS.h" + void setup() { // put your setup code here, to run once: MODBUS_FirstInit(); + //hmodbus1.RS_STATUS = RS_Init(&hmodbus1, &rs_huart, MB_SPEED, 0); + xTaskCreatePinnedToCore(RS_Task, "Modbus", 4096, &hmodbus1, 2, NULL, 1); Serial.begin(115200); // для отладки Serial.println("start"); @@ -11,9 +15,5 @@ void setup() { } void loop() { - // put your main code here, to run repeatedly: - RS_Process(&hmodbus1); - //delay(500); - //Serial.println("start"); - //rs_huart.println("start1"); -} + //RS_Process(&hmodbus1); +} \ No newline at end of file diff --git a/modbus.cpp b/modbus.cpp index 748f005..8b54355 100644 --- a/modbus.cpp +++ b/modbus.cpp @@ -87,15 +87,16 @@ void MODBUS_FirstInit(void) { MB_DevoceInentificationInit(); //-----------SETUP MODBUS------------- - // set up modbus: MB_RX_Size_NotConst and Timeout enable hmodbus1.ID = MODBUS_DEVICE_ID; hmodbus1.sRS_Timeout = MODBUS_TIMEOUT; hmodbus1.sRS_Mode = SLAVE_ALWAYS_WAIT; hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst; hmodbus1.pMessagePtr = &MODBUS_MSG; + hmodbus1.rx_pin = MODBUS_RX_PIN; + hmodbus1.tx_pin = MODBUS_TX_PIN; + hmodbus1.taskDelay = RS_IN_FREERTOS; // INIT - rs_huart.begin(115200, SERIAL_8N1, 8, 9); - hmodbus1.RS_STATUS = RS_Init(&hmodbus1, &rs_huart, 0); + hmodbus1.RS_STATUS = RS_Init(&hmodbus1, &rs_huart, MODBUS_SPEED, 0); RS_EnableReceive(); } diff --git a/modbus_config.h b/modbus_config.h index fa09d76..31ea3b5 100644 --- a/modbus_config.h +++ b/modbus_config.h @@ -7,14 +7,26 @@ #ifndef _MODBUS_CONFIG_H_ #define _MODBUS_CONFIG_H_ +#define RS_IN_FREERTOS 20 ///< значение - период таска + + // Включить/выключить debug -#define RS_DEBUG 0 ///< Отладка приема/передачи UART -#define MODBUS_DEBUG 0 ///< Отладка обработки запросов Modbus +#define RS_DEBUG 1 ///< Отладка приема/передачи UART +#define MODBUS_DEBUG 1 ///< Отладка обработки запросов Modbus #define MODBUS_ERR_DEBUG 1 ///< Отладка ошибок по CAN // MODBUS PARAMS #define MODBUS_DEVICE_ID 1 ///< девайс текущего устройства -#define MODBUS_TIMEOUT 5000 ///< максимальнйы тайтаут MB в тиках таймера +#define MODBUS_TIMEOUT 5000 ///< максимальнйы тайтаут MB в мс + +// PERIPH FUNCTIONS AND HANDLERS +#define HUART_TypeDef HardwareSerial +#define rs_huart Serial1 //используемый uart +#define MODBUS_SPEED 115200 +#define MODBUS_RX_PIN 8 +#define MODBUS_TX_PIN 9 + + // STRING OBJECTS MODBUS #define MODBUS_VENDOR_NAME "NIO PRIBOR" @@ -25,9 +37,6 @@ #define MODBUS_MODEL_NAME "Arduino" #define MODBUS_USER_APPLICATION_NAME "" -// PERIPH FUNCTIONS AND HANDLERS -#define rs_huart Serial1 //используемый uart -#define HUART_TypeDef HardwareSerial /** * @brief Поменять комманды 0x03 и 0x04 местами (для LabView терминалки от двигателей) diff --git a/rs_message.cpp b/rs_message.cpp index a5bc084..e2614a4 100644 --- a/rs_message.cpp +++ b/rs_message.cpp @@ -1,51 +1,76 @@ /** ************************************************************************** * @file rs_message.cpp -* @brief Модуль для реализации протоколов по RS/UART (Arduino). -**************************************************************************\ +* @brief Модуль для работы с протоколами RS/UART на Arduino. +************************************************************************** * @details -* Данный модуль реализует основные функции для приема и передачи сообщений -* по протоколу RS через UART. Реализована обработка приёма и передачи данных, -* управление состояниями RS, а также функции для инициализации и управления -* периферией Arduino Serial. +* Данный модуль обеспечивает приём и передачу сообщений по протоколу RS +* через UART на платформах Arduino. Поддерживаются два режима работы: +* - обычный (Arduino loop); +* - FreeRTOS (через StreamBuffer и отдельную задачу RS_Task). * -* Реализованы следующие функции: -* - RS_Init() — инициализация структуры RS и привязка к Serial-порту. -* - RS_Abort() — остановка работы RS/UART с очисткой флагов и структур. -* - RS_Handle_Transmit_Start() — запуск передачи данных. -* - RS_Process() — обработка входящих данных (вызов в loop()). +* Основные возможности: +* - Инициализация и управление структурой RS_HandleTypeDef. +* - Обработка приёма байтов, сборка пакетов и определение их длины. +* - Разбор полученных сообщений и формирование ответов. +* - Управление состояниями приёма и передачи (флаги RX/TX, busy/free). +* - Таймаут приёма и аварийная остановка передачи/приёма. * -* В модуле также определён буфер RS_Buffer[] для хранения принимаемых/передаваемых данных. +* Предоставляемые функции: +* - RS_Init() — инициализация структуры RS и Serial порта. +* - RS_Abort() — остановка работы RS/UART, очистка флагов. +* - RS_Handle_Transmit_Start() — подготовка и отправка сообщения. +* - RS_Process() — основной цикл обработки (Arduino loop). +* - RS_Process_Byte() — обработка одного принятого байта (для FreeRTOS). +* - RS_UART_RX_Handler() — ISR-приём данных UART (FreeRTOS). +* - RS_Task() — FreeRTOS задача обработки UART. * -* Пользователь должен определить функции: -* - RS_Response() — формирование ответа на принятое сообщение. -* - RS_Collect_Message() — подготовка сообщения для передачи. -* - RS_Parse_Message() — разбор принятого сообщения. -* - RS_Define_Size_of_RX_Message() — определение размера входящих данных. +* Пользователь должен реализовать слабые функции: +* - RS_Response() — формирование ответа на сообщение. +* - RS_Collect_Message() — заполнение буфера перед передачей. +* - RS_Parse_Message() — разбор принятого пакета. +* - RS_Define_Size_of_RX_Message() — определение длины ожидаемого пакета. * +* Буфер для приёма/передачи: RS_Buffer[MSG_SIZE_MAX]. +* * @note -* Для корректной работы требуется вызывать RS_Process() в основном цикле программы. -* UART используется через стандартный Arduino Stream API (write(), read(), available()). +* - В режиме Arduino loop необходимо вызывать RS_Process() в основном цикле. +* - В режиме FreeRTOS требуется определить макрос RS_IN_FREERTOS, +* создать задачу RS_Task и подключить RS_UART_RX_Handler() к ISR UART. +* - UART используется через стандартный Arduino Stream API (write, read, available). * -@verbatim -//-------------------Функции-------------------// -Functions: users - - RS_Parse_Message Разбор принятого сообщения - - RS_Collect_Message Заполнение структуры сообщения и буфера - - RS_Response Ответ на сообщение - - RS_Define_Size_of_RX_Message Определение размера принимаемых данных +* Пример использования (Arduino loop): +* @verbatim +RS_HandleTypeDef hRS; +RS_MsgTypeDef msg; +hRS.pMessagePtr = &msg; +RS_Init(&hRS, &Serial, 115200, NULL); + +void loop() { + RS_Process(&hRS); +} +* @endverbatim +* Пример использования с FreeRTOS: +* @verbatim +RS_HandleTypeDef hRS; +RS_MsgTypeDef msg; +hRS.pMessagePtr = &msg; +RS_Init(&hRS, &Serial, 115200, NULL); -Functions: general - - RS_Init Инициализация структуры RS и привязка Serial - - RS_Abort Остановка приёма/передачи - - RS_Handle_Transmit_Start Запуск передачи сообщения - - RS_Process Обработка приёма сообщений (в loop) - -@endverbatim -*************************************************************************/ +xTaskCreate(RS_Task, "RS_Task", 256, &hRS, 1, NULL); +//... +void eventSerial() { + RS_UART_RX_Handler(&hmodbus1); +} +* @endverbatim +**************************************************************************/ #include "rs_message.h" +#ifdef RS_IN_FREERTOS +#include +#endif + uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer //------------------------------------------------------------------- @@ -56,15 +81,16 @@ uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer * @param SerialPort - указатель на структуру с настройками UART. * @param pRS_BufferPtr - указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер. * @return RS_RES - статус о состоянии RS после инициализации. - * @note Инициализация перефирии и структуры для приема-передачи по RS. + * @note Инициализация периферии и структуры для приема-передачи по RS. */ -RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *SerialPort, uint8_t *pRS_BufferPtr) { +RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *SerialPort, uint32_t baudRate, uint8_t *pRS_BufferPtr) { if (!hRS || !SerialPort) { RS_DEBUG_PRINT("[RS] Init error: null handler or port"); return RS_ERR; } hRS->huart = SerialPort; + hRS->baudRate = baudRate; hRS->pBufferPtr = pRS_BufferPtr ? pRS_BufferPtr : RS_Buffer; hRS->RS_STATUS = RS_OK; RS_Set_Free(hRS); @@ -78,6 +104,8 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *SerialPort, uint8 RS_Set_Busy(hRS); RS_Set_RX_Flags(hRS); + hRS->huart->begin(hRS->baudRate, SERIAL_8N1, hRS->rx_pin, hRS->tx_pin); + RS_DEBUG_PRINT("[RS] Initialized successfully"); return RS_OK; } @@ -91,7 +119,7 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *SerialPort, uint8 - ABORT_RX_TX: Отмена приема и передачи по ЮАРТ, - ABORT_RS: Отмена приема-передачи RS, с очищением всей структуры. * @return RS_RES - статус о состоянии RS после аборта. - * @note В Arduino аппаратный UART (Serial) не отключается физически, + * @details В Arduino аппаратный UART (Serial) не отключается физически, * т.к. стандартный API HardwareSerial не даёт прямого доступа * к регистрах UART. RS_Abort лишь очищает внутренние флаги * и структуры, имитируя "отключение". @@ -125,7 +153,7 @@ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) { * @param hRS - указатель на хендлер RS. * @param RS_msg - указатель на структуру сообщения. * @return RS_RES - статус о состоянии RS после инициализации передачи. - * @note Определяет отвечать ли на команду или нет. + * @details Определяет отвечать ли на команду или нет. */ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { @@ -159,18 +187,31 @@ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef * return RS_OK; } +#ifdef RS_IN_FREERTOS /** - * @brief Main RS processing function. + * @brief Задача обработки UART приёма (FreeRTOS). + * @param pvParameters - указатель на RS_HandleTypeDef (передаётся при создании задачи). + * @details Вызывает функцию обработки приема UART по протоколу. + */ +void RS_Task(void *pvParameters) { + RS_HandleTypeDef *hRS = (RS_HandleTypeDef *)pvParameters; + uint8_t rxBuf[64]; + + for (;;) { + RS_Process(hRS); + vTaskDelay(pdMS_TO_TICKS(hRS->taskDelay)); + } +} +#endif // RS_IN_FREERTOS + + +/** + * @brief Основная функция обработки RS (вариант без FreeRTOS). * @param hRS - указатель на хендлер RS. - * @return None. - * @note Функция должна вызываться в основном цикле (loop()). - * Выполняет проверку таймаутов, обработку поступающих байт из UART - * и вызов пользовательских функций: - * - RS_Define_Size_of_RX_Message() для определения размера пакета; - * - RS_Parse_Message() для разбора принятого сообщения; - * - RS_Response() для ответа, если сообщение адресовано текущему устройству. - * В случае таймаута выполняется RS_Abort() с режимом ABORT_RX. + * @note Используется в Arduino loop(), если проект без FreeRTOS. + * @details Выполняет проверку таймаутов, обработку поступающих байт из UART + * по протоколу */ void RS_Process(RS_HandleTypeDef *hRS) { @@ -255,7 +296,7 @@ void RS_Process(RS_HandleTypeDef *hRS) * @param hRS - указатель на хендлер RS. * @param RS_msg - указатель на структуру сообщения. * @return RS_RES - статус о результате ответа на комманду. - * @note Обработка принятой комманды и ответ на неё. + * @details Обработка принятой комманды и ответ на неё. */ __attribute__((weak)) RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { return RS_ERR; } @@ -265,7 +306,7 @@ __attribute__((weak)) RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_Msg * @param RS_msg - указатель на структуру сообщения. * @param msg_uart_buff - указатель на буффер UART. * @return RS_RES - статус о результате заполнения буфера. - * @note Заполнение буффера UART из структуры сообщения. + * @details Заполнение буффера UART из структуры сообщения. */ __attribute__((weak)) RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { return RS_ERR; } @@ -275,7 +316,7 @@ __attribute__((weak)) RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, * @param RS_msg - указатель на структуру сообщения. * @param msg_uart_buff - указатель на буффер UART. * @return RS_RES - статус о результате заполнения структуры. - * @note Заполнение структуры сообщения из буффера UART. + * @details Заполнение структуры сообщения из буффера UART. */ __attribute__((weak)) RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { return RS_ERR; } @@ -284,6 +325,6 @@ __attribute__((weak)) RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, R * @param hRS - указатель на хендлер RS. * @param rx_data_size - указатель на переменную для записи кол-ва байт для принятия. * @return RS_RES - статус о корректности рассчета кол-ва байт для принятия. - * @note Определение сколько байтов надо принять по протоколу. + * @details Определение сколько байтов надо принять по протоколу. */ __attribute__((weak)) RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *rx_data_size) { return RS_ERR; } diff --git a/rs_message.h b/rs_message.h index 1fbb115..4c2cb0d 100644 --- a/rs_message.h +++ b/rs_message.h @@ -148,9 +148,14 @@ typedef struct // RS_HandleTypeDef uint8_t ID; ///< ID of RS "channel" RS_MsgTypeDef *pMessagePtr; ///< pointer to message struct uint8_t *pBufferPtr; ///< pointer to message buffer +#ifdef RS_IN_FREERTOS + uint16_t taskDelay; ///< freertos buffer +#endif uint32_t RS_Message_Size; ///< size of whole message, not only data /* HANDLERS and SETTINGS */ + uint8_t tx_pin; ///< Transmit pin + uint8_t rx_pin; ///< Receive pin HUART_TypeDef *huart; ///< handler for used uart RS_ModeTypeDef sRS_Mode; ///< setting: slave or master @ref RS_ModeTypeDef uint16_t sRS_Timeout; ///< setting: timeout in ms @@ -187,9 +192,12 @@ RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *r //-------------------------GENERAL FUNCTIONS------------------------- /*-----------------Should be called from main code-----------------*/ +/* Задача обработки UART приёма (FreeRTOS) */ +void RS_Task(void *pvParameters); +/* Основная функция обработки RS */ void RS_Process(RS_HandleTypeDef *hRS); /* Initialize UART and handle RS stucture */ -RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *huart, uint8_t *pRS_BufferPtr); +RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *SerialPort, uint32_t baudRate, uint8_t *pRS_BufferPtr); /* Abort RS/UART */ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode); /* Handle for starting transmit */