BAR-LEDマイコンゲーム
・LEDが光ったところにあるスイッチを素早く押すという、モグラたたきゲームのような、とても簡素なゲームを作ってみた。
・ゲームは簡素だが、回路とソフトは結構複雑になってしまった。
・CPUボードと電池ボックスは下層に収納して、コンパクト感を演出?
・もっと大きなLEDやスイッチにすれば、文化祭のゲームコーナーに出品して人気になるかもしれない。
使用部品
マイコン ATMEL ATmega168P-20PU
オプトサプライ10バーLEDアレイ 3色(緑5黄3赤2)タイプ OSX10201-GYR1
φ5mmLED (色はお好みで)×4個
圧電サウンダ(他励振) Murata PKM13EPYH4000-A0
カーボン抵抗器 470Ω x 14個、10kΩ
積層セラミックコンデンサ 0.1uF x 5個
ピンヘッダ 2x3 ( ISP用 )
タクトスイッチ 5個
スライドスイッチ
ピンヘッダ 1x12(4、4、1、1、2に分割して使用)
ボックスコネクタ 4本用×2、1本用×4
電池ボックス 単三型3本用
電池スナップ
ユニバーサル基板 70mm x 45mm ×3枚
スペーサ類 適宜
回路図
(CPUボード)
(LEDとスイッチ)
(バーLED)
※写真の回路では、バーLEDとCPUの接続を逆にしてしまったので、ファームウェアは修正してある。
ファームウェア ( led-game-mega168.c )
機能:
(1)スライドスイッチを入れると、バーLEDが順に点灯し、すべてのLEDが点灯する。
(2)バーLEDのすべてのLEDが点滅する。
(3)スタートスイッチを押すと、ゲーム開始。
(4)点灯しているLEDの下にあるスイッチを押すと、得点が1点加算され、バーLEDが得点の数だけ点灯する。
(5)間違ったボタンを押すと、得点は0になる。
(6)得点が10点になると、音とともにバーLEDが短い間隔で点灯する。
(7)スタートスイッチを押すと、バーLEDが点滅し、待機状態になる。(2)に戻る。
(4)〜(6)の間でスタートスイッチを押すと、(2)に戻る。
//
// led-game-mega168.c
//
//
// Created by kaimunantai on 2013/10/20.
//
// TARGET : ATmega168
//
// [ Output ]
// LED 1,2,3,4 : PB2, PB3, PB4, PB5
// Buzzer : PB1
// 10-BAR LED 0-9 : PD0, PD1, PD3, PD4, PB6, PB7, PD5, PD6, PD7, PB0
// LED No.
// 0 1 2 3 4 5 6 7 8 9
//
// [ Input ]
// Switch 1, 2, 3, 4 : PC0, PC1, PC2, PC3
// Start switch : PD2(INT0)
//
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
void wait(volatile unsigned long i)
{
while( i-- > 0 );
}
void InitPort(void)
// Initialize I/O Ports
{
DDRB = 0xff; // PORTB Output : all
PORTC = 0xff; // pull up reg enable
DDRC = ~( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) ); // PC0,1,2,3 : Input, Others: Output
PORTD = 0xff; // pull up reg enable
DDRD = ~(1<<PD2); // PD2 : Input, Others: Output
}
#define Led1On() ( PORTB |= (1<<PB2) )
#define Led2On() ( PORTB |= (1<<PB3) )
#define Led3On() ( PORTB |= (1<<PB4) )
#define Led4On() ( PORTB |= (1<<PB5) )
#define Led1Off() ( PORTB &= ~(1<<PB2) )
#define Led2Off() ( PORTB &= ~(1<<PB3) )
#define Led3Off() ( PORTB &= ~(1<<PB4) )
#define Led4Off() ( PORTB &= ~(1<<PB5) )
#define Buz() ( PORTB ^= (1<<PB1) )
#define IsStartSwOn() ( !(PIND & (1<<PD2)) )
#define IsSw1On() ( (~PINC) & (1<<PC0) )
#define IsSw2On() ( (~PINC) & (1<<PC1) )
#define IsSw3On() ( (~PINC) & (1<<PC2) )
#define IsSw4On() ( (~PINC) & (1<<PC3) )
#define IsSwOn() ( (~PINC) & ( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) ) )
#define BarLed0Off() (PORTD &= ~(1<<PD0) )
#define BarLed0On() (PORTD |= (1<<PD0) )
#define BarLed0() (PORTD ^= (1<<PD0) )
#define BarLed1Off() (PORTD &= ~(1<<PD1) )
#define BarLed1On() (PORTD |= (1<<PD1) )
#define BarLed1() (PORTD ^= (1<<PD1) )
#define BarLed2Off() (PORTD &= ~(1<<PD3) )
#define BarLed2On() (PORTD |= (1<<PD3) )
#define BarLed2() (PORTD ^= (1<<PD3) )
#define BarLed3Off() (PORTD &= ~(1<<PD4) )
#define BarLed3On() (PORTD |= (1<<PD4) )
#define BarLed3() (PORTD ^= (1<<PD4) )
#define BarLed4Off() (PORTB &= ~(1<<PB6) )
#define BarLed4On() (PORTB |= (1<<PB6) )
#define BarLed4() (PORTB ^= (1<<PB6) )
#define BarLed5Off() (PORTB &= ~(1<<PB7) )
#define BarLed5On() (PORTB |= (1<<PB7) )
#define BarLed5() (PORTB ^= (1<<PB7) )
#define BarLed6Off() (PORTD &= ~(1<<PD5) )
#define BarLed6On() (PORTD |= (1<<PD5) )
#define BarLed6() (PORTD ^= (1<<PD5) )
#define BarLed7Off() (PORTD &= ~(1<<PD6) )
#define BarLed7On() (PORTD |= (1<<PD6) )
#define BarLed7() (PORTD ^= (1<<PD6) )
#define BarLed8Off() (PORTD &= ~(1<<PD7) )
#define BarLed8On() (PORTD |= (1<<PD7) )
#define BarLed8() (PORTD ^= (1<<PD7) )
#define BarLed9Off() (PORTB &= ~(1<<PB0) )
#define BarLed9On() (PORTB |= (1<<PB0) )
#define BarLed9() (PORTB ^= (1<<PB0) )
void Led1234(unsigned char pattern)
{
if (pattern & 0b00000001) {
Led1On();
} else {
Led1Off();
}
if (pattern & (0b00000010)) {
Led2On();
} else {
Led2Off();
}
if (pattern & (0b00000100)) {
Led3On();
} else {
Led3Off();
}
if (pattern & (0b00001000)) {
Led4On();
} else {
Led4Off();
}
}
void BarLed(unsigned int number)
{
switch (number) {
case 0:
BarLed0Off();
BarLed1Off();
BarLed2Off();
BarLed3Off();
BarLed4Off();
BarLed5Off();
BarLed6Off();
BarLed7Off();
BarLed8Off();
BarLed9Off();
break;
case 1:
BarLed0On();
BarLed1Off();
BarLed2Off();
BarLed3Off();
BarLed4Off();
BarLed5Off();
BarLed6Off();
BarLed7Off();
BarLed8Off();
BarLed9Off();
break;
case 2:
BarLed0On();
BarLed1On();
BarLed2Off();
BarLed3Off();
BarLed4Off();
BarLed5Off();
BarLed6Off();
BarLed7Off();
BarLed8Off();
BarLed9Off();
break;
case 3:
BarLed0On();
BarLed1On();
BarLed2On();
BarLed3Off();
BarLed4Off();
BarLed5Off();
BarLed6Off();
BarLed7Off();
BarLed8Off();
BarLed9Off();
break;
case 4:
BarLed0On();
BarLed1On();
BarLed2On();
BarLed3On();
BarLed4Off();
BarLed5Off();
BarLed6Off();
BarLed7Off();
BarLed8Off();
BarLed9Off();
break;
case 5:
BarLed0On();
BarLed1On();
BarLed2On();
BarLed3On();
BarLed4On();
BarLed5Off();
BarLed6Off();
BarLed7Off();
BarLed8Off();
BarLed9Off();
break;
case 6:
BarLed0On();
BarLed1On();
BarLed2On();
BarLed3On();
BarLed4On();
BarLed5On();
BarLed6Off();
BarLed7Off();
BarLed8Off();
BarLed9Off();
break;
case 7:
BarLed0On();
BarLed1On();
BarLed2On();
BarLed3On();
BarLed4On();
BarLed5On();
BarLed6On();
BarLed7Off();
BarLed8Off();
BarLed9Off();
break;
case 8:
BarLed0On();
BarLed1On();
BarLed2On();
BarLed3On();
BarLed4On();
BarLed5On();
BarLed6On();
BarLed7On();
BarLed8Off();
BarLed9Off();
break;
case 9:
BarLed0On();
BarLed1On();
BarLed2On();
BarLed3On();
BarLed4On();
BarLed5On();
BarLed6On();
BarLed7On();
BarLed8On();
BarLed9Off();
break;
case 10:
BarLed0On();
BarLed1On();
BarLed2On();
BarLed3On();
BarLed4On();
BarLed5On();
BarLed6On();
BarLed7On();
BarLed8On();
BarLed9On();
break;
default:
BarLed0();
BarLed1();
BarLed2();
BarLed3();
BarLed4();
BarLed5();
BarLed6();
BarLed7();
BarLed8();
BarLed9();
}
}
void Beep(unsigned int period, volatile unsigned int length)
// Buzzer ON/OFF
{
volatile unsigned int i;
while (length-- > 0) {
Buz();
for ( i = 0; i < period; i++);
}
}
unsigned char GenerateNumber()
{
static unsigned char number = 0;
number += (unsigned char)(rand() % 3 + 1);
if (number > 4) { number -= 4; }
return number;
}
void GameOver(void)
{
volatile unsigned int i;
BarLed(10); Beep(2, 1000);
BarLed(0); Beep(10, 200);
}
void OpeningDemo(void)
{
volatile unsigned int i;
Led1234(0b0000);
for (i = 0; i <= 10; i++) {
BarLed(i); wait(5000);
Beep(11 - i ,100);
}
}
// Phase Identifier of Sequence
#define PHASE_READY 0
#define PHASE_GAME_START 1
#define PHASE_GAME_GENERATE_NUMBER 2
#define PHASE_GAME_HIT_OR_MISS 3
#define PHASE_GAME_OVER 4
volatile unsigned int Phase = PHASE_READY;
void InitInt0(void)
// Initialize Interrupt (INT0)
{
EIMSK |= (1<<INT0); // INT0 interrupt enable
EICRA |= (1<<ISC01) | (0<<ISC00); // The falling edge ofINT0 or INT1
sei(); // Enabel Interrupt
}
ISR(INT0_vect)
{
switch (Phase) {
case PHASE_READY:
Phase = PHASE_GAME_START;
break;
default:
BarLed(0);
Phase = PHASE_READY;
}
while(IsStartSwOn());
}
#define FLAG_HIT 0x01
#define FLAG_MISS 0x00
int main(void)
{
volatile unsigned int i; // Timing Counter
volatile unsigned char answer; // LED Lighting Position number 1,2,3,4
volatile unsigned int ishit; // Flag of HIT or MISS
volatile unsigned int score = 0; // Score
InitPort();
InitInt0();
OpeningDemo();
while (IsStartSwOn()); // wait for StartSwitch off
while (1) {
switch (Phase) {
case PHASE_READY :
score = 0;
Led1234(0b0000);
BarLed(11); wait(10000);// Blink Bar LED
break;
case PHASE_GAME_START :
score = 0;
Beep(8,1024);
Phase = PHASE_GAME_GENERATE_NUMBER;
break;
case PHASE_GAME_GENERATE_NUMBER :
// Generate Lighting LED number
answer = GenerateNumber();
Led1234((1<<(answer - 1)));
BarLed(score);
Phase = PHASE_GAME_HIT_OR_MISS;
break;
case PHASE_GAME_HIT_OR_MISS :
for (ishit = FLAG_MISS, i = 0; i < 20000; i++) {
if (IsSwOn()) {
if (answer == 1 && IsSw1On()) {
Beep(2, 1024);
ishit = FLAG_HIT;
break;
} else if (answer == 2 && IsSw2On()) {
Beep(4, 512);
ishit = FLAG_HIT;
break;
} else if (answer == 3 && IsSw3On()) {
Beep(8, 256);
ishit = FLAG_HIT;
break;
} else if (answer == 4 && IsSw4On()) {
Beep(16, 128);
ishit = FLAG_HIT;
break;
} else {
// MISS !
ishit = FLAG_MISS;
break;
}
}
}
if (ishit == FLAG_HIT) {
if (score >=0 && score < 10) {
score++;
Phase = PHASE_GAME_GENERATE_NUMBER;
} else {
Phase = PHASE_GAME_OVER;
}
} else {
Beep(128, 128);
if (Phase != PHASE_READY) {
Phase = PHASE_GAME_GENERATE_NUMBER;
}
score = 0;
}
while (IsSwOn());
break;
case PHASE_GAME_OVER :
// Game OVER
GameOver();
break;
default :
score = 0;
BarLed(0);
}
}
return 0;
}
Makefile
# AVR-GCC Makefile
PROJECT=led-game-mega168
SOURCES=$(PROJECT).c
CC=avr-gcc
OBJCOPY=avr-objcopy
MMCU=atmega168
TARGETDEV=m168p
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