Rack'n'Roll: Unterschied zwischen den Versionen

Aus Das Projektwiki
Zur Navigation springen Zur Suche springen
Keine Bearbeitungszusammenfassung
Zeile 153: Zeile 153:


===Auslesen der Messdaten===
===Auslesen der Messdaten===

[tba]


===Realisierung der Kontrollfunktion===
===Realisierung der Kontrollfunktion===

Version vom 22. Februar 2017, 15:41 Uhr

Im Projekt Rack'n'Roll wurde ein System zur Messdatenauswertung eines modularen Messsystems mit Spannungsbegrenzung entwickelt. Dieses System wurde dabei echtzeitfähig entwickelt und basiert auf einem Arduino Mega 2560. Entwickelt wurde das Programm von Peter Wiese im Rahmen des Moduls Vertiefung Systemtechnik am Campus Velber/Heiligenhaus der Hochschule Bochum und wird in einem modularen Messsystem, welches im Modul Elektronik und digitale Signalverarbeitung aufgebaut wurde, eingesetzt. Das Projekt ist mittels der Arduino IDE in C++ geschrieben und steht unter BSD Simplified Licence [1].

Einleitung

Im Rahmen des Moduls Sensortechnik und digitale Signalverarbeitung am Campus Velbert/Heiligenhaus wurde eine modulare Messeinrichtung entwickelt und aufgebaut. Dieses besteht aus einzelnen, wechselbaren Platinen welche verschiedene Aufgaben erfüllen sollen. So wurden bisher z.B. eine Platine entwickelt mit denen zwei Signale Addiert oder Subtrahiert werden können, eine Platine zur Strom-Spannungswandlung und eine Platine zur Implementierung diverser Filter. Da in diesen Schaltungen Operationsverstärker verwendet werden, welche nur in begrenzten Spannungsbereichen arbeiten, wurden auf den Platinen außerdem Kontrollschaltungen eingebaut. Diese erkennen, ob ein bestimmter Schwellwert überschritten wurden und informieren daraufhin den Nutzer, da es dadurch zu Messfehlern kommt. Alle Platinen sollen außerdem digital Ausgewertet werden können. Genau bei den letzten beiden Punkten kommt das hier dokumentierte Projekt ins Spiel.

Ziel dieses Projektes ist die Implementierung der digitalen Auswertung der Signale des Messaufbaus, sowie die Verwaltung der Kontrollschaltung. Dabei sollen die Signale mittels eines Arduino Mega 2560 verarbeitet und auf einem Computer ausgegeben werden. Außerdem soll der Arduino die Spannungsbegrenzung zurücksetzen und verwalten können.

Konzept und Echtzeitfähigkeit

Das Konzept des Systems ist relativ einfach gehalten. Die einzelnen Platinen sind an ein Bussystem angeschlossen, welches sich um die Spannungsversorgung und die Kommunikation mit dem Arduino kümmert. Die genaue Definition des Bussystems ist nachfolgend dargestellt.

Bahnnummer Verwendung
1 -12 V Spannungsversorgung
2 +12 V Spannungsversorgung
3 Masse
4 bis 14 analoge Ausgangssignale der Platinen
15 Reset der Spannungsbegrenzung
16 bis 29 Anzeige der einzelnen Spannungsbegrenzungen
30 ODER-Verknüpfte Begrenzung für der Interrupt
31 +5 V Spannungsversorgung
32 -5 V Spannungsversorgung

Dabei werden die analogen Ausgangssignale der Bahnen 4 bis 14 direkt mit den analogen Eingängen des Arduino verbunden um die schnelle Auswertung zu ermöglichen. Die Bahn 15 wird genutzt um die Spannungsbegrenzung zurückzusetzen und ist mit einem Ausgang des Arduino verbunden. Die Bahn 30 ist mit einem Interrupt-Pin des Arduino verbunden und sorgt dafür, dass ein Interrupt aufge- rufen wird, sobald eine Platine in die Begrenzung gerät. Anschließend können die Bahnen 16 bis 29 ausgewertet werden um herauszufinden, welche Platine dafür verantwortlich ist.

