← Back to CoursesStemExpert
StemExpert
Expert · Handboek · 37. Embedded systemen en IoT
StemExpert · Brecht Corbeel · schoolium.me
StemExpert
E37. Embedded systemen en IoT
EExpert · deel E7 · Informatica

Handboek · hoofdstuk 37Embedded systemen en IoT

Een verbonden sensor moet ook op tijd, zuinig en veilig blijven werken

De microcontroller moet een korte puls zien terwijl de Pi een netwerkverbinding herstelt. Je scheidt snelle lokale taken van vertraagbare telemetrie. Het ontwerp verbindt interrupts, bussen, MQTT, energie en toegangsbeheer in één controleerbaar netwerk.

9× uitleg4× uitgewerkt voorbeeld1× verhaal1× het geheel2× code11 opdrachten in het werkboek± 12 lestijden
Een draadloos netwerk verbindt onderdelen met verschillende timing- en energiebehoeften.
Een draadloos netwerk verbindt onderdelen met verschillende timing- en energiebehoeften.
Na dit hoofdstuk
Uitleg · 37.1

Interrupt of polling: wat kan je missen?

1/17

Polling ziet een ingang alleen wanneer de lus haar leest. Een puls van 1 ms kan volledig tussen twee reads van 50 ms vallen. Een interrupt legt de gebeurtenis meteen vast, maar stopt tijdelijk de gewone taak. De handler moet kort blijven: tel of zet een vlag; loggen, wifi, wachten en complexe berekeningen horen in de voorgrond.

volatile vertelt de compiler dat een waarde buiten de gewone control flow kan veranderen. Het maakt een 32-bit read op een 8-bit AVR niet atomair. De interrupt kan tussen twee byte-reads vallen; je krijgt een samengestelde waarde die nooit bestaan heeft. Kopieer in een korte kritieke sectie en herstel de eerdere interruptstatus in algemene librarycode. De eenvoudige lescode roept de sectie alleen vanuit de voorgrond aan waar interrupts vooraf actief zijn.

taakplaats
puls tellenISR, enkele instructies
toerental berekenenvoorgrond
MQTT publicerengatewaytaak
hardware-noodstoponafhankelijk elektrisch pad
Uitleg · 37.2

Timers en een vaste tijdschaal

2/17

Een hardwaretimer telt klokpulsen. Met 16 MHz en prescaler 64 wordt één tick 4 µs. Een 16-bit teller loopt dan na 65536 ticks, dus 262,144 ms, rond. Voor een compare-interval van 1 ms zijn 250 ticks nodig; bij tellen van 0 tot en met comparewaarde is het register 249. De timerconfiguratie hangt af van het bord en conflicteert soms met PWM of bibliotheken.

millis() geeft een modulo 32-tijd. Gebruik uint 32_t dt=nu-laatst, niet nu> laatst+periode. Unsigned aftrekken werkt over één rollover zolang de bedoelde tijdspanne korter is dan de tellercyclus. Een kalenderklok is voor logs, een monotone klok voor deadlines; NTP-correcties mogen geen actuatorvenster vooruit of achteruit springen.

timerresolutie
Uitgewerkt voorbeeld · 37.3

Turbinetoerental uit flanken

3/17
De generator heeft acht poolparen; één stijgende flank per elektrische periode wordt geteld.
Gegeven
  • 200 flanken in 5,000 s
  • n = 7,5 f (e19)
Gevraagd
  • Toerental en telresolutie
Oplossing
  1. 1
    f=200/5=40 Hz. Toerental n=7,5×40=300 tpm.
  2. 2
    Eén flank verandert f met 1/5=0,2 Hz en n met 1,5 tpm. Het telkwantisatie-effect wordt kleiner met een langer venster.
  3. 3
    Een 5 s-gemiddelde reageert traag op overtoeren. De lokale rembeveiliging gebruikt een apart snel, hardwarematig of getest periodemeetpad.
Antwoord
300 tpm; één-countresolutie 1,5 tpm.
Klopt dit? De telling is alleen correct na veilig laagspanningsconditioneren; de 59–223 V generatorlijn mag nooit op een ingang.
Code · 37.4

Een korte interrupt en een rollovervaste teller

4/17

