Signaalzoeker

 

Scan 1

Op de Open Dag van de Jonge Onderzoekers zagen zoon Kars Jan en ik een leuke vinding: een soort radio-ontvanger-met-koptelefoontje dat allerlei elektromagnetische straling hoorbaar maakt. Typisch het soort schakeling dat je als eerstejaars elektronicus voor je kiezen krijgt en ik was zelf dan ook niet onder de indruk. Voor Kars Jan ging er echter letterlijk een nieuwe wereld open en om hem een pleziertje te doen heb ik onderstaande schakeling opgebouwd en in een doosje gemonteerd. De antenne is een stukje montagedraad van ongeveer 30 centimeter en de hoofdtelefoon wordt met een 3,5mm stereo chassisdeel verbonden met het circuit. Een kleine drukschakelaar zorgt ervoor dat het apparaatje niet de hele dag aan blijft staan, na gebruik.

IMG_2501Het hele circuit is eigenlijk niets meer dan een uit drie transistoren bestaande versterkerschakeling, die de door de draadantenne opgevangen en de germanium-dioden gediscrimineerde radiosignalen geschikt maakt voor audio-weergave. De stroomopname is minimaal en de hele schakeling kost nog geen 10 euro, inclusief een lowbudget hoofdtelefoon, een geschikt doosje en een stukje gaatjesprint. Het uittekenen van de schakeling, bouwen en afmonteren was een fluitje van een cent, een briljante investering voor zo’n leuk stukje speelgoed.

Ik heb de schakeling ontleend aan de schakeling die we bij de Jonge Onderzoekers zagen. De oorspronkelijke bron hiervan is mogelijk Veron, die een sterk gelijkend ontwerp op haar website heeft staan. Ook Elektuur heeft in elk geval twee varianten gepubliceerd.

Like-O-Meter

Like-O-Meter prototypesStel 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 heb met de elektronische telkolommen hiernaast. De techniek 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’).

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.

IMG_1012

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. 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 RGB LED 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.

IMG_2474Het 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 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.

/*
 * 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 
#include 

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();
}