Hardware:
- LC Tech STM32 Study Board – a copy (but not a clone) of the MicroPython pyboard. Great Scott has a (great) review of this board
- SHT21 module based on the Sensirion SHT21 I2C temperature and humidity sensor
- LHT00SU1 logic analyser
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.

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.

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):

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:


