Les 3 · Module 1 · De ESP32 als sensorknooppunt
Sensoren via I2C
Sluit een SHT31-sensor aan op de I2C-bus van je ESP32, scan adressen, schrijf zelf een kleine driver die temperatuur en luchtvochtigheid uitleest, en controleer de CRC.
🎯 Na deze les kun je
- een I2C-sensor correct aansluiten op de ESP32
- de I2C-bus scannen en adressen herkennen
- een eenvoudige driver schrijven uit het datasheet
- meetwaarden controleren met een CRC en fouten afhandelen
Het meetstation begint bij de sensor. De SHT31 meet temperatuur en relatieve luchtvochtigheid nauwkeurig en praat via I2C: een bus met twee draden waarop meerdere apparaten kunnen zitten, elk met een eigen adres. In les 5 zet je het scherm op dezelfde bus.
Aansluiten
| SHT31 | ESP32 |
|---|---|
| VIN | 3V3 |
| GND | GND |
| SCL | GPIO 22 |
| SDA | GPIO 21 |
Gebruik 3,3 V, niet 5 V: de ESP32-pinnen zijn niet 5V-tolerant. De meeste breakoutbordjes hebben al pull-up-weerstanden op SDA en SCL.
De bus scannen
from machine import I2C, Pin
i2c = I2C(0, scl=Pin(22), sda=Pin(21), freq=100_000)
print([hex(a) for a in i2c.scan()])
Voorspel eerst: welk adres verwacht je, en wat zie je als een draad los zit?
Uitkomst
['0x44']: het standaardadres van de SHT31 (met de ADDR-pin aan VIN wordt het 0x45). Zit SDA of SCL los, dan krijg je []. Zijn SDA en SCL
omgewisseld, ook []. Een lege lijst betekent dus bijna altijd: bedrading. Zie je tientallen adressen, dan ontbreken pull-ups of zit er
een kortsluiting.
Het datasheet lezen
Voor één meting (single shot, high repeatability) zegt het datasheet van de SHT31:
- Stuur het commando
0x24 0x00. - Wacht minstens 15 ms.
- Lees 6 bytes: temperatuur (2 bytes + CRC), vochtigheid (2 bytes + CRC).
- Reken om:
T = -45 + 175 × raw / 65535°C enRH = 100 × raw / 65535%.
Een driver
lib/sensor.py:
import time
from micropython import const
_ADRES = const(0x44)
def _crc8(data):
crc = 0xFF
for b in data:
crc ^= b
for _ in range(8):
crc = ((crc << 1) ^ 0x31) & 0xFF if crc & 0x80 else (crc << 1) & 0xFF
return crc
class SensorFout(Exception):
pass
class SHT31:
def __init__(self, i2c, adres=_ADRES):
self.i2c = i2c
self.adres = adres
if adres not in i2c.scan():
raise SensorFout("SHT31 niet gevonden op 0x%02x" % adres)
def lees(self):
self.i2c.writeto(self.adres, b"\x24\x00")
time.sleep_ms(16)
d = self.i2c.readfrom(self.adres, 6)
if _crc8(d[0:2]) != d[2] or _crc8(d[3:5]) != d[5]:
raise SensorFout("CRC klopt niet")
t_raw = d[0] << 8 | d[1]
rh_raw = d[3] << 8 | d[4]
temp = -45 + 175 * t_raw / 65535
rv = 100 * rh_raw / 65535
return temp, rv
Gebruik:
from machine import I2C, Pin
from sensor import SHT31
s = SHT31(I2C(0, scl=Pin(22), sda=Pin(21)))
print("%.2f °C %.1f %%" % s.lees())
De CRC (een controlegetal) vangt bitfouten op door storing of lange draden. Een driver zonder CRC-controle geeft bij storing stilletjes rare waarden, bijvoorbeeld 130 °C.
Fouten afhandelen
I2C kan OSError: [Errno 19] ENODEV of ETIMEDOUT geven als de sensor even niet antwoordt. In main.py:
try:
temp, rv = s.lees()
except (OSError, SensorFout) as e:
print("meting mislukt:", e)
temp = rv = None
Een meetstation dat bij één mislukte meting crasht, is niet bruikbaar. In les 16 bouw je hier een volledig herstelpad omheen.
Typische fouten
OSError: [Errno 19] ENODEV: niets op dat adres; bedrading of verkeerd adres.- Temperatuur te hoog: de sensor zit vlak naast de ESP32, die warm wordt. Zet hem een paar centimeter verder, of aan een kabel.
- Andere pinnen: niet elk bord gebruikt 21/22 voor I2C. Elke GPIO met invoer/uitvoer kan; geef ze op bij
I2C(...).
Oefenen
- Sluit de SHT31 aan en scan de bus.
- Schrijf
lib/sensor.pyen lees elke 2 seconden temperatuur en vochtigheid. - Adem op de sensor. Wat gebeurt er met beide waarden, en hoe snel?
- Test de CRC-controle door in de code tijdelijk één byte te wijzigen (
d = bytearray(d); d[1] ^= 1). Wat gebeurt er?
Modelantwoord oefening 1
[0x44]. Zie je niets: controleer 3V3/GND en wissel SDA/SCL om.
Modelantwoord oefening 2
import time
from machine import I2C, Pin
from sensor import SHT31
s = SHT31(I2C(0, scl=Pin(22), sda=Pin(21)))
while True:
t, rv = s.lees()
print("%.2f °C %.1f %%" % (t, rv))
time.sleep(2)
Modelantwoord oefening 3
De luchtvochtigheid springt binnen een paar seconden naar 80–100%, de temperatuur stijgt een paar graden. Daarna zakken ze langzaam terug: de sensor reageert snel op stijgen, maar het opdrogen kost tientallen seconden. Daar heb je in les 4 iets aan.
Modelantwoord oefening 4
SensorFout: CRC klopt niet. Haal de wijziging daarna weer weg.
Lokaal oefenen
Geen live lab: je hebt de echte sensor nodig. Heb je nog geen sensor, schrijf dan een NepSensor-klasse met dezelfde lees()-methode die
willekeurige waarden geeft, zodat je verder kunt.
Samenvatting
- I2C: twee draden, apparaten met een adres; altijd 3,3 V.
scan()is je eerste diagnose: leeg = bedrading.- Een eigen driver uit het datasheet: commando, wachten, lezen, omrekenen, CRC.
- Vang sensorfouten op; één mislukte meting mag niet crashen.
- Volgende les: meten, filteren en kalibreren.