Auf der Gegenseite, also am Arduino, sind dann die Bahnen mit den Ports verbunden. Die konkrete Pin-Belegung des Arduino kann der nachfolgenden Tabelle entnommen werden. Dabei sind neben den Äquivalenten zum Bussystem auch noch weitere Pins definiert, welche für Schalter reserviert sind, mit denen ausgewählt werden kann, welche Analog-Pins abgefragt werden.

Port Verwendung
A4 bis A14 analoger Eingang, Bahnen 4 bis 14 vom Bus
2 Interrupt-Pin für Begrenzung, Bahn 30 vom Bus
3 Interrupt-Pin zum Neustart, Bahn 15 vom Bus
ungerade Pins 31 bis 51 Input-Pins für Schalter
gerade Pins 22 bis 48 Spannungsbegrenzungen, Bahnen 16 bis 29 vom Bus

Das System muss außerdem echtzeitfähig sein, damit die Messdaten mit einer definierten Abtastrate aufgenommen werden können. Die Abtastrate muss dabei für eine genaue Messung, nach dem nyquist-shannonschen Abtasttheorem[2], mindestens der doppelten maximalen Frequenz des abzutastenen Signals entsprechen.

Da die Werte alle in einem äquidistanten Zeitabstand abgetastet werden sollen, handelt es sich hierbei um ein System mit fester Echtzeit, bei dem eine Abtastrate von genau 8 kHz gegeben ist. Technisch realisiert wird dies über einen zeitlich gesteuerten Interrupt, welcher alle 125 µs aufgerufen wird und den Messwert in einem FIFO-Stack speichert. Die Ausgabe erfolgt über die serielle Schnittstelle mit einer Baud-Rate von 250000 Bd und wird immer in der Zeit, in der kein Interrupt aufgerufen wird ausgeführt. Die genauen Details der Realisierung werden im nachfolgenden Abschnitt erläutert.

Programmierung

Allgemeines

Für die softwareseitige Umsetzung des Projekts wird die offizielle Entwicklungsumgebung, die Arduino IDE, in der Version 1.8.1 genutzt. Die Programmierung selber erfolgt in C bzw. C++, wobei hauptsächlich die, unter der GNU Lesser General Public Licence[3] veröffentlichten, Arduino-Bibliotheken verwendet werden.

Der Vorteil der Arduino IDE sind die beiden vordefinierten Methoden void setup() und void loop(). Die Methode setup() wird dabei direkt zu Programmstart aufgeru- fen und dient hauptsächlich zur Initialisierung der I/O-Pins, der seriellen Schnittstelle und der Interrupts. Die Methode loop() ist dann für die zyklische Ausführung des Programmcodes zuständig.

Ein weiterer Vorteil der Arduino IDE sind die automatisch eingebundenen Arduino-Bibliotheken, welche eine einfache Ansteuerung der Pins ermöglichen. Die wichtigsten Methoden daraus sind void pinMode(uint8_t pin, uint8_t mode), welche verwendet wird um die Pins als Input oder Output-Pins zu initialisieren und die Methode int digitalRead(uint8_t pin), welche es ermöglicht den aktuellen Zustand eines Input-Pins auszulesen.

Zeitgesteuerte Interrupts

Für die Realisierung der Echtzeitfähigkeit wurden zeitgesteuerte Interrupts verwendet. Diese haben den Vorteil, dass sie in fest definierten Intervallen, unabhängig vom anderen Programmcode aufgerufen werden. Das einzige was man dabei beachten muss, dass die Funktion während des Interrupts so kurz wie möglich gehalten werden sollte, da zeitgleich keine anderen Methoden auf dem Arduino ausgeführt werden können. Die verwendete Methode des Interrupts wird auch als Clear Timer on Compare Match bzw. als CTC-Mode bezeichnet.

