Version 1

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

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_ */