1. Тема дня
UART/USART, RX через interrupt/DMA/ring buffer, RS-485 DE/RE, half-duplex, Modbus RTU timing. Главная мысль: UART - поток байтов; RS-485 добавляет управление направлением передачи.
2. Зачем это нужно в проектах
CLI, HIL через Raspberry Pi, EC25-like parser, RS-485/Modbus, промышленные модули, DMA/IDLE, watchdog-friendly архитектура.
3. Теория
Разделяй уровни:
UART/USART - периферия MCU.
RS-485 - физический дифференциальный интерфейс.
Modbus RTU - протокол поверх UART/RS-485.Polling-приём плох для production:
if (HAL_UART_Receive(&huart1, &b, 1, 10) == HAL_OK) {
parser_feed_byte(b);
}Лучше:
CLI/низкая скорость: interrupt per byte -> ring buffer
поток/Modbus: DMA circular RX + IDLE/timer -> parserInterrupt per byte:
static uint8_t s_rx_byte;
void uart_rx_start(void)
{
HAL_UART_Receive_IT(&huart1, &s_rx_byte, 1);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) {
ringbuf_put_from_isr(&uart1_rx_rb, s_rx_byte);
HAL_UART_Receive_IT(&huart1, &s_rx_byte, 1);
}
}RS-485 transceiver:
DI - MCU TX
RO - MCU RX
DE - driver enable
/RE - receiver enable
A/B - differential busDE нельзя выключать до последнего stop bit и нельзя держать слишком долго. Если MCU поддерживает аппаратный DE USART - лучше использовать его. Modbus RTU использует паузы:
t1.5 - пауза внутри кадра, кадр неполный
t3.5 - конец кадраДля baud > 19200 часто используют 750 us и 1.750 ms. Архитектура:
rs485_uart_driver -> rs485_link_service -> modbus_rtu_parser -> application4. Типичные ошибки
- Выключать DE сразу после записи байтов.
- Оставлять DE включённым слишком долго.
- Не обрабатывать ORE/FE/NE/PE.
- Делать Modbus RTU без таймеров.
- Давать application напрямую вызывать HAL_UART на bus UART.
- Игнорировать termination/bias/ESD/topology.
5. Практическое задание
Создай STM32_UART_RS485_POLICY.md.
typedef enum {
RS485_STATE_IDLE_RX = 0,
RS485_STATE_TX_ASSERT_DE,
RS485_STATE_TX_ACTIVE,
RS485_STATE_TX_WAIT_TC,
RS485_STATE_TURNAROUND,
RS485_STATE_WAIT_REPLY,
RS485_STATE_ERROR,
} rs485_state_t;
typedef struct {
uint32_t tx_frames;
uint32_t rx_frames;
uint32_t crc_errors;
uint32_t frame_timeouts;
uint32_t uart_ore;
uint32_t uart_fe;
uint32_t uart_ne;
uint32_t uart_pe;
uint32_t de_late_disable;
uint32_t rx_overflows;
uint32_t modbus_t15_violations;
uint32_t modbus_t35_detected;
} rs485_diag_t;6. Что почитать или попробовать дальше
STM32 HAL UART/USART, ST AN4113 RS-485 hardware DE, Modbus over Serial Line, DMA circular RX + IDLE examples.
Задание
При 9600 baud и формате 8E1 сколько длится символ? Вычислите 1.5 и 3.5 character times. Почему событие UART IDLE само по себе не доказывает конец Modbus RTU frame?
Критерии самопроверки: Покажите 11 bits, все три интервала и различие IDLE/RTU framing.
Показать ответ автора
8E1 содержит 1 start + 8 data + 1 parity + 1 stop = 11 bits. Tchar=11/9600≈1.146 ms; t1.5≈1.719 ms; t3.5≈4.010 ms. IDLE может обнаруживать более короткую паузу; для RTU нужен отдельный контроль требуемого silence interval.