While others use classical analog circuit (Mike's), I decided to do it with digital approach. Trying to maintain DIY'ability, it seems that DigiSpark board from fellow Kickstarter project (which I forgot at first) seems to be good choice. DigiSpark is cheap on eBay, but I am not sure if they are licensed from DigiStump and these cheap boards seem to have some flaws (or even the original has them, too)
Nonetheless, it turns out the DigiSpark is the right choice and then some -- I can even shove a OLED display in. Construction of circuit is described in the code (see below), it is rather simple with some exceptions -- pin 1 of the board seems to be tied to the on-board LED, so it must be pulled up with a 10K resistor (1K in my photo as I could not find one). Another exception is that the cheap DigiSpark board is probably a rip-off one, its pin 5, the reset pin is still ENABLED for reset. I do not have genuine DigiSpark board (they stopped selling till May) to test, so if you turn the POT and change voltage to lower than 2.5V, the board resets. Oh well, that is life
Output (in the picture) is now an LED instead of a transistor to trigger flash (or other lights), but it should be easy to change.
One key idea is to use the POT to change the voltage on an ADC pin, in this example, the P5 (analog 0). By turning the POT, you are changing the voltage and the DigiSpark can read it and convert that to change amount of delay.
Code:
Code: Select all
#include <DigisparkOLED.h> // DigiSpark OLED driver
#include <Wire.h>
// OLED I2C Slave address, this is important as different OLED might have different address
#define SSD1306_SA 0x78
// P0 is used for I2C SDA -- OLED Display
// P2 is used for I2C SCK -- OLED Display
// P1 is used for INPUT from camera or stack controller
// P5 is used as analog pin (analog 0)
// P4 is used as output to trigger flash or light
enum enumMode
{
mode_idle,
mode_down,
mode_wait,
mode_fire,
mode_last,
};
#define PIN_INPUT 1 // we use P1 as input signal from either camera or stack controller
#define PIN_OUTPUT 4 // use P4 as output to trigger flash/light
#define PIN_ANALOG 5 // Analog 0 is P5
#define PIN_ANALOG_NUM 0 // Analog 0 is P5
#define MAX_FLASH_DUR 200 // this controls how long the flash/lite is ON in milliseconds
// this is used to increase range.
#define MULTIPLIER 1
// this defines how often the POT is read
#define MAX_READ_TICK 30000
byte gv_ucMode = mode_idle;
long gv_tkRead = MAX_READ_TICK;
long gv_tkFire = MAX_FLASH_DUR;
long gv_slTick = 0;
long gv_tnWait = 0;
long gv_tkWait = 0;
// here to implement a digital filter on the ADC
// as ADC is very, very noisy.
#define NUM_FILTER 16
long gv_svRead = 0;
long gv_slRead = 0;
long gv_arRead[NUM_FILTER];
byte gv_ixRead = 0;
// this is a routine that takes a long value
// and fill it up to a buffer, right aligned
#define BUFFER_SIZE 6
byte gv_arBuffer[BUFFER_SIZE];
void fillBuffer(long val)
{
for(byte i=0; i<BUFFER_SIZE-1; i++)
{
gv_arBuffer[i] = ' ';
}
byte ucVal;
byte index = BUFFER_SIZE-2;
while(index)
{
gv_arBuffer[index] = val - (val / 10) * 10 + '0';
if (index > 0)
{
index--;
}
val = val / 10;
if (val == 0)
{
break;
}
}
// finally, terminate the string with NULL
gv_arBuffer[BUFFER_SIZE-1] = 0;
}
void setup()
{
// for analog read, no need to configure it.
// but for digital read, we need to
pinMode(PIN_INPUT, INPUT);
digitalWrite(PIN_INPUT, HIGH); // set pullup resistor on INPUT by writing HIGH to it.
pinMode(PIN_OUTPUT, OUTPUT); // we use P4 for output to trigger flash
digitalWrite(PIN_OUTPUT, LOW); // set initial state
pinMode(PIN_ANALOG, INPUT); // make analog pin INPUT pin
oled.begin();
// clear screen
oled.clear(); //all black
// set OLED fonts
// oled.setFont(FONT6X8); // smaller font
oled.setFont(FONT8X16); // large font
oled.setCursor(12, 6);
oled.print(F("www.mjkzz.com"));
}
void loop()
{
switch(gv_ucMode)
{
case mode_idle:
// sense INPUT
if (digitalRead(PIN_INPUT) == LOW)
{
gv_tkWait = gv_tnWait;
gv_ucMode = mode_wait; // down edge triggered
// gv_ucMode = mode_down; // up edge triggered
}
else
{
if (gv_tkRead == 0)
{
gv_arRead[gv_ixRead] = analogRead(PIN_ANALOG_NUM);
gv_ixRead++;
if (gv_ixRead > NUM_FILTER-1)
{
gv_ixRead = 0;
}
gv_slRead = 0;
for(byte i=0; i<NUM_FILTER; i++)
{
gv_slRead += gv_arRead[i];
}
gv_slRead /= NUM_FILTER;
if (gv_slRead != gv_svRead)
{
// new reading
gv_svRead = gv_slRead;
gv_tnWait = gv_slRead * MULTIPLIER;
oled.setCursor(5, 2);
oled.print(F("Delay : "));
fillBuffer(gv_tnWait);
oled.print((char *) gv_arBuffer);
oled.println(F("ms"));
}
gv_tkRead = MAX_READ_TICK;
}
else
{
gv_tkRead--;
}
}
break;
case mode_down:
if (digitalRead(PIN_INPUT) == HIGH)
{
gv_ucMode = mode_wait;
}
break;
case mode_wait:
if (gv_tkWait)
{
gv_tkWait--;
delay(1); // every tick is 1ms
}
else
{
gv_ucMode = mode_fire;
gv_tkFire = MAX_FLASH_DUR;
digitalWrite(PIN_OUTPUT, HIGH);
}
break;
case mode_fire:
if (gv_tkFire)
{
digitalWrite(PIN_OUTPUT, HIGH);
gv_tkFire--;
delay(1); // every tick is 1ms
}
else
{
// finished job, set flash off
digitalWrite(PIN_OUTPUT, LOW);
gv_ucMode = mode_idle;
}
break;
default:
gv_ucMode = mode_idle;
break;
}
}