Zorbing icon

[ES] SpaceInvaders.c

Zorbing | PRO | 06/12/14 08:25:11 PM UTC | 0 ⭐ | 423 👁️ | Never ⏰ | []
C |

9.93 KB

|

None

|

0 👍

/

0 👎

/*
* SpaceInvaders.c
*
* Created: 22.05.2014 16:26:08
*  Author: Ehlers
*/
 
 
#define F_CPU 1000000UL
 
/* ---------------------------------------------- */
// Includes
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdlib.h>
#include "avrx.h"
#include "avrxfifo.h"
#include "avrx-io.h"
#include "avrx-signal.h"
#include "hardware.h"
#include "lcd.h"
 
/* ---------------------------------------------- */
// Definitionen
#define NUMBER_ALIEN_SPECIES 4
#define SYMBOL_SPACESHIP 1
#define SYMBOL_SPACESHIP_FIRE 2
#define SYMBOL_EXPLOSION 3
#define SYMBOL_MISS 4
 
/* ---------------------------------------------- */
// Globale Variablen
// Position des Aliens in der erste Reihe
uint8_t alienPosition;
// Spezies des Aliens
uint8_t alienSpecies = 5;
// Position des Raumschiffes in der zweiten Reihe
uint8_t spaceshipPosition = 0;
// Fehlschuesse
uint8_t spaceshipRemainingEnergie;
// Punkte des Raumschiffes
uint8_t spaceshipPoints = 0;
// Spielzeit
uint8_t playTime = 60;
// Variablen zur Spielsteuerung
uint8_t gameEnd = 1;
uint8_t fire = 0;
uint8_t alienBlocked = 0;
 
/* ---------------------------------------------- */
// semaphoreData: Mutual exclusion der globalen Variablen
AVRX_MUTEX(semaphoreData);
// semaphoreStart: Start des Spiels
AVRX_MUTEX(semaphoreStart);
 
/* ---------------------------------------------- */
// Deklaration der Timer (Ein Timer kann nicht in mehreren Prozessen/Tasks genutzt werden)
TimerControlBlock TickTimerClock;
TimerControlBlock TickTimerAlien;
TimerControlBlock TickTimerSpaceship;
TimerControlBlock TickTimerButton;
TimerControlBlock TickTimerLCD;
 
/* ---------------------------------------------- */
// Deklaration der Nachrichten und der MessageQueue
MessageControlBlock UpdateDisplay;
MessageQueue LcdQueue;
 
/* ---------------------------------------------- */
// AD-Wandlung
uint16_t adc_read()
{
    // AD-Wandlung starten
    ADCSRA |= (1<<ADSC);
    // auf Abschluss der Konvertierung warten
    while (ADCSRA & (1<<ADSC));
    // Ergebnis auslesen, umrechnen in Bereich 0-14 und zurückgeben
    return ADCW;
}
 
/* ---------------------------------------------- */
// Initialisierung des AD Wandlers
void adc_init()
{
    // PINA0 als Eingang festlegen
    DDRA &= ~1;
    // Vcc als Referenzspannung
    ADMUX = (1<<REFS0);
    // Aktivieren und Pre-Scaler auf 128
    ADCSRA = (1<<ADEN) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);
    // Dummy-Wandlung
    adc_read(0);
}
 
/* ---------------------------------------------- */
// Interrupt Handler für die Timer
AVRX_SIGINT(TIMER0_OVF_vect)
{
    IntProlog();
    TCNT0 = TCNT0_INIT;
    AvrXTimerHandler();
    Epilog();
}
 
/* ---------------------------------------------- */
// Initialisierungen 
void init_function()
{
    MCUCR = _BV(SE);
    TCNT0 = TCNT0_INIT;
    TCCR0 = TMC8_CK256;
    TIMSK = _BV(TOIE0);
    
    DDRA  = DDRA  & ~(1 << PINA1);
    PORTA = PORTA |  (1 << PINA1);
}
 
 
/* ---------------------------------------------- */
// Zeitmessung
AVRX_GCC_TASKDEF(taskClock, 30, 0)
{
    while (1)
    {
        // warte eine Sekunde
        AvrXDelay(&TickTimerClock, 1000);
 
        // warte auf die Semaphore
        AvrXWaitSemaphore(&semaphoreData);
        // zaehle die Zeit um eine Sekunde runter
        playTime--;
        // falls die Zeit abgelaufen ist...
        if (playTime == 0)
        {
            // setze das Spiel auf beendet
            gameEnd = 1;
        }
        // das LCD aktualisieren
        AvrXSendMessage(&LcdQueue, &UpdateDisplay);
        // Semaphore freigeben
        AvrXSetSemaphore(&semaphoreData);
    }
}
 