Das Grundprinzip der Interrupt ist dabei relativ einfach. Es gibt im Mikrocontroller verschiedene Timer mit einzelnen Countern, welche bei jedem Tick der Systemuhr hochgezählt werden. Erreicht dieser Counter einen bestimmten Wert, welcher im Compare Match Register festgelegt ist, wird der Interrupt ausgelöst und der Counter zurückgesetzt. Dabei muss beachtet werden, dass es 16-Bit- und 8-Bit-Timer gibt, welche maximal 65535 bzw. 255 Counter-Werte speichern können. Würde der Counter jetzt mit der normalen Taktfrequenz von 16 MHz inkrementiert werden, wäre die langsamste Zeit pro Interrupt 4 ms für den 16-Bit- und 16 µs für den 8-Bit-Timer. Da dies für den allgemeinen Gebrauch eher ungeeignet ist, muss die Taktfrequenz des Timers über einen sogenannten Prescaler begrenzt werden. Die Taktfrequenz wird dann über folgende Formel berechnet:

f_timer = f_Arduino / Prescaler

Zum Festlegen des Prescalers müssen verschiedene Bits im Register des Timers gesetzt werden. In diesem Projekt wird ausschließlich mit dem 8-Bit-Timer timer2 gearbeitet. Die nötigen Bits zum setzen des Prescalers von diesem Timer sind in der nachfolgenden Tabelle angegeben:

CS22 CS21 CS20 Prescaler
0 0 1 1
0 1 0 8
0 1 1 32
1 0 0 64

Wurde der Prescaler entsprechend eingestellt, muss als nächstes der entsprechende Wert für das Compare Match Register gefunden werden, damit der Interrupt in der gewünschten Frequenz aufgerufen wird. Der Vergleichswert kann über folgende Formel bestimmt werden.[4]

Vergleichswert = (f_Arduino / (Prescaler * f_gewünscht)) - 1

Für die in diesem Projekt gewünschte Frequenz von 8 kHz bedeutet dies, dass bei einem Prescaler von 8 der Wert im Compare Match Register 249 betragen muss. Im Quellcode müssen diese Vorbereitungen in der setup()-Methode getroffen werden. Im nachfolgenden Beispiel ist eine setup()-Methode dargestellt, mit der timer2 auf 8 kHz festgelegt wird.

void setup() {
  cli(); //alle Interrupts deaktiviert
  TCCR2A = 0;// TCCR2A-Register auf 0 setzen
  TCCR2B = 0;// TCCR2B-Register auf 0 setzen
  TCNT2  = 0;// Initialisierung des Counter-Werts
  OCR2A = 249;// Vergleichswert setzen
  TCCR2A |= (1 << WGM21); // CTC-Mode aktivieren
  TCCR2B |= (1 << CS21); // CS21-Bit setzen
  TIMSK2 |= (1 << OCIE2A); //Timer Compare Interrupt aktivieren
  sei(); // alle Interrupts aktivieren
}

Wurde der zeitgesteuerte Interrupt ordentlich initialisiert, muss die Interrupt Service Routine (kurz ISR) implementiert werden. Die ISR ist dabei die Methode, welche immer in der vorher festgelegten Frequenz aufgerufen werden soll. Für den bereits erläuterten timer2 wird die ISR wie folgt implementiert:

ISR(TIMER2_COMPA_vect) {
	// Meine Interrupt Service Routine 
}

Innerhalb der ISR wird dann die Funktion zum Auslesen der Messdaten aufgerufen, welche im nächsten Abschnitt erläutert wird.

Auslesen der Messdaten

[tba]

Realisierung der Kontrollfunktion

Zusammenfassung und Ausblick

Einzelnachweise

  1. BSD Simplified Licence
  2. Claude E. Shannon: Communication in the Presence of Noise. In: Proceedings of the IEEE 37 (1948)
  3. GNU Lesser General Public Licence. Abgerufen am 22.02.2017
  4. [ http://www. instructables.com/id/Arduino-Timer-Interrupts/ Arduino Timer Interrupts]. Abgerufen am 06.02.2017