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).
  1. //  
  2. // Lunar Lander para o display JY-LKM1638  
  3. // Daniel Quadros - 19/11/2012  
  4. //  
  5. // Utiliza TM1638 Library de Ricardo Batista  
  6. //  
  7.   
  8. #include <TM1638.h>  
  9.   
  10. static TM1638 disp(8, 9, 7);  
  11.   
  12. static const int grav = 5;         // acelaração da gravidade  
  13.   
  14. static long altitude = 9990000;    // altitude atual  
  15. static int comb = 16000;           // combustível disponível  
  16. static int veloc = 5000;           // velocidade atual  
  17. static int burn = 0;               // taxa de queima do combustível  
  18.   
  19. // Valores para queima conforme a tecla apertada  
  20. // com a tensão no potenciômetro  
  21. const int queima[9] =  
  22. {  
  23.    4, 8, 12, 16, 20, 24, 27, 30, 0  
  24. };  
  25.   
  26. static void AtlDisplay (void);  
  27. static void LeTeclas (void);  
  28. static void Simula (void);  
  29.   
  30. // Iniciação  
  31. void setup()  
  32. {  
  33.   //Serial.begin (9600);  
  34. }  
  35.   
  36. // Loop principal  
  37. void loop()  
  38. {  
  39.   AtlDisplay ();  
  40.   LeTeclas ();  
  41.   //Serial.print (altitude);  
  42.   //Serial.print (" ");  
  43.   //Serial.print (veloc);  
  44.   //Serial.print (" ");  
  45.   //Serial.print (comb);  
  46.   //Serial.print (" ");  
  47.   //Serial.println (burn);  
  48.   Simula ();  
  49.   delay (100);  
  50. }  
  51.   
  52. // Simula o movimento  
  53. static void Simula (void)  
  54. {  
  55.   signed int newv;  
  56.     
  57.   if (altitude > 0)  
  58.   {  
  59.      if (burn)  
  60.      {  
  61.         if (burn > comb)  
  62.            burn = comb;  
  63.         comb -= burn;  
  64.         newv = veloc - burn + grav;  
  65.         burn = 0;  
  66.      }  
  67.      else  
  68.         newv = veloc + grav;  
  69.        
  70.      altitude -= (veloc + newv) >> 1;  
  71.      if (altitude < 0)  
  72.         altitude = 0;  
  73.      veloc = newv;  
  74.   }  
  75. }  
  76.   
  77. // Verifica se tem tecla apertada  
  78. // Se sim, queima combustível  
  79. static void LeTeclas (void)  
  80. {  
  81.   byte teclas = disp.getButtons();  
  82.   int i;  
  83.   for (i = 0; i < 8; i++)  
  84.     if (teclas & (1 << i))  
  85.       break;  
  86.   burn = queima [i];    
  87. }  
  88.   
  89. // Atualiza o display  
  90. static void AtlDisplay (void)  
  91. {  
  92.   int valor;  
  93.   int idot;  
  94.     
  95.   // Altitude  
  96.   if (altitude > 999900L)  
  97.   {  
  98.     valor = (int) (altitude / 1000L);  
  99.     idot = 3;  
  100.   }  
  101.   else if (altitude > 99990L)  
  102.   {  
  103.     valor = (int) (altitude / 100L);  
  104.     idot = 2;  
  105.   }  
  106.   else if (altitude > 9999L)  
  107.   {  
  108.     valor = (int) (altitude / 10L);  
  109.     idot = 1;  
  110.   }  
  111.   else  
  112.   {  
  113.     valor = (int) altitude;  
  114.     idot = 0;  
  115.   }  
  116.   disp.setDisplayDigit (valor / 1000, 0, idot == 0);  
  117.   disp.setDisplayDigit ((valor / 100) % 10, 1, idot == 1);  
  118.   disp.setDisplayDigit ((valor / 10) % 10, 2, idot == 2);  
  119.   disp.setDisplayDigit (valor % 10, 3, idot == 3);  
  120.     
  121.   // Velocidade  
  122.   if (veloc > 9999)  
  123.   {  
  124.     disp.setDisplayDigit (veloc / 10000, 4, false);  
  125.     disp.setDisplayDigit ((veloc / 1000) % 10, 5, false);  
  126.     disp.setDisplayDigit ((veloc / 100) % 10, 6, false);  
  127.     disp.setDisplayDigit ((veloc / 10) % 10, 7, true);  
  128.   }  
  129.   else if (veloc > 0)  
  130.   {  
  131.     disp.setDisplayDigit (veloc / 1000, 4, false);  
  132.     disp.setDisplayDigit ((veloc / 100) % 10, 5, false);  
  133.     disp.setDisplayDigit ((veloc / 10) % 10, 6, true);  
  134.     disp.setDisplayDigit (veloc % 10, 7, false);  
  135.   }  
  136.   else  
  137.   {  
  138.     disp.setDisplayToString ("-", 0, 4);  
  139.     valor = -veloc / 10;  
  140.     disp.setDisplayDigit (valor / 100, 5, false);  
  141.     disp.setDisplayDigit ((valor / 10) % 10, 6, false);  
  142.     disp.setDisplayDigit (valor % 10, 7, true);  
  143.   }  
  144.     
  145.   // Combustível  
  146.   if (comb > 2000)  
  147.   {  
  148.     int i, pos;  
  149.       
  150.     pos = 7 - (comb - 1) / 2000;  
  151.     for (i = 0; i < pos; i++)  
  152.       disp.setLED (0, i);  
  153.     for (; i < 8; i++)  
  154.       disp.setLED (TM1638_COLOR_GREEN, i);  
  155.   }  
  156.   else if (comb != 0)  
  157.   {  
  158.     int i, pos;  
  159.     pos = 7 - (comb - 1) / 250;  
  160.     for (i = 0; i < pos; i++)  
  161.       disp.setLED (0, i);  
  162.     for (; i < 8; i++)  
  163.       disp.setLED (TM1638_COLOR_RED, i);  
  164.   }  
  165.   else  
  166.     disp.setLEDs (0);  
  167. }  
O vídeo a seguir mostra o jogo em andamento.


Nenhum comentário: