游戏说明:
这是一个跑酷游戏, 需要火柴人(滑块)越过障碍(黑线), 若碰到黑线则游戏结束。
玩法:
1.上电启动,屏幕显示press key时按下按钮,屏幕会显示倒计时,倒计时时间为2s,因此在2s后就开始游戏了;
2. 当屏幕第一行显示”Go”第二行显示游戏时间时表示游戏正在进行中,你可以按下手中的按钮来让火柴人跳动,按一下火柴人跳动一下,按钮不支持长按,也就是说你一直按下按钮,火柴人也只是跳动一次;
3. 若在游戏过程中火柴人碰到了障碍物则游戏结束了,屏幕第一行显示“Game over”, 第二行显示你这次游戏的时间。
DIY:
1. 准备: L298电机驱动(也可以使用其他电机驱动)、红外对管黑线检测模块、LCD1602、key、舵机、直流减速电机、滚轮、传送带(纸)、框架、UNO;
2. 组装:
把各个模块与单片机连接就可以编写程序了
舵机的控制
舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms-2.5ms范围内的角度控制脉冲部分,总间隔为2ms。以180度角度伺服为例,那么对应的控制关系是这样的:
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;
红外对管黑线检测
当红外对管下面是黑色时由于黑色反光很弱,因此通过Q1的电流非常小,因此LM358的2脚的电压会接近电源电压,并且大于3脚的参考电压,此时LM358输出低电平,反之亦然。因此可以用单片机捕获这个电平变化。
参考程序
#include
#include
#include
#define BIT(x)(1<<(x))
Servomyservo;
// create servoobject to control a servo
int key =4; // key's pin
int motor =5; // motor's pin
intsliding_block = 2;
int servo =9;
int degree =100; // servo degree
float game_time= 0; // game's time
volatileunsigned int delay_counter = 0;
// tomydelay()
booleangame_over = true;
boolean reset =true;
LiquidCrystallcd(0);
void int0_init() // get sliding_block's data
{
DDRD &=~BIT(2);
PORTD |= BIT(2);
EICRA &=~BIT(1);
EICRA |= BIT(0);
EIFR |= BIT(0); // clear flag
EIMSK &=~BIT(0);
}
voidtimer0_init() // controlmotor
{
OCR0A = 100;
OCR0B = 10;
TCCR0A |= BIT(COM0A0) | BIT(COM0B1) | BIT(WGM01)| BIT(WGM00);
TCCR0B |= BIT(WGM02) | BIT(CS00);
}
voidtimer2_init()
// tomydelay(), because it seems like delay() can't be interrupted by otherinterrupt such as INT0
{
TCCR2A = 0;
TCCR2B = BIT(CS22) + BIT(CS21) +BIT(CS20); // 1024 divide
TCNT2 = 99; //10ms
TIMSK2 &= ~BIT(TOIE2);
}
void lcd_init()
{
lcd.begin(16, 2);
lcd.setCursor(0, 0);
lcd.print(" press key! ");
lcd.setBacklight(HIGH);
}
void setup()
{
myservo.attach(servo);
// attaches the servo on pin 9 to theservo object
pinMode(motor, OUTPUT);
timer0_init(); //motor
pinMode(key, INPUT);
pinMode(13, OUTPUT); //LED
digitalWrite(13, LOW);
timer2_init(); //mydelay
pinMode(sliding_block, INPUT);
int0_init(); //sliding_block
lcd_init();
sei();
}
voidmydelay(unsigned int x, void (*fun)(void))
//min=10ms
{
unsigned int time_count = x/10;
volatile unsigned int comp_count =delay_counter + time_count;
//comp_count and delay_counter must is a volatilevariable
TIMSK2 |= (1<
while(delay_counter < comp_count){
//in order to notwaste CPU, you can execute your function in this loop
if(0 != fun)
fun();
}
TIMSK2 &=~(1<
}
voidlcd_display(void)
{
lcd.setCursor(6, 1);
lcd.print(game_time);
}
void loop()
{
static int key_time = 0;
if(!game_over){
if(!digitalRead(key)){
if(key_time < 2)
degree = 140;
else
degree = 100;
key_time++;
}
else{
degree = 100;
key_time = 0;
}
myservo.write(degree);
// sets the servo positionaccording to the scaled value g
if(degree > 120){
mydelay(80, lcd_display);
game_time += 0.1;
mydelay(80, lcd_display);
game_time += 0.1;
}
else{
game_time += 0.1;
mydelay(80, lcd_display);
// waits for theservo to get there
}
}else{
if(!reset){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Game Over ");
lcd.setCursor(5, 1);
lcd.print(game_time);
mydelay(3000, 0);
}
reset = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" press key! ");
while(digitalRead(key)){
myservo.write(degree);
// sets the servo positionaccording to the scaled value
mydelay(32, 0);
// waits for theservo to get there
OCR0B = 10;
}
mydelay(64, 0);
while(!digitalRead(key));
lcd.clear();
lcd.setCursor(8, 0);
lcd.print("2");
mydelay(1000, 0);
lcd.clear();
lcd.setCursor(8, 0);
lcd.print("1");
mydelay(1000, 0);
lcd.clear();
lcd.setCursor(7, 0);
lcd.print("go");
game_over = false;
game_time = 0;
OCR0B = 60;
EIFR|= BIT(0);
EIMSK |= BIT(0);
//enable extern interrupt 0
}
}
ISR(INT0_vect)
{
EIMSK &=~BIT(0);
OCR0B = 10;
game_over = true;
TIMSK1 &=~BIT(TOIE1);
}
ISR(TIMER2_OVF_vect)
{
TCNT2 = 99; //10ms
delay_counter++;
}
|