Stel je voor, je loopt de zaal uit waar je net een presentatie hebt gevolgd en ziet op een tafeltje twee apparaten staan in het rood en groen. Beide hebben een verlichte knop aan de bovenkant, die uitnodigend pulserend verlicht is. Op het display zie je wat cijfers staan. Een poster aan de muur bevat de tekst ‘Evaluatie – Uw mening wordt op prijs gesteld’ en de kreet ‘Gebruik de Like-O-Meters hieronder’. Met een druk op de knop van de groene kolom kun je aangeven dat je de presentatie leuk vond, met een druk op de knop van de rode kolom geef je juist aan dat je het maar niks vond.
Dit is wat ik voor ogen had toen ik met project Meningteller begon. De zichtbare functionaliteit ervan is relatief simpel: een verlichte schakelaar aan de bovenkant, een display dat bij iedere druk op de knop één optelt en een stevige behuizing die ook bij intensief gebruik overeind blijft. Ik heb ze ‘Like-O-Meter’ gedoopt, een knipoog naar de ‘Like‘ knop die je van Facebook kent (‘Vind ik leuk’). Maar ‘Meningteller’ is eigenlijk leuker, want Nederlands.
Omdat het project gestalte moest krijgen tussen lunch en diner heb ik in in huis rondgezocht om te zien wat er aan materialen zouden kunnen passen. Ik had recentelijk wat PVC materialen ingekocht voor een uitbreiding aan de badkamer en daar nog wat van overgehouden. Daar zat net voldoende materiaal bij om twee gesloten ‘bussen’ te maken. En PCV laat zich gemakkelijk boren en zagen, dat hielp in de besluitvorming.
Het handgebouwde prototype van de Like-O-Meter is opgebouwd uit enkele PVC-delen van Martens, een Serieel led display, een led verlichte drukschakelaar en een ATtiny85. Het geheel is voorzien van een paar laagjes spuitlak van Motip.
Aan de softwarekant moest ik wat improviseren om het geheel met een ATtiny85 aan de gang te krijgen. De ATtiny is een kleine 8-pins microcontroller, met 6 pennen vrij te gebruiken voor I/O toepassingen, zoals het inlezen van de stand van een schakelaar, het activeren van een led of het serieel aansturen van een led display. Het led display gebruikt hiervan twee (I2C clock en I2C data), de schakelaar gebruikt er één en de led in de schakelaar ook één. Er zijn nog twee pennen vrij, voor bijvoorbeeld een rgbled in de schakelaar.
Voor de I2C communicatie heb ik gebruik gemaakt van de TinyWireM library van Bro Hogan, die met 320 bytes een veel kleinere footprint heeft dan de AdaFruit led Backpack library. De ATtiny85 heeft ruimte voor 8K gecompileerde programmatuur, hiervan gebruikt de Like-O-Meter iets meer dan 4K. De Arduino ontwikkelomgeving 1.01 heeft een fout die het gebruik van meer ruimte dan 4K voorkomt, dat was nog wel een uitzoekklusje. De broncode bevat aanwijzigingen voor het hercompileren en de benodigde codebibliotheken.
Het gedrag van de Like-O-Meter is als volgt. Zodra de 9 volt accu wordt ingeschakeld (de onderkant schroeft eenvoudig van de behuizing en de accu zit met een clipje vast) toont het display vier streepjes en wordt de led in de schakelaar een seconde ontstoken. Hierna wordt een ‘0’ op het display getoond en is de led in de schakelaar uit. Iedere keer als de schakelaar wordt ingedrukt brandt de led en toont het display de tekst ‘PLUS’. Als de schakelaar weer wordt losgelaten toont het display opnieuw het getal, dat nu met één is verhoogd.
Na ongeveer 15 minuten inactiviteit wordt het display wat gedimd en pulseert de led om de naderende slaapstand aan te kondigen. Een druk op de schakelaar levert het normale tel-er-een-bij-op gedrag en de slaapstand wordt onderbroken. Als er echter niet op de schakelaar wordt gedrukt dan gaat het display na een minuut uit. Het stroomverbruik is nu minimaal (ca. 7mA), maar de telstand wordt wel behouden. Als de schakelaar wordt ingedrukt dan wordt de tekst ‘AAN’ op het display getoond. Zodra de schakelaar nu wordt losgelaten dan toont het display de oude telstand en is de Like-O-Meter weer klaar voor gebruik. Om de telstand te wissen moet de accu (9 volt blokbatterij) worden losgekoppeld. Het stroomverbruik is sterk afhankelijk van het gebruik: met ‘8888’ op het display is de opgenomen stroom ongeveer 80mA. Bij regulier gebruik gaan de accu’s ongeveer 7 dagen mee.
De software is Public Domain, doe ermee wat je goed dunkt 🙂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | /* * Like-O-Meter firmware 1.00 * Copyright (c) 2013 Rudi Niemeijer * Placed in the Public Domain * * This is the firmware for the Like-O-Meter, a device that * acts as a counter with some light effects. * * A Like-O-Meter contains an Adafruit 4-digit 7-segment * LED backpack, button with built-in LED and an ATtiny85. * * In order to compile, this firmware requires the TinyWireM * library for I2C communication and the Tiny_LEDBackpack * library for the various LED display functions. * * TinyWireM library obtained from http://www.scenelight.nl/?wpfb_dl=22 * Tiny_LEDBackpack obtained from https://github.com/millerlp/Tiny_LEDBackpack * * ATtiny pin configuration * Pin 1 - Not connected * Pin 2 - Not connected (ATtiny PIN 3) * Pin 3 - Button (ATtiny PIN 4) * Pin 4 - GND * Pin 5 - SDA to LED backpack (grey) * Pin 6 - LED in button (ATtiny PIN 1 w. PWM) * Pin 7 - SCL to LED backpack (white) * Pin 8 - VCC/+5V * */ // These two libraries are essential #include <TinyWireM.h> #include <Tiny_LEDBackpack.h> Tiny_7segment likeOMeterDisplay = Tiny_7segment(); int buttonPin = 4; // button that pulls the pin UP int ledPin = 1; // indicator LED inside the button, pin 1 supports PWM int buttonState; // current state of the button int counterValue = 0; // current value for the counter #define maxLEDBrightness 150 // maximum LED brightness 0..255 #define maxLEDBrightnessFade 75 // maximum LED brightness in fade mode #define fadeSpeed 10 // increase LED brightness every fadeSpeed millis #define napTimeOut 900000 // millis before sleep, 15 minutes #define sleepTimeOut 960000 // millis before hybernation, 15 minutes + 60 seconds int currentLEDBrightness = 0; int brighter = true; unsigned long timeStampButtonPressed; unsigned long timeStamp = 0; #define i2c_addr 0x70 // stock address for Adafruit 7-segment LED backpack void setup() { pinMode(buttonPin, INPUT); pinMode(ledPin, OUTPUT); analogWrite(ledPin, maxLEDBrightness); likeOMeterDisplay.begin(i2c_addr); // initialize HT16K33 controller likeOMeterDisplay.clear(); // clear all digits on display likeOMeterDisplay.setBrightness(15); // set maximum display brightness likeOMeterDisplay.writeDigitRaw(0, 64); // dash on position 0 likeOMeterDisplay.writeDigitRaw(1, 64); // dash on position 1 likeOMeterDisplay.writeDigitRaw(3, 64); // dash on position 3 likeOMeterDisplay.writeDigitRaw(4, 64); // dash on position 4 likeOMeterDisplay.writeDisplay(); // push data to display delay(1000); // wait a second likeOMeterDisplay.clear(); // clear all digits on display displayInteger(counterValue); analogWrite(ledPin, 0); // disable the LED for visual verification timeStampButtonPressed = millis(); // simulate button pressed to prevent nap and sleep right from the beginning } void loop() { buttonState = digitalRead(buttonPin); // NAP MODE TO ATTRACT ATTENTION if ((millis() > timeStampButtonPressed + napTimeOut) && (millis() > timeStamp + fadeSpeed)) { timeStamp = millis(); if (currentLEDBrightness == 0) { likeOMeterDisplay.setBrightness(0); likeOMeterDisplay.writeDisplay(); } analogWrite(ledPin, currentLEDBrightness); if (brighter) { currentLEDBrightness++; if (currentLEDBrightness > maxLEDBrightnessFade) { currentLEDBrightness = maxLEDBrightnessFade; brighter = false; } } else { currentLEDBrightness--; if (currentLEDBrightness < 0) { currentLEDBrightness = 0; brighter = true; } } } // SLEEP MODE TO PREVENT BATTERY DEPLETION if ((currentLEDBrightness == 0) && (millis() > timeStampButtonPressed + sleepTimeOut)) // button not pressed for a very long time { // Sleep likeOMeterDisplay.clear(); // replace this with actual battery preserving code, like switching off likeOMeterDisplay.writeDisplay(); digitalWrite(ledPin, 0); while (!digitalRead(buttonPin)) // wait here until button is pressed { } // Wakeup likeOMeterDisplay.setBrightness(15); likeOMeterDisplay.writeDigitRaw(0, 119); // A on position 0 likeOMeterDisplay.writeDigitRaw(1, 119); // A on position 1 likeOMeterDisplay.writeDigitRaw(3, 55); // N on position 3 likeOMeterDisplay.writeDigitRaw(4, 0); // blank on position 4 likeOMeterDisplay.writeDisplay(); // push data to display delay(1000); // wait a second likeOMeterDisplay.clear(); // clear all digits on display displayInteger(counterValue); while (digitalRead(buttonPin)) // wait here until button is released { } timeStampButtonPressed = millis(); } if (buttonState) // button is pressed { analogWrite(ledPin, maxLEDBrightness); likeOMeterDisplay.setBrightness(15); likeOMeterDisplay.writeDisplay(); counterValue += 1; likeOMeterDisplay.clear(); likeOMeterDisplay.writeDisplay(); likeOMeterDisplay.writeDigitRaw(0,115); // P on position 0 likeOMeterDisplay.writeDigitRaw(1,56); // L on position 1 likeOMeterDisplay.writeDigitRaw(3,62); // U on position 3 likeOMeterDisplay.writeDigitRaw(4,109); // S on position 4 likeOMeterDisplay.writeDisplay(); delay(250); // debounce time while (digitalRead(buttonPin)) // wait here until button is released { } delay(250); // debounce time displayInteger(counterValue); analogWrite(ledPin, 0); currentLEDBrightness = 0; brighter = true; // nap light is increasing first timeStampButtonPressed = millis(); // administer last time button pressed } } void displayInteger(int number) { if (number == 0) { likeOMeterDisplay.writeDigitRaw(4, 63); // put a zero on the display } else { likeOMeterDisplay.print(number); // put the number on the display } likeOMeterDisplay.writeDisplay(); } |