Version 1

This commit is contained in:
Dustin Brunner 2021-03-28 15:48:30 +02:00
commit 9bce215a08
14 changed files with 614 additions and 0 deletions

Binary file not shown.

BIN
Program_ATtiny.fzz Normal file

Binary file not shown.

80
README.md Normal file
View File

@ -0,0 +1,80 @@
# ATtiny 13 WS2812B-LED Fire-Effect Garden Lamp
This is how you can build a Garden Lamp based on an ATtiny13 and some WS2812B (Neopixel) LEDs.
The LEDs are Simulating a nice-looking Fire-Effect. This effect is generated using a random number generator.
It also features a LDR Light-Sensor to turn on the Lamp in the Darkness automatically.
In the code you can set a time after which the lamp automatically turns off, even if it is still dark.
# Software
The software is based on several different code snippets. You can find links to them in the Sources-Tab.
There are a view different configuration options (like on-time, color, ...), which can be done in the `config.h` file. They are well described in this file.
### Features
1. Fire-Effect turns on when LDR-value gets under `on_val` as defined
2. Second state is entered after the timeout `max_on_time` is reached. The LEDs light in the color, defined as `timeout_...`.
3. If it gets light again the LEDs light in the color, defined as `day_...`. If you want it to be off, set all values to 0.
## Program the ATtiny
### 1. Upload `ArduinoISP` sketch to the Arduino
You can find it in the Examples folder of the Arduino-IDE
### 2. wiring
I use a Arduino Nano to program the ATtiny, but also a Arduino UNO will do fine. Hook up the ATtiny like it is shown in the schematic:
<img src="pictures/Program_ATtiny_Steckplatine.png" width="50%">
The capacitor is important because it prevents the Arduino from resetting itself while programming the ATtiny.
### 3. Download ATtiny13 support for the IDE
Add the URL `http://drazzy.com/package_drazzy.com_index.json` to the Additional Boards Manager URLs in the IDE Preferences. After that open the Boards-Manager, search for "DIY Attiny" and install it. Now you should find the Attiny13 and some other Attiny Boards in the Board menu.
### 4. Uploading
Open the code in the Arduino IDE and select the Attiny13 as the Board.
Select the following settings:
<img src="pictures/ide_settings.png" width="40%">
These settings are important:
- Processor-Speed to 9.6 Mhz
- Millis, Tone Support to "No Millis, No Tone"
**After that Press `Burn Bootloader` to make sure that these Settings are applied.**
Now you can upload the code by simply pressing **Upload**.
# Hardware
## Schematic
<img src="pictures/ATtiny_WS2812_garden_lamp_Schaltplan.png" width="80%">
## PCB Layout
<img src="pictures/ATtiny_WS2812_garden_lamp_Leiterplatte.png" width="40%">
## ATtiny-Pinout
<img src="pictures/attiny-pinout.png" width="40%">
<br>(Source: https://cdn.sparkfun.com/assets/f/8/f/d/9/52713d5b757b7fc0658b4567.png)
# Sources / Useful Links
You can find more detailed information here:
- Arduino ISP: https://www.instructables.com/Updated-Guide-on-How-to-Program-an-Attiny13-or-13a/
- Light sensor: https://www.elec-cafe.com/attiny85-light-sensor-switch/
- Timer Interrupt: https://arduinodiy.wordpress.com/2015/06/22/flashing-an-led-with-attiny13/
- WS2812B Lib:
- https://blog.podkalicki.com/attiny13-controlling-leds-ws2811ws2812/
- https://www.instructables.com/Updated-Guide-on-How-to-Program-an-Attiny13-or-13a/
- Random number gernerator lib:
- https://blog.podkalicki.com/attiny13-pseudo-random-numbers/
- https://github.com/lpodkalicki/blog/tree/master/avr/attiny13/009_lightweigth_prng_based_on_lfsr
- Fire Effect:
- https://codebender.cc/sketch:271084#Neopixel%20Flames.ino
- WS2812FX-Lib, "Fire-Flicker" Effect: https://github.com/kitesurfer1404/WS2812FX
<br>
### I hope you like this project!
<br>
<p xmlns:dct="http://purl.org/dc/terms/" xmlns:cc="http://creativecommons.org/ns#" class="license-text">This work by <span property="cc:attributionName">Dustin Brunner</span> is licensed under <a rel="license" href="https://creativecommons.org/licenses/by/4.0">CC BY 4.0<img style="height:15px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" /><img style="height:15px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" /></a></p>
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons Lizenzvertrag" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />Dieses Werk von <span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">Dustin Brunner</span> ist lizenziert unter einer <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Namensnennung 4.0 International Lizenz</a>.

134
code/code.ino Normal file
View File

@ -0,0 +1,134 @@
/*
ATtiny 13 WS2812B-LED Fire-Effect Garden Lamp
Author: dustinbrun
licensed under CC BY 4.0
Version 03.2021
Make sure to Set in the Board Settings:
Processor-Speed to 9.6 Mhz
Millis, Tone Support to "No Millis, No Tone"
After that Press "Burn Bootloader" to make sure that these Settings are applied
----------------------------- !!!! Configuration can be done in the "config.h file !!!! -----------------------------------------
*/
#include "light_ws2812.c"
#include "light_ws2812.h"
#include "random_avr.h"
#include "random_avr.c"
#include "config.h"
bool on = true;
bool was_on = true;
volatile unsigned long counter = 0;// interrupt needs volatile variable
struct pix
{
uint8_t g;
uint8_t r;
uint8_t b;
};
pix pixel[PIXEL_NUM];
ISR(TIMER0_OVF_vect) {
/*
Timer Configuration:
Prescaler 1024, CPU-Speed 9,6MHz = 9600000 Hz
Interrupt is called with a Frequency of: 9600000Hz/1024/256 = 36,6Hz
so every --> 0,027s <---
*/
counter++;
}
void setup()
{
random_init(0xabcd); // initialize 16 bit seed
pinMode(LDR_pin, INPUT);
pinMode(2, OUTPUT);
//Interrupt Setup
cli(); // Clear interrupts, just to make sure
TCCR0B |= (1 << CS02) | (1 << CS00); // set prescale timer to 1/1024th, set CS02 and CS00 bit in TCCR0B
TIMSK0 |= 1 << TOIE0; // enable timer overflow interrupt, left shift 1 to TOIE0 and OR with TIMSK
sei(); //start timer
}
void loop()
{
if (analogRead(LDR_pin) < on_val && !was_on)
{
on = true;
was_on = true;
counter = 0;
}
if (analogRead(LDR_pin) > off_val && was_on)
{
on = false;
was_on = false;
counter = 0;
for (int i = 0; i < PIXEL_NUM; i++)
{
pixel[i].r = day_red;
pixel[i].g = day_green;
pixel[i].b = day_blue;
}
ws2812_setleds((struct cRGB *)pixel, PIXEL_NUM);
}
if (counter > max_on_time && on)
{
on = false;
counter = 0;
for (int i = 0; i < PIXEL_NUM; i++)
{
pixel[i].r = timeout_red;
pixel[i].g = timeout_green;
pixel[i].b = timeout_blue;
}
ws2812_setleds((struct cRGB *)pixel, PIXEL_NUM);
}
if (on)
{
// Flicker, based on our initial RGB values
int flicker = random_avr() % indensity;
int f_red = red - flicker;
int f_green = green - flicker;
int f_blue = blue - flicker;
if (f_red < 0) f_red = 0;
if (f_green < 0) f_green = 0;
if (f_blue < 0) f_blue = 0;
for (int i = 0; i < PIXEL_NUM; i++)
{
pixel[i].r = f_red;
pixel[i].g = f_green;
pixel[i].b = f_blue;
}
ws2812_setleds((struct cRGB *)pixel, PIXEL_NUM);
delay(400 - random_avr() % d_delay);
}
else
{
counter = 0;
}
}

67
code/config.h Normal file
View File

@ -0,0 +1,67 @@
/*
* ----------------------------------------
* ------ Configuration Options -----------
* ----------------------------------------
*/
int on_val = 400; //LDR Value below that to switch the Light on
int off_val = 500; //LDR Value above that to switch the Light off
unsigned long max_on_time = 666666; // Calculation: ('on_time_in_minutes' * 60) / 0.027
//Example: 5h (=300min) ON-time: max_on_time = (300 * 60) / 0.027 = 666666
#define PIXEL_NUM 3 //Ammount of WS2812 LEDs
/*
* ----------------------------------------
* ---------- Colour Settings -------------
* ----------------------------------------
*/
//----------- Flickering Effect -----------
//Default Colours
int red = 255;
int green = 70;
int blue = 20;
// Purple flame:
// int red = 158, green = 8, blue = 148;
// Green flame:
//int red = 74, green = 150, blue = 12;
int indensity = 40; // Maximum Flickering offset
int d_delay = 300; // Maximum Delay offset
// ----- colour after timeout ----
// This is the Colour with which the leds light up, after the timeout (max_on_time) is reached until it gets light again
// If you want it to be off, set all values to 0
int timeout_red = 0;
int timeout_green = 0;
int timeout_blue = 5;
// ------ color throughout the day -------
// This is the Colour with which the leds light up, when the LDR detects daylight
int day_red = 0;
int day_green = 0;
int day_blue = 0;
/*
* ----------------------------------------
* ---------------- Pins ------------------
* ----------------------------------------
*/
#define LDR_pin A3
// Pin Defintion for LEDs in the light_ws2812.h File as "ws2812_pin" variable
/*
* ----------------------------------------
* ---------- End of config ---------------
* ----------------------------------------
*/

181
code/light_ws2812.c Normal file
View File

@ -0,0 +1,181 @@
/*
* light weight WS2812 lib V2.0b
*
* Controls WS2811/WS2812/WS2812B RGB-LEDs
* Author: Tim (cpldcpu@gmail.com)
*
* Jan 18th, 2014 v2.0b Initial Version
* Nov 29th, 2015 v2.3 Added SK6812RGBW support
*
* License: GNU GPL v2+ (see License.txt)
*/
#include "light_ws2812.h"
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
// Setleds for standard RGB
void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds)
{
ws2812_setleds_pin(ledarray, leds, _BV(ws2812_pin));
}
void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask)
{
ws2812_sendarray_mask((uint8_t *)ledarray, leds + leds + leds, pinmask);
_delay_us(ws2812_resettime);
}
// Setleds for SK6812RGBW
void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds)
{
ws2812_sendarray_mask((uint8_t *)ledarray, leds << 2, _BV(ws2812_pin));
_delay_us(ws2812_resettime);
}
void ws2812_sendarray(uint8_t *data, uint16_t datlen)
{
ws2812_sendarray_mask(data, datlen, _BV(ws2812_pin));
}
/*
This routine writes an array of bytes with RGB values to the Dataout pin
using the fast 800kHz clockless WS2811/2812 protocol.
*/
// Timing in ns
#define w_zeropulse 350
#define w_onepulse 900
#define w_totalperiod 1250
// Fixed cycles used by the inner loop
#define w_fixedlow 2
#define w_fixedhigh 4
#define w_fixedtotal 8
// Insert NOPs to match the timing, if possible
#define w_zerocycles (((F_CPU / 1000) * w_zeropulse) / 1000000)
#define w_onecycles (((F_CPU / 1000) * w_onepulse + 500000) / 1000000)
#define w_totalcycles (((F_CPU / 1000) * w_totalperiod + 500000) / 1000000)
// w1 - nops between rising edge and falling edge - low
#define w1 (w_zerocycles - w_fixedlow)
// w2 nops between fe low and fe high
#define w2 (w_onecycles - w_fixedhigh - w1)
// w3 nops to complete loop
#define w3 (w_totalcycles - w_fixedtotal - w1 - w2)
#if w1 > 0
#define w1_nops w1
#else
#define w1_nops 0
#endif
// The only critical timing parameter is the minimum pulse length of the "0"
// Warn or throw error if this timing can not be met with current F_CPU settings.
#define w_lowtime ((w1_nops + w_fixedlow) * 1000000) / (F_CPU / 1000)
#if w_lowtime > 550
#error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
#elif w_lowtime > 450
#warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
#warning "Please consider a higher clockspeed, if possible"
#endif
#if w2 > 0
#define w2_nops w2
#else
#define w2_nops 0
#endif
#if w3 > 0
#define w3_nops w3
#else
#define w3_nops 0
#endif
#define w_nop1 "nop \n\t"
#define w_nop2 "rjmp .+0 \n\t"
#define w_nop4 w_nop2 w_nop2
#define w_nop8 w_nop4 w_nop4
#define w_nop16 w_nop8 w_nop8
void inline ws2812_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t maskhi)
{
uint8_t curbyte, ctr, masklo;
uint8_t sreg_prev;
ws2812_DDRREG |= maskhi; // Enable output
masklo = ~maskhi & ws2812_PORTREG;
maskhi |= ws2812_PORTREG;
sreg_prev = SREG;
cli();
while (datlen--)
{
curbyte = *data++;
__asm volatile(
" ldi %0,8 \n\t"
"loop%=: \n\t"
" out %2,%3 \n\t" // '1' [01] '0' [01] - re
#if (w1_nops & 1)
w_nop1
#endif
#if (w1_nops & 2)
w_nop2
#endif
#if (w1_nops & 4)
w_nop4
#endif
#if (w1_nops & 8)
w_nop8
#endif
#if (w1_nops & 16)
w_nop16
#endif
" sbrs %1,7 \n\t" // '1' [03] '0' [02]
" out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
" lsl %1 \n\t" // '1' [04] '0' [04]
#if (w2_nops & 1)
w_nop1
#endif
#if (w2_nops & 2)
w_nop2
#endif
#if (w2_nops & 4)
w_nop4
#endif
#if (w2_nops & 8)
w_nop8
#endif
#if (w2_nops & 16)
w_nop16
#endif
" out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
#if (w3_nops & 1)
w_nop1
#endif
#if (w3_nops & 2)
w_nop2
#endif
#if (w3_nops & 4)
w_nop4
#endif
#if (w3_nops & 8)
w_nop8
#endif
#if (w3_nops & 16)
w_nop16
#endif
" dec %0 \n\t" // '1' [+2] '0' [+2]
" brne loop%=\n\t" // '1' [+3] '0' [+4]
: "=&d"(ctr)
: "r"(curbyte), "I"(_SFR_IO_ADDR(ws2812_PORTREG)), "r"(maskhi), "r"(masklo));
}
SREG = sreg_prev;
}

