Ruminações de um "Old Timer" sobre software e hardware
quinta-feira, novembro 22, 2012
Display de LEDs JY-LKM1638 - Parte 3
Encerrando esta série sobre o display JY-LKM1638, vou usá-lo junto com um Arduino para implementar um jogo de pouso lunar.
O Lunar Lander Mark II
Em 2009 eu montei o Lunar Lander Mark I. Este novo projeto aproveita a parte do código que faz a simulação, calculando a altitude e velocidade.
O Display
Para aproveitar bem o display, implementei a seguinte interface com o jogador:
Os quatro dígitos da esquerda apresentam a altitude. O jogo termina quando ela chega a zero.
Os quatro dígitos da direita apresentam a velocidade. Velocidade positiva indica que a nave está se aproximando da Lua, velocidade negativa indica que ela está se afastando.
O nível do combustível é mostrado nos LEDs. Inicialmente os LEDs são apresentados na cor verde. Quando sobra somente o último LED, o programa passa para um resolução maior com os LEDs em vermelho.
Os botões disparam a queima de combustível. Quanto mais à direita, maior a quantidade queimada.
Para controlar o display use a biblioteca TM168 do Ricardo Batista. Para apresentar os valores usei a rotina de escrever um dígito, pois a rotina de escrever números não suporta mostrar dois valores simultaneamente.
Abaixo está o código (que está também nos arquivos do blog, em LunarLander_LKM1638.zip).
//
// Lunar Lander para o display JY-LKM1638
// Daniel Quadros - 19/11/2012
//
// Utiliza TM1638 Library de Ricardo Batista
//
#include <TM1638.h>
static TM1638 disp(8, 9, 7);
static const int grav = 5; // acelaração da gravidade
static long altitude = 9990000; // altitude atual
static int comb = 16000; // combustÃvel disponÃvel
static int veloc = 5000; // velocidade atual
static int burn = 0; // taxa de queima do combustÃvel
// Valores para queima conforme a tecla apertada
// com a tensão no potenciômetro
const int queima[9] =
{
4, 8, 12, 16, 20, 24, 27, 30, 0
};
static void AtlDisplay (void);
static void LeTeclas (void);
static void Simula (void);
// Iniciação
void setup()
{
//Serial.begin (9600);
}
// Loop principal
void loop()
{
AtlDisplay ();
LeTeclas ();
//Serial.print (altitude);
//Serial.print (" ");
//Serial.print (veloc);
//Serial.print (" ");
//Serial.print (comb);
//Serial.print (" ");
//Serial.println (burn);
Simula ();
delay (100);
}
// Simula o movimento
static void Simula (void)
{
signed int newv;
if (altitude > 0)
{
if (burn)
{
if (burn > comb)
burn = comb;
comb -= burn;
newv = veloc - burn + grav;
burn = 0;
}
else
newv = veloc + grav;
altitude -= (veloc + newv) >> 1;
if (altitude < 0)
altitude = 0;
veloc = newv;
}
}
// Verifica se tem tecla apertada
// Se sim, queima combustÃvel
static void LeTeclas (void)
{
byte teclas = disp.getButtons();
int i;
for (i = 0; i < 8; i++)
if (teclas & (1 << i))
break;
burn = queima [i];
}
// Atualiza o display
static void AtlDisplay (void)
{
int valor;
int idot;
// Altitude
if (altitude > 999900L)
{
valor = (int) (altitude / 1000L);
idot = 3;
}
else if (altitude > 99990L)
{
valor = (int) (altitude / 100L);
idot = 2;
}
else if (altitude > 9999L)
{
valor = (int) (altitude / 10L);
idot = 1;
}
else
{
valor = (int) altitude;
idot = 0;
}
disp.setDisplayDigit (valor / 1000, 0, idot == 0);
disp.setDisplayDigit ((valor / 100) % 10, 1, idot == 1);
disp.setDisplayDigit ((valor / 10) % 10, 2, idot == 2);
disp.setDisplayDigit (valor % 10, 3, idot == 3);
// Velocidade
if (veloc > 9999)
{
disp.setDisplayDigit (veloc / 10000, 4, false);
disp.setDisplayDigit ((veloc / 1000) % 10, 5, false);
disp.setDisplayDigit ((veloc / 100) % 10, 6, false);
disp.setDisplayDigit ((veloc / 10) % 10, 7, true);
}
else if (veloc > 0)
{
disp.setDisplayDigit (veloc / 1000, 4, false);
disp.setDisplayDigit ((veloc / 100) % 10, 5, false);
disp.setDisplayDigit ((veloc / 10) % 10, 6, true);
disp.setDisplayDigit (veloc % 10, 7, false);
}
else
{
disp.setDisplayToString ("-", 0, 4);
valor = -veloc / 10;
disp.setDisplayDigit (valor / 100, 5, false);
disp.setDisplayDigit ((valor / 10) % 10, 6, false);
disp.setDisplayDigit (valor % 10, 7, true);
}
// CombustÃvel
if (comb > 2000)
{
int i, pos;
pos = 7 - (comb - 1) / 2000;
for (i = 0; i < pos; i++)
disp.setLED (0, i);
for (; i < 8; i++)
disp.setLED (TM1638_COLOR_GREEN, i);
}
else if (comb != 0)
{
int i, pos;
pos = 7 - (comb - 1) / 250;
for (i = 0; i < pos; i++)
disp.setLED (0, i);
for (; i < 8; i++)
disp.setLED (TM1638_COLOR_RED, i);
}
else
disp.setLEDs (0);
}
Nenhum comentário:
Postar um comentário