/* ---------------------------------------------- */
// Steuerung des Aliens
AVRX_GCC_TASKDEF(taskAlien, 60, 0)
{
    while (1)
    {
        // warte 1 Sekunde
        AvrXDelay(&TickTimerAlien, 1000);
 
        // warte auf die Semaphore
        AvrXWaitSemaphore(&semaphoreData);
        // die Alienposition zufaellig setzen
        alienPosition = rand() % 14;
        alienBlocked = 0;
 
        // das LCD aktualisieren
        AvrXSendMessage(&LcdQueue, &UpdateDisplay);
        // Semaphore freigeben
        AvrXSetSemaphore(&semaphoreData);
    }
}
 
/* ---------------------------------------------- */
// Steuerung des Raumschiffes
AVRX_GCC_TASKDEF(taskSpaceship, 60, 0)
{
    uint8_t oldPosition;
    while (1)
    {
        // warte 20 Millisekunden
        AvrXDelay(&TickTimerSpaceship, 20);
 
        // warte auf die Semaphore
        AvrXWaitSemaphore(&semaphoreData);
        // die alte Position speichern
        oldPosition = spaceshipPosition;
        // die neue Position des Raumschiffes aus dem Wert des AD Wandlers errechnen:
        // 1023 / 74 als Ganzzahl ist 13
        spaceshipPosition = adc_read() / 74;
 
        // das LCD nur aktualisieren, wenn sich die Position geaendert hat
        if (oldPosition != spaceshipPosition)
        {
            // das LCD aktualisieren
            AvrXSendMessage(&LcdQueue, &UpdateDisplay);
        }
        // Semaphore freigeben
        AvrXSetSemaphore(&semaphoreData);
    }
}
 
/* ---------------------------------------------- */
// Taster
AVRX_GCC_TASKDEF(taskButton, 60, 0)
{
    uint8_t isPressed = 0;
    while (1)
    {
        // warte 10 Millisekunden
        AvrXDelay(&TickTimerButton, 10);
 
        // falls der Taster gedrueckt ist...
        if (!(PINA & (1 << PINA1)))
        {
            // ... und vorher noch nicht gedrueckt war
            if (!isPressed)
            {
                // warte auf die Semaphore
                AvrXWaitSemaphore(&semaphoreData);
                // falls das Spiel beendet ist
                if (gameEnd)
                {
                    // starte das Spiel neu
                    gameEnd = 0;
                    playTime = 60;
                    spaceshipPoints = 0;
                    fire = 0;
                    spaceshipRemainingEnergie = 10;
 
                    // setze die Start-Semaphore
                    AvrXSetSemaphore(&semaphoreStart);
                }
                else
                {
                    // wurde das Alien getroffen?
                    if (alienPosition == spaceshipPosition)
                    {
                        // der Schuss war ein Treffer
                        fire = 1;
                        // erhoehe die Punktzahl
                        spaceshipPoints++;
                        // es gibt 2 Energiepunkte - 1 verbrauchten Energiepunkt
                        spaceshipRemainingEnergie++;
                        // setze die neue Alienspezies auf einen zufaelligen Wert
                        alienSpecies = 5 + rand() % NUMBER_ALIEN_SPECIES;
                    }
                    else
                    {
                        // der Schuss ging daneben
                        fire = 2;
                        // ziehe einen Energiepunkt ab
                        spaceshipRemainingEnergie--;
 
                        // falls keine Energie mehr ueber ist
                        if (!spaceshipRemainingEnergie)
                        {
                            // das Spiel ist vorbei
                            gameEnd = 2;
                        }
                    }
                }
                // das LCD aktualisieren
                AvrXSendMessage(&LcdQueue, &UpdateDisplay);
                // Semaphore freigeben
                AvrXSetSemaphore(&semaphoreData);
 
                // speichern, dass der Button gedrueckt wird
                isPressed = 1;
            }
        }
        else
        {
            // der Taster ist nicht gedrueckt
            isPressed = 0;
        }
    }
}
 
