STM32 - MODBUS RTU MASTER 8N1 115200 / DWIN;

Пример рабочий и спокойненько коннектится с DWIN, но тут есть одна подъебка, которая мешает принимать ответы и про которую я помню, но никому не скажу. Наверно, опытный программист и сам поймет, а неопытный пусть пострадает, потому что в таких муках зарождается ум.

#include "main.h"
#include <string.h>
#include <stdint.h>
/* ===================== Конфигурация ===================== */
#define SYSCLK_HZ           8000000UL
#define BAUDRATE            115200UL
#define TIMEOUT_MS          100U
#define IWDG_TIMEOUT_MS     2000U
#define FLASH_STATE_ADDR    0x08007C00UL
#define FLASH_MAGIC_VALUE   0xDEADBEEFUL
/* RS485 direction pin */
#define RS485_CONTROL_PIN   GPIO_PIN_1
#define RS485_CONTROL_PORT  GPIOF
/* DWIN / Modbus */
#define MODBUS_SLAVE_ID     1U
#define DWIN_VP_READ        0x1001U
#define DWIN_VP_WRITE       0x1500U
#define MODBUS_POLL_MS      10U
#define READ_QTY         10U
/* Светодиоды */
#define LED_COUNT           6
static const uint16_t led_pins[LED_COUNT] = {
    GPIO_PIN_15, GPIO_PIN_12, GPIO_PIN_11,
    GPIO_PIN_10, GPIO_PIN_9,  GPIO_PIN_8
};
/* ===================== Глобальные переменные ===================== */
volatile uint32_t timer_overflows = 0;
volatile uint32_t WatchdogTIMER_1 = 0;
volatile uint32_t WatchdogTIMER_2 = 1000;
typedef struct {
    uint8_t  led_states[LED_COUNT];
    uint32_t reset_count;
    uint32_t magic;
    uint32_t checksum;
} SystemState;
SystemState system_state = {0};
/* ===================== Прототипы ===================== */
void SystemClock_Config(void);
void MX_GPIO_Init(void);
void UART_Init(void);
void RS485_Init(void);
void RS485_SetTransmitMode(void);
void RS485_SetReceiveMode(void);
void Timer_Init(void);
void WatchdogTimer_Init(void);
void IWDG_Init(void);
void Delay_us(uint32_t us);
uint32_t millis(void);
void CheckResetCause(uint8_t *is_iwdg_reset);
void LoadSystemState(void);
void SaveSystemState(void);
uint32_t CalculateChecksum(SystemState *state);
void ApplyLedStates(void);
void UART_ClearRx(void);
void UART_SendBytes(const uint8_t *data, uint16_t len);
uint8_t UART_ReceiveExact(uint8_t *buf, uint16_t len, uint32_t timeout_ms);
uint16_t Modbus_CRC16(const uint8_t *data, uint16_t len);
uint8_t Modbus_ReadHoldingRegisters(uint8_t slave_id, uint16_t start_addr, uint16_t quantity, uint16_t *dest);
uint8_t Modbus_WriteSingleRegister(uint8_t slave_id, uint16_t reg_addr, uint16_t value);
void Error_Handler(void);
/* ===================== Задержка ===================== */
void Delay_us(uint32_t us)
{
    uint32_t cycles = (SYSCLK_HZ / 1000000UL) * us;
    while (cycles--) {
        __NOP();
    }
}
/* ===================== millis ===================== */
uint32_t millis(void)
{
    uint32_t overflows;
    uint32_t cnt;
    __disable_irq();
    overflows = timer_overflows;
    cnt = TIM3->CNT;
    __enable_irq();
    return (overflows * 1000UL) + cnt;
}
/* ===================== RS485 ===================== */
void RS485_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOF_CLK_ENABLE();
    GPIO_InitStruct.Pin = RS485_CONTROL_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(RS485_CONTROL_PORT, &GPIO_InitStruct);
    RS485_SetReceiveMode();
}
void RS485_SetTransmitMode(void)
{
    HAL_GPIO_WritePin(RS485_CONTROL_PORT, RS485_CONTROL_PIN, GPIO_PIN_SET);
    Delay_us(50);
}
void RS485_SetReceiveMode(void)
{
    HAL_GPIO_WritePin(RS485_CONTROL_PORT, RS485_CONTROL_PIN, GPIO_PIN_RESET);
    Delay_us(50);
}
/* ===================== UART ===================== */
void UART_Init(void)
{
    __HAL_RCC_USART1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /* PA2 = TX, PA3 = RX, AF1 */
    GPIOA->MODER &= ~(GPIO_MODER_MODER2_Msk | GPIO_MODER_MODER3_Msk);
    GPIOA->MODER |= (GPIO_MODER_MODER2_1 | GPIO_MODER_MODER3_1);
    GPIOA->AFR[0] &= ~((0xFUL << GPIO_AFRL_AFSEL2_Pos) | (0xFUL << GPIO_AFRL_AFSEL3_Pos));
    GPIOA->AFR[0] |=  ((0x1UL << GPIO_AFRL_AFSEL2_Pos) | (0x1UL << GPIO_AFRL_AFSEL3_Pos));
    USART1->CR1 = 0;
    USART1->CR2 = 0;
    USART1->CR3 = 0;
    /* 115200, 8N1 */
    USART1->BRR = (SYSCLK_HZ + (BAUDRATE / 2U)) / BAUDRATE;
    USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
}
void UART_ClearRx(void)
{
    while (USART1->ISR & USART_ISR_RXNE) {
        volatile uint8_t dummy = (uint8_t)USART1->RDR;
        (void)dummy;
    }
    if (USART1->ISR & (USART_ISR_ORE | USART_ISR_PE | USART_ISR_FE | USART_ISR_NE)) {
        USART1->ICR = USART_ICR_ORECF | USART_ICR_PECF | USART_ICR_FECF | USART_ICR_NCF;
    }
}
void UART_SendBytes(const uint8_t *data, uint16_t len)
{
    RS485_SetTransmitMode();
    for (uint16_t i = 0; i < len; i++) {
        while ((USART1->ISR & USART_ISR_TXE) == 0U) {
        }
        USART1->TDR = data[i];
    }
    while ((USART1->ISR & USART_ISR_TC) == 0U) {
    }
    Delay_us(50);
    RS485_SetReceiveMode();
}
uint8_t UART_ReceiveExact(uint8_t *buf, uint16_t len, uint32_t timeout_ms)
{
    uint32_t start = millis();
    uint16_t index = 0;
    while (index < len) {
        if (USART1->ISR & USART_ISR_RXNE) {
            buf[index++] = (uint8_t)USART1->RDR;
            start = millis();
        }
        if (USART1->ISR & (USART_ISR_ORE | USART_ISR_PE | USART_ISR_FE | USART_ISR_NE)) {
            USART1->ICR = USART_ICR_ORECF | USART_ICR_PECF | USART_ICR_FECF | USART_ICR_NCF;
            return 0;
        }
        if ((millis() - start) >= timeout_ms) {
            return 0;
        }
    }
    return 1;
}
/* ===================== Timer TIM3 для millis ===================== */
void Timer_Init(void)
{
    __HAL_RCC_TIM3_CLK_ENABLE();
    TIM3->PSC = (SYSCLK_HZ / 1000UL) - 1UL;
    TIM3->ARR = 1000UL - 1UL;
    TIM3->CNT = 0;
    TIM3->DIER |= TIM_DIER_UIE;
    NVIC_SetPriority(TIM3_IRQn, 1);
    NVIC_EnableIRQ(TIM3_IRQn);
    TIM3->CR1 |= TIM_CR1_CEN;
}
/* ===================== Timer TIM14 для watchdog ===================== */
void WatchdogTimer_Init(void)
{
    __HAL_RCC_TIM14_CLK_ENABLE();
    TIM14->PSC = (SYSCLK_HZ / 1000UL) - 1UL;
    TIM14->ARR = 1UL;
    TIM14->CNT = 0;
    TIM14->DIER |= TIM_DIER_UIE;
    NVIC_SetPriority(TIM14_IRQn, 2);
    NVIC_EnableIRQ(TIM14_IRQn);
    TIM14->CR1 |= TIM_CR1_CEN;
}
void TIM14_IRQHandler(void)
{
    if (TIM14->SR & TIM_SR_UIF) {
        TIM14->SR &= ~TIM_SR_UIF;
        WatchdogTIMER_1++;
    }
}
void TIM3_IRQHandler(void)
{
    if (TIM3->SR & TIM_SR_UIF) {
        TIM3->SR &= ~TIM_SR_UIF;
        timer_overflows++;
    }
}
/* ===================== IWDG ===================== */
void IWDG_Init(void)
{
    __HAL_RCC_LSI_ENABLE();
    while ((RCC->CSR & RCC_CSR_LSIRDY) == 0U) {
    }
    IWDG->KR = 0x5555;
    IWDG->PR = 0x04;
    IWDG->RLR = 2500U;
    IWDG->KR = 0xAAAA;
    IWDG->KR = 0xCCCC;
}
/* ===================== Flash state ===================== */
uint32_t CalculateChecksum(SystemState *state)
{
    uint32_t sum = 0;
    for (int i = 0; i < LED_COUNT; i++) {
        sum += state->led_states[i];
    }
    sum += state->reset_count;
    return sum;
}
void LoadSystemState(void)
{
    SystemState *flash_state = (SystemState *)FLASH_STATE_ADDR;
    if ((flash_state->magic == FLASH_MAGIC_VALUE) &&
        (flash_state->checksum == CalculateChecksum(flash_state))) {
        memcpy(&system_state, flash_state, sizeof(SystemState));
    } else {
        memset(system_state.led_states, 0, sizeof(system_state.led_states));
        system_state.reset_count = 0;
        system_state.magic = FLASH_MAGIC_VALUE;
        system_state.checksum = CalculateChecksum(&system_state);
        SaveSystemState();
    }
}
void SaveSystemState(void)
{
    HAL_StatusTypeDef status;
    FLASH_EraseInitTypeDef erase_init = {0};
    uint32_t page_error = 0;
    uint32_t *state_ptr = (uint32_t *)&system_state;
    system_state.checksum = CalculateChecksum(&system_state);
    system_state.magic = FLASH_MAGIC_VALUE;
    HAL_FLASH_Unlock();
    erase_init.TypeErase   = FLASH_TYPEERASE_PAGES;
    erase_init.PageAddress = FLASH_STATE_ADDR;
    erase_init.NbPages     = 1;
    status = HAL_FLASHEx_Erase(&erase_init, &page_error);
    if (status != HAL_OK) {
        HAL_FLASH_Lock();
        return;
    }
    for (uint32_t i = 0; i < (sizeof(SystemState) / 4U); i++) {
        status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
                                   FLASH_STATE_ADDR + (i * 4U),
                                   state_ptr[i]);
        if (status != HAL_OK) {
            break;
        }
    }
    HAL_FLASH_Lock();
}
/* ===================== LED ===================== */
void ApplyLedStates(void)
{
    for (int i = 0; i < LED_COUNT; i++) {
        HAL_GPIO_WritePin(GPIOA, led_pins[i],
                          system_state.led_states[i] ? GPIO_PIN_SET : GPIO_PIN_RESET);
    }
}
/* ===================== Reset cause ===================== */
void CheckResetCause(uint8_t *is_iwdg_reset)
{
    uint32_t reset_flags = RCC->CSR;
    *is_iwdg_reset = (reset_flags & RCC_CSR_IWDGRSTF) ? 1U : 0U;
    RCC->CSR |= RCC_CSR_RMVF;
}
/* ===================== GPIO ===================== */
void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_PIN_8  | GPIO_PIN_9  | GPIO_PIN_10 |
                          GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_GPIO_WritePin(GPIOA,
                      GPIO_PIN_8  | GPIO_PIN_9  | GPIO_PIN_10 |
                      GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_15,
                      GPIO_PIN_RESET);
}
/* ===================== Clock ===================== */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK |
                                  RCC_CLOCKTYPE_SYSCLK |
                                  RCC_CLOCKTYPE_PCLK1;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
        Error_Handler();
    }
}
/* ===================== Modbus CRC ===================== */
uint16_t Modbus_CRC16(const uint8_t *data, uint16_t len)
{
    uint16_t crc = 0xFFFFU;
    for (uint16_t pos = 0; pos < len; pos++) {
        crc ^= (uint16_t)data[pos];
        for (uint8_t i = 0; i < 8; i++) {
            if (crc & 0x0001U) {
                crc >>= 1;
                crc ^= 0xA001U;
            } else {
                crc >>= 1;
            }
        }
    }
    return crc;
}
/* ===================== Modbus RTU Master ===================== */
uint8_t Modbus_ReadHoldingRegisters(uint8_t slave_id, uint16_t start_addr, uint16_t quantity, uint16_t *dest)
{
    uint8_t tx[8];
    uint8_t rx[64];
    uint16_t crc;
    uint16_t expected_len;
    if ((quantity == 0U) || (quantity > 29U) || (dest == NULL)) {
        return 0;
    }
    tx[0] = slave_id;
    tx[1] = 0x03;
    tx[2] = (uint8_t)(start_addr >> 8);
    tx[3] = (uint8_t)(start_addr & 0xFF);
    tx[4] = (uint8_t)(quantity >> 8);
    tx[5] = (uint8_t)(quantity & 0xFF);
    crc = Modbus_CRC16(tx, 6);
    tx[6] = (uint8_t)(crc & 0xFF);
    tx[7] = (uint8_t)((crc >> 8) & 0xFF);
    UART_ClearRx();
    UART_SendBytes(tx, 8);
    expected_len = (uint16_t)(5U + (2U * quantity));
    if (!UART_ReceiveExact(rx, expected_len, TIMEOUT_MS)) {
        return 0;
    }
    if (rx[0] != slave_id) return 0;
    if (rx[1] & 0x80U) return 0;
    if (rx[1] != 0x03U) return 0;
    if (rx[2] != (uint8_t)(quantity * 2U)) return 0;
    crc = Modbus_CRC16(rx, expected_len - 2U);
    if ((rx[expected_len - 2U] != (uint8_t)(crc & 0xFF)) ||
        (rx[expected_len - 1U] != (uint8_t)((crc >> 8) & 0xFF))) {
        return 0;
    }
    for (uint16_t i = 0; i < quantity; i++) {
        dest[i] = ((uint16_t)rx[3U + (2U * i)] << 8) |
                  (uint16_t)rx[4U + (2U * i)];
    }
    return 1;
}
uint8_t Modbus_WriteSingleRegister(uint8_t slave_id, uint16_t reg_addr, uint16_t value)
{
    uint8_t tx[8];
    uint8_t rx[8];
    uint16_t crc;
    tx[0] = slave_id;
    tx[1] = 0x06;
    tx[2] = (uint8_t)(reg_addr >> 8);
    tx[3] = (uint8_t)(reg_addr & 0xFF);
    tx[4] = (uint8_t)(value >> 8);
    tx[5] = (uint8_t)(value & 0xFF);
    crc = Modbus_CRC16(tx, 6);
    tx[6] = (uint8_t)(crc & 0xFF);
    tx[7] = (uint8_t)((crc >> 8) & 0xFF);
    UART_ClearRx();
    UART_SendBytes(tx, 8);
    if (!UART_ReceiveExact(rx, 8, TIMEOUT_MS)) {
        return 0;
    }
    if (memcmp(tx, rx, 8) != 0) {
        return 0;
    }
    return 1;
}
/* ===================== main ===================== */
int main(void)
{
    uint8_t is_iwdg_reset = 0;
    uint32_t last_poll_time = 0;
    uint16_t src_value = 0;
    uint8_t heartbeat = 0;
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    RS485_Init();
    UART_Init();
    Timer_Init();
    WatchdogTimer_Init();
    IWDG_Init();
    CheckResetCause(&is_iwdg_reset);
    LoadSystemState();
    system_state.reset_count++;
    if (!is_iwdg_reset) {
        memset(system_state.led_states, 0, sizeof(system_state.led_states));
    }
    ApplyLedStates();
    SaveSystemState();
    while (1) {
        if (WatchdogTIMER_1 >= WatchdogTIMER_2) {
            IWDG->KR = 0xAAAA;
            WatchdogTIMER_1 = 0;
        }
        if ((millis() - last_poll_time) >= MODBUS_POLL_MS) {
            last_poll_time = millis();
            if (Modbus_ReadHoldingRegisters(MODBUS_SLAVE_ID, DWIN_VP_READ, 1, &src_value)) {
                if (Modbus_WriteSingleRegister(MODBUS_SLAVE_ID, DWIN_VP_WRITE, src_value)) {
                    heartbeat ^= 1U;
                    system_state.led_states[0] = heartbeat;
                    system_state.led_states[1] = 1;
                    system_state.led_states[2] = 0;
                } else {
                    system_state.led_states[1] = 0;
                    system_state.led_states[2] = 1;
                }
            } else {
                system_state.led_states[1] = 0;
                system_state.led_states[2] = 1;
            }
            ApplyLedStates();
        }
    }
}
/* ===================== Error ===================== */
void Error_Handler(void)
{
    __disable_irq();
    while (1) {
    }
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
    (void)file;
    (void)line;
}
#endif