De schets draait op een afzonderlijke turbinemonitor en hergebruikt geen bezette klimaatpin. De bron wordt tegen de gedeelde Arduino-stub gecompileerd. De stub controleert flanktelling en rollover, geen fysieke ISR-latentie.

C++ (Arduino)turbine_teller.ino27 regelsDownload
// Afzonderlijke turbinemonitor, niet de bestaande klimaatpin2 hergebruiken.#include <Arduino.h>#include <stdint.h>volatile uint32_t flanken = 0;uint32_t laatst = 0;void puls() { ++flanken; }void setup() {  pinMode(2, INPUT);  attachInterrupt(digitalPinToInterrupt(2), puls, RISING);  Serial.begin(115200);  laatst = millis();}void loop() {  uint32_t nu = millis();  uint32_t dt = nu - laatst;     // modulo32, robuust tegen millis-overloop  if (dt >= 5000UL) {    // Alleen voorgrond met interrupts vooraf aan; houd deze sectie kort.    noInterrupts();    uint32_t aantal = flanken;    flanken = 0;    interrupts();    laatst = nu;    float f = aantal * 1000.0f / dt;    Serial.print("pulsen="); Serial.print(aantal);    Serial.print(",tpm="); Serial.println(7.5f*f, 1);  }}

Getest scenario: 200 stijgende flanken gedurende 5 s geven pulsen=200, tpm=300.0; dezelfde telling over een millis-rollover geeft dezelfde uitvoer. De gemeten werkelijke dt, niet blind 5 s, staat in de deler.

Uitleg · 37.5

Real-time is een deadline, geen snelle gemiddelde laptop

5/17

Een hard real-time eis faalt zodra de deadline gemist wordt; een soft real-time eis tolereert aantoonbaar beperkte vertraging. Een noodstop mag niet van een gemiddelde MQTT-respons afhangen. De lokale regeltaak draait met vaste periode; de logger mag een korte achterstand bufferen, met een expliciete grens en meldgedrag.

Maak een taakbudget met worst-case uitvoeringstijd C, periode T en maximale blokkeertijd. kleiner dan 1 is noodzakelijk voor één CPU, maar bewijst niet dat een willekeurige scheduler alle deadlines haalt. Prioriteit, interrupts, niet-preëmptieve stukken en I/O blokkeren ook. In i40 duurde de langste gesimuleerde loop 48,8 ms; dat is bewijs voor dat scenario, geen universele worst-case grens.

voorbeeldtaakC modelTbijdrage
regelstap2 ms1000 ms0,002
sensorinlezen3 ms2000 ms0,0015
logbuffer5 ms1000 ms0,005

De modelbenutting is 0,0085 = 0,85 %. Een blokkerende wifi-connect van 2 s kan ondanks dit lage getal een 1 s-deadline missen.

Uitgewerkt voorbeeld · 37.6

Een UART-frame in het tijdsbudget

6/17
Een 8N1-UART verstuurt startbit, acht databits en stopbit.
Gegeven
  • 115 200 bit/s
  • bericht 120 bytes
Gevraagd
  • Minimale serialisatietijd
Oplossing
  1. 1
    Elk byte vraagt 10 bits; 120 bytes vragen 1200 bits.
  2. 2
    1200/115200=0,0104167 s = 10,42 ms.
  3. 3
    Dit is alleen draadserialisatie. Een softwarebuffer kan eerst kopiëren, maar de fysieke uitvoer loopt door; een volle buffer kan alsnog blokkeren.
Antwoord
10,42 ms vóór parsing, scheduling of hertransmissie.
Klopt dit? Baudrate is een lijnsnelheid, niet de snelheid waarmee de toepassing sensorrecords verwerkt.
Uitleg · 37.7

UART: twee richtingen, één elektrisch contract

7/17

UART is asynchroon: beide kanten stemmen baudrate en frame af. TX gaat naar RX en er is een gemeenschappelijke referentie, tenzij een geïsoleerde interface gebruikt wordt. Een Mega-uitgang van 5 V is niet automatisch veilig voor een 3,3 V-gateway. Gebruik geschikte niveauaanpassing; TTL-UART is geen RS-232 of RS-485.

