diff --git a/firmware/ATTINY85_2026_MorseThrowie/ATTINY85_2026_MorseThrowie.ino b/firmware/ATTINY85_2026_MorseThrowie/ATTINY85_2026_MorseThrowie.ino new file mode 100644 index 0000000..6aba0ad --- /dev/null +++ b/firmware/ATTINY85_2026_MorseThrowie/ATTINY85_2026_MorseThrowie.ino @@ -0,0 +1,544 @@ +/* + ============================================================================= + FireFly Morse Throwie + - a light controled (LED as Sensor) morseblinker throwie with ATTiny45/85 + ============================================================================= + + Project definitions, sources + ----------------------------------------------------------------------------- + Version: 0.1 - Attiny85 Version + Date : 25.05.2026 + + ----------------------------------------------------------------------------- + + Inspired by Karl Lunt's FireFly project I wrote some code to make this + Throwie lasting longer, blinking only at low light levels and morse also + some text. + http://www.seanet.com/~karllunt/fireflyLED.html + + How it works (only the Morsethrowy part): + LED detects light level, using bleeding out time of LED pn-capacitor. + If dark enough blink a text in morsecode (ATTiny45 = 22 Chars, text will + be defined in line 191/192 of this file) + To save energy go to powersave mode after blinking or light level is + over threshold. Tests this every 8s (maximum time for watchdog timer + possible for ATTiny). Repeat this endless + + + The wiring, it's very simple, see also HW part of the Project. + + +---+ +------\/------+ + | | ATTINY45 /85 | + > | -+1=PB5 VCC=8+-> to SuperCap / DC-DC 3V/5V + xxx Ohm < | | | + > +------+2=PB3 PB2=7+- + | | | + ----- +------+3=PB4 PB1=6+- + LED / \ | | | + ----- | +--+4=GND PB0=5+- + | | | | | + +---+ | +--------------+ + | + +---------------------> to battery GND + + You can use other pins if necessary, theoretical up to 3 LEDs, as example I + tried out to connect another one at PB2&PB1. working fine. Basic wiring: + + + LED_N_Side), wired to a digital pin, NOT Vcc + | + < + > 100 - 460 ohm resistor depending Voltage + < + | + | + ----- + / \ LED, maybe a 5mm, clear plastic is good + ----- + | + | + + LED_P_Side), wired to a digital pin, NOT Gnd + + ----------------------------------------------------------------------------- + Im just a newbe in ATTiny / Arduino programming, so many thanks to: + + Programming ATTiny with Arduino IDE: + http://highlowtech.org/?p=1695 + + LED Lightsensor, Arduino Playground: + http://playground.arduino.cc/Learning/LEDSensor + + Powersaving Mode for Attiny45/85: + A good description by Martin Nawrath nawrath@khm.de and the folks at + http://www.insidegadgets.com/2011/02/05/reduce-attiny-power-consumption-by-sleeping-with-the-watchdog-timer/ + + With this description I got ~5uA during sleep mode. + in Morse-Mode with LED OFF: 1.7mA + LED ON: 6.9mA + --> I hope to run this throwies ~40days with one CR2032. + + Morsecode + To translate a text into morsecode, there are several ways. You can use + this fine online translator: + http://morsecode.scphillips.com/jtranslator.html + + There is also a great morse coder / encoder from Matthias Esterl aka madc. + Works fine for Arduino, but not for ATTiny because of RAM limitations. But + maybe this is helpful if your project works with an Arduino. + https://gist.github.com/madc/4474559 + + For this project I use a simple case structur. Looks arkward, but the + ATTiny45 has only 256byte RAM but 4kFlash. A data structure is better programming + but needs a lot of RAM we not have. Therefore this ugly case structure. + This will waste the flash memory but we have enough and saving RAM for + our payload - the ASCII-string with the morsetext. + + BTW - Morsecode itself: + + 'A', ".-" 'B', "-..." 'C', "-.-." + 'D', "-.." 'E', "." 'F', "..-." + 'G', "--." 'H', "...." 'I', ".." + 'J', ".---" 'K', ".-.-" 'L', ".-.." + 'M', "--" 'N', "-." 'O', "---" + 'P', ".--." 'Q', "--.-" 'R', ".-." + 'S', "..." 'T', "-" 'U', "..-" + 'V', "...-" 'W', ".--" 'X', "-..-" + 'Y', "-.--" 'Z', "--.." + + '1', ".----" '2', "..---" '3', "...--" + '4', "....-" '5', "....." '6', "-...." + '7', "--..." '8', "---.." '9', "----." + '0', "-----" + + '.', ".-.-.-" ',', "--..--" '?', "..--.." + '!', "-.-.--" ':', "---..." ';', "-.-.-." + '(', "-.--." ')', "-.--.-" '"', ".-..-." + '@', ".--.-." '&', ".-..." + + ----------------------------------------------------------------------------- + Legal stuff / Copyright: + Creative Commons Attribution ShareAlike 3.0.: + http://creativecommons.org/licenses/by-sa/3.0/legalcode + ----------------------------------------------------------------------------- +*/ + + +// =========================================================================== +// Ok folks, let's start +// =========================================================================== +// for sleep Mode / Powersave we need some additional stuff. Its alredy there, +// if you installed the Attiny extension for Arduino IDE, no additional +// installing needed. +#include +#include + +// =========================================================================== +// Some definitions for powersave depending of ATTiny type. +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +// =========================================================================== +// for ATTiny85 +// Unit length < 150 will hard to be read for optical morse code +// > 300 are too slow in my feeling for longer text +// +// for ATTiny85 at 8MHz (for 1MHz see ATTiny45) +// Unit length < 5 will hard to be read for optical morse code +// > 10 are too slow in my feeling for longer text +// +// + +#define unitLength 100 + +// --------------------------------------------------------------------------- +// LED Pin definitions, +// theoretical you can use up to 3 LED. For example you can use it for a +// landmark beacon. So if you point this LEDs to different directions you can +// detect the position in dependence of your location to the bacon. +#define LED1_N_SIDE 3 +#define LED1_P_SIDE 4 + +// =========================================================================== +// Variables +// =========================================================================== +// ########################################################################### +// # and now the text, but be aware, only 256Byte RAM for Attiny45 # +// # so there are only 22 Chars left for your message. # +// # BTW with an Attiny85 you will have additional 256byte # +// # => more than for twitter :-) # +// # => for FireFly with SuperCap: less ist better, charge last longer # + +String morseText = + "TOGO LAB"; +// # "....5....1....5....2.."; just a ruler, remember 22 Chars for ATTiny # +// IT IS USELESS +// HAIL GLOW CLOUD +// ########################################################################### + +// Define light trigger threshold. best way to set it on dusk / dawn level +// diffuse red ones are less sensitive than clear green ones... +int darknessThreshold = 17000; + +// Interrupt Flag, should be volatile, means: read from RAM, not register +// because registers are used for interrupt handling, it have to be volatile. +volatile boolean f_wdt = 1; + +// =========================================================================== +// Setup watchdog +// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms +// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec +// =========================================================================== +void setup() +{ + setup_watchdog(9); +} + +// =========================================================================== +// Main +// =========================================================================== + +void loop(){ + + if (f_wdt==1) { // wait for timed out watchdog + // flag is set when a watchdog timeout occurs + f_wdt=0; // reset flag + + // if it's dark enough [>darknesThreshold] morse + if (sensDarkness(LED1_N_SIDE, LED1_P_SIDE) > darknessThreshold){ + // looks like it's dark, so do your job + morse(LED1_N_SIDE, LED1_P_SIDE); + } + } + // set all used port to intput to save power + pinMode(LED1_N_SIDE,INPUT); + pinMode(LED1_P_SIDE,INPUT); + system_sleep(); + f_wdt=0; // 2nd time sleep + system_sleep(); +} + +// =========================================================================== +// Subroutines for Sleeping +// =========================================================================== +// set system into the sleep state +// system wakes up when wtchdog is timed out +void system_sleep() { + cbi(ADCSRA,ADEN); // switch Analog to + // Digitalconverter OFF + + set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here + sleep_enable(); + + sleep_mode(); // System sleeps here + + sleep_disable(); // System continues execution here when + // watchdog timed out + sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON +} + +// ---------------------------------------------------------------------------- +// Setup for watchdog. Parameter ii for sleeping time: +// 0 = 16ms, 1 = 32ms, 2 = 64ms, +// 3 = 128ms, 4 = 250ms, 5 = 500ms +// 6 = 1 sec, 7 = 2 sec, 8 = 4 sec, +// 9 = 8 sec +void setup_watchdog(int ii) { + + byte bb; + int ww; + if (ii > 9 ) ii=9; + bb=ii & 7; + if (ii > 7) bb|= (1<<5); + bb|= (1<