[BC19-02]LEDサイコロ

電子工作の定番、LEDを7個使った電子サイコロ

タクトスイッチや光センサでサイコロを振ることができる。

使用部品

AVRマイコン Microchip (Atmel) AT tiny 26L / 861

LED 7個

フォトトランジスタ 新日本無線 NJL7502

圧電スピーカ(13mm) 村田製作所 PKM13EPYH4000-A0

タクトスイッチ 2ピン・ラジアルリード TVDT18-050CW-T

積層セラミックコンデンサ 0.1uF

カーボン抵抗器 150Ω 7個、100kΩ 1個

ブレッドボード EIC-801

バッテリースナップ

電池ボックス(単3形2本用、バッテリスナップタイプ)

ジャンパ線

回路図

実体配線図

プログラマとの接続

ISPコネクタの1番をMISOとして、下図のように接続する。

ファームウェア

ソースコード(AVR-GCC)

/* 7-LED-DICE
* Traget : ATTINY26/861
*
* Input :
 *  ADC3(PA4) <PIN14> : A-D Convertor ( optical transistor ) Input : bright->Low V, dark->High V
*  PB6(INT0) <PIN9>   :  Tact Switch   1:ON 0:OFF
* Output:
*  PA0123 <PIN20,19,18,17> : LED1,2,3,4
*  PB012  <PIN1,2,3> : LED5,6,7
*  PA7 <PIN11> : Buzzer
*
*  # LED layout
*   PA0  PA1  PA2
*        PA3
*   PB0  PB1  PB2
*
*/

#include <avr/io.h>

#define  led1_on()   ( PORTA |= (1<<PA0) )
#define led2_on()     ( PORTA |= (1<<PA1) )
#define led3_on()     ( PORTA |= (1<<PA2) )
#define led4_on()     ( PORTA |= (1<<PA3) )
#define led5_on()     ( PORTB |= (1<<PB0) )
#define led6_on()     ( PORTB |= (1<<PB1) )
#define led7_on()     ( PORTB |= (1<<PB2) )

#define led1_off()     ( PORTA &= ~(1<<PA0) )
#define led2_off()     ( PORTA &= ~(1<<PA1) )
#define led3_off()     ( PORTA &= ~(1<<PA2) )
#define led4_off()     ( PORTA &= ~(1<<PA3) )
#define led5_off()     ( PORTB &= ~(1<<PB0) )
#define led6_off()     ( PORTB &= ~(1<<PB1) )
#define led7_off()     ( PORTB &= ~(1<<PB2) )

#define led_b_on() ( PORTB |= 0b00000111 )
#define led_a_on() ( PORTA |= 0b00001111 )
#define led_b_off() ( PORTB &= ~0b00000111 )
#define led_a_off() ( PORTA &= ~0b00001111 )

#define buz()  ( PORTA ^= (1<<PA7) )

#define is_switch()   !( PINB & (1<<PB6) )

#define OFF 0x00
#define ON  0xff

#define TONE_LENGTH  100
#define PAUSE_LENGTH 5000
#define DARK_THRESHOLD 220

int adconv(void)
/* AD Convertor */
{
 int adata;
 /* Tiny26 */
 ADCSR |= (1<<ADEN) | (1<<ADSC); // A-D convertor enable,
 ADMUX = (1<<ADLAR) | (0b011); // Tyny26/861 : ADLAR=1, ADC3 SingleEndedInput
 while ( !(ADCSR & (1<<ADIF)) ); // Tiny26
 adata = ADCH;
 ADCSR &=~(1<<ADIF); // Tiny26

 /* Tiny 861
 ADCSRA |= (1<<ADEN) | (1<<ADSC); // Tiny861 A-D convertor enable,
 ADMUX = (1<<ADLAR) | (0b011); // Tyny26/861 : ADLAR=1, ADC3 SingleEndedInput
 while ( !(ADCSRA & (1<<ADIF)) ); // Tiny861
 adata = ADCH;
 ADCSRA &=~(1<<ADIF); // Tiny861
  */

 return adata;
}

uint8_t is_adc_switch(void)
// return value : bright -> dark : 0xff, else  : 0x00
{
 static uint8_t previous = 0x00; // Previous blightness 0xff: bright, 0x00:dark
 int d;
  uint8_t result;

 d = adconv();
  if (d > DARK_THRESHOLD) {
  // dark
  if (previous == 0xff) {
   result = 0xff;
  } else {
   result = 0x00;
  }
  previous = 0x00;
 } else {
  // bright
  result = 0x00;
  previous = 0xff;
 }
 return result;
}

uint8_t is_dark(void)
// return value : dark : 0, bright : 0xff
{
  int d;
  d = adconv();
  if (d > DARK_THRESHOLD) {
   //dark
   return 0xff;
  } else {
   return 0x00;
  }
}

void wait(volatile int32_t i)
{
 while (i-- > 0);
}


void init_io(void)
{
 // Initialize I/O Port
 PORTB |= (1<<PB6); // Pull up ON PB6 (switch)
 DDRB &= ~(1<<PB6); // PB6 as input
 DDRB |= (1<<PB0) | (1<<PB1) | (1<<PB2);

 DDRA &= ~(1<<PA4); // PA4 (ADC3) as input
 DDRA |= (1<<PA0) | (1<<PA1) | (1<<PA2) | (1<<PA3) | (1<<PA7);

}


void tone(int16_t length)
{
 int16_t i;
 for (i = 0; i < length; i++) {
  buz();
  wait(8);
 }
}

void dice1(void)
{
 led4_on(); tone(TONE_LENGTH * 10); wait(PAUSE_LENGTH);
}

void dice2(void)
{
 led1_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led7_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
}

void dice3(void)
{
 led1_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led4_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led7_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
}


void dice4(void)
{
 led1_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led3_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led5_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led7_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
}

void dice5(void)
{
 led1_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led3_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led4_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led5_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led7_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
}

void dice6(void)
{
 led1_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led2_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led3_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led5_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led6_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
 led7_on();   tone(TONE_LENGTH); wait(PAUSE_LENGTH);
}

void dice_off()
{
 led1_off();
 led2_off();
 led3_off();
 led4_off();
 led5_off();
 led6_off();
 led7_off();
}

int main(void)
{

 init_io();
 volatile uint8_t v = 0;

 while(is_adc_switch() || is_switch());
 dice_off();

 while(1) {
  if (is_adc_switch() || is_switch()) {
   dice_off();
   while(is_adc_switch() || is_switch() ) {

    // ready
    led_a_on();
    wait(500);
    led_b_on();
    wait(500);
    led_a_off();
    wait(500);
    led_b_off();
    wait(500);
    v++;
   }
   // dice
   switch (v % 6){
    case 0:
     dice6();
     break;
    case 1:
     dice1();
     break;
    case 2:
     dice2();
     break;
    case 3:
     dice3();
     break;
    case 4:
     dice4();
     break;
    case 5:
     dice5();
     break;
    default:
     dice_off();
   }
   while ( !is_switch() && is_dark() ) {
    v++;
   }
  } else {
   v++;
  }
 }
 return 0;
}

Makefile

プログラマにはAVR ISP mkIIを使用する場合を示す。

ヒューズの設定は、内部クロック8MHz, 8分周(実質クロック1MHz)

AT tiny 26用

# AVR-GCC Makefile
PROJECT=dice-tiny26
SOURCES=$(PROJECT).c
CC=avr-gcc
OBJCOPY=avr-objcopy
MMCU=attiny26
TARGETDEV=t26

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

AT tiny861用

# AVR-GCC Makefile
PROJECT=dice-tiny26
SOURCES=$(PROJECT).c
CC=avr-gcc
OBJCOPY=avr-objcopy
MMCU=attiny861
TARGETDEV=t861

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