ESP32 MicroPython UART Testing

1. Key Points of UART Hardware Resources and Configuration

  1. UART Resources of ESP32ESP32 supports 3 UART controllers (UART0, UART1, UART2), but actual availability is limited by pin conflicts:

  • UART0: Default for REPL debugging (flashing and serial monitoring), using GPIO1 (TX), GPIO3 (RX)
  • UART1: Some development boards connect to external Flash/SD cards (conflicts should be avoided), default GPIO9 (TX), GPIO10 (RX)
  • UART2: Recommended for use, can freely map pins
  • Pin Mapping Flexibility Customizable pin mapping through <span>tx</span> and <span>rx</span> parameters

    from machine import UART
    uart = UART(2, baudrate=115200, tx=17, rx=16) # Map UART2 to GPIO16 (RX), GPIO17 (TX)
    
  • ESP32 MicroPython UART Testing

    2. Detailed Explanation of Core Functions

    1. Constructor

    <span>UART(id, baudrate, bits, parity, rx, tx, stop, timeout)</span>

    Parameter Description Common Values
    <span>id</span> Serial port number 1 (UART1), 2 (UART2)
    <span>baudrate</span> Baud rate 9600, 115200 (default)
    <span>bits</span> Data bit length 8 (default), 7, 9
    <span>parity</span> Parity method None (default), 0 (even), 1 (odd)
    <span>rx/tx</span> Receive/Send GPIO pin number e.g., 16, 17
    <span>stop</span> Stop bits 1 (default), 2
    <span>timeout</span> Read timeout (milliseconds) 10 (default)

    ESP32 MicroPython UART TestingFunction IntroductionESP32 MicroPython UART Testing

    2. Data Read and Write Methods

    Function Function Description Example
    <span>uart.read(n)</span> Read n bytes, returns<span>bytes</span> object <span>data = uart.read(10)</span>
    <span>uart.readline()</span> Read a line (ends with<span>\n</span>) <span>line = uart.readline()</span>
    <span>uart.readinto(buf)</span> Read data into buffer <span>buf = bytearray(10); uart.readinto(buf)</span>
    <span>uart.write(buf)</span> Send byte data <span>uart.write(b'ABC')</span>
    <span>uart.any()</span> Returns the number of bytes available to read <span>if uart.any(): ...</span>
    <span>uart.deinit()</span> Close UART and release resources <span>uart.deinit()</span>

    ESP32 MicroPython UART Testing

    <span>uart.any()</span>: Returns an integer that counts the number of characters that can be read without blocking. If no characters are available, it returns 0; if there are characters, it returns a positive number. Even if multiple characters are available, this method may return 1.ESP32 MicroPython UART Testing

    3. Test Code Example

    1. Testing

    from machine import UART, Pin
    import time
    
    # Initialize UART communication interface
    # Use UART2 (ESP32 supports UART0/1/2)
    # Set baud rate to 115200 (bit rate for data transmission speed)
    # Specify GPIO16 as the send pin (TX), GPIO17 as the receive pin (RX)
    uart = UART(2, baudrate=115200, tx=16, rx=17)
    
    # Loopback test function: send back the received data as is
    def echo_test():
        print("UART loopback test started. Type something and press Enter to send.")
        while True:
            # Check if there is data to read
            if uart.any():
                # Read all available byte data
                data = uart.read()
                # Print the received data in REPL (for debugging)
                print(f"Received: {data}")
                # Send the received data back (loopback function)
                uart.write(data)
                if data.decode() == "end":
                    break;
            # Short delay to avoid high CPU usage
            time.sleep(0.1)
    
    # Automatic test function: send preset data and verify reception, short-circuit for send/receive
    
    def auto_test():
        # Define test data (byte type)
        test_data = b'Hello, UART!\r\n'
        # Display the sent test data in REPL
        print(f"Sending test data: {test_data}")
        # Send test data via UART
        uart.write(test_data)
    
        # Wait enough time for data transmission and return (0.5 seconds)
        time.sleep(0.5)
    
        # Check if there is response data
        if uart.any():
            # Read response data
            received = uart.read()
            # Display the received data in REPL
            print(f"Received: {received}")
            # Verify if the received data matches the sent data
            if received == test_data:
                print("Test passed!")  # Test success message
            else:
                print("Test failed!")  # Test failure message
        else:
            print("No response received!")  # No response message
    
    # Execute automatic test (run once at program startup)
    auto_test()
    
    # Start loopback test (enter infinite loop after automatic test)
    echo_test()
    

    Wiring Instructions: Connect GPIO16 and GPIO17 of the ESP32 with Dupont wires.

    ESP32 MicroPython UART Testing

    2. Reading Modbus RTU Devices (Temperature and Humidity Sensor)

    from machine import UART
    import ustruct  # Structure parsing library for parsing binary data
    
    # Initialize UART2 interface, connected to RS485 module
    # Baud rate 9600 (matching the sensor)
    # TX pin GPIO16 (sending data)
    # RX pin GPIO17 (receiving data)
    uart = UART(2, baudrate=9600, tx=16, rx=17)
    
    # Modbus RTU protocol request frame
    # [Slave address, Function code, Start register address high byte, Start register address low byte, Register count high byte, Register count low byte, CRC check low byte, CRC check high byte]
    modbus_cmd = bytes([0x02, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x38])
    
    # Function to read temperature and humidity sensor data
    def read_sensor():
        uart.write(modbus_cmd)  # Send Modbus request
        utime.sleep_ms(200)  # Wait for sensor response (200 milliseconds)
    
        # Check if enough bytes are received (complete response at least 7 bytes)
        if uart.any() >= 7:
            res = uart.read(7)  # Read 7 bytes of response data
    
            # Parse temperature value (register 0)
            # res[3:5] is temperature data (2 bytes) temperature value at index 3-4
            # '>h' indicates big-endian signed short (16 bits)
            # Dividing by 10.0 because the sensor precision is 0.1°C
            temp = ustruct.unpack('>h', res[3:5])[0] / 10.0
    
            # Parse humidity value (register 1)
            # res[5:7] is humidity data (2 bytes) humidity value at index 5-6
            hum = ustruct.unpack('>h', res[5:7])[0] / 10.0
    
            return temp, hum  # Return temperature and humidity tuple
        return None  # Return None if insufficient data received
    
    # Main loop: read sensor data every 2 seconds
    while True:
        result = read_sensor()  # Call read function
        if result:  # If successfully read data
            # Format output temperature and humidity values
            print(f"Temperature: {result[0]}°C, Humidity: {result[1]}%")
        utime.sleep(2)  # Wait 2 seconds before reading again
    

    4. Common Problem Solutions

    1. Incomplete data reception (single character not string)Reason:<span>read()</span><span> defaults to reading 1 byte.</span><strong><span>Solution</span></strong><span>: Use </span><code><span>read(n)</span><span> to specify length or </span><code><span>readline()</span><span> to read a line:</span>

      data = uart.readline()  # Read a whole line
      
    2. UART resource conflict error

      E (214129) uart: UART driver already installed
      

      Solution: Call <span>uart.deinit()</span><span> to release resources before reusing.</span>

    3. End character recognition failureReason: Serial screen requires binary end character.Correct usage:

      uart.write(b"n0.val=100\xff\xff\xff")  # Correct: binary send
      uart.write("n0.val=100\xff\xff\xff")  # Incorrect: text escape invalid
      
    4. Pin conflict suggestions

    • Avoid using UART0 (debug occupied)
    • Default pins GPIO9/10 of UART1 may connect to Flash, recommended to remap:
      uart = UART(1, tx=17, rx=16)  # Remap to GPIO16/17
      
    • Flow control: RTS/CTS must be enabled when setting <span>rtx</span> and <span>cts</span> parameters
    • Large data volume: Increase <span>timeout</span> or use <span>readinto()</span><span> to avoid data loss</span>
    • Multiple devices: RS485 requires enabling pin control for send/receive direction (requires additional GPIO)

    References

    http://www.micropython.com.cn/en/latet/esp32/quickref.html#uart-serial-bus

    https://docs.micropython.org/en/latest/library/machine.UART.html

    https://developer.quectel.com/doc/quecpython/API_reference/zh/peripherals/machine.UART.html

    Leave a Comment