Hardware:

SHT21 range and resolution:

The sensor’s temperature and humidity ranges are -40…125°C and 0…100%RH respectively, however the normal/useful range is given by the graph below.

Fig. 1 – SHT21 Operating Range

The sensor has multiple measurement resolutions for temperature and humidity, the data sheet stating a default resolution of 14bit (temperature) / 12bit (humidity) – we’ll see later how to check this and change it if needed.
Please note the measurement times as a function of measurement resolution – this will be helpful later when we need to decide the wait time between sending the measurement command to the sensor and reading the data.

Fig. 2 – SHT21 Resolution

Wiring:

MicroPython code:

from machine import Pin
from machine import SoftI2C
import time

scl = Pin('X9')
sda = Pin('X10')
bytes_read = bytearray(2)

# Sensor commands:
tMeasNoHold = b'\xF3'        # b11110011
RHMeasNoHold = b'\xF5'       # b11110101
ReadUserRegister = b'\xE7'   # b11100111

# I2C Header:
# The I2C header consists of the 7bit I2C device address ‘1000000’ and an SDA direction bit (Read R: ‘1’, Write W: ‘0’):
I2CHeader_Write = b'\x80' # b10000000
I2CHeader_Read = b'\x81'  # b10000001

# Start the I2C comms:
I2C = SoftI2C(scl, sda, freq=1000, timeout=50000)


def get_temp():
    # #######################################################
    # Send Write command, trigger a Temp measurement:

    # Transmission Start condition(S):
    I2C.start()

    # write the 2 bytes data frame (header + command).
    # The sensor indicates the proper reception of a byte by pulling the SDA pin low (ACK bit)
    # after the falling edge of the 8th SCL clock.
    noACKw = I2C.write(I2CHeader_Write + tMeasNoHold)
    print('Write command, No. of ACK bits: ',noACKw)

    # When using the no hold master mode it is recommended to include a wait period of 20 µs
    # after the reception of the sensor’s ACK bit and before the Stop condition.
    time.sleep_us(20)

    # Transmission Stop condition(P):
    I2C.stop()

    # #######################################################
    # Wait for the measurement to finish before reading the data:

    # For a 14bit resolution the max measuring time for temp is 85ms
    time.sleep_ms(85)

    # #######################################################
    # Read the measurement data:

    # Transmission Start condition(S):
    I2C.start()
    noACKr = I2C.write(I2CHeader_Read)
    print('Read command , No. of ACK bits: ', noACKr)

    # Read the data (2 bytes)
    I2C.readinto(bytes_read)

    # Transmission Stop condition(P):
    I2C.stop()

    # #######################################################
    # convert the binary data to something more meaningful using the formula in the SHT21 data sheet:

    t_SHT21 = (bytes_read[0] << 8) + bytes_read[1]
    t_SHT21 *= 175.72
    t_SHT21 /= pow(2,16)
    t_SHT21 -= 46.85

    # Debug:
    print ('***************************************************************')
    print ('bytes_read[0]: ', bin(bytes_read[0]))
    print ('bytes_read[0] shifted left by 8 bits: ', bin((bytes_read[0] << 8)))
    print ('bytes_read[1]: ', bin(bytes_read[1]))
    print ('Measurement data = : ', bin((bytes_read[0] << 8) + bytes_read[1]))
    print ('***************************************************************')

    return round (t_SHT21,2)

Logic analyser snapshots:

SCL frequency set to 1000Hz (see line 20):

I2C SCL frequency

Write command (see lines 25 … 41):

Wait for the measurement to finish:

Read the measurement data (see lines 49…61):

Quite a hot day:
The above logic analyser snaphots are corelated to the following get_temp() run: