STM32F103通过UART中断无法接收数据问题求助
Alright, let's dig into why your STM32F103 BluePill isn't receiving data via UART interrupt when talking to the Eastron SDM630 over Modbus RS485. I've worked through similar issues before, so here's a step-by-step breakdown of the most likely culprits and how to check them:
1. Nail Down RS485 DE/RE Control Timing
The PA8 pin handling DE/RE is critical here—if you don't toggle it correctly, your RS485 module might stay stuck in transmit mode, blocking incoming data entirely.
- Key check: After sending your Modbus request, you need to set PA8 low to switch to receive mode, and this has to happen after the last byte finishes transmitting.
- Add a check for the transmission complete (TC) flag before toggling the pin—don't rely solely on the
HAL_UART_Transmitreturn. Here's a quick snippet to illustrate:// Send your Modbus request frame HAL_UART_Transmit(&huart1, tx_buffer, tx_frame_length, HAL_MAX_DELAY); // Wait for the final byte to leave the UART while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET); // Switch RS485 to receive mode HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); // Now enable the receive interrupt HAL_UART_Receive_IT(&huart1, rx_buffer, expected_response_length);
2. Verify UART Interrupt & NVIC Configuration
If the interrupt never fires, your configuration is off somewhere:
- In CubeMX, double-check that USART1 Global Interrupt is enabled under the NVIC Settings tab.
- Ensure the RXNE (Receive Data Register Not Empty) interrupt is enabled. For HAL, this is usually handled when you call
HAL_UART_Receive_IT, but you can manually confirm the register:USART1->CR1 |= USART_CR1_RXNEIE; - Check interrupt priorities: Don't set USART1's priority lower than critical system interrupts, but also make sure it isn't getting starved by higher-priority interrupts that run constantly.
3. Validate Hardware Wiring & RS485 Setup
Bad wiring is one of the most common offenders here:
- RS485 A/B Lines: Confirm you've connected A to A and B to B between the module and SDM630—reversing these will cause garbage data or no response at all.
- Termination Resistor: If your cable run is longer than a few meters, enable the 120Ω termination resistor on your RS485 module (many have a physical switch for this). This prevents signal reflections that can corrupt data.
- Pin Connections: Double-check that PA9 (USART1 TX) goes to the RS485 module's DI pin, PA10 (USART1 RX) to RO, and PA8 is wired to DE/RE. Also confirm PA8 is set as a push-pull output in your GPIO config.
- Power: Make sure the RS485 module is getting a stable 5V supply—fluctuations here can break communication.
4. Test with Polling First to Isolate the Issue
To rule out whether the problem is with interrupts or the communication itself, switch to polling-based reception temporarily:
// Set RS485 to receive mode HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); // Try receiving with a timeout if(HAL_UART_Receive(&huart1, rx_buffer, expected_response_length, 1000) == HAL_OK) { // Print the received data via USART3 for debugging HAL_UART_Transmit(&huart3, rx_buffer, expected_response_length, HAL_MAX_DELAY); }
- If polling works, the issue is definitely with your interrupt setup. If polling also fails, the problem is in hardware, wiring, or your Modbus request format.
5. Check Your Modbus Request Frame
The SDM630 won't respond if your Modbus RTU frame is invalid:
- Confirm the slave address (default is 1 unless you've reconfigured the meter).
- Use the correct function code (e.g., 0x03 for reading holding registers).
- Double-check the register address and quantity you're requesting.
- Ensure you're appending the correct CRC16 checksum to the end of the frame.
- Use a USB-RS485 adapter and tool like Modbus Poll to monitor the bus—verify your STM32 is sending a valid frame, and that the SDM630 is actually responding. If the meter doesn't send a response, your request is incorrect.
6. Debug the Interrupt Callback
Add debug output to your interrupt callback to confirm if it's even being called:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { // Send a debug message over USART3 to confirm the interrupt fired uint8_t debug_msg[] = "USART1 Receive Interrupt Triggered!\r\n"; HAL_UART_Transmit(&huart3, debug_msg, sizeof(debug_msg), HAL_MAX_DELAY); // Re-enable the interrupt for the next reception HAL_UART_Receive_IT(&huart1, rx_buffer, expected_response_length); } }
- If you never see the debug message, go back to checking NVIC and interrupt enables. If you do see it but the data is garbage, confirm your UART settings match the SDM630: 9600 baud, 8 data bits, 1 stop bit, no parity.
内容的提问来源于stack exchange,提问作者X16