Een eigen frame bevat versie, lengte, payload en checksum of CRC. Een regel met newline kan eenvoudiger zijn, maar krijgt een maximale lengte en parse-timeout. Negeer onbekende versies, meld beschadigde frames en resynchroniseer. Een CRC detecteert transmissiefouten; een aanvaller kan ook de CRC herberekenen, dus het is geen authenticatie. De bridge laat de bestaande lokale logger en regeling werken als zij uitvalt.

velddoel
versie/lengtebegrensd parsen
boot/seqherstart en duplicaten
meetmoment/kwaliteitleeftijd bepalen
CRCtoevallige transportfout
Uitleg · 37.8

I²C blijft een lokale bus

8/17

I²C gebruikt SDA en SCL met open-drain uitgangen en pull-ups. De stijgtijd groeit met buscapaciteit: ruwweg tᵣ≈0,8473RC tussen 30 en 70 % van de voedingsspanning. De NXP-specificatie geeft voor Standard-mode 100 kbit/s een stijgtijdgrens van 1000 ns. Lange kabels, parallelle pull-ups en verschillende spanningen moeten samen getoetst worden.

Behoud i30: SHT31 0x44, DS3231 0x68, INA226 0x40/0x41; e14 heeft ADS1115 0x48 en BME280 0x76 op zijn eigen luchtknoop. Twee sensoren met hetzelfde adres vragen een tweede bus, alternatief adres of multiplexer. Wifi vergroot het netwerkbereik zonder alle stationskabelcapaciteit aan één I²C-bus toe te voegen.

RC-stijgtijd van een open-drain bus
Uitgewerkt voorbeeld · 37.9

Pull-up en kabelcapaciteit

9/17
De effectieve pull-up is 1,8 kΩ en de gemeten buscapaciteit 400 p F.
Gegeven
  • Standard-mode grens tᵣ≤1000 ns
Gevraagd
  • Stijgtijd en ontwerpreserve
Oplossing
  1. 1
    tᵣ≈0,8473×1800×400×10⁻¹²=610 ns.
  2. 2
    Dat ligt 390 ns onder de grens. Bij 700 p F wordt het 1068 ns en faalt dezelfde berekening.
  3. 3
    Ook de sinkstroom bij laag niveau en de werkelijk gemeten golfvorm moeten passen; een RC-schatting vervangt de oscilloscoopcontrole niet.
Antwoord
610 ns bij 400 p F; lange stationsverbindingen krijgen een gateway in plaats van een onbegrensde I²C-verlenging.
Uitleg · 37.10

SPI: snelle lokale selectie

10/17

SPI gebruikt een klok, MOSI, MISO en per slave een selectielijn. Snelheid, clock polarity/phase en woordlengte worden per apparaat afgesproken. Er is geen algemeen ingebouwd adres- of afleverprotocol. Een deselected slave moet MISO vrijgeven; anders vechten twee uitgangen. Een SD-kaart kan tijdens schrijven lang bezig zijn, ook als de SPI-klok snel is.

Behoud de SD-interface van i30 op de Mega, met CS53. Schrijf eerst een begrensde RAM-buffer en plan flush/close; bij stroomuitval is wat alleen in RAM of de kaartcache zit niet gegarandeerd bewaard. Een vlotteralarm mag geen SD-write afwachten. Pas de buffer aan het 8 k B SRAM-budget van de Mega aan en leg verliesgedrag bij vol geheugen vast.

bussterktebeperking
UARTeenvoudige puntverbindingframe en levels zelf afspreken
I²Cveel lokale adressenRC en adresconflicten
SPIhoge lokale transfersnelheidselectielijnen en apparaatbusy
Uitleg · 37.11

Wifi en MQTT: transport plus betekenis

11/17

Wifi geeft een lokaal IP-netwerk; MQTT verbindt publishers en subscribers via een broker. De Pi host de lokale broker. Een topic als habitat/kas/telemetrie benoemt een stroom; habitat/module/setpoint benoemt een gecontroleerd voorstel. Een node krijgt alleen toegang tot eigen publicaties en toegestane commando's.

Qo S0 is hoogstens eenmaal; Qo S1 minstens eenmaal en dus mogelijk dubbel; Qo S2 levert eenmaal binnen het protocolpad met meer overhead. Geen niveau bewijst dat een fysieke pompbeurt precies eenmaal is uitgevoerd. Gebruik request-ID en applicatiebevestiging met aanvaard/weigering/voltooid. Retained bewaart de laatste payload voor latere subscribers: geschikt voor status mét leeftijd, gevaarlijk voor een oud startbevel. Commando's zijn hier niet retained en hebben een vervaltijd.

