\documentclass[12pt,a4paper]{scrartcl} \usepackage[utf8]{inputenc} \usepackage[ngerman]{babel} \usepackage{graphicx} \usepackage{amsmath,amssymb,amsfonts} \usepackage[table,dvipsnames]{xcolor} \usepackage{array} \usepackage{makecell} \usepackage{refstyle} \usepackage{float} \definecolor{tablehead}{hsb}{0,0,0.9} \newcolumntype{C}[1]{>{\centering\arraybackslash}p{#1}} \title{Pinlock: Dokumentation} \subtitle{Mikrocontroller-Seminar} \author{Leonard Kugis, Mattes Melius} \begin{document} \maketitle \tableofcontents \newpage \section{Idee} Für unser Mikrocontroller-Projekt haben wir uns für ein vierstelliges Zahlenschloss entschieden. Dieses soll nach Eingabe eines validen Codes in einen "Geöffnet"-Zustand wechselt und im "Geschlossen"-Zustand verweilt, wenn der Code inkorrekt war. Zudem soll dem Benutzer die Möglichkeit gegeben werden einen persönlich gewählten Code einzuspeichern und den alten zu Überschreiben. \section{Hardware} \subsection{Platinenaufbau} Unser Mikrocontroller liegt auf einer 100mmx80mm großen Platine welche über zwei Kupferlagen verfügt. Als Hauptbaustein wird der ATmega16A benutzt. Des weiteren befinden sich auf unserer Platine neben üblichen Grundbausteinen eine Ausgabe- sowie eine "externe" Eingabe-Einheit, als auch Status-LEDs. \begin{figure}[H] \centering \includegraphics[width=15cm,height=10cm,keepaspectratio]{resources/Pinlock_Schema} \caption{Schaltbild Hauptschaltung} \end{figure} \newpage \subsection{Mikrocontroller ATmega16A} Der ATmega16A ist ein 8-Bit CMOS Controller, welcher bei einer Spannung von 2,7- 5V arbeitet. In unserem Projekt nutzen wir nicht alle Features des Bausteins. Um unsere Schaltung zu realisieren, brauchen wir die GPIO, die eingebaute AVR-CPU und das EEPROM. Mit der GPIO und der AVR-CPU ist es uns möglich die Inputs aus der Eingabematrix in Sinnvolle werte umzurechnen und in den Registern der CPU einzuspeichern. Diese werden nun auch an die Display-Units weitergegeben, welche diese anzeigen können um dem Benutzer visuell darzustellen, welche Zahlen eingegeben wurden, ob richtige Eingabe erfolgt ist oder ob ein Code invalide war. Auch der Zustand (geöffnet/geschlossen) wird in den Registern des ATmega's gespeichert und auch an die Status-LEDs gesendet. Im EEPROM wird der valide Code abgespeichert, sodass dieser auch nach einen Neustart zur Verfügung steht und nicht gelöscht wird. So ist es dem Nutzer möglich den Code bis zu 100,000 zu ändern. \subsection{Sonstige Komponenten} \begin{figure}[H] \centering \includegraphics[width=15cm,height=10cm,keepaspectratio]{resources/buttons} \caption{Schaltbild Eingabecontroller} \end{figure} \begin{figure}[H] \centering \includegraphics[width=15cm,height=10cm,keepaspectratio]{resources/Display_Schema} \caption{Schaltbild Display-Units} \end{figure} \begin{figure}[H] \centering \includegraphics[width=15cm,height=10cm,keepaspectratio]{resources/Status_LED_Schema} \caption{Schaltbild Status-LEDs} \end{figure} \section{Software} Das Programm wurde in AVR-Assembler geschrieben, mit Assemblerdirektiven für den \emph{Avra}-Assembler. Grundsätzlich wurden für dieses Programm die in Tabelle~\ref{tbl:registermap} Register-Neudefinitionen vorgenommen, um den Code lesbarer zu gestalten. \begin{table}[!htb] \centering \begin{tabular}{|C{0.2\linewidth}|C{0.2\linewidth}|C{0.5\linewidth}|} \hline \rowcolor{tablehead} ATmega16A Register & Neu definierte Registerbezeichnung & Funktion \\ \hline \texttt{r16} & \texttt{tmp0} & Temporäres Pufferregister 0 \\ \hline \texttt{r17} & \texttt{par0} & Parameterregister 0 \\ \hline \texttt{r18} & \texttt{par1} & Parameterregister 1 \\ \hline \texttt{r19} & \texttt{tmp1} & Temporäres Pufferregister 1 \\ \hline \texttt{r20} & \texttt{tmp2} & Temporäres Pufferregister 2 \\ \hline \texttt{r21} & \texttt{ret0} & Rückgaberegister 0 \\ \hline \texttt{r22} & \texttt{ret1} & Rückgaberegister 1 \\ \hline \texttt{r23} & \texttt{par2} & Parameterregister 2 \\ \hline \texttt{r24} & \texttt{par3} & Parameterregister 3 \\ \hline \texttt{r25} & \texttt{par4} & Parameterregister 4 \\ \hline \texttt{r26} & \texttt{ret2} & Rückgaberegister 2 \\ \hline \texttt{r27} & \texttt{heart} & Debug \\ \hline \texttt{r28} & \texttt{dig0} & Pufferregister für Ziffern 0 und 1 \\ \hline \texttt{r29} & \texttt{dig1} & Pufferregister für Ziffern 2 und 3 \\ \hline \end{tabular} \caption{Neu definierte Registerbezeichnungen für Register des ATmega16A} \label{tbl:registermap} \end{table} \subsection{Grundprinzip} Nach Zurücksetzen des Mikrocontrollers durchläuft das Programm eine Initialisierungsroutine. Diese beinhaltet im Wesentlichen folgende Schritte: \begin{enumerate} \item Initialisierung des Stackpointers mit den Grenzen des verfügbaren RAMs \item Konfiguration der GPIO-Ports \item Initialisierung der Displays \item Lesen des Zugangscodes aus dem EEPROM \end{enumerate} Anschließend wird eine endlose Hauptschleife durchlaufen, die folgende Aktionen periodisch ausführt: \begin{enumerate} \item Warte 12240 Zyklen. \item Lese alle Tasten der Eingabematrix aus. \item Ermittle Änderungen des neuen Tastenstatus zu dem alten Tastenstatus. \item Bei positiver Flanke (Taste war vorher nicht gedrückt und ist jetzt gedrückt): Behandle den Tastendruck bezüglich des aktuellen Zustands (s.u.). \item Puffere den neuen Tastenstatus. \end{enumerate} Die einzelnen Routinen, die dabei aufgerufen werden, werden genauer in Sektion~\ref{sec:functions} erläutert. Die Behandlung der (neu) gedrückten Taste bezüglich des aktuellen Zustandes erfolgt nach der in Abbildung~\ref{fig:states} dargestellten \emph{Finite-State-Machine} (FSM). Die Zustände sind dabei nach folgendem Schema benannt: \begin{tabular}{r@{: }l r@{: }l} \texttt{A} & \emph{Authenticating}, Authentifizierung findet gerade durch Codeeingabe statt \\ \texttt{AS} & \emph{Authentication Submitted}, Code wurde bestätigt und wird überprüft \\ \texttt{AD} & \emph{Authenticated}, Benutzer ist authentifiziert und hat Zugriff \\ \texttt{C} & \emph{Change}, Benutzer ändert den Zugriffscode \end{tabular} Dabei folgt die Notation der Transitionsbedingungen dem Schema \\ \colorbox{lightgray}{\texttt{ / }}. Die Tastendarstellungen innerhalb des Programmes unterliegen dabei der Zuordnung in Tabelle~\ref{tbl:keymap}. \begin{figure}[!htb] \centering \includegraphics[width=0.7\linewidth, keepaspectratio]{resources/states} \caption{FSM der Behandlung von Tastendrücken (schematisch)} \label{fig:states} \end{figure} \begin{table}[!htb] \centering \begin{tabular}{|c|c|} \hline \rowcolor{tablehead} Taste extern & Taste intern \\ \hline \texttt{0..9} & \texttt{0x00..0x09} \\ \hline \texttt{A..D} & \texttt{0x0A..0x0D} \\ \hline \texttt{*} & \texttt{0x0E} \\ \hline \texttt{\#} & \texttt{0x0F} \\ \hline \end{tabular} \caption{Zuordnung von externen zu internen Tastendarstellungen} \label{tbl:keymap} \end{table} \subsection{Routinen}\label{sec:functions} \subsubsection{\texttt{wait}} \begin{tabular}{r@{: }l r@{: }l} Parameter & \makecell[l]{\texttt{par0}: Wartezyklen Stufe 1, \\ \texttt{par1}: Wartezyklen Stufe 2, \\ \texttt{par2}: Wartezyklen Stufe 3} \\ Rückgabe & - \end{tabular} Warte über drei verschachtelte Schleifen mit verschiedenen Durchlaufzahlen. Die gesamte, zu wartende Zyklendauer beträgt somit $\Delta t_\text{ges} = \text{\texttt{par0}} \cdot \text{\texttt{par1}} \cdot \text{\texttt{par2}}$. \subsubsection{\texttt{write\_code}} \begin{tabular}{r@{: }l r@{: }l} Parameter & - \\ Rückgabe & - \end{tabular} Schreibe statisch die Werte 0x01 und 0x23 (entspricht der Zahlenkombination \texttt{0123}) in das EEPROM an die Adressen 0x00 und 0x01. \subsubsection{\texttt{load\_code}} \begin{tabular}{r@{: }l r@{: }l} Parameter & - \\ Rückgabe & \makecell[l]{\texttt{ret0}: Ziffern 0 und 1, \\ \texttt{ret1}: Ziffern 2 und 3} \end{tabular} Lese die gespeicherte Zahlenkombination aus dem EEPROM (Adressen 0x00 und 0x01) aus. \subsubsection{\texttt{shift\_out}} \begin{tabular}{r@{: }l r@{: }l} Parameter & \makecell[l]{\texttt{par0}: Zu schreibendes Byte, \\ \texttt{par1..par2}: Adresse zur Funktion, um 0 zu schreiben, \\ \texttt{par3..par4}: Adresse zur Funktion, um 1 zu schreiben} \\ Rückgabe & - \end{tabular} Schreibe ein Byte Bit für Bit durch Funktionsaufrufe, welche das Schreiben des 0- und 1-Bits implementieren. Das können beispielsweise Funktionen sein, die 0 bzw. 1 an ein Schieberegister anlegen. \subsubsection{\texttt{shift\_in}} \begin{tabular}{r@{: }l r@{: }l} Parameter & \makecell[l]{\texttt{par0..par1}: Adresse zur Funktion, um einen Clockzyklus zu durchlaufen, \\ \texttt{par2..par3}: Adresse zur Funktion, das zugehörige Bit zu lesen} \\ Rückgabe & \makecell[l]{\texttt{ret0}: Gelesenes Byte} \end{tabular} Lese ein Byte Bit für Bit aus einem Schieberegister. Das Durchlaufen eines Clockzyklus und Lesen des Bits ist in übergebenen Funktionen implementiert. \subsubsection{\texttt{eeprom\_write}} \begin{tabular}{r@{: }l r@{: }l} Parameter & \makecell[l]{\texttt{par0..par1}: Zieladresse, \\ \texttt{par2}: Zu schreibender Wert} \\ Rückgabe & - \end{tabular} Schreibt ein Byte an die gegebene Adresse in das interne EEPROM. \subsubsection{\texttt{eeprom\_read}} \begin{tabular}{r@{: }l r@{: }l} Parameter & \makecell[l]{\texttt{par0..par1}: Adresse} \\ Rückgabe & \makecell[l]{\texttt{ret0}: Gelesener Wert} \end{tabular} Liest ein Byte von der gegebenen Adresse im internen EEPROM. \subsubsection{\texttt{status}} \begin{tabular}{r@{: }l r@{: }l} Parameter & \makecell[l]{\texttt{par0}: Statusbits} \\ Rückgabe & - \end{tabular} Gibt die gegebenen Statusbits über die LEDs aus. Dabei wird das Schieberegister dafür benutzt. \subsubsection{\texttt{display}} \begin{tabular}{r@{: }l r@{: }l} Parameter & \makecell[l]{\texttt{par0}: Displaynummer, \\ \texttt{par1}: Darzustellende Ziffer} \\ Rückgabe & - \end{tabular} Zeige die gegebene Ziffer auf dem gegebenen Display. \subsubsection{\texttt{set\_digit}} \begin{tabular}{r@{: }l r@{: }l} Parameter & \makecell[l]{\texttt{par0}: Ziffernstelle, \\ \texttt{par1}: Ziffer} \\ Rückgabe & - \end{tabular} Schreibt die Ziffer an die Ziffernstelle des internen Puffers. \subsubsection{\texttt{get\_digit}} \begin{tabular}{r@{: }l r@{: }l} Parameter & \makecell[l]{\texttt{par0}: Ziffernstelle} \\ Rückgabe & \makecell[l]{\texttt{ret0}: Ziffer an der Stelle} \end{tabular} Liest die Ziffer der gegebenen Stelle von dem internen Puffer. \subsubsection{\texttt{input}} \begin{tabular}{r@{: }l r@{: }l} Parameter & - \\ Rückgabe & \makecell[l]{\texttt{ret0}: Tastenstatus mit Belegung: \texttt{0852*741}, \\ \texttt{ret1}: Tastenstatus mit Belegung: \texttt{DCBA\#963}} \end{tabular} Liest den Tastenstatus aller Tasten aus. Ein 1-Bit entspricht einer gedrückten, ein 0-Bit einer nicht gedrückten Taste. Das Auslesen der Tasten der Eingabematrix erfolgt über die Schieberegister: eines (Serial-In-Parallel-Out) zur Selektion der auszulesenden Zeile und eines (Parallel-In-Serial-Out) zum eigentlichen Auslesen selbiger. Dies wird innerhalb der Ausleseroutine mit jeder Zeile gemacht, um gedrückte Tasten zu identifizieren. \subsubsection{\texttt{translate}} \begin{tabular}{r@{: }l r@{: }l} Parameter & \makecell[l]{\texttt{par0}: Tastenstatus Bits \texttt{7..0}, \\ \texttt{par1}: Tastenstatus Bits \texttt{15..8}} \\ Rückgabe & \makecell[l]{\texttt{ret0}: Übersetzter Tastencode} \end{tabular} Übersetzt den Tastenstatus in die entsprechende, interne Tastendarstellung. Dabei wird nach der Zuordnung aus Tabelle~\ref{tbl:keymap} vorgegangen. \subsubsection{\texttt{handle}} \begin{tabular}{r@{: }l r@{: }l} Parameter & \makecell[l]{\texttt{par0}: Aktueller Zustand, \\ \texttt{par1}: Tastencode} \\ Rückgabe & \makecell[l]{\texttt{ret0}: Neuer Zustand} \end{tabular} Behandle den Tastencode unter dem aktuellen Zustand. Das Zustandsfeld hat folgende Belegung (ein Zeichen entspricht einem Bit): \begin{center} \texttt{CSSSSSDD} \end{center} \begin{tabular}{r@{: }l r@{: }l} \texttt{0} & Reserviert \\ \texttt{C} & Pufferbit für Blinken der ausgewählten Stelle \\ \texttt{S} & Zustandsinformationen \\ \texttt{D} & Aktuell ausgewähltes Display \end{tabular} Die Behandlung erfolgt nach dem in Abbildung~\ref{fig:states} dargestellten Schema. \section{Bedienung} Nach Zurücksetzen des Systems ist man in der Authentifizierungsphase. In dieser ist die richtige Ziffernkombination einzugeben, welcher vorher gespeichert wurde. Der Standardcode ist \texttt{0123}. Es stehen dabei folgende Optionen zur Auswahl: \begin{tabular}{r@{: }l r@{: }l} \texttt{0..9} & Ziffer eingeben \\ \texttt{A} & Eingabe bestätigen \\ \texttt{*} & Zeigerposition nach links schieben \\ \texttt{\#} & Zeigerposition nach rechts schieben \end{tabular} Wurde die falsche Ziffernkombination eingegeben und bestätigt, erlischen alle Displays für wenige Sekunden und es ist eine erneute Eingabe möglich. \\ Wurde die richtige Ziffernkombination eingegeben und bestätigt, wird dies mit setzen aller Displays auf 0 und erlischen des Zeigers angezeigt. Man ist nun authentifiziert, was einem Zugriff auf das System darstellt. In diesem Zustand stehen folgende Funktionen zur Auswahl: \begin{tabular}{r@{: }l r@{: }l} \texttt{B} & Ändern des Zugangscodes \\ \texttt{D} & Ausloggen \end{tabular} Der Zugangscode lässt sich nach Drücken von \texttt{B} mit der selben Steuerung wie bei der Zifferneingabe in der Authentifizierungsphase ändern, wobei \texttt{A} dem Bestätigen der Änderung entspricht. Dabei wird der Zugangscode in den persistenten Speicher geschrieben und in zukünftigen Authentifizierungsphasen abgefragt. \\ Durch Ausloggen wird der authentifizierte Zustand verlassen und man ist wieder in der Authentifizierungsphase. \end{document}