Arduino Nano Oven-controller

Keramiek-oven controller met de Arduino nano
Concept-schema (uiteindelijke schema is hier en daar wat anders)

Zoals al gemeld op mijn algemene Arduino-pagina, mijn regelaar voor mijn keramiek-oven mocht wel eens een update gebruiken. Het was een schakeling met discrete logica en een draaiknop voor het energieniveau. In plaats daarvan is het nu meer als in mijn plaatje hiernaast, met een 4-cijferig display voor temperatuur (tot 1250 graden) en wat drukknopjes voor de invoer. De Arduino Nano zorgt voor de tijd, programma-stap en zo voort. Op die manier hoef ik de oven niet meer zelf in de gaten te houden, maar neemt de Nano het stappenplan (zoals in de grafiek onderaan de pagina over de oude controller) over. Dat was het idee; nu de uitvoering...

De eerste stap is het opzetten van voorlopige hardware om de software te kunnen maken. Een prototype-bordje, plus het display, een bordje met knopjes dat ik nog had liggen, en een LED in plaats van de uiteindelijke SSR (Solid State Relais) zodat ik kan zien wanneer en hoe hard de oven aan gaat staat. Dit is nog een versie zonder temperatuurmeting: eigenlijk de oude regeling maar dan met een automatisch afspelende programma's voor verschillende temperatuur-profielen. Zo moet de eerste keer bakken altijd heel geleidelijk gaan, de tweede bak met glazuur mag sneller (zie de oven-pagina).

De opbouw

Oven controller prototype
Prototype board met de eerste opzet
Display: "P=01", programma 1.

Display (€3 bij dx.com) is blijkbaar toch niet echt I2C-compatible... Dus toch maar op twee andere pinnen aansluiten. Gelukkig heeft 'avishorp' al een goede Arduino library voor de TM1637 geschreven: werkt in een keer, en in de zip download zit ook de English datasheet (niet alleen de Chinese versie)! Dankzij het 'character designer' spreadsheet van JosePino kan ik ook tekst makkelijk weergeven, niet alleen getallen.

Knopjes uitlezen is makkelijker, zitten direct op de I/O pinnen. Waar je wel op moet letten is de 'contact-dender'; schakelaars en drukknoppen kunnen met indrukken een paar keer 'stuiteren' en dus in korte termijn meerdere pulsjes geven. Ik los dit op door ze meerdere keren te lezen (met een kleine pauze er tussen), en pas een signaal te geven als de waarde stabiel is.

Eindresultaat van de ovencontroller
En zo ziet het ingebouwde resultaat er uit
(teruggeplaatst in het oude kastje).
Display: "E=10", energieniveau 10 van de 16.

Voor de veiligheid heb ik ook de watchdog-timer gebruikt: als de processor crasht (niet vanwege een softwarefout, maar door bijvoorbeeld spanningspieken tijdens het schakelen) schakelt de oven automatisch na twee seconden uit... Safety first!

Het geheel is vrij compact (eigenlijk alleen een nieuw frontje met 2 cm elektronica er achter, het prototype bordje zelf is uiteraard niet ingebouwd), en ik heb het weer in mijn oude kastje terug kunnen plaatsen, de voeding en het SSR is hergebruikt. Moest wel een nieuw frontje maken uit een stukje plexiglas dat ik nog had.

De timing

De 50Hz op INT0 is op het proto-board nog niet aangesloten, in plaats daarvan gebruik ik de TimerOne library om daarmee 50Hz te maken (maakt het testen makkelijker). In de uiteindelijke software test ik tijdens het opstarten of er van buitenaf 50 Hz binnenkomt (want gaat de interrupt-teller omhoog), zo niet dan maak ik zelf de 50 Hz met de timer; zie de voorbeeldcode hieronder. Onderstaande code komt uit mijn Arduino setup() functie, die bij het opstarten wordt aangeroepen.

// Externe interrupt op de INT0PIN met de 50Hz: de routine verhoogt 'clkToProcess'
  attachInterrupt(digitalPinToInterrupt(INT0PIN), myIntHandler, RISING);

  display.setSegments(str2seg(segBuf1, "boot"));
  delay(1000);                 // 1 seconde wachten (op display de tekst 'boot')

// Is er 50Hz gevonden (is de teller opgehoogt)? Zo niet: maak zelf 50 Hertz
  if(clkToProcess == 0)        // Geen interrupts gezien op INT0?
  {                            // Dan omschakelen naar de interne timer
    detachInterrupt(digitalPinToInterrupt(INT0PIN));
    display.setSegments(str2seg(segBuf1, "no50"));
    delay(1000);
    Timer1.initialize(20000);  // Zet de timer op 20000 microseconds = 50 Hz
    Timer1.attachInterrupt( myIntHandler ); // interrupt routine op deze timer
    no50Hz = true;             // Even onthouden dat we niet echt 50 Hz hebben
  }

In de interrupt routine zelf gebeurt overigens meer dan alleen het ophogen van de teller (hier niet weergegeven), zo worden ook de toetsen hier gelezen en verwerkt, en wordt het Solid State Relais aan- en uitgezet. Maar in een interrupt-routine wil je in het algemeen zo min mogelijk doen, al is het hier bij de oven niet kritisch. Het 'grove' werk heb ik daarom nooit in de interrupt-routine, maar gewoon in het hoofdprogramma zitten.

De interrrupt-routine wordt elke 20 milliseconde (50 Hz) aangeroepen. Ik deel dat door 5 (met behulp van de clkTicks variabele), en elke 100 milliseconde verhoog ik de variabele clkToProcess. Die wordt in het hoofdprogramma gebruikt om te kijken of er weer wat moet gebeuren, en om de tijd bij te houden. Vooral clkToProcess moet als 'volatile' gedefinieerd worden, zodat de compiler weet dat deze terwijl het hoofdprogramma loopt zomaar in de interrupt-routine gewijzigd kan worden!

volatile uint8_t clkTicks = 0;
volatile uint8_t clkToProcess = 0;// openstaande process requests

void myIntHandler(void)        // in setup() aan de interrupt gekoppeld
{
    clkTicks++;                // at 10 Hz (every 5 ticks) update clkToProcess
    if(clkTicks == 5) { clkTicks = 0; clkToProcess++; }

    ... doe de SSR aan/uit-regeling ... // voor het voorbeeld verwijderd
    ... doe de toetsenbord-scan ...
}

void loop()                    // Arduino 'main()' functie
{
    if(clkToProcess)           // is er een 100 ms clock-tick geweest?
    {
      --clkToProcess;          // verlaag de teller (is er een afgehandeld)
      ... en verder ...

En dan...

De volgende stap wordt (denk ik) het aansluiten van mijn thermo-koppel. Ik kan hier natuurlijk zelfs een versterkertje voor maken (thermokoppel-signalen zijn te zwak om gelijk op de Arduino aan te sluiten, 41 µV per °C), maar ik denk dat ik maar ga voor de kant-en-klare Adafruit module met de MAX31856. Zit een voorversterker in, maar ook linearisatie, 50-Hertz filtering, koude-las compensatie, A/D converter en alles wat er voor een thermokoppel nodig is. Aansluiting via SPI. Ook in Nederland in diverse webshops verkrijgbaar, voor zo'n €20.

Nuttige Libraries etc