Elektronisches Schließfach: Unterschied zwischen den Versionen
(→Software: S-Function Code hinzugefügt) |
|||
Zeile 259: | Zeile 259: | ||
<br/> | <br/> | ||
Insgesamt wurden vier S-Function Blöcke erstellt, um den Fingerabdrucksensor, das LCD-Display, das Tastenfeld und den EEPROM-Speicher des Arduinos in Simulink einzubinden. Der Quellcode für die jeweiligen S-Function Blöcke ist nachfolgend aufgeführt. | Insgesamt wurden vier S-Function Blöcke erstellt, um den Fingerabdrucksensor, das LCD-Display, das Tastenfeld und den EEPROM-Speicher des Arduinos in Simulink einzubinden. Der Quellcode für die jeweiligen S-Function Blöcke ist nachfolgend aufgeführt. | ||
==== S-Function EEPROM Speicher ==== | |||
<div class="mw-collapsible mw-collapsed"> | <div class="mw-collapsible mw-collapsed"> | ||
<syntaxhighlight lang="cpp" style="border: none; background-color: #EFF1C1; font-size:small"> | |||
/* Includes_BEGIN */ | |||
#ifndef MATLAB_MEX_FILE | |||
#include <math.h> | |||
#include <EEPROM.h> | |||
#endif | |||
/* Includes_END */ | |||
/* Externs_BEGIN */ | |||
/* Externs_END */ | |||
void EEPROM_Speicher_Start_wrapper(real_T *xD) | |||
{ | |||
/* Start_BEGIN */ | |||
/* Start_END */ | |||
} | |||
void EEPROM_Speicher_Outputs_wrapper(const uint8_T *EingabePIN, | |||
const uint8_T *PinStatus, | |||
uint8_T *PIN, | |||
const real_T *xD) | |||
{ | |||
/* Output_BEGIN */ | |||
#ifndef MATLAB_MEX_FILE | |||
for (int i = 0; i < 4; i++) // Auslesen der vier EEPROM Addressen | |||
{ | |||
PIN[i] = EEPROM.read(i); | |||
} | |||
if (PinStatus[0] == 1) // Wenn das Passwort geändert wurde: | |||
{ | |||
for (int i = 0; i < 4; i++) // Updaten der vier EEPROM Addressen | |||
{ | |||
EEPROM.update(i, EingabePIN[i]); | |||
} | |||
} | |||
#endif | |||
/* Output_END */ | |||
} | |||
void EEPROM_Speicher_Update_wrapper(const uint8_T *EingabePIN, | |||
const uint8_T *PinStatus, | |||
uint8_T *PIN, | |||
real_T *xD) | |||
{ | |||
/* Update_BEGIN */ | |||
/* Update_END */ | |||
} | |||
void EEPROM_Speicher_Terminate_wrapper(real_T *xD) | |||
{ | |||
/* Terminate_BEGIN */ | |||
/* Terminate_END */ | |||
} | |||
</syntaxhighlight> | |||
</pre> | </pre> | ||
Zeile 298: | Zeile 371: | ||
[[Datei:PIN-Änderung.png|800px|mini|links|Abbildung 2.4d: PAP PIN-Änderung]] | [[Datei:PIN-Änderung.png|800px|mini|links|Abbildung 2.4d: PAP PIN-Änderung]] | ||
[[Datei:FingerabdruckHinzu.png|800px|mini|rechts|Abbildung 2.4e: PAP Fingerabdruck hinzufügen]] | [[Datei:FingerabdruckHinzu.png|800px|mini|rechts|Abbildung 2.4e: PAP Fingerabdruck hinzufügen]] | ||
</pre> | |||
</div> | |||
<br clear = all> | |||
==== S-Function leseFingerabdruck ==== | |||
<div class="mw-collapsible mw-collapsed"> | |||
<syntaxhighlight lang="cpp" style="border: none; background-color: #EFF1C1; font-size:small"> | |||
/* Includes_BEGIN */ | |||
#ifndef MATLAB_MEX_FILE | |||
#include <Adafruit_Fingerprint.h> | |||
#include <Wire.h> | |||
#include <FingerprintFunctions.h> | |||
#define mySerial Serial2 | |||
// Festlegen der Seriellen Schnittstelle des Fingerabdrucksensors auf Serial2 | |||
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial); | |||
// Anlegen der Programmvariablen | |||
unsigned char state = 0; | |||
#endif | |||
/* Includes_END */ | |||
/* Externs_BEGIN */ | |||
/* Externs_END */ | |||
void leseFingerabdruck_Start_wrapper(real_T *xD) | |||
{ | |||
/* Start_BEGIN */ | |||
#ifndef MATLAB_MEX_FILE | |||
delay(100); | |||
// Setzen der Baudrate für den seriellen Sensorport | |||
finger.begin(57600); | |||
// Überprüfen der Verbindung zum Fingerabdrucksensor | |||
delay(5); | |||
finger.verifyPassword(); | |||
// Auslesen der Sensorparameter | |||
finger.getParameters(); | |||
finger.getTemplateCount(); | |||
#endif | |||
/* Start_END */ | |||
} | |||
void leseFingerabdruck_Outputs_wrapper(const uint8_T *FingerEin, | |||
uint8_T *FingerStatus, | |||
const real_T *xD) | |||
{ | |||
/* Output_BEGIN */ | |||
#ifndef MATLAB_MEX_FILE | |||
if (FingerEin[0] == 1) | |||
{ | |||
finger.LEDcontrol(true); // Einschalten des Fingerabdrucksensors | |||
state = getFingerprintID(finger); // Auslesen und Abgleich des Fingerabdrucks mit Sensordatenbank | |||
if (state > 0 && state < 121) { FingerStatus[0] = 1; delay(100); } | |||
} | |||
else if (FingerEin[0] == 2) | |||
{ | |||
finger.LEDcontrol(true); // Einschalten des Fingerabdrucksensors | |||
state = getFingerprintEnroll(finger); // erstes Bild vom Fingerabdruck erstellen | |||
if (state == 2) { FingerStatus[0] = 2; delay(100); } | |||
} | |||
else if (FingerEin[0] == 3) | |||
{ | |||
finger.LEDcontrol(true); // Einschalten des Fingerabdrucksensors | |||
state = getFingerprintEnroll1(finger); // zweites Bild vom Fingerabdruck erstellen | |||
if (state == 3) { FingerStatus[0] = 3; delay(100); } // bei Übereinstimmung in Sensordatenbank speichern | |||
} | |||
else | |||
{ | |||
finger.LEDcontrol(false); // Ausschalten des Fingerabdrucksensors wenn nicht benötigt | |||
FingerStatus[0] = 0; | |||
} | |||
#endif | |||
/* Output_END */ | |||
} | |||
void leseFingerabdruck_Update_wrapper(const uint8_T *FingerEin, | |||
uint8_T *FingerStatus, | |||
real_T *xD) | |||
{ | |||
/* Update_BEGIN */ | |||
/* Update_END */ | |||
} | |||
void leseFingerabdruck_Terminate_wrapper(real_T *xD) | |||
{ | |||
/* Terminate_BEGIN */ | |||
/* Terminate_END */ | |||
} | |||
</syntaxhighlight> | |||
</pre> | |||
</div> | |||
<br clear = all> | |||
==== S-Function LCD Display ==== | |||
<div class="mw-collapsible mw-collapsed"> | |||
<syntaxhighlight lang="cpp" style="border: none; background-color: #EFF1C1; font-size:small"> | |||
/* Includes_BEGIN */ | |||
#ifndef MATLAB_MEX_FILE | |||
#include <Wire.h> | |||
#include <hd44780.h> | |||
#include <hd44780ioClass/hd44780_I2Cexp.h> | |||
// Anlegen der Displayvariablen | |||
hd44780_I2Cexp lcd; | |||
const char LCD_COLS = 16; | |||
const char LCD_ROWS = 2; | |||
unsigned char displaystate = 0; | |||
#endif | |||
/* Includes_END */ | |||
/* Externs_BEGIN */ | |||
/* Externs_END */ | |||
void LCD_Display_Start_wrapper(real_T *xD) | |||
{ | |||
/* Start_BEGIN */ | |||
#ifndef MATLAB_MEX_FILE | |||
int status; | |||
status = lcd.begin(LCD_COLS, LCD_ROWS); // Initialisierung des Displays | |||
if(status) | |||
{ | |||
hd44780::fatalError(status); | |||
} | |||
#endif | |||
/* Start_END */ | |||
} | |||
void LCD_Display_Outputs_wrapper(const uint8_T *DisplayStatus, | |||
const real_T *xD) | |||
{ | |||
/* Output_BEGIN */ | |||
#ifndef MATLAB_MEX_FILE | |||
displaystate = DisplayStatus[0]; | |||
switch(displaystate) // Wechseln zwischen verschiedenen Displayausgaben | |||
{ | |||
case 0: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Bitte mit Taste"); | |||
lcd.setCursor(0,1); | |||
lcd.print("A / B anmelden"); | |||
break; | |||
case 1: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Bitte geben Sie"); | |||
lcd.setCursor(0,1); | |||
lcd.print("den PIN ein!"); | |||
break; | |||
case 2: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Eingabe korrekt"); | |||
break; | |||
case 3: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("PIN falsch bitte"); | |||
lcd.setCursor(0,1); | |||
lcd.print("erneut versuchen"); | |||
break; | |||
case 4: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Funktionsauswahl"); | |||
lcd.setCursor(0,1); | |||
lcd.print("Taste A / B / C"); | |||
break; | |||
case 5: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Schloss wird"); | |||
lcd.setCursor(0,1); | |||
lcd.print("entsperrt"); | |||
break; | |||
case 6: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Zum Verriegeln"); | |||
lcd.setCursor(0,1); | |||
lcd.print("[1] dr\365cken"); | |||
break; | |||
case 7: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Finger auflegen"); | |||
lcd.setCursor(0,1); | |||
lcd.print("und [1] dr\365cken"); | |||
break; | |||
case 8: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Fingerabdruck"); | |||
lcd.setCursor(0,1); | |||
lcd.print("wird gepr\365ft"); | |||
break; | |||
case 9: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Fingerabdruck"); | |||
lcd.setCursor(0,1); | |||
lcd.print("nicht erkannt"); | |||
break; | |||
case 10: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("ALARM: ZUGRIFF"); | |||
lcd.setCursor(0,1); | |||
lcd.print("VERWEIGERT"); | |||
break; | |||
case 11: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Abdruck wird"); | |||
lcd.setCursor(0,1); | |||
lcd.print("erneut gepr\365ft"); | |||
break; | |||
case 12: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Fingerabdruck"); | |||
lcd.setCursor(0,1); | |||
lcd.print("wurde gewechselt"); | |||
break; | |||
case 13: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Finger ab- und"); | |||
lcd.setCursor(0,1); | |||
lcd.print("auflegen [1]"); | |||
break; | |||
case 14: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Zum PIN wechseln"); | |||
lcd.setCursor(0,1); | |||
lcd.print("[1] dr\365cken"); | |||
break; | |||
case 15: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Bitte 1. Ziffer"); | |||
lcd.setCursor(0,1); | |||
lcd.print("vom PIN eingeben"); | |||
break; | |||
case 16: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Bitte 2. Ziffer"); | |||
lcd.setCursor(0,1); | |||
lcd.print("vom PIN eingeben"); | |||
break; | |||
case 17: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Bitte 3. Ziffer"); | |||
lcd.setCursor(0,1); | |||
lcd.print("vom PIN eingeben"); | |||
break; | |||
case 18: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("Bitte 4. Ziffer"); | |||
lcd.setCursor(0,1); | |||
lcd.print("vom PIN eingeben"); | |||
break; | |||
case 19: | |||
lcd.clear(); | |||
lcd.setCursor(0,0); | |||
lcd.print("PIN erfolgreich"); | |||
lcd.setCursor(0,1); | |||
lcd.print("gewechselt"); | |||
break; | |||
} | |||
#endif | |||
/* Output_END */ | |||
} | |||
void LCD_Display_Update_wrapper(const uint8_T *DisplayStatus, | |||
real_T *xD) | |||
{ | |||
/* Update_BEGIN */ | |||
/* Update_END */ | |||
} | |||
void LCD_Display_Terminate_wrapper(real_T *xD) | |||
{ | |||
/* Terminate_BEGIN */ | |||
/* Terminate_END */ | |||
} | |||
</syntaxhighlight> | |||
</pre> | |||
</div> | |||
<br clear = all> | |||
==== S-Function Tastenfeld ==== | |||
<div class="mw-collapsible mw-collapsed"> | |||
<syntaxhighlight lang="cpp" style="border: none; background-color: #EFF1C1; font-size:small"> | |||
/* Includes_BEGIN */ | |||
#ifndef MATLAB_MEX_FILE | |||
#include <Keypad.h> | |||
const byte ROWS = 4; // rows | |||
const byte COLS = 4; // columns | |||
//Definition der Symbole des Tastenfelds | |||
char hexaKeys[ROWS][COLS] = { | |||
{'1','2','3','A'}, | |||
{'4','5','6','B'}, | |||
{'7','8','9','C'}, | |||
{'*','0','#','D'} | |||
}; | |||
byte rowPins[ROWS] = {9, 8, 7, 6}; //Pinbelegung der Reihen des Tastenfelds | |||
byte colPins[COLS] = {5, 4, 3, 2}; //Pinbelegung der Spalten des Tastenfelds | |||
//Initialisierung der Tastenfeldklasse | |||
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); | |||
#endif | |||
/* Includes_END */ | |||
/* Externs_BEGIN */ | |||
/* Externs_END */ | |||
void Tastenfeld_Start_wrapper(real_T *xD) | |||
{ | |||
/* Start_BEGIN */ | |||
#ifndef MATLAB_MEX_FILE | |||
#endif | |||
/* Start_END */ | |||
} | |||
void Tastenfeld_Outputs_wrapper(const uint8_T *TasteStatus, | |||
uint8_T *Taste, | |||
uint8_T *nTaste, | |||
const real_T *xD) | |||
{ | |||
/* Output_BEGIN */ | |||
#ifndef MATLAB_MEX_FILE | |||
if (TasteStatus[0] == 0 && nTaste[0] > 0) { nTaste[0] = 0; } // Reset des Tastencounters | |||
char customKey = customKeypad.getKey(); // Auslesen der Taste bei Betätigung | |||
if (customKey) { | |||
Taste[0] = customKey; // Speichern der Taste in Variable | |||
nTaste[0] += 1; // Erhöhung des Tastencounters | |||
} | |||
#endif | |||
/* Output_END */ | |||
} | |||
void Tastenfeld_Update_wrapper(const uint8_T *TasteStatus, | |||
uint8_T *Taste, | |||
uint8_T *nTaste, | |||
real_T *xD) | |||
{ | |||
/* Update_BEGIN */ | |||
/* Update_END */ | |||
} | |||
void Tastenfeld_Terminate_wrapper(real_T *xD) | |||
{ | |||
/* Terminate_BEGIN */ | |||
/* Terminate_END */ | |||
} | |||
</syntaxhighlight> | |||
</pre> | </pre> |
Version vom 15. Januar 2024, 02:44 Uhr
WS 23/24: Fachpraktikum Elektrotechnik (MTR) und Angewandte Elektrotechnik (BSE)
Autoren: Kilian Engelhardt & Jörn-Hendrik Beleke
Betreuer: Prof. Schneider
Einleitung
Das Projekt "Elektronisches Schließfach" entsteht im Rahmen des Praktikums "Fachpraktikum Elektrotechnik" im Studiengang "Mechatronik (MTR)".
Ziel des genannten Projekts ist die Entwicklung eines Schließfachs zum Verstauen privater Gegenstände, welches komfortabel durch die Eingabe eines PIN-Codes oder biometrischer Daten durch eine Fingerabdruckerkennung auf einem Bedienfeld durch den Besitzer entsperrt werden kann. Zusätzlich verfügt das Schließfach über Zahlentasten , wodurch die Öffnung des Schließfachs durch weitere Personen mit der Eingabe eines PIN-Codes ermöglicht wird. Zur Entsperrung des Verschlussriegels soll ein Servomotor eingesetzt werden. Über ein LCD-Display werden Anweisungen und der Eingabestatus für den Bediener dargestellt. Eine erfolgreiche sowie mehrfach fehlerhafte Eingabe soll akustisch durch einen Ton bzw. Alarm eines Summers und visuell durch das Leuchten von LEDS bestätigt werden. Zusätzlich wird eine Funktion zur Änderung des Zahlencodes und Fingerabdrucks implementiert.
Anforderungen
Die Anforderungen an das Projekt werden in der nachfolgenden Tabelle 1 aufgezeigt. Dabei sind diese in die Bereiche Hardware, Mechanik und Software unterteilt.
Nr. | Beschreibung | Bereich | Datum | Status |
---|---|---|---|---|
1 | Das elektronische Schließfach muss ein Bedienpanel mit Fingerabdruckerkennung und Tastern zur PIN-Code-Eingabe besitzen. | Hardware | 04.10.2023 | Erledigt |
2 | Das Bedienpanel muss über ein LCD-Display und LEDs zur Visualisierung des Eingabestatus verfügen. | Hardware | 04.10.2023 | Erledigt |
3 | Für das Schließfach muss eine Spannungsquelle bereitgestellt werden. | Hardware | 04.10.2023 | Erledigt |
4 | Als Mikrocontroller muss ein Arduino eingesetzt werden. | Hardware | 04.10.2023 | Erledigt |
5 | Als Schließmechanismus muss ein Servomotor mit Sperrriegel eingesetzt werden. | Hardware | 04.10.2023 | Erledigt |
6 | Für das Schließfach muss ein Gehäuse angefertigt werden. | Mechanik | 04.10.2023 | Erledigt |
7 | Der Algorithmus muss die Signale der Fingerabdruck- und PIN-Code-Eingabe erfassen und verarbeiten. | Software | 04.10.2023 | Erledigt |
8 | Der Schließmechanismus muss durch den Algorithmus betätigt werden. | Software | 04.10.2023 | Erledigt |
9 | Der Algorithmus muss über eine Funktion zur Änderung des PIN-Codes bzw. Fingerabdrucks verfügen. | Software | 04.10.2023 | Erledigt |
10 | Auf dem LCD Display muss der Eingabestatus durch den Algorithmus visualisiert werden. | Software | 04.10.2023 | Erledigt |
11 | Der Algorithmus muss eine Alarmfunktion für wiederholt falsche Eingaben besitzen. | Software | 04.10.2023 | Erledigt |
12 | Die Umsetzung des Algorithmus muss unter Matlab/Simulink erfolgen. | Software | 04.10.2023 | Erledigt |
Funktionaler Systementwurf/Technischer Systementwurf
Zur näheren Erläuterung wird der Systementwurf in Komponenten unterteilt:
- Gehäuse: Das Gehäuse beinhaltet alle folgenden Komponenten und bietet die grundlegende Funktion eines Schließfachs in Kombination mit dem Schließmechanismus.
- Schließmechanismus: Als Schließmechanismus wird ein Servomotor eingesetzt, welcher das Schließfach über einen Verschlussriegel öffnet oder sperrt.
- Endschalter: Diese Komponente erfasst den geöffneten oder geschlossenen Zustand der Schließfachtür.
- Tastenfeld und Fingerabdrucksensor: Diese Komponenten erfassen die Eingabe des PIN-Codes und der biometrischen Daten.
- LCD-Display: Auf dem Display werden Anweisungen und der Eingabestatus für den Nutzer dargestellt.
- Summer: Dieser Lautsprecher informiert den Nutzer akustisch über den Eingabestatus.
- Arduino: An den Arduino Mikrocontroller sind die genannten elektrischen Komponenten angebunden. Der Mikrocontroller führt den Algorithmus aus, welcher die Eingaben des Nutzers auf dem Bedienpanel erfasst, verarbeitet und entsprechende Aktionen durch die Komponenten steuert.
- Spannungsquelle: Als Spannungsquelle für den Arduino mit Platine wird eine 9V-Block-Batterie eingesetzt.
Die nachfolgenden Abbildungen 1.1 und 1.2 stellen eine Skizze des Systementwurfs sowie den Signalfluss des Systems dar.
Komponentenspezifikation
In der nachfolgenden Tabelle 2 sind alle für das Projekt verwendeten Komponenten aufgelistet, welche anhand des Systementwurfs ausgewählt wurden.
Nr. | Komponentenbezeichnung | Beschreibung | Bild |
---|---|---|---|
1 | Arduino MEGA |
|
|
2 | Fingerabdrucksensor JM 101 |
|
|
3 | Mechanischer Endschalter |
|
|
4 | MG90S Micro Servo |
|
|
5 | 4x4 Tastenfeld |
|
|
6 | 16x02 I2C LCD Modul |
|
|
7 | Piezo Lautsprecher |
|
|
8 | Spannungsquelle |
|
|
9 | Montageplatte Arduino Mega |
|
|
10 | Industriegehäuse |
|
Umsetzung (HW/SW)
Hardware
Montage der Komponenten
Nach den Funktionstests der Einzelkomponenten (siehe Kapitel Komponententest) wurden diese im Gehäuse verbaut. Dazu mussten entsprechende Aussparungen für den Fingerabdrucksensor, das Tastenfeld und das LCD-Display an der Schließfachtür angefertigt werden, siehe Abbildung 2.1a.
Um den Servomotor am Schließmechanismus zu befestigen, wurden Bohrungen in den Verschlussriegel des Schließmechanismus eingebracht. Mittels Schrauben wurde dann ein im Lieferumfang enthaltenes Verbindungsstück mit dem Motor und den Bohrungen verbunden. Wie in Abbildung 2.1b dargestellt, wurde der Motor anschließend über passend zugesägte Kunststoffwinkel an der Innenseite der Schließfachtür angebracht.
Der Endschalter (Abbildung 2.1c) wurde an der Innenkante des Gehäuses angebracht, sodass dieser betätigt wird, wenn die Tür geschlossen ist.
Verdrahtung der Komponenten
Im Anschluss an die Montage der einzelnen Komponenten im Gehäuse mussten alle elektronischen Komponenten mit dem Arduino Mikrocontroller elektrisch verbunden werden. Dazu wurde der folgende Verdrahtungsplan nach Abbildung 2.2 für das Gesamtsystem angefertigt. Die Komponenten sind entsprechend der Komponentenliste nummeriert.
Software
Die Umsetzung der Software für das Gesamtsystems des elektronischen Schließfachs erfolgt unter MATLAB Simulink. Da für dieses Projekt ein Arduino Mega 2560 als Mikrocontroller eingesetzt wird, wurde das "Simulink Support Package für Arduino Hardware" aus dem MATLAB Add-On Explorer zur einfachen Integration der Arduino-Hardware in Simulink installiert. Zusätzlich wird der Block "S-Function Builder" aus der Simulink Bibliothek zur Softwareentwicklung verwendet. Durch diesen Funktionsblock kann C++-Code in Simulink-Modellen integriert werden, was die Verwendung von Arduino-Bibliotheken zur Steuerung der Arduino-Hardware ermöglicht. Als Hilfestellung bei der Implementation der S-Funtions im Simulink-Modell wurde sich am folgenden Wiki-Artikel orientiert: https://wiki.hshl.de/wiki/index.php/Datei:S-Function_Tutorial.pdf
Insgesamt wurden vier S-Function Blöcke erstellt, um den Fingerabdrucksensor, das LCD-Display, das Tastenfeld und den EEPROM-Speicher des Arduinos in Simulink einzubinden. Der Quellcode für die jeweiligen S-Function Blöcke ist nachfolgend aufgeführt.
S-Function EEPROM Speicher
/* Includes_BEGIN */
#ifndef MATLAB_MEX_FILE
#include <math.h>
#include <EEPROM.h>
#endif
/* Includes_END */
/* Externs_BEGIN */
/* Externs_END */
void EEPROM_Speicher_Start_wrapper(real_T *xD)
{
/* Start_BEGIN */
/* Start_END */
}
void EEPROM_Speicher_Outputs_wrapper(const uint8_T *EingabePIN,
const uint8_T *PinStatus,
uint8_T *PIN,
const real_T *xD)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
for (int i = 0; i < 4; i++) // Auslesen der vier EEPROM Addressen
{
PIN[i] = EEPROM.read(i);
}
if (PinStatus[0] == 1) // Wenn das Passwort geändert wurde:
{
for (int i = 0; i < 4; i++) // Updaten der vier EEPROM Addressen
{
EEPROM.update(i, EingabePIN[i]);
}
}
#endif
/* Output_END */
}
void EEPROM_Speicher_Update_wrapper(const uint8_T *EingabePIN,
const uint8_T *PinStatus,
uint8_T *PIN,
real_T *xD)
{
/* Update_BEGIN */
/* Update_END */
}
void EEPROM_Speicher_Terminate_wrapper(real_T *xD)
{
/* Terminate_BEGIN */
/* Terminate_END */
}
Die drei verbleibenden Komponenten Endschalter, Piezo-Lautsprecher und Servo-Motor konnten Funktionsblöcken aus der Standard Simulink und Arduino Support Package Bibliothek direkt ausgelesen bzw. angesteuert werden. Da der Endschalter an PIN 11 des Arduinos angeschlossen ist, wurde ein Digital Input Block für PIN 11 verwendet, um den Status des Endschalters (Tür geöffnet / geschlossen) auszulesen. Da der Endschalter als Öffner betrieben ist, gibt der Block eine 1 bei geöffneter Tür und 0 bei geschlossener Tür als Ausgabewert aus. Zur Verwendung des Piezo-Lautsprechers an PIN 12 benötigt es einen PWM-Signal Block, welcher auf eine feste Frequenz von 245.1 Hz eingestellt wurde. Dieser Block kann mit einem Eingabewert zwischen 0 und 255 für einen Pulsweitenmodulation von 0 bis 100% angesteuert werden. Der verwendete Block "Standard Servo Write" aus der Arduino Bibliothek benötigt einen Eingabewert in Grad, um den Servomotor an PIN 10 entsprechend zu drehen. In diesem Modell gibt es die beiden Fälle 0° für die Sperrung und 90° zur Entsperrung der Tür.
Nach Einbindung der einzelnen Komponenten in das Simulink Modell müssen diese noch miteinander logisch verknüpft werden, um die gewünschten Funktionen zu bieten. Bei diesem Projekt eignet sich Simulink Stateflow hervorragend für die logische Steuerung des Modells, da dies ermöglicht, die Ein- und Ausgangsvariablen der Komponenten über verschiedene Zustände (States) mit Übergangsbedingungen zu steuern. Alle Funktionsblöcke der einzelnen Komponenten werden an das "Stateflow-Chart" angeschlossen, wodurch sich das in Abbildung 2.3 dargestellte Simulink Gesamtmodell ergibt.
Durch folgende Programmablaufpläne (Abbildung 2.4a bis 2.4e) wird die Planung des Hauptprogramms und der Unterfunktionen dargestellt.
Programmablaufplan Hauptprogramm
Programmablaufplan Unterfunktionen
S-Function leseFingerabdruck
/* Includes_BEGIN */
#ifndef MATLAB_MEX_FILE
#include <Adafruit_Fingerprint.h>
#include <Wire.h>
#include <FingerprintFunctions.h>
#define mySerial Serial2
// Festlegen der Seriellen Schnittstelle des Fingerabdrucksensors auf Serial2
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);
// Anlegen der Programmvariablen
unsigned char state = 0;
#endif
/* Includes_END */
/* Externs_BEGIN */
/* Externs_END */
void leseFingerabdruck_Start_wrapper(real_T *xD)
{
/* Start_BEGIN */
#ifndef MATLAB_MEX_FILE
delay(100);
// Setzen der Baudrate für den seriellen Sensorport
finger.begin(57600);
// Überprüfen der Verbindung zum Fingerabdrucksensor
delay(5);
finger.verifyPassword();
// Auslesen der Sensorparameter
finger.getParameters();
finger.getTemplateCount();
#endif
/* Start_END */
}
void leseFingerabdruck_Outputs_wrapper(const uint8_T *FingerEin,
uint8_T *FingerStatus,
const real_T *xD)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
if (FingerEin[0] == 1)
{
finger.LEDcontrol(true); // Einschalten des Fingerabdrucksensors
state = getFingerprintID(finger); // Auslesen und Abgleich des Fingerabdrucks mit Sensordatenbank
if (state > 0 && state < 121) { FingerStatus[0] = 1; delay(100); }
}
else if (FingerEin[0] == 2)
{
finger.LEDcontrol(true); // Einschalten des Fingerabdrucksensors
state = getFingerprintEnroll(finger); // erstes Bild vom Fingerabdruck erstellen
if (state == 2) { FingerStatus[0] = 2; delay(100); }
}
else if (FingerEin[0] == 3)
{
finger.LEDcontrol(true); // Einschalten des Fingerabdrucksensors
state = getFingerprintEnroll1(finger); // zweites Bild vom Fingerabdruck erstellen
if (state == 3) { FingerStatus[0] = 3; delay(100); } // bei Übereinstimmung in Sensordatenbank speichern
}
else
{
finger.LEDcontrol(false); // Ausschalten des Fingerabdrucksensors wenn nicht benötigt
FingerStatus[0] = 0;
}
#endif
/* Output_END */
}
void leseFingerabdruck_Update_wrapper(const uint8_T *FingerEin,
uint8_T *FingerStatus,
real_T *xD)
{
/* Update_BEGIN */
/* Update_END */
}
void leseFingerabdruck_Terminate_wrapper(real_T *xD)
{
/* Terminate_BEGIN */
/* Terminate_END */
}
S-Function LCD Display
/* Includes_BEGIN */
#ifndef MATLAB_MEX_FILE
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>
// Anlegen der Displayvariablen
hd44780_I2Cexp lcd;
const char LCD_COLS = 16;
const char LCD_ROWS = 2;
unsigned char displaystate = 0;
#endif
/* Includes_END */
/* Externs_BEGIN */
/* Externs_END */
void LCD_Display_Start_wrapper(real_T *xD)
{
/* Start_BEGIN */
#ifndef MATLAB_MEX_FILE
int status;
status = lcd.begin(LCD_COLS, LCD_ROWS); // Initialisierung des Displays
if(status)
{
hd44780::fatalError(status);
}
#endif
/* Start_END */
}
void LCD_Display_Outputs_wrapper(const uint8_T *DisplayStatus,
const real_T *xD)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
displaystate = DisplayStatus[0];
switch(displaystate) // Wechseln zwischen verschiedenen Displayausgaben
{
case 0:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Bitte mit Taste");
lcd.setCursor(0,1);
lcd.print("A / B anmelden");
break;
case 1:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Bitte geben Sie");
lcd.setCursor(0,1);
lcd.print("den PIN ein!");
break;
case 2:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Eingabe korrekt");
break;
case 3:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("PIN falsch bitte");
lcd.setCursor(0,1);
lcd.print("erneut versuchen");
break;
case 4:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Funktionsauswahl");
lcd.setCursor(0,1);
lcd.print("Taste A / B / C");
break;
case 5:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Schloss wird");
lcd.setCursor(0,1);
lcd.print("entsperrt");
break;
case 6:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Zum Verriegeln");
lcd.setCursor(0,1);
lcd.print("[1] dr\365cken");
break;
case 7:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Finger auflegen");
lcd.setCursor(0,1);
lcd.print("und [1] dr\365cken");
break;
case 8:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Fingerabdruck");
lcd.setCursor(0,1);
lcd.print("wird gepr\365ft");
break;
case 9:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Fingerabdruck");
lcd.setCursor(0,1);
lcd.print("nicht erkannt");
break;
case 10:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("ALARM: ZUGRIFF");
lcd.setCursor(0,1);
lcd.print("VERWEIGERT");
break;
case 11:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Abdruck wird");
lcd.setCursor(0,1);
lcd.print("erneut gepr\365ft");
break;
case 12:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Fingerabdruck");
lcd.setCursor(0,1);
lcd.print("wurde gewechselt");
break;
case 13:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Finger ab- und");
lcd.setCursor(0,1);
lcd.print("auflegen [1]");
break;
case 14:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Zum PIN wechseln");
lcd.setCursor(0,1);
lcd.print("[1] dr\365cken");
break;
case 15:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Bitte 1. Ziffer");
lcd.setCursor(0,1);
lcd.print("vom PIN eingeben");
break;
case 16:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Bitte 2. Ziffer");
lcd.setCursor(0,1);
lcd.print("vom PIN eingeben");
break;
case 17:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Bitte 3. Ziffer");
lcd.setCursor(0,1);
lcd.print("vom PIN eingeben");
break;
case 18:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Bitte 4. Ziffer");
lcd.setCursor(0,1);
lcd.print("vom PIN eingeben");
break;
case 19:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("PIN erfolgreich");
lcd.setCursor(0,1);
lcd.print("gewechselt");
break;
}
#endif
/* Output_END */
}
void LCD_Display_Update_wrapper(const uint8_T *DisplayStatus,
real_T *xD)
{
/* Update_BEGIN */
/* Update_END */
}
void LCD_Display_Terminate_wrapper(real_T *xD)
{
/* Terminate_BEGIN */
/* Terminate_END */
}
S-Function Tastenfeld
/* Includes_BEGIN */
#ifndef MATLAB_MEX_FILE
#include <Keypad.h>
const byte ROWS = 4; // rows
const byte COLS = 4; // columns
//Definition der Symbole des Tastenfelds
char hexaKeys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; //Pinbelegung der Reihen des Tastenfelds
byte colPins[COLS] = {5, 4, 3, 2}; //Pinbelegung der Spalten des Tastenfelds
//Initialisierung der Tastenfeldklasse
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
#endif
/* Includes_END */
/* Externs_BEGIN */
/* Externs_END */
void Tastenfeld_Start_wrapper(real_T *xD)
{
/* Start_BEGIN */
#ifndef MATLAB_MEX_FILE
#endif
/* Start_END */
}
void Tastenfeld_Outputs_wrapper(const uint8_T *TasteStatus,
uint8_T *Taste,
uint8_T *nTaste,
const real_T *xD)
{
/* Output_BEGIN */
#ifndef MATLAB_MEX_FILE
if (TasteStatus[0] == 0 && nTaste[0] > 0) { nTaste[0] = 0; } // Reset des Tastencounters
char customKey = customKeypad.getKey(); // Auslesen der Taste bei Betätigung
if (customKey) {
Taste[0] = customKey; // Speichern der Taste in Variable
nTaste[0] += 1; // Erhöhung des Tastencounters
}
#endif
/* Output_END */
}
void Tastenfeld_Update_wrapper(const uint8_T *TasteStatus,
uint8_T *Taste,
uint8_T *nTaste,
real_T *xD)
{
/* Update_BEGIN */
/* Update_END */
}
void Tastenfeld_Terminate_wrapper(real_T *xD)
{
/* Terminate_BEGIN */
/* Terminate_END */
}
Komponententest
Test der Einzelkomponenten
Servomotor
Um die Funktion des Servomotors zu testen, wurde dieser in der Ausgangsstellung von 0° am Verschlussriegel im geschlossenen Zustand (waagerecht) montiert. Um den Verschlussriegel zu öffnen, musste dieser vom Servomotor um 90° gedreht werden. Dazu wurde ein Simulink-Modell erstellt, welches in Abbildung 3.1a und 3.1b dargestellt ist.
Durch das maximale Drehmoment des Motors von 2kg/cm konnte der Verschlussriegel erfolgreich um 90° gedreht und somit in den geöffneten Zustand versetzt werden, wie in Abbildung 3.2a und 3.2b gezeigt.
Fingerabdrucksensor
Die Funktion des Fingerabdrucksensors wurde mithilfe eines Sketches der Arduino-Bibliothek "Adafruit Fingerprint Sensor" überprüft. Der Testaufbau ist in Abbildung 3.3a dargestellt. Es konnte erfolgreich ein Fingerabdruck eingelesen und verifiziert werden, siehe Abbildung 3.3b.
LCD Display
Eine Funktionsprüfung des 16x02 LCD Displays mit HD44780 I2C-Modul wurde mithilfe der Arduino-Bibliothek "HD44780" ermöglicht. Auf Abbildung 3.4 ist die Textausgabe auf dem LCD-Display gezeigt.
Tastenfeld
Die Funktion des Tastenfelds konnte ebenfalls durch die Verwendung einer Arduino-Bibliothek "Adafruit Keypad" getestet werden. Dazu wurde das Tastenfeld an 8 digitale I/O-Pins (Pin 2 bis Pin 9) des Arduinos angeschlossen, siehe Abbildung 3.5a. Testweise wurden alle Tasten betätigt und die Betätigung auf dem seriellen Monitor ausgegeben (Abbildung 3.5b).
Test des Gesamtsystems
Ergebnis
Zusammenfassung
Lessons Learned
Projektunterlagen
Projektplan
Zur Planung der Projektdurchführung wurde der folgende Gantt-Projektplan (Abbildung 4.1) mit den einzelnen Projektvorgängen und Meilensteinen erstellt.
YouTube Video
Weblinks
Literatur
→ zurück zur Übersicht: WS 23/24: Angewandte Elektrotechnik (BSE)