Kas / sensorknooplokale metingMega klimaatlokale actuatorenWifi-gatewaybuffer + TLSPi: MQTT-brokerACL + loggerUART lokaalwifiModel / predictorbegrensde voorstellenVeiligheid en regeling blijven lokaal bij netwerkuitval.
Telemetrie gebruikt het netwerk; noodstop en lokale regeling hebben geen broker nodig.
Code · 37.12

Berichtcontract en energiebudget toetsen

12/17

De validator is een offline applicatietest, geen volledige MQTT-client. Geauthenticeerde transportidentiteit, boot-ID, schema, volgnummer, bereik en leeftijd werken samen. Een nieuwe boot mag sequence 0 gebruiken; de broker moet de identiteit en sessie al hebben geauthenticeerd.

Pythonbericht_contract.py28 regelsDownload
import math class Ontvanger:    def __init__(self): self.volgnummer = {}    def verwerk(self, bericht, nu):        verplicht = {"node","boot","seq","tijd_s","temperatuur_C"}        if not verplicht <= bericht.keys(): return "schemafout"        if type(bericht["seq"]) is not int or bericht["seq"] < 0: return "sequencefout"        t,T = bericht["tijd_s"],bericht["temperatuur_C"]        if not all(type(x) in (int,float) and math.isfinite(x) for x in (t,T,nu)):            return "getalfout"        if not -30 <= T <= 60 or not 0 <= nu-t <= 90: return "oud/bereik"        sleutel=(bericht["node"],bericht["boot"])        if bericht["seq"] <= self.volgnummer.get(sleutel,-1): return "duplicaat/volgorde"        self.volgnummer[sleutel]=bericht["seq"]        return "aanvaard" r=Ontvanger()b={"node":"kas","boot":"sessie-a","seq":12,"tijd_s":100,"temperatuur_C":21.1}for bericht,nu in [(b,101),(b,102),(dict(b,seq=13),200),                   (dict(b,boot="sessie-b",seq=0,tijd_s=201),202)]:    print(r.verwerk(bericht,nu))actief=120.0  # mA, gemeten ontwerpaanname voor hele knooprust=0.05    # mA, inclusief regelaar en lekstromen in rekenmodelI=(actief*2+rust*58)/60print("gemiddelde",round(I,3),"mA")print("2000mAh, 80pct bruikbaar",round(1600/I/24,1),"dagen")assert abs(I-4.048333333)<1e-7
aanvaard
duplicaat/volgorde
oud/bereik
aanvaard
gemiddelde 4.048 mA
2000mAh, 80pct bruikbaar 16.5 dagen
Uitleg · 37.13

Slaap kost ook tijd en verbinding

13/17

Een telemetrieknoop kan 2 s actief zijn en 58 s slapen. Met de expliciete rekenwaarden 120 m A actief en 0,05 m A rust is gemiddeld 4,048 m A. Een batterij van 2000 m Ah met 80 % bruikbaar houdt in dat model 16,47 dagen, vóór zelfontlading, kou en regelaarverlies. Gebruik stroommetingen van het hele bord: een powerled of USB-omzetter kan de chipwinst tenietdoen.

Bij deep sleep van de ESP32 wordt veel toestand uitgezet en blijft wifi niet gewoon verbonden. Ontwaken, DHCP, TLS en publiceren kosten tijd en energie. Reken per cyclus de werkelijke herverbinding mee. Een vaste veiligheidssensor met snelle deadline mag daarom niet dezelfde slaapstrategie gebruiken als een buitenweerlogger. Voed alarm- en regelknopen vast; slaap alleen waar gemiste tussenmetingen verantwoord zijn.

energie per meetcyclus
Uitgewerkt voorbeeld · 37.14

Buffer bij een netwerkgat

14/17
Een knoop maakt elke minuut een record van 96 bytes. Wifi kan 2 h wegvallen.
Gegeven
  • 120 records
  • 20 % reserve
Gevraagd
  • Buffer en terughaalgedrag
