Ostereiersuche mit NanoAxe-Controller
Seite 4: Quellcode
Im Folgenden beschreiben wir ausführlich den BASIC-Quellcode für den Nano-Axe-Controller. Sie können das Projekt natürlich auch ohne tieferes Verständnis aufbauen, dann geht es für Sie auf der nächsten Seite weiter. Ganz oben im Quellcode kann mit CODE_DIGIT1 bis CODE_DIGIT4 der gewünschte vierstellige Pincode definiert werden. Wenn für Testzwecke eine Debugausgabe auf dem Picaxe-Terminal gewünscht ist, muss das Kommentarzeichen (Semikolon) beim Define ENABLE_DEBUG_OUTPUT entfernt werden. Dadurch werden alle mit DEBUGTEXT aufgerufenenTextausgaben mit dem sertxd-Befehl ausgegeben. Hiermit können dann beispielsweise die erkannten Codeziffern auf dem Terminal sichtbar gemacht werden. Anschließend werden die Portpins für die LEDs, den Hallsensor sowie den Servomotor definiert. Außerdem werden die beim servopos-Befehl benötigten Werte für die beiden Servostellungen „verriegelt“ und „entriegelt“ festgelegt.
#picaxe 08m2
; 4-stelligen Pincode fuer das Codeschloss definieren
#define CODE_DIGIT1 1
#define CODE_DIGIT2 2
#define CODE_DIGIT3 3
#define CODE_DIGIT4 4
; wenn keine Debugausgabe per Terminal gewuenscht, dann folgende Zeile auskommentieren
;#define ENABLE_DEBUG_OUTPUT
symbol LEDS_PIN = C.1
#define LEDS_OFF low LEDS_PIN
#define LEDS_ON high LEDS_PIN
symbol HALL_PIN = pinC.3
symbol HALL_PULLUP_MASK = %01000
symbol SERVO_PIN = C.4
symbol SERVO_POS_CLOSED = 150 ; Servo Position 90 Grad = verriegelt
symbol SERVO_POS_OPEN = 240 ; Servo Position 180 Grad = entriegelt
#ifdef ENABLE_DEBUG_OUTPUT
#define DEBUGTEXT sertxd
#else
#define DEBUGTEXT ;
#endif
symbol RAM_ADDR_KEYCODE = 28
symbol counter = b0
symbol codeInputActive = b1
symbol codeDigit = b2
symbol timeout = b3
pullup HALL_PULLUP_MASK
gosub initPincode
codeInputActive = 0
codeDigit = 0
timeout = 0
LEDS_ON
do
loop until HALL_PIN = 0
gosub lock
do
loop while HALL_PIN = 0
LEDS_OFF
pause 500
main:
if HALL_PIN = 0 then
codeInputActive = 1
LEDS_ON
pause 250
LEDS_OFF
pause 1000
codeDigit = codeDigit + 1 % 10
DEBUGTEXT(" ", #codeDigit)
timeout = 0
else
if codeInputActive = 1 then
gosub checkCode
codeInputActive = 0
timeout = 50 ; Timeout 50*100ms = 5s
codeDigit = 0
LEDS_ON
pause 1000
LEDS_OFF
pause 500
endif
endif
pause 100
if timeout != 0 then
dec timeout
if timeout = 0 then
DEBUGTEXT(cr,lf, "Timeout",cr,lf)
for counter = 1 to 3
LEDS_ON
pause 250
LEDS_OFF
pause 250
next counter
gosub initPincode
endif
endif
goto main
checkCode: ; Code ueberpruefen
if codeDigit = @bptr then
DEBUGTEXT(cr,lf, "Codeziffer richtig",cr,lf)
inc bptr
if @bptr = 0xFF then
LEDS_ON
DEBUGTEXT(cr,lf, "*** Code richtig ***",cr,lf)
gosub unlock
do
LEDS_OFF
pause 500
LEDS_ON
pause 500
loop
endif
else
DEBUGTEXT(cr,lf, "Codeziffer falsch",cr,lf)
gosub initPincode
endif
return
lock: ; Schloss verriegeln
DEBUGTEXT(cr,lf,"Lock",cr,lf)
pause 100
servo SERVO_PIN, SERVO_POS_CLOSED
servopos SERVO_PIN, SERVO_POS_CLOSED
pause 1000
return
unlock: ; Schloss entriegeln
DEBUGTEXT(cr,lf,"Unlock",cr,lf)
pause 100
servopos SERVO_PIN, SERVO_POS_OPEN
pause 1000
servo SERVO_PIN,OFF
return
initPincode: ; Initialisierung des Pincodes
bptr = RAM_ADDR_KEYCODE
@bptrinc = CODE_DIGIT1
@bptrinc = CODE_DIGIT2
@bptrinc = CODE_DIGIT3
@bptrinc = CODE_DIGIT4
@bptrinc = 0xFF
bptr = RAM_ADDR_KEYCODE
return
Beim Programmstart wird zunächst der interne Pullup für das Hallsensormodul aktiviert. Im Unterprogramm initPincode wird der oben festgelegte Pincode ins RAM ab der Adresse RAM_ADDR_KEYCODE geschrieben, gefolgt vom Wert 0xFF als Endekennung. Die Variable bptr wird auf den Wert RAM_ADDR_KEYCODE gesetzt, sodass diese als Pointer auf die erste Codeziffer zeigt. Anschließend werden die beiden LEDs eingeschaltet, sodass die Augen des Hasen leuchten. Es wird nun so lange gewartet, bis der Hallsensor ein Magnetfeld erkennt, d.h. ein LOW-Pegel auftritt. Hierzu muss die Karotte an die richtige Position unterhalb der Nase des Hasen gehalten werden. Dann wird die Truhe durch Aufruf des Unterprogramms lock verriegelt, wodurch der Servomotor in die Verriegelungsposition (Mittelstellung) bewegt wird. Anschließend wird so lange gewartet, bis der Hallsensor kein Magnetfeld mehr detektiert und dann die LEDs ausgeschaltet. Ab jetzt ist das Codeschloss scharf geschaltet.
Die main-Schleife prüft, ob der Hallsensor ein Magnetfeld erkennt. Wenn ja, beginnt die Codeeingabe und die Variable codeInputActive wird auf 1 gesetzt. Die beiden LEDs leuchten kurz auf (250ms an, 1s aus) und die Variable codeDigit wird um 1 erhöht, da diese die Pulse für die Eingabe der aktuellen Codeziffer mitzählt. Außerdem wird die Variable timeout auf 0 zurückgesetzt. Nach dem endif-Befehl (Zeile 70) wartet das Programm 100ms, die anschließende if-Bedingung für die timeout-Variable ist nicht erfüllt, sodass sie wieder an den Beginn der main-Schleife springt. Erkennt der Sensor immer noch ein Magnetfeld, dann wird der nächste Lichtpuls ausgegeben und codeDigit erneut erhöht. Wie weit der Eingabewert für die aktuelle Codeziffer hochgezählt wird, ist abhängig davon, wie lange wir die magnetische Karotte unter die Nase des Hasen halten.
Dies wiederholt sich also so lange, bis kein Magnetfeld mehr erkannt wurde, sodass dann der else-Zweig ab Zeile 60 ausgeführt wird. Wenn die Variable codeInputActive eine laufende Codeeingabe anzeigt, dann prüft das Unterprogramm checkCode, ob die gerade eingegebene Ziffer korrekt ist. Hierzu vergleicht sie den Wert von codeDigit mit dem RAM-Wert, auf den bptr zeigt. Wenn diese unterschiedlich sind, wird im else-Zweig ab Zeile 104 durch Aufruf von initPincode die Variable bptr wieder auf den Anfang im RAM zurückgesetzt, sodass der bisher eingegebene Pincode komplett verworfen und mit return zurückgekehrt wird.
Überprüfung der Codeziffer
Bei richtiger Codeziffer wird hingegen der if-Zweig ab Zeile 90 ausgeführt und bptr inkrementiert, sodass dieser Pointer auf die nächste erwartete Codeziffer zeigt. Falls diese den Wert 0xFF hat, dann wurden alle 4 Codeziffern richtig eingegeben und das Unterprogramms unlock bewegt den Servomotor in die Entriegelungsposition, sodass sich die Schatztruhe nun öffnen lässt. Die LED-Augen blinken nun in einer Endlosschleife, denn die Osterrallye wurde erfolgreich abgeschlossen. Falls der Code jedoch noch nicht komplett eingegeben wurde, wird checkCode mit return verlassen.
Nach dem Rücksprung aus checkCode geht es ab Zeile 62 weiter. Die Variable codeInputActive wird zurückgesetzt, da die Eingabe der aktuellen Codeziffer beendet ist. Nun wird ein Timeout von ca. 5 Sekunden (50 * 100ms) über die entsprechende Variable vorbereitet und codeDigit auf Null zurückgesetzt, damit die nächste Codezifferneingabe wieder mit 1 startet. Die LEDs leuchten eine Sekunde lang auf und signalisieren dadurch optisch die abgeschlossene Eingabe der aktuellen Codeziffer. Nach einer Pause von 100ms in Zeile 71 ist nun die if-Bedingung erfüllt. Somit wird die timeout-Variable dekrementiert. Da sie jedoch noch nicht auf Null steht, erfolgt wieder ein Sprung an den Beginn der main-Schleife. Falls kein Magnetfeld erkannt wird, erfolgt lediglich eine Pause von 100ms (Zeile 71). Wenn also 5 Sekunden lang kein Magnetfeld erkannt wurde, ist der Timeout abgelaufen und verzweigt in Zeile 75. Die LEDs blinken dreimal schnell hintereinander und signalisieren so optisch, dass die Codeeingabe aufgrund zu langer Inaktivität zurückgesetzt wurde. Der Pincode muss also wieder komplett neu eingegeben werden.
Wenn jedoch während der 5-sekündigen Timeoutphase ein Magnetfeld erkannt wird, geht es mit Zeile 51 weiter, wo die Eingabe der nächsten Codeziffer verarbeitet wird. Es bleibt also nach jeder eingegebenen Codeziffer ein Zeitfenster von rund 5 Sekunden, um die nächste Ziffer einzugeben.