【MBC-06】息で吹き消せ!LEDライト

概要

blow-out-led

・ロウソクのように、息を吹きかけると消えるLEDライトを作ってみた。

・圧電スピーカに振動を与えると、わずかだが電圧が発生する。その電圧をマイコンのアナログコンパレータで検出すると、LEDが消える。

・ファームウェアRev.1では、本当のロウソクと違って、もう一度息を吹きかけると点灯してしまう。もっとも、この動作はプログラムでどうにでもなるわけだが。

・そこで、ファームウェアRev.2では、1回吹いただけでは点灯しないように変更。1秒程度の間隔をあけてセンサを2回たたくと点灯する。効果音も追加してみた。

使用部品

parts list

ミニブレッドボード BB-601

AVRマイコン ATTINY2313-20PU またはATTINY2313V-10PU

5mm径LED

圧電スピーカ (13mm)PKM13EPYH4000-A0

カーボン抵抗器 150Ω、1/4W 2個

カーボン抵抗器 100kΩ、1/4W

カーボン抵抗器 10kΩ、1/4W

バッテリースナップ

単3電池2本用電池ボックス

ジャンパ線1本

回路図

schematics

実体配線図

breadboard-001

ファームウェア (AVR-GCC)

(Rev.2 吹くと音が鳴って点滅しながら消灯、約1秒間隔で2回たたくと、音がなり、点滅しながら点灯する。)

// Analog Cmparator Application ( Blow Out LED )
// TARGET : ATTINY2313 (Internal OSC : 8MHz / 8 ( Factory default ) 
// AIN1 : Resistor
// AIN0 ( PB0 ) : Piezo speaker
// PB3 : LED (0:ON, 1:OFF)
#include <avr/io.h>
#include <avr/interrupt.h>

#define led_off() ( PORTB |= (1<<PB3) )

#define led_on() ( PORTB &= ~(1<<PB3) )

#define led() ( PORTB ^= (1<<PB3) )

#define buz() ( PORTB ^= (1<<PB0) )

#define is_analog_in() ( ACSR & (1<<ACO) ) // Analog Comparator Output

void wait(volatile long i)

{

while (i-- > 0);

}
void init_timer0(void)
{
    //Set Timer Counter Control Register A (TCCR0A)

// (WGM02) WGM01 WGM00

// ( 0 ) 0 0 // Normal mode

// ( 0 ) 1 1 // Fast PWM mode

// ( 0 ) 1 0 // CTC mode

// ( 1 ) 1 1 // Fast PWM mode TOP is OCR0A

// ( 1 ) 0 1 // PWM Phase correct TOP is OCR0A

// COM0A1 COM0A0 COM0B1 COM0B0

    //    0      0       0      0   // Normal Port Operation, OC0A Disconnected.

// 1 0 1 0 // Clear OC0A on Compare Match, set OC0A at TOP

    TCCR0A = (0<<WGM02) | (0<<WGM00) | (0<<WGM00) |
                (0<<COM0A0) | (0<<COM0A1) | (0<<COM0B0) | (0<<COM0B1);
            // Normal mode, OC0A/B no output

//Set Timer Counter Control Register B (TCCR0B)

// FOC0A FOC0B

// 0 0 ... TCCR0A, TCCR0B is written.

// CS02 CS01 CS00

// 0 0 1 ... No prescaling

// 0 1 0 ... clki/o / 8

// 0 1 1 ... clki/o / 64

// 1 0 0 ... clki/o / 256

// 1 0 1 ... clki/o / 1024

   TCCR0B = (0<<CS02) | (1<<CS01) | (0<<CS00) ; // Clock Prescale : Clki/o  / 8
    // 1 interrrupt = 2.048ms
    TIMSK |= (1<<TOIE0); // TIMER0 interrupt enable
}

volatile unsigned long TCOUNTER = 0; // Timer 0 Counter

#define TC500MS 25
#define TC2S 1000
ISR(TIMER0_OVF_vect)
{
    TCOUNTER++;
}

void waitms(volatile unsigned long t)

// Pause Execution about t[ms]
{

volatile unsigned long limit;

    limit = t / 2;
    TCOUNTER = 0;
    while (TCOUNTER < limit);
}
enum LED {ON, OFF};
enum BOOLEAN {FALSE, TRUE};
int main(void)
{

int i, j;

unsigned int flag_light, flag_analog_in;

    

// Initialize I/O Port

DDRB = (1<<PB3) | (1<<PB0); // PB0: Output mode

// Initialize TIMER0

    init_timer0();
    //Enable Interrupt
    sei();
    

for (i = 0; i < 3; i++) {

led_on(); waitms(100);

for ( j = 0; j < 500; j++) { buz(); wait(5); }

led_off(); waitms(100);

}

DDRB &= ~(1<<PB0); // PB0: Input mode

led_on(); flag_light = ON;

while (1) {

        
        switch (flag_light) {
            case OFF:
                // Light OFF -> ON
                // When Input Signal is H->L->H, LED light on.
                if (is_analog_in()) {
                    waitms(500);
                    flag_analog_in = FALSE;
                    TCOUNTER = 0;
                    while (TCOUNTER < TC500MS) {
                        if (is_analog_in()) {
                            flag_analog_in = TRUE;
                            break;
                        }
                    }
                    if (flag_analog_in == FALSE) {
                        TCOUNTER = 0;
                        while (TCOUNTER < TC2S) {
                            if (is_analog_in()) {
                                for (i = 150; i > 0; i--) {buz(); led(); wait(i); }
                                led_on(); flag_light = ON;
                                waitms(1000);
                                break;
                            }
                        }
                    }
                }
                break;
            case ON:
                // Light ON -> OFF
                // When Input Signal is detected, LED light on.
                if (is_analog_in()) {
                    for (j = 1; j < 5; j++) {
                        for (i = j * 100; i > 0; i--) {
                             buz();
                             wait(5);
                         }
                         led();
                    }
                    led_off(); flag_light = OFF;
                    waitms(1000);
                }
                break;
            default :
                led_off();  flag_light = OFF;
        }

}

return 0;

}

(Rev.1 単純に吹いたとき消灯、次に吹くと点灯)

// Analog comparator test
// TARGET : ATTINY2313
// AIN1 : Resistor
// AIN0 ( PB0 ) : Piezo speaker
// PB3 : LED (0:ON, 1:OFF)
#include <avr/io.h>

#define led_off() ( PORTB |= (1<<PB3) )

#define led_on() ( PORTB &= ~(1<<PB3) )

#define led() ( PINB |= (1<<PB3) )

#define buz() ( PINB |= (1<<PB0) )

#define is_analog_in() ( ACSR & (1<<ACO) ) // Analog Comparator Output

void wait(volatile long i)
{

while (i-- > 0);

}
int main(void)
{

int i, j;

// Initialize I/O Port

DDRB = (1<<PB3) | (1<<PB0); // PB0: Output mode


for (i = 0; i < 3; i++) {

led_on(); wait(5000);

for ( j = 0; j < 1000; j++) { buz(); wait(10); }

led_off(); wait(5000);

}

DDRB &= ~(1<<PB0); // PB0: Input mode

led_on();

while (1) {

if (is_analog_in()) {

led();

wait(10000);

}

}

return 0;

}

Makefile (AVR-GCC (Linux, OS X Cross-Pack) 用)

# AVR-GCC Makefile
PROJECT=anacmp-2313
SOURCES=$(PROJECT).c
CC=avr-gcc
OBJCOPY=avr-objcopy
MMCU=attiny2313
TARGETDEV=t2313
CFLAGS=-mmcu=$(MMCU) -Wall
$(PROJECT).hex: $(PROJECT).out

$(OBJCOPY) -j .text -O ihex $(PROJECT).out $(PROJECT).hex

$(PROJECT).out: $(SOURCES)

$(CC) $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES)

program: $(PROJECT).hex

sudo avrdude -p $(TARGETDEV) -P usb -c avrispmkII -e -U flash:w:$(PROJECT).hex

clean:

rm -f $(PROJECT).out

rm -f $(PROJECT).hex