Zorbing

[ES] SpaceInvaders.c

Jun 12th, 2014
451
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.93 KB | None | 0 0
  1. /*
  2. * SpaceInvaders.c
  3. *
  4. * Created: 22.05.2014 16:26:08
  5. *  Author: Ehlers
  6. */
  7.  
  8.  
  9. #define F_CPU 1000000UL
  10.  
  11. /* ---------------------------------------------- */
  12. // Includes
  13. #include <avr/io.h>
  14. #include <util/delay.h>
  15. #include <stdint.h>
  16. #include <stdlib.h>
  17. #include "avrx.h"
  18. #include "avrxfifo.h"
  19. #include "avrx-io.h"
  20. #include "avrx-signal.h"
  21. #include "hardware.h"
  22. #include "lcd.h"
  23.  
  24. /* ---------------------------------------------- */
  25. // Definitionen
  26. #define NUMBER_ALIEN_SPECIES 4
  27. #define SYMBOL_SPACESHIP 1
  28. #define SYMBOL_SPACESHIP_FIRE 2
  29. #define SYMBOL_EXPLOSION 3
  30. #define SYMBOL_MISS 4
  31.  
  32. /* ---------------------------------------------- */
  33. // Globale Variablen
  34. // Position des Aliens in der erste Reihe
  35. uint8_t alienPosition;
  36. // Spezies des Aliens
  37. uint8_t alienSpecies = 5;
  38. // Position des Raumschiffes in der zweiten Reihe
  39. uint8_t spaceshipPosition = 0;
  40. // Fehlschuesse
  41. uint8_t spaceshipRemainingEnergie;
  42. // Punkte des Raumschiffes
  43. uint8_t spaceshipPoints = 0;
  44. // Spielzeit
  45. uint8_t playTime = 60;
  46. // Variablen zur Spielsteuerung
  47. uint8_t gameEnd = 1;
  48. uint8_t fire = 0;
  49. uint8_t alienBlocked = 0;
  50.  
  51. /* ---------------------------------------------- */
  52. // semaphoreData: Mutual exclusion der globalen Variablen
  53. AVRX_MUTEX(semaphoreData);
  54. // semaphoreStart: Start des Spiels
  55. AVRX_MUTEX(semaphoreStart);
  56.  
  57. /* ---------------------------------------------- */
  58. // Deklaration der Timer (Ein Timer kann nicht in mehreren Prozessen/Tasks genutzt werden)
  59. TimerControlBlock TickTimerClock;
  60. TimerControlBlock TickTimerAlien;
  61. TimerControlBlock TickTimerSpaceship;
  62. TimerControlBlock TickTimerButton;
  63. TimerControlBlock TickTimerLCD;
  64.  
  65. /* ---------------------------------------------- */
  66. // Deklaration der Nachrichten und der MessageQueue
  67. MessageControlBlock UpdateDisplay;
  68. MessageQueue LcdQueue;
  69.  
  70. /* ---------------------------------------------- */
  71. // AD-Wandlung
  72. uint16_t adc_read()
  73. {
  74.     // AD-Wandlung starten
  75.     ADCSRA |= (1<<ADSC);
  76.     // auf Abschluss der Konvertierung warten
  77.     while (ADCSRA & (1<<ADSC));
  78.     // Ergebnis auslesen, umrechnen in Bereich 0-14 und zurückgeben
  79.     return ADCW;
  80. }
  81.  
  82. /* ---------------------------------------------- */
  83. // Initialisierung des AD Wandlers
  84. void adc_init()
  85. {
  86.     // PINA0 als Eingang festlegen
  87.     DDRA &= ~1;
  88.     // Vcc als Referenzspannung
  89.     ADMUX = (1<<REFS0);
  90.     // Aktivieren und Pre-Scaler auf 128
  91.     ADCSRA = (1<<ADEN) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);
  92.     // Dummy-Wandlung
  93.     adc_read(0);
  94. }
  95.  
  96. /* ---------------------------------------------- */
  97. // Interrupt Handler für die Timer
  98. AVRX_SIGINT(TIMER0_OVF_vect)
  99. {
  100.     IntProlog();
  101.     TCNT0 = TCNT0_INIT;
  102.     AvrXTimerHandler();
  103.     Epilog();
  104. }
  105.  
  106. /* ---------------------------------------------- */
  107. // Initialisierungen
  108. void init_function()
  109. {
  110.     MCUCR = _BV(SE);
  111.     TCNT0 = TCNT0_INIT;
  112.     TCCR0 = TMC8_CK256;
  113.     TIMSK = _BV(TOIE0);
  114.    
  115.     DDRA  = DDRA  & ~(1 << PINA1);
  116.     PORTA = PORTA |  (1 << PINA1);
  117. }
  118.  
  119.  
  120. /* ---------------------------------------------- */
  121. // Zeitmessung
  122. AVRX_GCC_TASKDEF(taskClock, 30, 0)
  123. {
  124.     while (1)
  125.     {
  126.         // warte eine Sekunde
  127.         AvrXDelay(&TickTimerClock, 1000);
  128.  
  129.         // warte auf die Semaphore
  130.         AvrXWaitSemaphore(&semaphoreData);
  131.         // zaehle die Zeit um eine Sekunde runter
  132.         playTime--;
  133.         // falls die Zeit abgelaufen ist...
  134.         if (playTime == 0)
  135.         {
  136.             // setze das Spiel auf beendet
  137.             gameEnd = 1;
  138.         }
  139.         // das LCD aktualisieren
  140.         AvrXSendMessage(&LcdQueue, &UpdateDisplay);
  141.         // Semaphore freigeben
  142.         AvrXSetSemaphore(&semaphoreData);
  143.     }
  144. }
  145.  
  146. /* ---------------------------------------------- */
  147. // Steuerung des Aliens
  148. AVRX_GCC_TASKDEF(taskAlien, 60, 0)
  149. {
  150.     while (1)
  151.     {
  152.         // warte 1 Sekunde
  153.         AvrXDelay(&TickTimerAlien, 1000);
  154.  
  155.         // warte auf die Semaphore
  156.         AvrXWaitSemaphore(&semaphoreData);
  157.         // die Alienposition zufaellig setzen
  158.         alienPosition = rand() % 14;
  159.         alienBlocked = 0;
  160.  
  161.         // das LCD aktualisieren
  162.         AvrXSendMessage(&LcdQueue, &UpdateDisplay);
  163.         // Semaphore freigeben
  164.         AvrXSetSemaphore(&semaphoreData);
  165.     }
  166. }
  167.  
  168. /* ---------------------------------------------- */
  169. // Steuerung des Raumschiffes
  170. AVRX_GCC_TASKDEF(taskSpaceship, 60, 0)
  171. {
  172.     uint8_t oldPosition;
  173.     while (1)
  174.     {
  175.         // warte 20 Millisekunden
  176.         AvrXDelay(&TickTimerSpaceship, 20);
  177.  
  178.         // warte auf die Semaphore
  179.         AvrXWaitSemaphore(&semaphoreData);
  180.         // die alte Position speichern
  181.         oldPosition = spaceshipPosition;
  182.         // die neue Position des Raumschiffes aus dem Wert des AD Wandlers errechnen:
  183.         // 1023 / 74 als Ganzzahl ist 13
  184.         spaceshipPosition = adc_read() / 74;
  185.  
  186.         // das LCD nur aktualisieren, wenn sich die Position geaendert hat
  187.         if (oldPosition != spaceshipPosition)
  188.         {
  189.             // das LCD aktualisieren
  190.             AvrXSendMessage(&LcdQueue, &UpdateDisplay);
  191.         }
  192.         // Semaphore freigeben
  193.         AvrXSetSemaphore(&semaphoreData);
  194.     }
  195. }
  196.  
  197. /* ---------------------------------------------- */
  198. // Taster
  199. AVRX_GCC_TASKDEF(taskButton, 60, 0)
  200. {
  201.     uint8_t isPressed = 0;
  202.     while (1)
  203.     {
  204.         // warte 10 Millisekunden
  205.         AvrXDelay(&TickTimerButton, 10);
  206.  
  207.         // falls der Taster gedrueckt ist...
  208.         if (!(PINA & (1 << PINA1)))
  209.         {
  210.             // ... und vorher noch nicht gedrueckt war
  211.             if (!isPressed)
  212.             {
  213.                 // warte auf die Semaphore
  214.                 AvrXWaitSemaphore(&semaphoreData);
  215.                 // falls das Spiel beendet ist
  216.                 if (gameEnd)
  217.                 {
  218.                     // starte das Spiel neu
  219.                     gameEnd = 0;
  220.                     playTime = 60;
  221.                     spaceshipPoints = 0;
  222.                     fire = 0;
  223.                     spaceshipRemainingEnergie = 10;
  224.  
  225.                     // setze die Start-Semaphore
  226.                     AvrXSetSemaphore(&semaphoreStart);
  227.                 }
  228.                 else
  229.                 {
  230.                     // wurde das Alien getroffen?
  231.                     if (alienPosition == spaceshipPosition)
  232.                     {
  233.                         // der Schuss war ein Treffer
  234.                         fire = 1;
  235.                         // erhoehe die Punktzahl
  236.                         spaceshipPoints++;
  237.                         // es gibt 2 Energiepunkte - 1 verbrauchten Energiepunkt
  238.                         spaceshipRemainingEnergie++;
  239.                         // setze die neue Alienspezies auf einen zufaelligen Wert
  240.                         alienSpecies = 5 + rand() % NUMBER_ALIEN_SPECIES;
  241.                     }
  242.                     else
  243.                     {
  244.                         // der Schuss ging daneben
  245.                         fire = 2;
  246.                         // ziehe einen Energiepunkt ab
  247.                         spaceshipRemainingEnergie--;
  248.  
  249.                         // falls keine Energie mehr ueber ist
  250.                         if (!spaceshipRemainingEnergie)
  251.                         {
  252.                             // das Spiel ist vorbei
  253.                             gameEnd = 2;
  254.                         }
  255.                     }
  256.                 }
  257.                 // das LCD aktualisieren
  258.                 AvrXSendMessage(&LcdQueue, &UpdateDisplay);
  259.                 // Semaphore freigeben
  260.                 AvrXSetSemaphore(&semaphoreData);
  261.  
  262.                 // speichern, dass der Button gedrueckt wird
  263.                 isPressed = 1;
  264.             }
  265.         }
  266.         else
  267.         {
  268.             // der Taster ist nicht gedrueckt
  269.             isPressed = 0;
  270.         }
  271.     }
  272. }
  273.  
  274. /* ---------------------------------------------- */
  275. // LCD Ansteuerung
  276. AVRX_GCC_TASKDEF(taskLcd, 100, 4)
  277. {
  278.     MessageControlBlock *p;
  279.     while (1)
  280.     {
  281.         // Wait for messages in the message queue
  282.         p = AvrXWaitMessage(&LcdQueue);
  283.         // Is the message the one we are waiting for?
  284.         if (p == &UpdateDisplay)
  285.         {
  286.             if (gameEnd)
  287.             {
  288.                 AvrXWaitSemaphore(&semaphoreData);
  289.                 lcd_clear();
  290.                 char buf[16];
  291.                 switch (gameEnd)
  292.                 {
  293.                     case 1:
  294.                         lcd_setcursor(3, 1);
  295.                         snprintf(buf, 16, "Time Over!");
  296.                         lcd_string(buf);
  297.                         break;
  298.                     case 2:
  299.                         lcd_setcursor(2, 1);
  300.                         snprintf(buf, 16, "No Ammo Left!");
  301.                         lcd_string(buf);
  302.                         break;
  303.                 }
  304.                 lcd_setcursor(3, 2);
  305.                 snprintf(buf, 16, "Points: %u", spaceshipPoints);
  306.                 lcd_string(buf);
  307.                
  308.                 AvrXDelay(&TickTimerLCD, 2000);
  309.                 AvrXSetSemaphore(&semaphoreData);
  310.                
  311.                 AvrXWaitSemaphore(&semaphoreStart);
  312.             }
  313.             else
  314.             {
  315.                 AvrXWaitSemaphore(&semaphoreData);
  316.                
  317.                 lcd_clear();
  318.                 lcd_setcursor(14, 1);
  319.                 char buf[3];
  320.                 if (playTime < 10)
  321.                 {
  322.                     snprintf(buf, 3, "0%u", playTime);
  323.                 }
  324.                 else
  325.                 {
  326.                     snprintf(buf, 3, "%u", playTime);
  327.                 }
  328.                 lcd_string(buf);
  329.                
  330.                 lcd_setcursor(14, 2);
  331.                 if (spaceshipRemainingEnergie < 10)
  332.                 {
  333.                     snprintf(buf, 3, "0%u", spaceshipRemainingEnergie);
  334.                 }
  335.                 else
  336.                 {
  337.                     snprintf(buf, 3, "%u", spaceshipRemainingEnergie);
  338.                 }
  339.                 lcd_string(buf);
  340.                
  341.                 if (fire)
  342.                 {
  343.                     lcd_setcursor(spaceshipPosition, 2);
  344.                     lcd_data(SYMBOL_SPACESHIP_FIRE);
  345.                     if (fire == 1)
  346.                     {
  347.                         lcd_setcursor(alienPosition, 1);
  348.                         lcd_data(SYMBOL_EXPLOSION);
  349.                         alienBlocked = 1;
  350.                     }
  351.                     else
  352.                     {
  353.                         lcd_setcursor(alienPosition, 1);
  354.                         lcd_data(alienSpecies);
  355.                         lcd_setcursor(spaceshipPosition, 1);
  356.                         lcd_data(SYMBOL_MISS);
  357.                     }
  358.                     AvrXDelay(&TickTimerLCD, 250);
  359.                     fire = 0;
  360.                 }
  361.                 else
  362.                 {
  363.                     if (!alienBlocked)
  364.                     {
  365.                         lcd_setcursor(alienPosition, 1);
  366.                         lcd_data(alienSpecies);
  367.                     }
  368.                    
  369.                     lcd_setcursor(spaceshipPosition, 2);
  370.                     lcd_data(SYMBOL_SPACESHIP);
  371.                 }
  372.                
  373.                 AvrXSetSemaphore(&semaphoreData);
  374.             }
  375.         }
  376.     }
  377. }
  378.  
  379. /* ---------------------------------------------- */
  380. int main(void)
  381. {
  382.     // Initialisierungen
  383.    
  384.     // Definition des Stack Pointers der main
  385.     AvrXSetKernelStack(0);
  386.     // Initialisierung von AvrX
  387.     init_function();
  388.     // Initialisierung der LEDs
  389.     lcd_init();
  390.     // Initialisierung des ADW
  391.     adc_init();
  392.    
  393.     // Definition und Initialisierung des Raumschiffes und der Aliens
  394.     uint8_t symbols[] = {0x00, 0x00, 0x00, 0x04, 0x0A, 0x0A, 0x1B, 0x15,
  395.         0x04, 0x04, 0x0A, 0x04, 0x0A, 0x0A, 0x1B, 0x15,
  396.         0x0A, 0x00, 0x11, 0x0A, 0x0A, 0x11, 0x00, 0x0A,
  397.         0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00,
  398.         0x00, 0x00, 0x00, 0x0E, 0x15, 0x1B, 0x0E, 0x1B,
  399.         0x00, 0x11, 0x1F, 0x15, 0x1F, 0x0A, 0x0E, 0x0A,
  400.         0x00, 0x00, 0x0E, 0x15, 0x0E, 0x04, 0x0A, 0x11,
  401.         // Die folgende Zeile ersetzen, um den eigenen Alien zu erstellen
  402.         0x04, 0x0A, 0x0E, 0x11, 0x0A, 0x04, 0x0A, 0x11};
  403.    
  404.     for(int i = 0; i < 8; i++)
  405.     {
  406.         lcd_generatechar(i+1, symbols+(i*8));
  407.     }
  408.    
  409.     // Starten des Tasks
  410.     AvrXRunTask(TCB(taskClock));
  411.     AvrXRunTask(TCB(taskAlien));
  412.     AvrXRunTask(TCB(taskSpaceship));
  413.     AvrXRunTask(TCB(taskButton));
  414.     AvrXRunTask(TCB(taskLcd));
  415.    
  416.     // Setzen der Semaphore
  417.     AvrXSetSemaphore(&semaphoreData);
  418.  
  419.     // Aufrufen des Schedulers
  420.     Epilog();
  421.     while(1);
  422. }
Advertisement
Add Comment
Please, Sign In to add comment