Mikrocontroller

An der Programmierung und Planung sowie Beschaltung des Microcontrollers arbeiten 4 Personen.

Aufgabe des Microcontrolllers (Atmega32) ist es, über Kommunikationsschnittstellen zu anderen Gruppen, Informationen wie beispielsweise der Highscore oder das Batterie-Signal zu erhalten und diese Informationen so aufzubereiten und auszugeben, dass dem Benutzer über die LED-Matrix die übergebenen Informationen angezeigt werden können.

Zur Ansteuerung 

Mithilfe eines Atmega32 wird die LED-Matrix zeilenweise angesteuert und pro Zeile werden jeweils die Pins an den LED’s auf bestimmte Potentiale gesetzt, die gerade Leuchten sollen. Dies geschieht mit einer so hohen Frequenz (mehr als 25 frames pro Sekunde), dass das Auge ein zusammenhangendes Bild wahrnimmt.
Das folgende Bild soll die darauffolgende Erklärung der Funktionsweise verdeutlichen:

 

Schaltung mit Reihensystem_PNGAbbildung 1: Prinzipieller Aufbau der LED-Matrix mit 3 Spalten& 3 Zeilen

Damit nun z.B. LED 1 leuchtet, muss der Pin IN1 auf High und der Pin OUT1 auf Low
gesetzt werden, damit die Spannung über der Diode positiv ist und diese leitet. Damit
z.B. die erste Zeile leuchtet, müssen zusätzlich OUT2 und OUT3 auf High gesetzt werden.
Das Setzen der Pins soll mit Hilfe von Schieberegistern erfolgen, die seriell vom µC gesteuert werden, welche Output Pins auf welchem Potential sein sollen. Getaktet werden die
Register mit zwei PWM-Signalen des Controllers, eines davon wird als Shift-Clock, das
andere als Latch-Clock verwendet. Letztere hat in der finalen Schaltung ein sechzehntel der
Frequenz der Shift-Clock, da die Zeilen und Spalten parallel mit Daten versorgt werden
und wir jeweils 16 davon haben. Die Schieberegister werden sich später auf derselben
Platine wie die LED-Matrix befinden; die Daten sowie die Taktsignale werden dann über
einen 10-Pin Stecker übertragen. Das Eagle-Schematic dazu ist in folgender Abbildung 2 zu sehen.

Die Information darüber, was gerade angezeigt werden soll(u.A. Highscore-Wert,aktueller Punktestand, aktuelle Spielzeit), wird über SPI von der Spiellogik empfangen empfangen und dann im uC verarbeitet. Dabei werden pro Übertragungsvorgang 3 Bytes übertragen. Die 8 unterschiedlichen Informationstypen der Datenpakete sind über 3 Bits zu unterschieden. Hierbei ist kurz zu sagen, dass für den Buchstabendatentyp die ASCII-Tabelle verwendet wurde.

Quelltext und Programmierkonzepte

Sowohl zum Senden der Daten an die Schieberegister, als auch für das Empfangen der Daten der Spiellogik sowie das Auslesen des Akkustands war einige Programmierarbeit notwendig. Diese wird im Folgenden Schritt für Schritt betrachtet.

ADU

Über den Bus erhalten wir von der Energieversorgungsgruppe einen Spannungswert, welcher bei 12-14V liegen sollte. Da der ADU des ATMEGA32 allerdings keine großen Spannungen verträgt, ist es nötig, die Spannung mit Hilfe eines Spannungsteilers bestehend aus einem 10k Ohm und eines 1k Ohm Widerstands herunterzubrechen.
Was den Programmieraufwand angeht, ist der ADU eine der leichteren Aufgaben, was aber keineswegs bedeutet, dass der Code kurz ist. Wir haben uns dafür entschieden, den Code in folgende Untermethoden aufzuteilen:

  • Eine Methode, die alle erforderlichen Bits im Kontrollregister des ADU setzt
  • Eine Methode, die die Spannungsmessung auslöst und den gemessenen Wert zurückgibt
  • ein Abschnitt in der main-Methode, der die ausgelesenen Werte verarbeitet

 

 

Schaltplan des Microcontrollers

Abbildung 2: Schaltplan des µC

 

Die ersten beiden Methoden sind im folgenden zu sehen:

Abbildung 2: CodesAnzeige/ADU

Abbildung 3: CodesAnzeige/ADU

 

Bei der intialisierung des ADU wird zunächst eine Umwandlung gestartet – dies wird empfohlen, damit der ADU “warmläuft“. Aufgerufen werden die beiden Methoden jeweils in der main-Methode: ADC\_init einmalig zum Begin, vor der while-Schleife und ADC\_Read jeweils dann, wenn ein Counter, der im Hintergrund läuft, seinen Maximalwert erreicht hat. Mit Hilfe einer weiteren Methode, welche im Grunde nur if-Abfragen enthält wird der Spannungswert in einen Character umgewandelt, welcher später in die Schieberegister geschoben werden kann, um den Akkustand anzuzeigen.

SPI

Die Umsetzung des SPI ist ähnlich konzipiert wie die des ADU: Auch hier gibt es wieder eine Methode zur initialisierung, eine zum Empfang- und zur Auswertung der Daten und einen Abschnitt in der main-Methode, der das ganze auslöst:

Abbildung :CodesAnzeige/SPI1

Abbildung 4: CodeAnzeige/SPI1

 

Die Methode zur Initialisierung des SPI-Moduls des ATMEGA32 ist dabei vollständig aus dem Datenblatt des Herstellers übernommen, die Methode zum Empfang wurde von uns erweitert.
Zunächst wird der erste Character verarbeitet: die ersten drei Bit geben an, was empfangen wird. Aus dieser Information und der Schnittstellenübersicht kann man erschließen, wieviele Bytes nun empfangen werden müssen. Diese Information wird in der Variable “ByteMax“ gespeichert, welche später (sofern keine Buchstaben für den Hiscorenamen empfangen wurden) als Abbruchbedingung genutzt wird. Zudem wird, wenn ein Buchstabe empfangen wird, das Boolean “istBuchstabe“ auf “true“ gesetzt, was nötig ist, da diese gesondert behandelt werden müssen und andere Abbruchbedingungen erfüllen müssen, damit das Empfangen der Daten beendet wird.
Im Anschluss daran wird, falls es sich nicht um Buchstaben handelt, der empfangene Character in ein Hilfsarray (“ZS“) geschrieben. Dabei ist jedoch zu beachten, dass im ersten Character noch die Information enthalten ist, was gerade empfangen wird. Diese wird vor dem speichern noch von dem Wert abgezogen.
Da beim Highscorenamen der erste Character keine Informationen enthält, die gespeichert werden müssen, wird dort erst der zweite Character und alle folgenden in das Hilfsarray gespeichert.
Die empfangenen Daten werden beim Beenden des Empfangs alle in ein struct gespeichert, welches die relevanten Informationen für die Anzeige enthält:

Abbildung :CodeAnzeige/SPI2

Abbildung 5: CodeAnzeige/SPI2

 

Nachdem der letzte Buchstabe empfangen wird, was durch eine “0x00“ im Datenregister des SPI signalisiert wird, werden die Werte in dem Array von der Methode “Buchstabenwandler()“ noch von den ASCII-Werten in die Nummern im Alphabet umgewandelt, welche in der Bibliothek, die im folgenden beschrieben ist, hinterlegt sind. Aufgerufen wird die Methode, wenn die Spiellogik den Slave-Select Pin auf low setzt, mit Hilfe einer if-Abfrage in der main-Methode.

Bibliothek für die Buchstaben

Um den Code etwas übersichtlicher zu gestalten, haben wir die einzelnen Zeilen der Buchstaben in Arrays abgespeichert und in einer Bibliotheksdatei gespeichert. Als Beispiel dient hier der Buchstabe A:

A[5] = {0b11011111,0b10101111,0b10001111,0b10101111,b10101111}

Zur Anzeige des Buchstabens ‚A‘ werden zunächst die entsprechenden Drains an der Spalte auf 0 oder 1 geschaltet (man beachte, dass 0 eine leuchtende Spalte zur Folge hat, da eine 1 einem Kurzschluss auf GND entspricht) und anschließend die zugehörige Zeile auf GND geschaltet (hier wiederum eine 1 an der gewünschten Stelle!). Dazu müssen die entsprechenden Daten an die Schieberegister gesendet werden, was mit einer weiteren Untermethode passiert.

USART

Zum Übertragen der Daten haben wir uns für die Emulation von USART mit Hilfe von Bit-Banging entschieden. Der Grund dafür ist ganz einfach der, dass USART immer Stop-Bits schickt, die die Daten in unseren Schieberegistern durcheinander bringen würden, und zur Folge hätten, dass wir 2 Zeilen und 2 Spalten nicht mehr kontrollieren könnten.
Daher simulieren wir das USART Modul mit der Methode “BitBanger“, welche im folgenden zu sehen ist:

Abbildung : CodesAnzeige/BitBanger

Abbildung 6: CodesAnzeige/BitBanger

 

Wie bereits angesprochen werden von dieser Methode zunächst die Daten in die Spaltenregister geschoben und im Anschluss die entsprechende Zeile angeschaltet, indem in die Zeilenregister eine 1 an die richtige Stelle geschoben wird.
Wir benutzen für die Zeilen und Spalten jeweils eine Shift-Clock und einen Datenpin. Die getrennte Ansteuerung wird über getrennte Latch-Clocks der Register realisiert.
Übergeben werden dem BitBanger die 3 Character, die die Zeilen der drei Buchstaben widerspiegeln und die Zeile, die gerade angesteuert wird. Die drei “nutzlosen“ Bits in den Buchstaben-Charactern wurden bereits beim Aufruf des BitBangers entfernt, der in der main-Methode zu finden ist.

main-Methode

In der main-Methode werden im Großen und Ganzen lediglich Variablen deklariert und initialisiert und in regelmäßigen Abständen geschaut, ob die Spiellogik etwas schickt oder der Akkustand überprüft werden sollte. Falls weder das eine noch das andere zutrifft, wird (momentan) nur der Highscorename auf der Matrix angezeigt.