Oplossing
  1. 1
    120×96=11520 bytes payload. Met 20% reserve is 13 824 bytes nodig, zonder object- en bestands overhead.
  2. 2
    Dit past niet in 8 k B SRAM van de Mega. De gateway bewaart lokaal op flash of kaart en houdt de Mega-interface klein.
  3. 3
    Na reconnect stuur je oude records naar archief mét oude tijd, niet als verse regelmeting. Begrens replay zodat actuele meldingen niet verdrongen worden.
Antwoord
Minimaal 13,8 k B als rekenbudget; kies een gatewaybuffer met apart metadata- en slijtagebudget.
Uitleg · 37.15

Beveiliging begint bij bevoegdheden

15/17

TLS beschermt transport vertrouwelijkheid en integriteit en controleert het certificaat van de peer. Certificaatcontrole uitzetten om een klokfout te omzeilen verwijdert een kernbescherming. Geef elke knoop een eigen credential, beperkte ACL en een intrekbaar updatepad. Een gedeeld wachtwoord op alle nodes maakt één verloren sensor een stationsincident.

Minimale toegang, veilige updates, inventaris, logbare wijzigingen en herstel horen bij het ontwerp. Firmware-updates worden ondertekend of anders aantoonbaar geauthenticeerd; test een mislukte update en terugrol. Een MQTT-payload is onbetrouwbare invoer: stel maximale grootte, vaste schema's en bereik in, voer er geen code uit. Koppel het sensornet van gastenwifi; toegang tot een topic is geen recht om de hardware-noodstop te wijzigen.

dreigingmaatregeltest
spoof sensoreigen credential + ACLvreemde node publiceert geweigerd
replay commandoID+verval+ackoud bevel geweigerd
malformed payloadschema/limietenNaN en oversize testen
updatefoutauthenticatie+rollbackstroomuitval tijdens update
Verhaal · 37.16

Een protocolstandaard is een bruikbaar verhaal

16/17

OASIS definieert MQTT als publish/subscribe-berichtprotocol en benoemt de drie Qo S-niveaus en retained-gedrag. De standaard beschrijft aflevering, niet de veiligheid van een klimaatregeling. Espressif beschrijft slaapmodi en de gevolgen voor wifi. Juist die grenzen maken standaarden bruikbaar: ze vertellen wat je wel uit het transport mag afleiden en welk deel van het contract nog jouw verantwoordelijkheid blijft.

Primaire bronnen, geraadpleegd 30-09-2026: OASIS MQTT5, NXP UM10204, Microchip ATmega 2560, ESP32 slaapmodi en ESP-MQTT.

standaardapplicatie blijft ontwerpen
MQTTactie-ID en procesveiligheid
I²Ckabelbudget en adressen
MCUdeadline en taakbudget
Het geheel · 37.17

Het netwerk ondersteunt het lokale brein

17/17

De elektronische bus, softwareinterface en systeemarchitectuur moeten dezelfde tijd- en foutafspraken gebruiken. Sensorfusie krijgt kwaliteit en leeftijd; AI krijgt historische data; veiligheid krijgt een zelfstandig pad.

Bussen, adressen en UTC+1-logs blijven behouden.

Toerental uit generatorfrequentie.

Adapters met een tijd- en foutcontract.

Data veroudert en kan uitvallen.

Habitat

Voor Habitat: lokale MQTT-broker op Pi, wifi-gateways, MQTT5 waar ondersteund, telemetrie elke 60 s met leeftijdgrens 90 s voor de centrale monitor. Dit vervangt geen snelle lokale regeling. Qo S1 met boot/seq; commando's niet retained, voorzien van ID en verval. Alarm- en regelknopen blijven vast gevoed; turbinefrequentie wordt met 5 s-vensters gelogd, met aparte snelle beveiliging.

Samenvatting

In het kort

Begrippen

Wat je nu kent

interrupt
Een gebeurtenis die de processor een korte handler laat uitvoeren buiten de gewone programmalus.
deadline
Het laatste tijdstip waarop een resultaat nog aan zijn eis voldoet.
Qo S
De afgesproken MQTT-afleverwijze voor een bericht.
idempotent
Een bewerking waarvan herhaling niet nogmaals hetzelfde effect veroorzaakt.
ACL
Regels die bepalen welke identiteit op welke topics mag lezen of schrijven.
Aan de slag in het werkboek11 opdrachten, van oefenen tot uitdagen