I guess I can't stop doing badges. Really love the @pimoroni #bearables - but they don't have sloths :(
there are some nifty tricks hidden in the bearables badges, a cool menu etc. I want to replicate the behaviour with an ATTINY13A.
sloth badge | new design!
2018-02-20 23:59:57
After a fallout with pimoroni I'm no longer allowed to use the sloth badge design. So here is the new design:
Just kidding! I've bought a soic8 adapter that I will solder into place and make this a dedicated SOIC8 programmer for the kit chips! I haven't heard from pimoroni in a while though, need to ping them in a tweet some time.
After a fallout with pimoroni I'm no longer allowed to use the sloth badge design. So here is the new design:
Just kidding! I've bought a soic8 adapter that I will solder into place and make this a dedicated SOIC8 programmer for the kit chips! I haven't heard from pimoroni in a while though, need to ping them in a tweet some time.
sloth badge | current code, anyone any ideas to save space?
2018-02-19 11:28:26
I won't lie, this feels messy. This currently features 5 animations, where 2 of them are just "played accelerating" .
Some things I'm not happy with:
- the button does not work within the animations, so you need to push the button until the animation cycle is over
#include <avr/sleep.h>#define nop() asm volatile("nop")
boolean leds_on = true;
byte badly_programmed_counter = 0;
byte animation_counter_max = 5;
byte animation_counter = 0;
// we need two frames with 8 bits for 12 LEDs
byte frame1 = 0;
byte frame2 = 0;
// animation where every third LED is glowing
// I could shift that continuosly and drop 4 bytes
constbyte three_apart_length = 6;
constbyte three_apart[three_apart_length] PROGMEM = {
0b10010010, 0b01000000,
0b01001001, 0b00100000,
0b00100100, 0b10010000,
};
// this one is huge
// is there a math function to do that instead?
constbyte updown_length = 14;
constbyte updown[updown_length] PROGMEM = {
0b00100000, 0b00000000,
0b01010000, 0b00000000,
0b10001000, 0b00000000,
0b00000100, 0b00010000,
0b00000010, 0b00100000,
0b00000001, 0b01000000,
0b00000000, 0b10000000,
};
// that's just blinking each led
// maybe inverting the data bitwise does the trick
constbyte two_apart_length = 4;
constbyte two_apart[two_apart_length] PROGMEM = {
0b10101010, 0b10100000,
0b01010101, 0b01010000,
};
// should have taken a switch, sleep stuff is huge
ISR(INT0_vect) {
sleep_disable();
leds_on = true;
}
voidsetup(){
// this is for the button setup
PORTB |= (1 << PB1);
DDRB &= ~(1 << PB1);
shutdown_chip();
}
voidloop(){
if (leds_on)
{
cli();
leds_on = false;
// I call it that, because the millis stuff
// and the interrupts collided and broke
badly_programmed_counter = 0;
}
// fancy way of checking the button state
if (!(PINB & (1 << PB1)))
{
badly_programmed_counter++;
my_100ms_delay();
// check if button was released before time
// so animation index can be incremented
// maybe a modulo with animation_counter_max
// safes space
if ( (PINB & (1 << PB1)) )
{
badly_programmed_counter = 0;
animation_counter++;
if (animation_counter == animation_counter_max)
{
animation_counter = 0;
}
charlie(animation_counter);
// calling a function instead of writing it down
// 5 times helps already
for (byte b = 0; b < 5; b++) my_100ms_delay();
}
if (badly_programmed_counter >= 7)
{
// blink when shutdown is immanent
for (byte b = 0; b < 5; b++) blip();
shutdown_chip();
}
}
else
{
animate_leds();
badly_programmed_counter = 0;
}
}
// this is probably already at it's best
voidcharlie(bytevar){
leds_off();
switch (var) {
case0: // 1
DDRB |= (1 << PB0) | (1 << PB2); // output
PORTB |= (1 << PB0); // HIGHbreak;
case1: // 2
DDRB |= (1 << PB0) | (1 << PB2); // output
PORTB |= (1 << PB2); // HIGHbreak;
case2: // 3
DDRB |= (1 << PB2) | (1 << PB3); // output
PORTB |= (1 << PB2); // HIGHbreak;
case3: // 4
DDRB |= (1 << PB2) | (1 << PB3); // output
PORTB |= (1 << PB3); // HIGHbreak;
case4: // 5
DDRB |= (1 << PB3) | (1 << PB4); // output
PORTB |= (1 << PB3); // HIGHbreak;
case5: // 6
DDRB |= (1 << PB3) | (1 << PB4); // output
PORTB |= (1 << PB4); // HIGHbreak;
case6: // 7
DDRB |= (1 << PB0) | (1 << PB3); // output
PORTB |= (1 << PB0); // HIGHbreak;
case7: // 8
DDRB |= (1 << PB0) | (1 << PB3); // output
PORTB |= (1 << PB3); // HIGHbreak;
case8: // 9
DDRB |= (1 << PB2) | (1 << PB4); // output
PORTB |= (1 << PB2); // HIGHbreak;
case9: // 10
DDRB |= (1 << PB2) | (1 << PB4); // output
PORTB |= (1 << PB4); // HIGHbreak;
case10: // 11
DDRB |= (1 << PB0) | (1 << PB4); // output
PORTB |= (1 << PB0); // HIGHbreak;
case11: // 12
DDRB |= (1 << PB0) | (1 << PB4); // output
PORTB |= (1 << PB4); // HIGHbreak;
default:
;
nop();
}
}
voidshutdown_chip(){
animation_counter = 0;
leds_off();
/* Clear WDRF in MCUSR */
MCUSR &= ~(1 << WDRF);
/* Write logical one to WDCE and WDE *//* Keep old prescaler setting to prevent unintentional time-out */
WDTCR |= (1 << WDCE) | (1 << WDE);
/* Turn off WDT */
WDTCR = 0x00;
ADCSRA &= ~(1 << ADEN); // turn off adc
GIMSK |= (1 << INT0);
GIMSK |= (1 << PCIE);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sei(); // Enable global interrupts
sleep_cpu();
sleep_disable();
}
voidanimate_leds(){
switch (animation_counter)
{
case0:
animate_frames(
three_apart_length,
three_apart,
512
);
break;
case1:
for (byte acc_counter = 1; acc_counter < 64; acc_counter += 2)
{
animate_frames(
three_apart_length,
three_apart,
acc_counter * 8
);
}
break;
case2:
animate_frames(
updown_length,
updown,
512
);
break;
case3:
animate_frames(
two_apart_length,
two_apart,
2048
);
break;
case4:
for (byte acc_counter = 1; acc_counter < 64; acc_counter += 2)
{
animate_frames(
updown_length,
updown,
(63-acc_counter) * 4
);
}
break;
default:
leds_off();
break;
}
}
voidanimate_frames(
byte animation_length,
constbyte* animation_array,
uint16_t frame_duration
){
for (byte i = 0; i < animation_length; i += 2)
{
// save the last time you blinked the LED
frame1 = pgm_read_byte_near(animation_array + i);
frame2 = pgm_read_byte_near(animation_array + i + 1);
show_frame(frame_duration);
}
}
// this just looks ugly, but needs to be done
// for loop through frame bytes to set the LEDs with
// the charlie plex function
voidshow_frame(uint16_t byteframe_length){
for (uint16_t j = 0; j < byteframe_length; j++)
{
//iterate through bit maskfor (byte i = 0; i < 12; i++)
{
// if bitwise AND resolves to trueif (
(
i < 8 &&
1 << i & frame1
) ||
(
i > 7 &&
1 << (i - 4) & frame2
)
)
{
charlie(i);
}
else
{
charlie(255);
}
}
}
}
voidleds_off(){
DDRB &= ~(0b00011101);
PORTB &= ~(0b00011101);
}
voidblip(){
charlie(11);
// delay(100);
my_100ms_delay();
charlie(255);
// delay(100);
my_100ms_delay();
}
voidmy_100ms_delay(){
for (uint32_t i=0;i<40000;i++) nop();
}
sloth badge | current code, anyone any ideas to save space?
2018-02-19 11:28:26
I won't lie, this feels messy. This currently features 5 animations, where 2 of them are just "played accelerating" .
Some things I'm not happy with:
- the button does not work within the animations, so you need to push the button until the animation cycle is over
#include <avr/sleep.h>#define nop() asm volatile("nop")
boolean leds_on = true;
byte badly_programmed_counter = 0;
byte animation_counter_max = 5;
byte animation_counter = 0;
// we need two frames with 8 bits for 12 LEDs
byte frame1 = 0;
byte frame2 = 0;
// animation where every third LED is glowing
// I could shift that continuosly and drop 4 bytes
constbyte three_apart_length = 6;
constbyte three_apart[three_apart_length] PROGMEM = {
0b10010010, 0b01000000,
0b01001001, 0b00100000,
0b00100100, 0b10010000,
};
// this one is huge
// is there a math function to do that instead?
constbyte updown_length = 14;
constbyte updown[updown_length] PROGMEM = {
0b00100000, 0b00000000,
0b01010000, 0b00000000,
0b10001000, 0b00000000,
0b00000100, 0b00010000,
0b00000010, 0b00100000,
0b00000001, 0b01000000,
0b00000000, 0b10000000,
};
// that's just blinking each led
// maybe inverting the data bitwise does the trick
constbyte two_apart_length = 4;
constbyte two_apart[two_apart_length] PROGMEM = {
0b10101010, 0b10100000,
0b01010101, 0b01010000,
};
// should have taken a switch, sleep stuff is huge
ISR(INT0_vect) {
sleep_disable();
leds_on = true;
}
voidsetup(){
// this is for the button setup
PORTB |= (1 << PB1);
DDRB &= ~(1 << PB1);
shutdown_chip();
}
voidloop(){
if (leds_on)
{
cli();
leds_on = false;
// I call it that, because the millis stuff
// and the interrupts collided and broke
badly_programmed_counter = 0;
}
// fancy way of checking the button state
if (!(PINB & (1 << PB1)))
{
badly_programmed_counter++;
my_100ms_delay();
// check if button was released before time
// so animation index can be incremented
// maybe a modulo with animation_counter_max
// safes space
if ( (PINB & (1 << PB1)) )
{
badly_programmed_counter = 0;
animation_counter++;
if (animation_counter == animation_counter_max)
{
animation_counter = 0;
}
charlie(animation_counter);
// calling a function instead of writing it down
// 5 times helps already
for (byte b = 0; b < 5; b++) my_100ms_delay();
}
if (badly_programmed_counter >= 7)
{
// blink when shutdown is immanent
for (byte b = 0; b < 5; b++) blip();
shutdown_chip();
}
}
else
{
animate_leds();
badly_programmed_counter = 0;
}
}
// this is probably already at it's best
voidcharlie(bytevar){
leds_off();
switch (var) {
case0: // 1
DDRB |= (1 << PB0) | (1 << PB2); // output
PORTB |= (1 << PB0); // HIGHbreak;
case1: // 2
DDRB |= (1 << PB0) | (1 << PB2); // output
PORTB |= (1 << PB2); // HIGHbreak;
case2: // 3
DDRB |= (1 << PB2) | (1 << PB3); // output
PORTB |= (1 << PB2); // HIGHbreak;
case3: // 4
DDRB |= (1 << PB2) | (1 << PB3); // output
PORTB |= (1 << PB3); // HIGHbreak;
case4: // 5
DDRB |= (1 << PB3) | (1 << PB4); // output
PORTB |= (1 << PB3); // HIGHbreak;
case5: // 6
DDRB |= (1 << PB3) | (1 << PB4); // output
PORTB |= (1 << PB4); // HIGHbreak;
case6: // 7
DDRB |= (1 << PB0) | (1 << PB3); // output
PORTB |= (1 << PB0); // HIGHbreak;
case7: // 8
DDRB |= (1 << PB0) | (1 << PB3); // output
PORTB |= (1 << PB3); // HIGHbreak;
case8: // 9
DDRB |= (1 << PB2) | (1 << PB4); // output
PORTB |= (1 << PB2); // HIGHbreak;
case9: // 10
DDRB |= (1 << PB2) | (1 << PB4); // output
PORTB |= (1 << PB4); // HIGHbreak;
case10: // 11
DDRB |= (1 << PB0) | (1 << PB4); // output
PORTB |= (1 << PB0); // HIGHbreak;
case11: // 12
DDRB |= (1 << PB0) | (1 << PB4); // output
PORTB |= (1 << PB4); // HIGHbreak;
default:
;
nop();
}
}
voidshutdown_chip(){
animation_counter = 0;
leds_off();
/* Clear WDRF in MCUSR */
MCUSR &= ~(1 << WDRF);
/* Write logical one to WDCE and WDE *//* Keep old prescaler setting to prevent unintentional time-out */
WDTCR |= (1 << WDCE) | (1 << WDE);
/* Turn off WDT */
WDTCR = 0x00;
ADCSRA &= ~(1 << ADEN); // turn off adc
GIMSK |= (1 << INT0);
GIMSK |= (1 << PCIE);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sei(); // Enable global interrupts
sleep_cpu();
sleep_disable();
}
voidanimate_leds(){
switch (animation_counter)
{
case0:
animate_frames(
three_apart_length,
three_apart,
512
);
break;
case1:
for (byte acc_counter = 1; acc_counter < 64; acc_counter += 2)
{
animate_frames(
three_apart_length,
three_apart,
acc_counter * 8
);
}
break;
case2:
animate_frames(
updown_length,
updown,
512
);
break;
case3:
animate_frames(
two_apart_length,
two_apart,
2048
);
break;
case4:
for (byte acc_counter = 1; acc_counter < 64; acc_counter += 2)
{
animate_frames(
updown_length,
updown,
(63-acc_counter) * 4
);
}
break;
default:
leds_off();
break;
}
}
voidanimate_frames(
byte animation_length,
constbyte* animation_array,
uint16_t frame_duration
){
for (byte i = 0; i < animation_length; i += 2)
{
// save the last time you blinked the LED
frame1 = pgm_read_byte_near(animation_array + i);
frame2 = pgm_read_byte_near(animation_array + i + 1);
show_frame(frame_duration);
}
}
// this just looks ugly, but needs to be done
// for loop through frame bytes to set the LEDs with
// the charlie plex function
voidshow_frame(uint16_t byteframe_length){
for (uint16_t j = 0; j < byteframe_length; j++)
{
//iterate through bit maskfor (byte i = 0; i < 12; i++)
{
// if bitwise AND resolves to trueif (
(
i < 8 &&
1 << i & frame1
) ||
(
i > 7 &&
1 << (i - 4) & frame2
)
)
{
charlie(i);
}
else
{
charlie(255);
}
}
}
}
voidleds_off(){
DDRB &= ~(0b00011101);
PORTB &= ~(0b00011101);
}
voidblip(){
charlie(11);
// delay(100);
my_100ms_delay();
charlie(255);
// delay(100);
my_100ms_delay();
}
voidmy_100ms_delay(){
for (uint32_t i=0;i<40000;i++) nop();
}
sloth badge | everything ready for a small run
2018-01-01 14:41:50
After a little email exchange with Paul from pimoroni we agreed on me doing a small run of badges on @Tindie is alright with everyone, including their designer, so I will finally do a batch run with @oshpark for the first time.
The code has some potential, needs some cleaning up and some options for animations like I have added to my #K.I.T.T. - KNIGHT RIDER badge/brooch. I should use a higher value of resistors for the LEDs, they blink quite bright.
Part wise I'm all set, everything is ordered so I can sell them as kits, but might add soldered up options like I did with Kitt.
sloth badge | everything ready for a small run
2018-01-01 14:41:50
After a little email exchange with Paul from pimoroni we agreed on me doing a small run of badges on @Tindie is alright with everyone, including their designer, so I will finally do a batch run with @oshpark for the first time.
The code has some potential, needs some cleaning up and some options for animations like I have added to my #K.I.T.T. - KNIGHT RIDER badge/brooch. I should use a higher value of resistors for the LEDs, they blink quite bright.
Part wise I'm all set, everything is ordered so I can sell them as kits, but might add soldered up options like I did with Kitt.
sloth badge | ahhh... I need help, I don't see it
2017-12-09 23:53:17
Somewhere along I had it go to sleep just fine, but it didn't wake up. Now it wakes up fine, but doesn't want to go to sleep. Seems like I don't have the millis stuff right anymore, I don't get to where the comment "// HOW DO I GET HERE?" is. Too tired to see it,
gonna go to bed.
Somewhere along I had it go to sleep just fine, but it didn't wake up. Now it wakes up fine, but doesn't want to go to sleep. Seems like I don't have the millis stuff right anymore, I don't get to where the comment "// HOW DO I GET HERE?" is. Too tired to see it,
gonna go to bed.
seems like they use 1.1mA in sleep mode, which isn't really good for a coin cell that has around 230mAh of power - 9 days of doing nothing o.O so with the right settings my sloth badge will already last a lot longer! nice :3
sloth badge | bearables power consumption
2017-11-30 15:32:19
seems like they use 1.1mA in sleep mode, which isn't really good for a coin cell that has around 230mAh of power - 9 days of doing nothing o.O so with the right settings my sloth badge will already last a lot longer! nice :3