diff --git a/Core/Inc/main.h b/Core/Inc/main.h index 388fe4d..2f5138e 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -66,6 +66,18 @@ typedef enum { START, STOP } OptStates; extern OptStates opt_state; +extern uint16_t modbus_cnt; + +#define DEVICE_CONTROL 0x01 +#define DEVICE_CNT modbus_cnt +#define DEVICE_MIN_RECEIVE_PULSES 5 +#define DEVICE_MAX_LOST_PULSES 20 +#define DEVICE_MIN_PULSE_WIDTH 250 +#define DEVICE_MAX_PULSE_WIDTH 750 + +typedef struct {} ModbusRegistersStruct; +extern ModbusRegistersStruct ModbusRegisters; + /* USER CODE END Private defines */ #ifdef __cplusplus diff --git a/Core/Inc/modbus_crc.h b/Core/Inc/modbus_crc.h new file mode 100644 index 0000000..9901e75 --- /dev/null +++ b/Core/Inc/modbus_crc.h @@ -0,0 +1,36 @@ +/* + * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU. + * Copyright (c) 2006 Christian Walter + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * File: $Id: mbcrc.h,v 1.5 2006/12/07 22:10:34 wolti Exp $ + */ + +#ifndef _MB_CRC_H +#define _MB_CRC_H + +CRC_t usMBCRC16( UCHAR * pucFrame, USHORT usLen ); + +#endif diff --git a/Core/Inc/modbus_lib.h b/Core/Inc/modbus_lib.h new file mode 100644 index 0000000..df4bc22 --- /dev/null +++ b/Core/Inc/modbus_lib.h @@ -0,0 +1,84 @@ +#define MODBUS_LIB_MAX_BUFFER 256 + +/* ----------------------- Defines ------------------------------------------*/ +#define MB_ADDRESS_BROADCAST ( 0 ) /*! Modbus broadcast address. */ +#define MB_ADDRESS_MIN ( 1 ) /*! Smallest possible slave address. */ +#define MB_ADDRESS_MAX ( 247 ) /*! Biggest possible slave address. */ +#define MB_FUNC_NONE ( 0 ) +#define MB_FUNC_READ_COILS ( 1 ) +#define MB_FUNC_READ_DISCRETE_INPUTS ( 2 ) +#define MB_FUNC_WRITE_SINGLE_COIL ( 5 ) +#define MB_FUNC_WRITE_MULTIPLE_COILS ( 15 ) +#define MB_FUNC_READ_HOLDING_REGISTERS ( 3 ) +#define MB_FUNC_READ_INPUT_REGISTER ( 4 ) +#define MB_FUNC_WRITE_REGISTER ( 6 ) +#define MB_FUNC_WRITE_MULTIPLE_REGISTERS ( 16 ) +#define MB_FUNC_READWRITE_MULTIPLE_REGISTERS ( 23 ) +#define MB_FUNC_DIAG_READ_EXCEPTION ( 7 ) +#define MB_FUNC_DIAG_DIAGNOSTIC ( 8 ) +#define MB_FUNC_DIAG_GET_COM_EVENT_CNT ( 11 ) +#define MB_FUNC_DIAG_GET_COM_EVENT_LOG ( 12 ) +#define MB_FUNC_OTHER_REPORT_SLAVEID ( 17 ) +#define MB_FUNC_ERROR ( 128 ) + +/*----------------------- Response types ------------------------------*/ +#define MBUS_RESPONSE_OK 0x00 +#define MBUS_RESPONSE_NONE 0xFF +/* MBUS_RESPONSE_ILLEGAL_FUNCTION +The function code received in the query is not an allowable action +for the server. This may be because the function code is only +applicable to newerdevices, and was not implemented in the unit +selected. It could also indicate that the serveris in the wrong state to +process a request of this type, for example because it is +unconfigured and is being asked to return register values. +*/ +#define MBUS_RESPONSE_ILLEGAL_FUNCTION 0x01 + +/* MBUS_RESPONSE_ILLEGAL_DATA_ADDRESS +The data address received in the query is not an allowable address +for the server. More specifically, the combination of reference number +and transfer length is invalid. For a controller with 100 registers, +the PDU addresses the first register as 0, and the last one as 99. If +a request is submitted with a starting register address of 96 and a +quantity of registers of 4, then this request will successfully +operate (address-wise at least) on registers 96, 97, 98, 99. If +a request is submitted with a starting register address of 96 and +a quantity of registers of 5, then this request will fail with +Exception Code 0x02 “Illegal Data Address” since it attempts to +operate on registers 96, 97, 98, 99 and 100, and there is no +register with address 100. +*/ +#define MBUS_RESPONSE_ILLEGAL_DATA_ADDRESS 0x02 + +/* A value contained in the query data field is not an allowable value +for server. This indicates a fault in the structure of the remainder of +a complex request, such as that the implied length is +incorrect. It specifically does NOT mean that a data item submitted for +storage in a register has a value outside the expectation of the application +program, since the MODBUS protocol is unaware of the significance of +any particular val ue of any particular register. +*/ +#define MBUS_RESPONSE_ILLEGAL_DATA_VALUE 0x03 +/* +An unrecoverable error occurred while the server +was attempting to perform the requested action. +*/ +#define MBUS_RESPONSE_SERVICE_DEVICE_FAILURE 0x04 + + +#define MB_ADDRESS_HOLDING_REGISTER_OFFSET (40001) + +typedef struct ModbusConfig_t{ + uint16_t address; +} ModbusConfig_t; + +extern uint8_t g_modbus_lib_received_telegram[MODBUS_LIB_MAX_BUFFER]; +extern uint16_t g_modbus_lib_received_length; + +extern int modbus_lib_init(ModbusConfig_t*); +extern void modbus_lib_append_data(uint8_t); +extern void modbus_lib_end_of_telegram(void); +extern uint16_t modbus_lib_send_error(int error_code); +extern int modbus_lib_transport_write(uint8_t* buffer, uint16_t length); +extern uint16_t modbus_lib_read_handler(uint16_t la); +extern uint16_t modbus_lib_write_handler(uint16_t la, uint16_t value); diff --git a/Core/Inc/modbus_lib_types.h b/Core/Inc/modbus_lib_types.h new file mode 100644 index 0000000..3f96048 --- /dev/null +++ b/Core/Inc/modbus_lib_types.h @@ -0,0 +1,10 @@ +#ifndef _MODBUS_LIB_H_ +#define _MODBUS_LIB_H_ + +#include + +/* ----------------------- Defines ------------------------------------------*/ +#define MODBUS_LIB_MIN_TELEGRAM_SIZE 4 /*!< Minimum size of a Modbus RTU frame. */ + + +#endif // _MODBUS_LIB_H_ \ No newline at end of file diff --git a/Core/Inc/port.h b/Core/Inc/port.h new file mode 100644 index 0000000..7791824 --- /dev/null +++ b/Core/Inc/port.h @@ -0,0 +1,21 @@ +#include + +typedef unsigned char BOOL; + +typedef unsigned char UCHAR; +typedef char CHAR; + +typedef unsigned int USHORT; +typedef int SHORT; + +typedef unsigned long ULONG; +typedef long LONG; + +typedef union { + struct { + uint8_t low; + uint8_t high; + } bytes; + uint16_t value; +} CRC_t, MbDataField; + diff --git a/Core/Src/main.c b/Core/Src/main.c index 05c5cc6..4a7fa39 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -41,12 +41,15 @@ /* Private variables ---------------------------------------------------------*/ TIM_HandleTypeDef htim2; +TIM_HandleTypeDef htim3; TIM_HandleTypeDef htim4; UART_HandleTypeDef huart1; +UART_HandleTypeDef huart2; /* USER CODE BEGIN PV */ OptStates opt_state = STOP; +ModbusRegistersStruct ModbusRegisters; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ @@ -55,6 +58,8 @@ static void MX_GPIO_Init(void); static void MX_TIM4_Init(void); static void MX_USART1_UART_Init(void); static void MX_TIM2_Init(void); +static void MX_TIM3_Init(void); +static void MX_USART2_UART_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ @@ -95,6 +100,8 @@ int main(void) MX_TIM4_Init(); MX_USART1_UART_Init(); MX_TIM2_Init(); + MX_TIM3_Init(); + MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(&htim2); HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); @@ -191,6 +198,7 @@ static void MX_TIM2_Init(void) htim2.Init.Prescaler = 72; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 5000; + htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) @@ -220,12 +228,63 @@ static void MX_TIM2_Init(void) { Error_Handler(); } + sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI; + sConfigIC.ICFilter = 0; + if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) + { + Error_Handler(); + } /* USER CODE BEGIN TIM2_Init 2 */ /* USER CODE END TIM2_Init 2 */ } +/** + * @brief TIM3 Initialization Function + * @param None + * @retval None + */ +static void MX_TIM3_Init(void) +{ + + /* USER CODE BEGIN TIM3_Init 0 */ + + /* USER CODE END TIM3_Init 0 */ + + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + + /* USER CODE BEGIN TIM3_Init 1 */ + + /* USER CODE END TIM3_Init 1 */ + htim3.Instance = TIM3; + htim3.Init.Prescaler = 0; + htim3.Init.CounterMode = TIM_COUNTERMODE_UP; + htim3.Init.Period = 65535; + htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&htim3) != HAL_OK) + { + Error_Handler(); + } + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN TIM3_Init 2 */ + + /* USER CODE END TIM3_Init 2 */ + +} + /** * @brief TIM4 Initialization Function * @param None @@ -318,6 +377,39 @@ static void MX_USART1_UART_Init(void) } +/** + * @brief USART2 Initialization Function + * @param None + * @retval None + */ +static void MX_USART2_UART_Init(void) +{ + + /* USER CODE BEGIN USART2_Init 0 */ + + /* USER CODE END USART2_Init 0 */ + + /* USER CODE BEGIN USART2_Init 1 */ + + /* USER CODE END USART2_Init 1 */ + huart2.Instance = USART2; + huart2.Init.BaudRate = 115200; + huart2.Init.WordLength = UART_WORDLENGTH_8B; + huart2.Init.StopBits = UART_STOPBITS_1; + huart2.Init.Parity = UART_PARITY_NONE; + huart2.Init.Mode = UART_MODE_TX_RX; + huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart2.Init.OverSampling = UART_OVERSAMPLING_16; + if (HAL_UART_Init(&huart2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN USART2_Init 2 */ + + /* USER CODE END USART2_Init 2 */ + +} + /** * @brief GPIO Initialization Function * @param None diff --git a/Core/Src/modbus_crc.c b/Core/Src/modbus_crc.c new file mode 100644 index 0000000..2d6406d --- /dev/null +++ b/Core/Src/modbus_crc.c @@ -0,0 +1,98 @@ +/* + * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU. + * Copyright (c) 2006 Christian Walter + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * File: $Id: mbcrc.c,v 1.7 2007/02/18 23:50:27 wolti Exp $ + */ + +/* ----------------------- Platform includes --------------------------------*/ +#include "port.h" + +static const UCHAR aucCRCHi[] = { + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40 +}; + +static const UCHAR aucCRCLo[] = { + 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, + 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, + 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, + 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, + 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, + 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, + 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, + 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, + 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, + 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, + 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, + 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, + 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, + 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, + 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, + 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, + 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, + 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, + 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, + 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, + 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, + 0x41, 0x81, 0x80, 0x40 +}; + +CRC_t +usMBCRC16( UCHAR * pucFrame, USHORT usLen ) +{ + UCHAR ucCRCHi = 0xFF; + UCHAR ucCRCLo = 0xFF; + int iIndex; + + while( usLen-- ) + { + iIndex = ucCRCLo ^ *( pucFrame++ ); + ucCRCLo = ( UCHAR )( ucCRCHi ^ aucCRCHi[iIndex] ); + ucCRCHi = aucCRCLo[iIndex]; + } + return ( CRC_t ){ .bytes.high = ucCRCHi, .bytes.low = ucCRCLo }; +} diff --git a/Core/Src/modbus_lib.c b/Core/Src/modbus_lib.c new file mode 100644 index 0000000..b3f08f3 --- /dev/null +++ b/Core/Src/modbus_lib.c @@ -0,0 +1,141 @@ +/******************************************************* + * + * Implementation reference: + * + * http://www.mayor.de/lian98/doc.en/html/u_mbusser-rtu_struct.htm + * https://www.modbustools.com/modbus.html + * + * Example telegrams: + * Read holding registers: 010300000002c40b (read 2 registers starting from 40001) + * Read holding registers: 0103000000044409 (read 4 registers starting from 40001) + * + * Write single register: 01060000007bc9e9 (write "123" to register 40001) + * + * Write multiple registers: 01100000000204007b0237c300 + * + *******************************************************/ + +#include "modbus_lib_types.h" +#include "modbus_lib.h" +#include "port.h" +#include "modbus_crc.h" + +uint8_t g_modbus_lib_received_telegram[MODBUS_LIB_MAX_BUFFER]; +uint16_t g_modbus_lib_received_length = 0; +uint8_t g_modbus_lib_exception_occurred = 0; +ModbusConfig_t* config; + +int modbus_lib_init(ModbusConfig_t* cfg){ + config = cfg; + return 0; +} + +void modbus_lib_append_data(uint8_t byte){ + if (g_modbus_lib_received_length < MODBUS_LIB_MAX_BUFFER){ + g_modbus_lib_received_telegram[g_modbus_lib_received_length++] = byte; + } +} + +void modbus_lib_end_of_telegram(){ + (void) 0; // debugger: p/x *g_modbus_lib_received_telegram@g_modbus_lib_received_length + + // Check length + if (g_modbus_lib_received_length < MODBUS_LIB_MIN_TELEGRAM_SIZE){ + modbus_lib_send_error(MBUS_RESPONSE_NONE); + return; + } + + // Check CRC + CRC_t expected = usMBCRC16(g_modbus_lib_received_telegram, g_modbus_lib_received_length-2); + UCHAR got_low = g_modbus_lib_received_telegram[g_modbus_lib_received_length-2]; + UCHAR got_high = g_modbus_lib_received_telegram[g_modbus_lib_received_length-1]; + if ((expected.bytes.low != got_low) || (expected.bytes.high != got_high)){ + modbus_lib_send_error(MBUS_RESPONSE_NONE); + return; + } + + // Check address + if (config->address != g_modbus_lib_received_telegram[0]){ + modbus_lib_send_error(MBUS_RESPONSE_NONE); + return; + } + + // Telegram is okay, call the relevant handler + // ------------------------------------------- + uint8_t outgoing_telegram[MODBUS_LIB_MAX_BUFFER]; + uint16_t oindex = 0; + + outgoing_telegram[oindex++] = config->address; + + volatile MbDataField start_addr, count, res, addr, value; + + switch (g_modbus_lib_received_telegram[1]){ + case MB_FUNC_READ_HOLDING_REGISTERS: + start_addr.bytes.high = g_modbus_lib_received_telegram[2]; + start_addr.bytes.low = g_modbus_lib_received_telegram[3]; + count.bytes.high = g_modbus_lib_received_telegram[4]; + count.bytes.low = g_modbus_lib_received_telegram[5]; + + outgoing_telegram[oindex++] = g_modbus_lib_received_telegram[1]; // function code + outgoing_telegram[oindex++] = count.value * 2; // byte count + + for (uint16_t i=0; i < count.value; i++){ + res.value = modbus_lib_read_handler(start_addr.value + i + MB_ADDRESS_HOLDING_REGISTER_OFFSET); + if (g_modbus_lib_exception_occurred){ + g_modbus_lib_exception_occurred = 0; + return; + } + outgoing_telegram[oindex++] = res.bytes.high; + outgoing_telegram[oindex++] = res.bytes.low; + } + + CRC_t crc = usMBCRC16(outgoing_telegram, oindex); + outgoing_telegram[oindex++] = crc.bytes.low; + outgoing_telegram[oindex++] = crc.bytes.high; + + modbus_lib_transport_write(outgoing_telegram, oindex); + break; + case MB_FUNC_WRITE_REGISTER: + addr.bytes.high = g_modbus_lib_received_telegram[2]; + addr.bytes.low = g_modbus_lib_received_telegram[3]; + value.bytes.high = g_modbus_lib_received_telegram[4]; + value.bytes.low = g_modbus_lib_received_telegram[5]; + + if (modbus_lib_write_handler(addr.value + MB_ADDRESS_HOLDING_REGISTER_OFFSET, value.value) == 0){ + // success + // normal response is the echo of received telegram + modbus_lib_transport_write(g_modbus_lib_received_telegram, g_modbus_lib_received_length); + } else { + // error + g_modbus_lib_exception_occurred = 0; + } + break; + default: + // unimplemented + modbus_lib_send_error(MBUS_RESPONSE_SERVICE_DEVICE_FAILURE); + g_modbus_lib_exception_occurred = 0; + return; + } + + g_modbus_lib_received_length = 0; +} + +#define MB_EXCEPTION_LENGTH 5 + +uint16_t modbus_lib_send_error(int error_code){ + if (error_code != MBUS_RESPONSE_NONE){ + g_modbus_lib_exception_occurred = 1; + uint8_t res[MB_EXCEPTION_LENGTH] = { + config->address, + g_modbus_lib_received_telegram[1] | 0x80, + error_code + }; + CRC_t crc = usMBCRC16(res, MB_EXCEPTION_LENGTH - 2); + res[MB_EXCEPTION_LENGTH - 2] = crc.bytes.low; + res[MB_EXCEPTION_LENGTH - 1] = crc.bytes.high; + + modbus_lib_transport_write(res, MB_EXCEPTION_LENGTH); + } + g_modbus_lib_received_length = 0; + return -1; +} diff --git a/Core/Src/stm32f1xx_hal_msp.c b/Core/Src/stm32f1xx_hal_msp.c index eb5f467..4664300 100644 --- a/Core/Src/stm32f1xx_hal_msp.c +++ b/Core/Src/stm32f1xx_hal_msp.c @@ -101,13 +101,15 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM2 GPIO Configuration - PA0-WKUP ------> TIM2_CH1 + PA15 ------> TIM2_CH1 */ - GPIO_InitStruct.Pin = GPIO_PIN_0; + GPIO_InitStruct.Pin = GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + __HAL_AFIO_REMAP_TIM2_PARTIAL_1(); + /* TIM2 interrupt Init */ HAL_NVIC_SetPriority(TIM2_IRQn, 14, 0); HAL_NVIC_EnableIRQ(TIM2_IRQn); @@ -115,6 +117,17 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) /* USER CODE END TIM2_MspInit 1 */ } + else if(htim_base->Instance==TIM3) + { + /* USER CODE BEGIN TIM3_MspInit 0 */ + + /* USER CODE END TIM3_MspInit 0 */ + /* Peripheral clock enable */ + __HAL_RCC_TIM3_CLK_ENABLE(); + /* USER CODE BEGIN TIM3_MspInit 1 */ + + /* USER CODE END TIM3_MspInit 1 */ + } else if(htim_base->Instance==TIM4) { /* USER CODE BEGIN TIM4_MspInit 0 */ @@ -170,9 +183,9 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base) __HAL_RCC_TIM2_CLK_DISABLE(); /**TIM2 GPIO Configuration - PA0-WKUP ------> TIM2_CH1 + PA15 ------> TIM2_CH1 */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0); + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_15); /* TIM2 interrupt DeInit */ HAL_NVIC_DisableIRQ(TIM2_IRQn); @@ -180,6 +193,17 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base) /* USER CODE END TIM2_MspDeInit 1 */ } + else if(htim_base->Instance==TIM3) + { + /* USER CODE BEGIN TIM3_MspDeInit 0 */ + + /* USER CODE END TIM3_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM3_CLK_DISABLE(); + /* USER CODE BEGIN TIM3_MspDeInit 1 */ + + /* USER CODE END TIM3_MspDeInit 1 */ + } else if(htim_base->Instance==TIM4) { /* USER CODE BEGIN TIM4_MspDeInit 0 */ @@ -230,6 +254,33 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart) /* USER CODE END USART1_MspInit 1 */ } + else if(huart->Instance==USART2) + { + /* USER CODE BEGIN USART2_MspInit 0 */ + + /* USER CODE END USART2_MspInit 0 */ + /* Peripheral clock enable */ + __HAL_RCC_USART2_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**USART2 GPIO Configuration + PA2 ------> USART2_TX + PA3 ------> USART2_RX + */ + GPIO_InitStruct.Pin = GPIO_PIN_2; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_PIN_3; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* USER CODE BEGIN USART2_MspInit 1 */ + + /* USER CODE END USART2_MspInit 1 */ + } } @@ -259,6 +310,24 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart) /* USER CODE END USART1_MspDeInit 1 */ } + else if(huart->Instance==USART2) + { + /* USER CODE BEGIN USART2_MspDeInit 0 */ + + /* USER CODE END USART2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_USART2_CLK_DISABLE(); + + /**USART2 GPIO Configuration + PA2 ------> USART2_TX + PA3 ------> USART2_RX + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3); + + /* USER CODE BEGIN USART2_MspDeInit 1 */ + + /* USER CODE END USART2_MspDeInit 1 */ + } } diff --git a/Core/Src/stm32f1xx_it.c b/Core/Src/stm32f1xx_it.c index dd1284c..22a8dca 100644 --- a/Core/Src/stm32f1xx_it.c +++ b/Core/Src/stm32f1xx_it.c @@ -213,15 +213,29 @@ void TIM2_IRQHandler(void) _state_counter = 0; LED_GPIO_Port->BSRR = LED_Pin; } + // задний фронт, убывающий + if (sr & TIM_SR_CC2IF) { + uint32_t ccr = TIM2->CCR2; + if (ccr >= DEVICE_MIN_PULSE_WIDTH && ccr <= DEVICE_MAX_PULSE_WIDTH) { + // можно считать что это импульс + if (_state_counter > DEVICE_MIN_RECEIVE_PULSES) { + LED_GPIO_Port->BSRR = (uint32_t)LED_Pin << 16; + opt_state = START; + } else { + _state_counter++; + } + } +// else { +// // какое-то говно, а не импульс +// // ну я ничего не делаю +// } + } + + // передний возрастающий фронт + // тут по сути надо обнулить CNT, и вроде все if (sr & TIM_SR_CC1IF) { TIM2->SR = TIM_SR_CC1IF; TIM2->CNT = 0; // обнуляем счетчик таймера - if (_state_counter > 20) { - LED_GPIO_Port->BSRR = (uint32_t)LED_Pin << 16; - opt_state = START; - } else { - _state_counter++; - } } /* USER CODE END TIM2_IRQn 0 */ HAL_TIM_IRQHandler(&htim2); diff --git a/f103-my-tests.ioc b/f103-my-tests.ioc index 83406bf..8678feb 100644 --- a/f103-my-tests.ioc +++ b/f103-my-tests.ioc @@ -7,25 +7,31 @@ Mcu.IP0=NVIC Mcu.IP1=RCC Mcu.IP2=SYS Mcu.IP3=TIM2 -Mcu.IP4=TIM4 -Mcu.IP5=USART1 -Mcu.IPNb=6 +Mcu.IP4=TIM3 +Mcu.IP5=TIM4 +Mcu.IP6=USART1 +Mcu.IP7=USART2 +Mcu.IPNb=8 Mcu.Name=STM32F103C(8-B)Tx Mcu.Package=LQFP48 Mcu.Pin0=PD0-OSC_IN Mcu.Pin1=PD1-OSC_OUT -Mcu.Pin10=VP_SYS_VS_Systick -Mcu.Pin11=VP_TIM2_VS_ClockSourceINT -Mcu.Pin12=VP_TIM4_VS_ClockSourceINT -Mcu.Pin2=PA0-WKUP -Mcu.Pin3=PB12 -Mcu.Pin4=PA9 -Mcu.Pin5=PA10 -Mcu.Pin6=PA13 -Mcu.Pin7=PA14 -Mcu.Pin8=PB5 -Mcu.Pin9=PB6 -Mcu.PinsNb=13 +Mcu.Pin10=PB5 +Mcu.Pin11=PB6 +Mcu.Pin12=VP_SYS_VS_Systick +Mcu.Pin13=VP_TIM2_VS_ClockSourceINT +Mcu.Pin14=VP_TIM2_VS_indirect_ch1 +Mcu.Pin15=VP_TIM3_VS_ClockSourceINT +Mcu.Pin16=VP_TIM4_VS_ClockSourceINT +Mcu.Pin2=PA2 +Mcu.Pin3=PA3 +Mcu.Pin4=PB12 +Mcu.Pin5=PA9 +Mcu.Pin6=PA10 +Mcu.Pin7=PA13 +Mcu.Pin8=PA14 +Mcu.Pin9=PA15 +Mcu.PinsNb=17 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32F103C8Tx @@ -43,13 +49,17 @@ NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true NVIC.TIM2_IRQn=true\:14\:0\:true\:false\:true\:true\:true NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false -PA0-WKUP.Signal=S_TIM2_CH1_ETR PA10.Mode=Asynchronous PA10.Signal=USART1_RX PA13.Mode=Serial_Wire PA13.Signal=SYS_JTMS-SWDIO PA14.Mode=Serial_Wire PA14.Signal=SYS_JTCK-SWCLK +PA15.Signal=S_TIM2_CH1_ETR +PA2.Mode=Asynchronous +PA2.Signal=USART2_TX +PA3.Mode=Asynchronous +PA3.Signal=USART2_RX PA9.Mode=Asynchronous PA9.Signal=USART1_TX PB12.GPIOParameters=GPIO_Label @@ -119,8 +129,9 @@ SH.S_TIM4_CH1.0=TIM4_CH1,PWM Generation1 CH1 SH.S_TIM4_CH1.ConfNb=1 TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE TIM2.Channel-Input_Capture1_from_TI1=TIM_CHANNEL_1 +TIM2.Channel-Input_Capture2_from_TI1_63=TIM_CHANNEL_2 TIM2.ICFilter_CH1=1 -TIM2.IPParameters=Channel-Input_Capture1_from_TI1,ICFilter_CH1,Prescaler,Period,AutoReloadPreload +TIM2.IPParameters=Channel-Input_Capture1_from_TI1,ICFilter_CH1,Prescaler,Period,AutoReloadPreload,Channel-Input_Capture2_from_TI1_63 TIM2.Period=5000 TIM2.Prescaler=72 TIM4.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 @@ -130,10 +141,16 @@ TIM4.Prescaler=72 TIM4.Pulse-PWM\ Generation1\ CH1=500 USART1.IPParameters=VirtualMode USART1.VirtualMode=VM_ASYNC +USART2.IPParameters=VirtualMode +USART2.VirtualMode=VM_ASYNC VP_SYS_VS_Systick.Mode=SysTick VP_SYS_VS_Systick.Signal=SYS_VS_Systick VP_TIM2_VS_ClockSourceINT.Mode=Internal VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT +VP_TIM2_VS_indirect_ch1.Mode=Input_Capture2_from_TI1_63 +VP_TIM2_VS_indirect_ch1.Signal=TIM2_VS_indirect_ch1 +VP_TIM3_VS_ClockSourceINT.Mode=Internal +VP_TIM3_VS_ClockSourceINT.Signal=TIM3_VS_ClockSourceINT VP_TIM4_VS_ClockSourceINT.Mode=Internal VP_TIM4_VS_ClockSourceINT.Signal=TIM4_VS_ClockSourceINT board=custom