#include "Arduino.h"
/*
BITTE ERSTELLEN SIE SICH VORAB EINE PRIVATE KOPIE, DAZU
AUF "SAVE AS" GEHEN.
Aufgabenbeschreibung:
Es soll eine Steuerung aufgebaut werden, welche einen einfachen
Reaktionstester umsetzt.
Die Steuerung soll auf einem µC (AT-Mega 328, Arduino Uno)
realisiert werden.
Folgende Pin Belegung ist zu beachten
Port B
Bit 0/1/2/3/4/5/6/7
Bez Res/Res/Res/Res/Res/Res/Res/Res
Port D
Bit 0/1/2/3/4/5/6/7
Bez Res/Res/xTaster/Res/yBlue/Res/yYellow/Res
R1) Ein Taster ist angeschlossen und das Signal des Tasters
wird als xTaster in der Pin Belegung abgebildet.
R2) Es seien zwei LEDs angeschlossen, eine gelbe und eine blaue. Diese
sind durch über die Anschlüsse yBlue und yYellow in der Pin Belegung
abgebildet. Die beiden anderen LEDs dienen zur Überprüfung, ob Sie
reservierte Bits geändert haben.
R3) Der Reaktionstester soll fortwährend laufen, bis ein Fehler
in der HAS auftritt.
R4) Der Reaktionstester soll die Funktion void randomWait(void)
aufrufen, welche eine zufällige Zeit wartet. Sobald die Zeit abgelaufen
ist, soll die gelbe LED angeschaltet werden. Dies ist für den
Anwender das Zeichen, so schnell wie möglich auf den Taster zu drücken.
War die Reaktionszeit schneller als die bisherige Bestzeit des
Users, soll die blaue LED für eine Sekunde leuchten. Die gelbe LED
soll zeitgleich erlöschen.
Dies können Sie über die Funktion delay([Zeit in ms]) erreichen. War die
Zeit schlechter als die Bestzeit, soll die gelbe LED erlöschen, sobald
der User den Taster losgelassen hat. Die blaue LED soll in diesem
Fall nicht aufleuchten.
R5) Die Datenrichtungen sollen in einer InitIO() Funktion eingestellt werden.
R6) Alle Ihnen zur Verfügung stehenden Ausgänge sollen zu Beginn für
einen Zyklus auf 1 und dann auf 0 initialisiert werden. Dies soll in der initIO() geschehen.
R7) Nutzen Sie zum Lesen und Schreiben der digitalen Ein- und
Ausgänge die Funktionen InputByte und OutputByte der HAS.
R8) Wird beim Einlesen oder Ausgeben über die HAS ein Fehlerwert
zurückgegeben, sollen blaue und gelbe LED aufleuchten.
R9) Reservierte Bits dürfen nicht in Wert oder Datenrichtung geändert werden.
Ausgänge sind rücklesbar.
ACHTUNG:
Bitte nutzen Sie anstatt des bekannten int main(void) Aufbaus
eine void setup() + void loop() Struktur, wie folgend dargestellt.
Die Funktion setup() wird dabei bei der Abarbeitung einmal durchlaufen
und die Funktion loop() anschließend permanent.
*/
// typ bool ist bereits deklariert
typedef unsigned char uint8_t;
typedef unsigned char BYTE;
typedef enum
{
PB,
PC,
PD
} PORT;
typedef enum
{
K0 = 0,
K1,
K2,
K3,
K4,
K5,
K6,
K7
} CHANNEL;
typedef struct
{
bool taster; // Taster gedrückt =1
} InVec_Reaktion;
typedef struct
{
bool blue; // 1 = LED ist an
bool yellow; // 1= LED ist an
} OutVec_Reaktion;
void preSetup(void)
{
// Pseudo-Funktion soll testen, ob reservierte Bits geändert wurden
BYTE PDval = 0b00000000;
BYTE PBval = 0b00100000;
DDRD = 0b00000010; // Output := 1, Input := 0
DDRB = 0b00100100; // Output := 1, Input := 0
OutputByte(PD, PDval);
OutputByte(PB, PBval);
}
BYTE InputByte(PORT PortName, BYTE *ReadValue)
{
// Hardwareabstraktionsschicht, Einlesen und Abspeichern an Adresse ReadValue
if (PortName == PB)
{
*ReadValue = PINB;
}
else if (PortName == PC)
{
*ReadValue = PINC;
}
else if (PortName == PD)
{
*ReadValue = PIND;
}
// Pseudo Error Code Generation
int returnVal = 0;
int randNumber = random(900); // Random number for error code
if (randNumber < 7)
returnVal = randNumber; // Return Value depending on random number
return (returnVal);
}
BYTE OutputByte(PORT PortName, BYTE WriteValue)
{
// Hardwareabstraktionsschicht, Ausgabe des Bytes WriteValue am Port PortName
if (PortName == PB)
{
PORTB = WriteValue;
}
else if (PortName == PC)
{
PORTC = WriteValue;
}
else if (PortName == PD)
{
PORTD = WriteValue;
}
// Pseudo Error Code Generation
int returnVal = 0;
int randNumber = random(900); // Random number for error code
if (randNumber > 980)
returnVal = randNumber; // Return Value depending on random number
return (returnVal);
}
BYTE readByte(InVec_Reaktion *InVec)
{
BYTE retVal = 0; // Rückgabewert für Fehlerverarbeitung
BYTE PIND_val; // Speicher für Wert von PIND
retVal |= InputByte(PD, &PIND_val); // Auslesen des PIND-Registers
if (retVal == 0) // bei Einlesefehler den Wert nicht weiterverarbeiten
{
InVec->taster = (PIND & (1 << 2)); // Maskieren des Inputs, Auslesen des Tasterwerts
}
return retVal;
}
BYTE writeByte(OutVec_Reaktion *OutVec)
{
BYTE retVal = 0; // Rückgabewert für Fehlerverarbeitung
BYTE PORTD_val;
retVal |= InputByte(PD, &PORTD_val);
if (retVal == 0)
{
if (OutVec->blue) // blaue LED an
{
PORTD_val = PORTD_val & ~(1 << 4); // 1 an PD4 schreiben
}
else
{
PORTD_val = PORTD_val | (1 << 4); // 0 an PD4 schreiben
}
if (OutVec->yellow) // gelbe LED an
{
PORTD_val = PORTD_val & ~(1 << 6); // 1 an PD4 schreiben
}
else
{
PORTD_val = PORTD_val | (1 << 6); // 0 an PD4 schreiben
}
}
retVal |= OutputByte(PD, PORTD_val); // schreiben des PORTD
return retVal;
}
BYTE InitIO()
{
BYTE retVal = 0;
OutVec_Reaktion OutVecOFF = {0, 0};
OutVec_Reaktion OutVecON = {1, 1};
InVec_Reaktion InVec;
// Datenrichtung
DDRD |= (1 << 2); // PIN D2 Eingang für Taster
DDRD &= ~((1 << 4) | (1 << 6)); // PIN D4 Ausgang für Blau, D6 Ausgang für Gelb
// Testen der Ein und Ausgänge
retVal |= writeByte(&OutVecON); // LEDs an
delay(200);
retVal |= writeByte(&OutVecOFF); // LEDs aus
retVal |= readByte(&InVec); // Taster einlesen testen
return retVal;
}
void randomWait(void)
{
Serial.println("Timer Started");
int randMilliSec = 3000 + random(20000); // Value between 3000 and 23000 ms
delay(randMilliSec);
}
void terminate()
{
Serial.println("Terminated!");
OutVec_Reaktion OutVecOFF = {0, 0};
OutVec_Reaktion OutVecON = {1, 1};
while (true)
{
// Endlos Blinken
writeByte(&OutVecON); // LEDs an
delay(100);
writeByte(&OutVecOFF); // LEDs aus
delay(100);
}
}
BYTE reaction(InVec_Reaktion *inVec, OutVec_Reaktion *outVec)
{
BYTE retVal = 0; // Rückgabewert
static uint8_t lowest = INT16_MAX; // speichern der schnellsten Reaktion
uint8_t counter = 0; // Zaehler für die jetztige Reaktion
randomWait(); // Warte Zufällige Zeit
retVal |= readByte(inVec); // aktuellen Tasterwert einlesen
if (retVal != 0)
{
// schalte gelbe LED an
outVec->yellow = 1;
retVal |= writeByte(outVec);
// warte bis Nutzer auf Knopf drückt
while ((inVec->taster) && (retVal == 0))
{
Serial.print(counter);
counter++; // erhöhe verstrichene Zeit
delay(1); // warte eine Milli sekunde
retVal |= readByte(inVec); // lese aktuellen Taster ein
}
if (retVal != 0)
{
if (counter < lowest) // Reaktion war schneller
{
// Gelb aus, Blau an schalten
outVec->yellow = 0;
outVec->blue = 1;
retVal |= writeByte(outVec);
delay(1000);
if (retVal != 0)
{
// Blau wieder ausschalten
outVec->blue = 0;
retVal |= writeByte(outVec);
}
}
else //Reaktion war langsamer
{
//warte bis Knopf losgelassen
while (!(inVec->taster) && (retVal == 0))
{
retVal |= readByte(inVec); // lese aktuellen Taster ein
}
if (retVal==0)
{
//LED geht aus
outVec->yellow=0;
retVal|=writeByte(outVec);
}
}
}
}
return retVal;
}
void setup()
{
// Pseudofunktion zum Testen, ob reservierte Bits geaendert wurden
// Rote LED darf nicht leuchten, Gruene muss leuchten
preSetup();
Serial.begin(9600);
if (InitIO() != 0)
{
terminate(); // Endlosschleife zur Fehlererkennung
}
Serial.println("Setup Complete");
}
void loop()
{
static BYTE retVal = 0; // Rückgabewert zur Fehlererkennung
static InVec_Reaktion inVec; // Eingabe Vektor
static OutVec_Reaktion outVec; // Ausgabe Vektor
retVal |= readByte(&inVec);
if (retVal == 0) // Fehlerhafte Eingänge nicht weiterverarbeiten
{
Serial.println("reaction started");
retVal |= reaction(&inVec, &outVec); // reaktionsTester, setzt Ausgänge um
}
if (retVal != 0) // Abbruch, wenn Fehler in HAS
{
while (1)
{
terminate();
}
}
}