/* ---------------------------------------------- */
// LCD Ansteuerung
AVRX_GCC_TASKDEF(taskLcd, 100, 4)
{
    MessageControlBlock *p;
    while (1)
    {
        // Wait for messages in the message queue
        p = AvrXWaitMessage(&LcdQueue);
        // Is the message the one we are waiting for?
        if (p == &UpdateDisplay)
        {
            if (gameEnd)
            {
                AvrXWaitSemaphore(&semaphoreData);
                lcd_clear();
                char buf[16];
                switch (gameEnd)
                {
                    case 1:
                        lcd_setcursor(3, 1);
                        snprintf(buf, 16, "Time Over!");
                        lcd_string(buf);
                        break;
                    case 2:
                        lcd_setcursor(2, 1);
                        snprintf(buf, 16, "No Ammo Left!");
                        lcd_string(buf);
                        break;
                }
                lcd_setcursor(3, 2);
                snprintf(buf, 16, "Points: %u", spaceshipPoints);
                lcd_string(buf);
                
                AvrXDelay(&TickTimerLCD, 2000);
                AvrXSetSemaphore(&semaphoreData);
                
                AvrXWaitSemaphore(&semaphoreStart);
            }
            else
            {
                AvrXWaitSemaphore(&semaphoreData);
                
                lcd_clear();
                lcd_setcursor(14, 1);
                char buf[3];
                if (playTime < 10)
                {
                    snprintf(buf, 3, "0%u", playTime);
                }
                else
                {
                    snprintf(buf, 3, "%u", playTime);
                }
                lcd_string(buf);
                
                lcd_setcursor(14, 2);
                if (spaceshipRemainingEnergie < 10)
                {
                    snprintf(buf, 3, "0%u", spaceshipRemainingEnergie);
                }
                else
                {
                    snprintf(buf, 3, "%u", spaceshipRemainingEnergie);
                }
                lcd_string(buf);
                
                if (fire)
                {
                    lcd_setcursor(spaceshipPosition, 2);
                    lcd_data(SYMBOL_SPACESHIP_FIRE);
                    if (fire == 1)
                    {
                        lcd_setcursor(alienPosition, 1);
                        lcd_data(SYMBOL_EXPLOSION);
                        alienBlocked = 1;
                    }
                    else
                    {
                        lcd_setcursor(alienPosition, 1);
                        lcd_data(alienSpecies);
                        lcd_setcursor(spaceshipPosition, 1);
                        lcd_data(SYMBOL_MISS);
                    }
                    AvrXDelay(&TickTimerLCD, 250);
                    fire = 0;
                }
                else
                {
                    if (!alienBlocked)
                    {
                        lcd_setcursor(alienPosition, 1);
                        lcd_data(alienSpecies);
                    }
                    
                    lcd_setcursor(spaceshipPosition, 2);
                    lcd_data(SYMBOL_SPACESHIP);
                }
                
                AvrXSetSemaphore(&semaphoreData);
            }
        }
    }
}
 
/* ---------------------------------------------- */
int main(void)
{
    // Initialisierungen
    
    // Definition des Stack Pointers der main
    AvrXSetKernelStack(0);
    // Initialisierung von AvrX
    init_function();
    // Initialisierung der LEDs
    lcd_init();
    // Initialisierung des ADW
    adc_init();
    
    // Definition und Initialisierung des Raumschiffes und der Aliens
    uint8_t symbols[] = {0x00, 0x00, 0x00, 0x04, 0x0A, 0x0A, 0x1B, 0x15,
        0x04, 0x04, 0x0A, 0x04, 0x0A, 0x0A, 0x1B, 0x15,
        0x0A, 0x00, 0x11, 0x0A, 0x0A, 0x11, 0x00, 0x0A,
        0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00,
        0x00, 0x00, 0x00, 0x0E, 0x15, 0x1B, 0x0E, 0x1B,
        0x00, 0x11, 0x1F, 0x15, 0x1F, 0x0A, 0x0E, 0x0A,
        0x00, 0x00, 0x0E, 0x15, 0x0E, 0x04, 0x0A, 0x11,
        // Die folgende Zeile ersetzen, um den eigenen Alien zu erstellen
        0x04, 0x0A, 0x0E, 0x11, 0x0A, 0x04, 0x0A, 0x11};
    
    for(int i = 0; i < 8; i++)
    {
        lcd_generatechar(i+1, symbols+(i*8));
    }
    
    // Starten des Tasks
    AvrXRunTask(TCB(taskClock));
    AvrXRunTask(TCB(taskAlien));
    AvrXRunTask(TCB(taskSpaceship));
    AvrXRunTask(TCB(taskButton));
    AvrXRunTask(TCB(taskLcd));
    
    // Setzen der Semaphore
    AvrXSetSemaphore(&semaphoreData);
 
    // Aufrufen des Schedulers
    Epilog();
    while(1);
}

Comments