103
code/light_ws2812.h Normal file
View File

@ -0,0 +1,103 @@
/*
light_ws2812_config.h
v2.4 - Nov 27, 2016
User Configuration file for the light_ws2812_lib
*/
///////////////////////////////////////////////////////////////////////
// Define I/O pin
///////////////////////////////////////////////////////////////////////
#define ws2812_port B // Data port
#define ws2812_pin 0 // Data out pin
///////////////////////////////////////////////////////////////////////
// Define Reset time in µs.
//
// This is the time the library spends waiting after writing the data.
//
// WS2813 needs 300 µs reset time
// WS2812 and clones only need 50 µs <<<-----
//
///////////////////////////////////////////////////////////////////////
#define ws2812_resettime 50
// -------------------------------------------------------------------------------------------------------------
/* WS2812_CONFIG_H_
* light weight WS2812 lib include
*
* Version 2.3 - Nev 29th 2015
* Author: Tim (cpldcpu@gmail.com)
*
* Please do not change this file!"
*
* License: GNU GPL v2+ (see License.txt)
*
*/
#ifndef LIGHT_WS2812_H_
#define LIGHT_WS2812_H_
#include <avr/io.h>
#include <avr/interrupt.h>
/*
* Structure of the LED array
*
* cRGB: RGB for WS2812S/B/C/D, SK6812, SK6812Mini, SK6812WWA, APA104, APA106
* cRGBW: RGBW for SK6812RGBW
*/
struct cRGB { uint8_t g; uint8_t r; uint8_t b; };
struct cRGBW { uint8_t g; uint8_t r; uint8_t b; uint8_t w;};
/* User Interface
*
* Input:
* ledarray: An array of GRB data describing the LED colors
* number_of_leds: The number of LEDs to write
* pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0)
*
* The functions will perform the following actions:
* - Set the data-out pin as output
* - Send out the LED data
* - Wait 50µs to reset the LEDs
*/
void ws2812_setleds (struct cRGB *ledarray, uint16_t number_of_leds);
void ws2812_setleds_pin (struct cRGB *ledarray, uint16_t number_of_leds,uint8_t pinmask);
void ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t number_of_leds);
/*
* Old interface / Internal functions
*
* The functions take a byte-array and send to the data output as WS2812 bitstream.
* The length is the number of bytes to send - three per LED.
*/
void ws2812_sendarray (uint8_t *array,uint16_t length);
void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask);
/*
* Internal defines
*/
#define CONCAT(a, b) a ## b
#define CONCAT_EXP(a, b) CONCAT(a, b)
#define ws2812_PORTREG CONCAT_EXP(PORT,ws2812_port)
#define ws2812_DDRREG CONCAT_EXP(DDR,ws2812_port)
#endif /* LIGHT_WS2812_H_ */

33
code/random_avr.c Normal file
View File

@ -0,0 +1,33 @@
/**
Copyright (c) 2017, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com>
Lightweight library of 16 bit random number generator based on LFSR.
*/
#include <avr/eeprom.h>
#include "random_avr.h"
static uint16_t random_number = 0;
static uint16_t
lfsr16_next(uint16_t n)
{
return (n >> 0x01U) ^ (-(n & 0x01U) & 0xB400U);
}
void random_init(uint16_t seed)
{
#ifdef USE_RANDOM_SEED
random_number = lfsr16_next(eeprom_read_word((uint16_t *)RANDOM_SEED_ADDRESS) ^ seed);
eeprom_write_word((uint16_t *)0, random_number);
#else
random_number = seed;
#endif /* !USE_RANDOM_SEED */
}
uint16_t
random_avr(void)
{
return (random_number = lfsr16_next(random_number));
}

16
code/random_avr.h Normal file
View File

@ -0,0 +1,16 @@
/*
Copyright (c) 2017, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com>
Lightweight library of 16 bit random number generator based on LFSR.
*/
#ifndef _RANDOM_H_
#define _RANDOM_H_
#ifdef USE_RANDOM_SEED
#define RANDOM_SEED_ADDRESS 0x00
#endif /* !USE_RANDOM_SEED */
void random_init(uint16_t seed);
uint16_t random_avr(void);
#endif /* !_RANDOM_H_ */

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

BIN
pictures/attiny-pinout.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
pictures/ide_settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB