赤外線射的ゲーム(ATtiny26L/861)

4つの的を赤外線光線銃で狙って撃つと、当たった的の数と種類に応じて得点が加算され、スコアLEDが点灯する。

赤外線光線銃の弾は4発。スコアLEDがたくさん点灯した人の勝ちだ。

赤外線は壁や天井、床で反射するため、なかなか狙いがつけにくい。

赤外線射的ゲーム の 的(まと)
赤外線射的ゲームの赤外線発信機


使用部品

的センサ基板(1枚当たりの数量。同じものを4枚作成する。)

赤外線リモコン受信モジュール PL-IRM0208 (38kHzで変調された信号を受信すると、出力がHigh→Lowに変化)

カーボン抵抗器 470Ω, 1/4W

LED Φ5mm

ユニバーサル基板 サンハヤトICB-90

分割ロングピンソケット 1x2 2個、1x3 1個

ブレッドボード用ジャンパワイヤ

基板固定用スペーサ、ネジ

的制御基板

AVRマイコン ATtiny26L (または ATtiny861 … ソース変更と再コンパイル必要)

ユニバーサル基板 PICOK200 94V-D ブレッドボード配線パターン

圧電サウンダ OKM13EPYH4000-A0 リード線ピッチ5mm, 直径12.6mm

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

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

タクトスイッチ

スライドスイッチ

LED Φ5mm × 4個

ICソケット 20PIN

集合抵抗 330Ω 4個入

バッテリースナップ

電池ボックス 単3×3本用、バッテリースナップタイプ

分割ロングピンソケット 1x4 2個、2x4 1個

基板固定用スペーサ、ネジ

赤外線射的の的

赤外線発信機

AVRマイコン ATtiny26L (または ATtiny861 … ソース変更と再コンパイル必要)

ユニバーサル基板 PICOK200 94V-D ブレッドボード配線パターン

圧電サウンダ OKM13EPYH4000-A0 リード線ピッチ5mm, 直径12.6mm

半固定抵抗器 1kΩ(つまみ付き)

カーボン抵抗器 10kΩ, 470Ω, 150Ω, いずれも1/4W

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

タクトスイッチ

スライドスイッチ

LED Φ5mm × 5個

赤外線LED Φ5mm

ICソケット 20PIN

集合抵抗 330Ω 4個入

バッテリースナップ

電池ボックス 単3×3本用、バッテリースナップタイプ

分割ロングピンソケット 1x4 2個、2x4 1個

発信機の説明

回路図

的制御基板

赤外線射的ゲーム 的制御基板の回路図

的用赤外線センサと表示用LED基板

赤外線発信機基板

赤外線射的ゲームの発信機回路図

赤外線信号の形式

発信機は、図のような変調をかけた赤外線信号を発信する。

赤外線信号のフォーマット

ファームウェア

蛍光灯などでの誤動作を防ぐため、変調をかけた版を以下に示す。バイナリ等は添付ファイルir-shooting-tiny26(-tiny861).zipを参照。

なお、変調をかけていない単純な構成の版は添付ファイルir-shooting-no-modulation-tiny26(-tiny861).zipにある。

的制御基板用(AVR-GCCソース)

// TARGET : ATTINY26 / (ATTINY861)

//

// Input Port

// PA0,1,2,3 : PIN 20,19,18,17 : IR-remote control reciever : Active low

//

// Output Port

// PA4,5,6,7 : PIN 14,13,12,11 : score LED 1:ON, 0:OFF

// PB0,1,2,3 : PIN 1,2,3,4 : hit Target LED 1:OFF, 0:ON

// PB6 : PIN 9 : Buzzer

#define F_CPU 1000000UL // clock frequency 1MHz

#include <util/delay.h>

#include <avr/io.h>

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

#define getIrSensor() ( PINA & 0b00001111 )

void wait(volatile long i)

{

while (i-- > 0);

}

void targetLed(uint8_t pattern)

// pattern : 1: LED ON, 0: LED OFF

{

PORTB = (~pattern) & 0b00001111;

}

void targetLedOn(uint8_t portNo) {

PORTB &= ~(1<<portNo);

}

void targetLedOff(uint8_t portNo) {

PORTB |= (1<<portNo);

}

void scoreLed(uint8_t pattern)

{

pattern <<= 4;

PORTA = pattern & 0b11110000 ;

}

uint8_t getIrSignal(uint8_t portNo)

// return value : Sensor #3210 -> 1:ON, 0:OFF

{

return !( PINA & ( 1<<portNo ) );

}

uint8_t getModulatedIrSignalBits(void)

// #senosr #3210

// ON : 1

// OFF : 0

{

uint8_t InBit, RetBit=0x00;

uint8_t BitPattern[3] = {0, 0, 0}; // Signal BIT pattern

volatile int i;

InBit = getIrSensor();

if ( InBit == 0b1111 ) {

RetBit = 0; // no sense

} else {

_delay_us(2000); // wait 2ms

InBit = getIrSensor();

if (InBit == 0b1111) {

RetBit = 0; // no valid signal

} else {

while ( InBit != 0b1111 ) {

InBit = getIrSensor();

} // wait for bit pattern 0b1111 (rising edge)

_delay_ms(1);

BitPattern[0] = getIrSensor();

_delay_ms(2);

BitPattern[1] = getIrSensor();

_delay_ms(2);

BitPattern[2] = getIrSensor();

}

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

if ( ( BitPattern[0] & (1<<i) ) == 0 &&

( BitPattern[1] & (1<<i) ) == 0 &&

( BitPattern[2] & (1<<i) ) != 0 ) {

RetBit |= (1<<i); // detect signal on port #i

} else {

RetBit &= ~(1<<i);

}

}

}

return RetBit & 0b00001111;

}

void beep(int height, int period)

{

int i;

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

buz();

wait((int)height);

}

}

void initPort(void)

{

// Initialize I/O Port

PORTA = 0b00000000; // NO PORT Enable Interal Pull ups

DDRA = 0b11110000; // PA7654 Output mode , PA3210 Input Mode

DDRB = 0b01111111; //PB0-6 Output Mode

}

int main(void)

{

uint8_t irSignalBits;

uint8_t score;

uint8_t i;

initPort();

targetLed(0b0000); // All target LEDs are OFF

scoreLed(0b0000); // All score LED are OFF

while (getModulatedIrSignalBits()); // wait no signal

wait(10000); // wait few seconds

beep(5,200); // START !

score = 0;

while (1)

{

// sensor #0,#1,#2 : HIT +1 pts

// sensor #3 : HIT +2 pts

irSignalBits = getModulatedIrSignalBits();

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

if ( irSignalBits & (1<<i) ) {

targetLedOn(i);

switch (i) {

case 0:

case 1:

case 2:

score ++;

beep(30, 50);

break;

case 3:

score += 2;

beep(2, 300);

break;

}

}

}

if (irSignalBits) {

wait(40000); //wait for a few second.

while ( getIrSensor() != 0b1111 ); // wait until no sense

}

while (irSignalBits) {

// wait until no signal

irSignalBits = getModulatedIrSignalBits();

};

targetLed(0b0000); // All target LEDs OFF

if (score > 15) {

score = 0;

}

scoreLed(score);

}

return 0;

}

的制御基板用(Makefile)

# AVR-GCC Makefile
PROJECT=tiny26irtarget
SOURCES=$(PROJECT).c
CC=avr-gcc
OBJCOPY=avr-objcopy
#for ATtiny26
MMCU=attiny26
TARGETDEV=t26
# for ATtiny861
#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

赤外線発信機用(AVR-GCCソース)

// Ir-Shooting Game System
//  Ir-Transmitter (Modulation mode)
//
// TARGET : ATTINY26 (ATTINY861)
//
// Input Port
//  PA0 : PIN 11 : Tact switch pullup register enable 0:ON, 1:OFF
//
// Output Port
//  PB1 : PIN 2 : Infarred LED : 1:ON, 0:OFF
//  PB3 : PIN 4 : LED (Trigger ON) : 1:ON, 0:OFF
//  PA7654 : PIN 14,13,12,11 : LED ( Energy Gage) 1:ON, 0:OFF
//  PB6 : PIN 9 : Buzzer
#define F_CPU 1000000UL // clock frequency 1MHz
#include <util/delay.h>
#include <avr/io.h>

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

#define led_on()    (PORTB |= (1<<PB3))
#define led_off()   (PORTB &= ~(1<<PB3))
#define isSwitchOn() (!(PINA & (1<<PA0)))
void wait(volatile long i)
{

while (i-- > 0);

}
void beep(void)
{
    int i;
    for (i = 0; i < 300; i++) {
        buz();
        wait(2);
    }
}
#define FREQ38KHZ 208 // (CK 1Mhz) value of OCR1A at 38kHz Frequency
void initTimer1CTC(void)
// Initialize Timer/Counter1 CTC (Clear Timer on Compare mode) mode
{
    // Freq = 2 * PLL clock (64MHz/8) / N(1 + OCR1C) , N=2(1/2 Prescaling)
    PLLCSR |= (1<<PLLE) | (1<<PCKE); //PCK Enable
    TCCR1B = (1<<CTC1) | (0<<CS13) | (0<<CS12) | (1<<CS11) | (1<<CS10); // ATtiny26L
    // TCCR1B = (0<<CS13) | (0<<CS12) | (1<<CS11) | (1<<CS10); // ATtiny861
    OCR1C = FREQ38KHZ;
    
    TIMSK |= (1<<OCIE1A);
}
void connect_OC1A(void)
{
    TCCR1A = (0<<COM1A1) | (1<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<PWM1A);
}
void disconnect_OC1A(void)
{
    TCCR1A = 0x00;
}
void showEnergyGage(uint8_t energy)
{
    PORTA &= 0b00001111; // all Gage LED off
    switch (energy) {
        case 4 :
            PORTA |= 0b11110000;
            break;
        case 3 :
            PORTA |= 0b11100000;
            break;
        case 2 :
            PORTA |= 0b11000000;
            break;
        case 1 :
            PORTA |= 0b10000000;
            break;
        default :
            PORTA |= 0;
    }
}
void initPort(void)
{
    // Initialize I/O Port
    PORTA = 0b11110001; // PA0 Enable Interal Pull ups, PA0123 High (Energy Gage LED OFF)
    DDRA  = 0b11111110; // PA0 Input Mode
    
    DDRB  = 0b01111111; //PB6543210 Output Mode
}
void modulateOutput(void)
{
    connect_OC1A();
    _delay_ms(3);
    
    disconnect_OC1A();
    _delay_us(500);
    
    connect_OC1A();
    _delay_us(1500);
    disconnect_OC1A();
    _delay_us(500);
    
    connect_OC1A();
    _delay_us(1500);
    
    disconnect_OC1A();
    _delay_ms(5);
}
int main(void)
{
    uint8_t energy;
    int OutputCounter;
    
    initPort();
    initTimer1CTC();
    disconnect_OC1A();
    
    energy = 4;
    showEnergyGage(energy);
    
    while( isSwitchOn() );
    

while (1)

{

        while (energy > 0) {
            if ( isSwitchOn() ) {
                led_on();
                beep();
                
                for (OutputCounter = 0; OutputCounter < 50; OutputCounter++) {
                    modulateOutput();
                }
                
                energy--;
                showEnergyGage(energy);
                while (isSwitchOn());
            } else {
                disconnect_OC1A();
                led_off();
            }
        }
        disconnect_OC1A();
        led_off();

}

return 0;

}

赤外線発信機用(Makefile)

# AVR-GCC Makefile
PROJECT=ir-transmitter-tiny26
SOURCES=$(PROJECT).c
CC=avr-gcc
OBJCOPY=avr-objcopy
#for ATtiny26
MMCU=attiny26
TARGETDEV=t26
# for ATtiny861
#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