Tiefpass-Filter-Projekt

Ähnliche Dokumente
Dokumentation IBIS Monitor

Einführung in die Programmierung

Versuch 3. Frequenzgang eines Verstärkers

Enigmail Konfiguration

1 Einleitung. Lernziele. automatische Antworten bei Abwesenheit senden. Einstellungen für automatische Antworten Lerndauer. 4 Minuten.

S7-Hantierungsbausteine für R355, R6000 und R2700

Mandant in den einzelnen Anwendungen löschen

Konfiguration der Messkanäle. Konfiguration der Zeitachse. Abb. 3: Konfigurationsmenü des Sensoreingangs A. Abb. 4: Messparameter Konfigurationsmenü

AutoCAD Dienstprogramm zur Lizenzübertragung

Kontakte Dorfstrasse 143 CH Kilchberg Telefon 01 / Telefax 01 / info@hp-engineering.com

S/W mit PhotoLine. Inhaltsverzeichnis. PhotoLine

AGROPLUS Buchhaltung. Daten-Server und Sicherheitskopie. Version vom b

Bekannte Effekte bei Soft- und Hardware der ESTEC Datenlogger sowie der PC Auswertesoftware

Allgemeine Anleitung Treiber für CP2102

MSXFORUM - Exchange Server 2003 > SMTP Konfiguration von Exchange 2003

Elektrische Messtechnik Protokoll - Bestimmung des Frequenzgangs durch eine Messung im Zeitbereich

Handbuch Fischertechnik-Einzelteiltabelle V3.7.3

RS-Flip Flop, D-Flip Flop, J-K-Flip Flop, Zählschaltungen

1 Vom Problem zum Programm

Installation OMNIKEY 3121 USB

Software-Beschreibung Elektronische Identifikations-Systeme BIS Softwarekopplung PROFIBUS DP mit BIS C-60_2-...an S7

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang

Anton Ochsenkühn. amac BUCH VERLAG. Ecxel für Mac. amac-buch Verlag

104 WebUntis -Dokumentation

DSO. Abtastrate und Speichertiefe

Abwesenheitsnotiz im Exchange Server 2010

ZVT TA7.0 Protokoll beim ICT250 aktivieren

Erweiterung der Aufgabe. Die Notenberechnung soll nicht nur für einen Schüler, sondern für bis zu 35 Schüler gehen:

Zwischenablage (Bilder, Texte,...)

Die elektronische Rechnung als Fortsetzung der elektronischen Beauftragung so einfach geht es:

Historical Viewer. zu ETC5000 Benutzerhandbuch 312/15

Arbeiten mit UMLed und Delphi

Excel Auswertungen in XAuftrag / XFibu

Internet online Update (Mozilla Firefox)

10.0 Quick Start mit AT89LP2052 Elliptecmotor Kit

Installationsanleitung für das KKL bzw. AGV4000 Interface

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Handbuch. NAFI Online-Spezial. Kunden- / Datenverwaltung. 1. Auflage. (Stand: )

DELFI. Benutzeranleitung Dateiversand für unsere Kunden. Grontmij GmbH. Postfach Bremen. Friedrich-Mißler-Straße Bremen

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Microsoft Access 2010 Navigationsformular (Musterlösung)

CMS.R. Bedienungsanleitung. Modul Cron. Copyright CMS.R Revision 1

Elektrische Logigsystem mit Rückführung

DIGITALVARIO. Anleitung Bootloader. Ausgabe 0.1 deutsch für Direkt-Digital-Vario. Firmware ab Hardware 01 Seriennummer ab 0003

EasyWk DAS Schwimmwettkampfprogramm

Import und Export von Übergängern

Einführungskurs MOODLE Themen:

Mailbox Ihr Anrufbeantworter im primacom-netz Anleitung. Inhaltsverzeichnis. 1 Mailbox einrichten. 1.1 Ersteinrichtung. 1.

Beispiel: Siemens AG 900E03 9 Seiten Update:

Barcodedatei importieren

Anleitung. Einrichtung vom HotSync Manager für den Palm 1550 bis 1800 unter Windows 7. Palm SPT 1500 / 1550 Palm SPT 1700 / Bits & Bytes Seite 1

Sie können diesen Service verwenden, um fast beliebig große Dateien auch über 2 GB zu versenden.

C++ Tutorial: Timer 1

Programmierkurs Java

Stammdatenanlage über den Einrichtungsassistenten

Inhaltsverzeichnis

Klausur in Programmieren

Erwin Grüner

Stepperfocuser 2.0 mit Bootloader

Handbuch ECDL 2003 Basic Modul 5: Datenbank Access starten und neue Datenbank anlegen

Technische Alternative elektronische Steuerungsgerätegesellschaft mbh. A-3872 Amaliendorf, Langestr. 124 Tel +43 (0)

Anleitung zur Verwendung der VVW-Word-Vorlagen

Versuch 3: Anwendungen der schnellen Fourier-Transformation (FFT)

ecaros2 Installer procar informatik AG 1 Stand: FS 09/2012 Eschenweg Weiterstadt

Präventionsforum+ Erfahrungsaustausch. HANDOUT GRUPPEN-ADMINISTRATOREN Anlage zum Endnutzer-Handbuch. Stand: Änderungen vorbehalten

Handbuch ECDL 2003 Professional Modul 3: Kommunikation Kalender freigeben und andere Kalender aufrufen

Grundlagen verteilter Systeme

LDAP Konfiguration nach einem Update auf Version 6.3 Version 1.2 Stand: 23. Januar 2012 Copyright MATESO GmbH

Massenversand Dorfstrasse 143 CH Kilchberg Telefon 01 / Telefax 01 / info@hp-engineering.com

HANDBUCH PHOENIX II - DOKUMENTENVERWALTUNG

Benutzung der LS-Miniscanner

Deklarationen in C. Prof. Dr. Margarita Esponda

Technische Hochschule Georg Agricola WORKSHOP TEIL 3. IKT (Informations- und Kommunikationstechnik) an einer MorseApp erklärt

1. Einführung. 2. Alternativen zu eigenen Auswertungen. 3. Erstellen eigener Tabellen-Auswertungen

Daten-Synchronisation zwischen dem ZDV-Webmailer und Outlook ( ) Zentrum für Datenverarbeitung der Universität Tübingen

Anwendertreffen 20./21. Juni

Technical Note 0201 Gateway

Zählen von Objekten einer bestimmten Klasse

Guideline. Facebook Posting. mit advertzoom Version 2.3

Übung 9 - Lösungsvorschlag

Technische Dokumentation SilentStatistikTool

Befehlssatz zum High Speed Interface-88-USB (HSI-88-USB) (ab Firmware 0.71) (Version 1.2)

Dokumentation zur Versendung der Statistik Daten

Lieferschein Dorfstrasse 143 CH Kilchberg Telefon 01 / Telefax 01 / info@hp-engineering.com

Thermoguard. Thermoguard CIM Custom Integration Module Version 2.70

ShopwareAutoinvoice Installations- und Benutzeranleitung

Handbuch ECDL 2003 Professional Modul 2: Tabellenkalkulation Arbeiten mit Pivot-Tabellen

Übergabe nach Outlook

Wintersemester Maschinenbau und Kunststofftechnik. Informatik. Tobias Wolf Seite 1 von 18

Windows Vista Security

1&1 MAILBOX KONFIGURATION. für D-Netz INHALT. Ersteinrichtung Nachrichten abhören Mailbox-Einstellungen Rufumleitungen Hilfe und Kontakt

PhPepperShop Modul Remarketing. Datum: 13. September 2013 Version: 1.2. Warenkorb Wiederherstellung. Bestellabbruch Benachrichtigung.

Buchungs- und Umsatzsteuerzeitraum ändern

1. Einführung Erstellung einer Teillieferung Erstellung einer Teilrechnung 6

MdtTax Programm. Programm Dokumentation. Datenbank Schnittstelle. Das Hauptmenü. Die Bedienung des Programms geht über das Hauptmenü.

Neuerungen der Ck-Schnittstelle in dms.net Rev. 4895

Simulink: Einführende Beispiele

Objektorientierte Programmierung

Inhaltsverzeichnis Seite

Transkript:

1 1 Einleitung Tiefpass-Filter-Projekt Beispielprojekt für die Verwendung der Mikro-Controller-Plattform mit Hilfe der initdevice-klasse Ort: Hochschule Karlsruhe - Technik und Wirtschaft Fakultät für Elektro- und Informationstechnik Name: Florian Kanis Zeitraum: Wintersemester 2015/16

Inhaltsverzeichnis 1 Einleitung... 3 2 Implementierungsablauf... 4 3 Konfiguration von Timer2, ADC1, DAC1 und der Zusatzbeschaltung... 5 3.1 Konfiguration von Timer2... 5 3.2 Konfiguration von ADC1... 6 3.3 Implementierung der ADC-Interrupt-Service-Routine... 6 3.4 Test der ADC-Interrupt-Service-Routine... 7 3.5 Konfiguration von DAC1... 7 3.6 Konfiguration der Zusatzbeschaltung von ADC1 und DAC1... 8 3.7 Test mit Signalgenerator und Oszilloskop... 8 4 Implementierung der digitalen Tiefpass-Filter... 9 4.1 Rekursives Tiefpass-Filter... 10 4.2 Moving-Average-Filter... 10 4.3 Test der Filter mit Signalgenerator und Oszilloskop... 11 5 UART-Kommunikation zwischen Mikro-Controller-Plattform und PC... 13 5.1 Konfiguration der USART1-Schnittstelle... 13 5.2 Implementierung der USART1-Interrupt-Service-Routine... 14 5.3 Definition der Funktion USART_SEND()... 15 5.4 Test der USART-Interrupt-Service-Routine... 15 5.5 Implementierung der Filtersteuerung... 16 5.6 Test der UART-Kommunikation mit Hyperterminal... 17 5.7 Test der Filter mit Hilfe der MATLAB GUI... 18 6 Abbildungsverzeichnis... 21 7 Anhang 1: Quellcode... 22

Einleitung 3 1 Einleitung In diesem Dokument wird ein Beispielprojekt für die Verwendung der Mikro-Controller- Plattform mit Hilfe der initdevice-klasse beschrieben. Die beschriebene Vorgehensweise basiert auf dem Dokument Mesysto Mikro-Controller-Plattform.pdf, auf welches sich in diesem Dokument mit [1] bezogen wird. Auf die verwendeten Funktionen der initdevice-klasse in der Datei initdevice.cpp wird sich mit [2] bezogen. Implementiert wurde ein Programm, welches ein analoges Signal einliest, dieses digitalisiert, digital filtert und zum Schluss wieder in ein analoges Signal wandelt. Es kann zwischen einem rekursiven Tiefpass-Filter und einem Moving-Average-Filter, jeweils mit anpassbaren Filterkoeffizienten, gewählt werden. Die Steuerung der Filter, also die Auswahl des Filters und die Anpassung der Filterkoeffizienten, kann entweder mit Hilfe eines Terminalprogramms oder der bereitgestellten MATLAB GUI durchgeführt werden. Es ist zu beachten dass sie Verwendung der MATLAB GUI nur in Kombination mit der Messkarte BNC-2110 von National Instruments durchgeführt werden kann. Über diese Messkarte werden die benötigten Signale von der MAT- LAB GUI an die Mikro-Controller-Plattform übergeben und die Ausgabewerte wiederum eingelesen, um diese dann in der MATLAB GUI darzustellen. Dieses Dokument ist so aufgebaut, dass die Reihenfolge der diskutierten Themenbereiche den zeitlichen Ablauf der Implementierung dieses Programms wiederspiegelt. In Kapitel 2 wird zu Beginn dieser generelle Ablauf besprochen. Kapitel 3 diskutiert die Schritte, die benötigt werden, um ein Eingangssignal zu digitalisieren, das digitale Signal für die Signalverarbeitung bereitzustellen und es schließlich wieder in ein analoges Signal umzuwandeln. Dabei werden die einzelnen Implementierungsschritte sowie deren Testmöglichkeiten in der Reihenfolge diskutiert, in der sie implementiert wurden. In Kapitel 4 wird daraufhin auf die Implementierung der beiden digitalen Filter und die Möglichkeit, deren Verhalten zu testen, eingegangen. Bis zu diesem Punkt kann dieses Dokument als Grundlage für jegliche Signalverarbeitung mit digitalen Filtern verwendet werden. In Kapitel 5 wird auf die Kommunikation zwischen PC und Mikro-Controller-Plattform mittels Universal Asynchronous Synchronous Receive Transmit-Schnittstelle (USART) eingegangen. Zu Beginn wird diese generell diskutiert und im späteren Verlauf des Kapitels speziell auf die USART-Kommunikation zum Test der Implementierung der Filtersteuerung eingegangen. Für andere Projekte, die eine USART-Kommunikation benötigen, ist Kapitel 5 daher auch von Interesse. Kapitel 6 enthält den kompletten implementierten Quellcode und kann als Referenz verwendet werden, da in den vorigen Kapiteln nur die grundlegenden Funktionalitäten besprochen werden.

4 Implementierungsablauf 2 Implementierungsablauf In diesem Kapitel wird der generelle Ablauf der Implementierung beschrieben und ist in Abbildung 1 dargestellt. In den folgenden Kapiteln wird daraufhin auf die einzelnen Schritte detailliert eingegangen. Auf den ersten Schritt, dem Erstellen des Projektes, wird dabei verzichtet, da [1] hierfür alle notwendigen Information bereitstellt. Der erste Arbeitsschritt, der in diesem Dokument diskutiert wird, ist daher die Konfiguration der Peripherie, um ein analoges Signal zu digitalisieren (ADC1), dieses zwischen zu speichern und dann wieder in ein analoges Signal umzuwandeln (DAC1). Die Abtastfrequenz der AD- Wandlung wird hierbei mit Timer2 gesteuert. Des Weiteren muss die Zusatzbeschaltung der Mikro-Controller-Plattform konfiguriert werden. Der nächste Schritt ist die Implementierung der digitalen Tiefpass-Filter mittels Differenzengleichung. Er wird in Kapitel 4 diskutiert. Hier wird die Implementierung eines rekursiver Tiefpass-Filters und eines Moving-Average-Filters besprochen. Zum Schluss wird in Kapitel 5 die Konfiguration der USART1-Schnittstelle diskutiert. Diese wird verwendet, um die Filtersteuerung, also die Auswahl des Filters sowie die Festlegung der jeweiligen Filtereigenschaften, von einem Terminalprogramm oder einer MATLAB GUI aus zu steuern. Die Kommunikation via USART wird außerdem verwendet, um Messwerte von der Mikro-Controller-Plattform an die MATLAB GUI zu senden. Abbildung 1: Reihenfolge der Implementierung

Konfiguration von Timer2, ADC1, DAC1 und der Zusatzbeschaltung 5 3 Konfiguration von Timer2, ADC1, DAC1 und der Zusatzbeschaltung In diesem Kapitel wird beschrieben, wie das analoge Eingangssignal mit Hilfe des AD- Wandlers (ADC1) digitalisiert wird, die Abtastfrequenz mit Timer2 festgelegt wird und das digitale Signal wieder mit Hilfe des DA-Wandlers (DAC1) wieder in ein analoges Signal gewandelt wird. Des Weiteren wurde die Zusatzbeschaltung der Mikro-Controller-Plattform für ADC1 und DAC1 konfiguriert. Die Reihenfolge dieses Prozesses, sowie die Möglichkeit den jeweiligen Implementierungsstatus zu testen, ist in Abbildung 2 dargestellt Abbildung 2:Konfiguration von Timer2, ADC1, DAC1 und der Zusatzbeschaltung 3.1 Konfiguration von Timer2 Die Abtastfrequenz von ADC1 wurde, entsprechend Kapitel 2.2 in [1], durch die Initialisierung von Timer2 mit folgendem Code durchgeführt: device.settimer(2); device.setftimer(22050); device.settimeroutput(trigger); device.timerinit(); Mit der Funktion settimer(2) wird zu Beginn Timer2 ausgewählt. ftimer() stellt daraufhin die Abtastfrequenz auf 44,1kHz ein. Hierbei ist zu beachten, dass wenn Timer2 als Trigger für ADC1 verwendet wird, die Funktion setftimer() nicht auf 44100 sondern auf die Hälfte, also 22050, eingestellt werden muss. Der Faktor 0,5 ist zu verwenden, wenn der Timer Output als

6 Konfiguration von Timer2, ADC1, DAC1 und der Zusatzbeschaltung Trigger für eine andere Peripherie verwendet wird. settimeroutput(trigger) definiert daraufhin, dass das ausgelöste Event von Timer2 als Trigger für eine andere Peripherieeinheit verwendet wird. Die Verknüpfung von Timer2 und ADC1 wird im kommenden Kapitel 3.2 beschrieben. Zum Schluss werden die Einstellungen mit der Funktion timerinit() übernommen. Die von [2] bereitgestellten Funktionen settimer(), setftimer(), settimeroutput() und timerinit() konfigurieren im Hintergrund automatisch alle relevanten Elemente. Für genauere Informationen zu den verwendeten Funktionen sind in [2] die Funktionsdefinitionen einzusehen. 3.2 Konfiguration von ADC1 Die Konfiguration des ADC1 wurde, wie in Kapitel 2 in [1] beschrieben, mit folgendem Code durchgeführt: device.setadc(1); device.setadctrigger(timer2adc_trgo); device.adcinit(); device.setirqchannel(adcinterrupt); device.nvicinit(); Zu Beginn wurde mit der Funktion setadc(1) die Verwendung von ADC1 definiert. Daraufhin wurde mit setadctrigger(timer2adc_trgo) festgelegt, dass der Ausgang von Timer2 als Trigger für ADC1 verwendet wird. Mit der Funktion adcinit() werden diese Einstellungen übernommen. Da mit jedem neu gewandelten Wert ein Interrupt ausgelöst wird, wird im Nested Vector Interrupt Controller (NVIC) der Kanal für den ADC-Interrupt freigegeben. Das wird mit setirqchannel(adcinterrupt) bewerkstelligt, woraufhin die Einstellung mit der Funktion nvicinit() übernommen wird. Die von [2] bereitgestellten Funktionen setadc(), setadctrigger(), adcinit(), setirqchannel() und nvicinit() konfigurieren im Hintergrund automatisch alle relevanten Elemente (GPIOs, Prescaler, Triggereigenschaften, usw.). Für genauere Informationen zu den verwendeten Funktionen sind in [2] die Funktionsdefinitionen einzusehen. 3.3 Implementierung der ADC-Interrupt-Service-Routine Die ADC-Interrupt-Service-Routine wird aufgerufen, sobald ADC1 einen neuen Wert gewandelt hat und dieser zur Verfügung steht. Dies wird durch das End-Of-Conversion-Flag (EOC) anzeigt. Abgesehen von dem regelmäßigen Aufrufen im laufenden Betrieb wird die ADC- Interrupt-Service-Routine einmal zu Beginn, bei der Ausführung des Befehls adcinit(), aufgerufen. Die ADC-Interrupt-Service-Routine wurde wie in Kapitel 2 in [1] beschrieben, mit folgendem Code implementiert: extern "C" void ADC_IRQHandler(void) If(ADC_GetITStatus(ADC1, ADC_IT_EOC) == SET) ADC_ClearITPendingBit(ADC1, ADC_IT_EOC); //hier folgt später der weitere Code //siehe Kapitel 3.5 Konfiguration von DAC1 Zu Beginn wird abgefragt, ob das EOC-Flag gesetzt ist. Ist das der Fall, so wird es zurückgesetzt, sodass nach der nächsten Wandlung die ADC-Interrupt-Service-Routine erneut aufgerufen werden kann. An dieser Stelle wird später die Signalverarbeitung mit den digitalen Filtern und die Ausgabe über den DAC implementiert. Die Funktionen ADC_GetITStatus() und

Konfiguration von Timer2, ADC1, DAC1 und der Zusatzbeschaltung 7 ADC_ClearITPendingBit() werden von der STM-Bibliothek, siehe Kapitel 1.1 in [1] bereitgestellt und wurden nicht eigens in [2] definiert. 3.4 Test der ADC-Interrupt-Service-Routine Wenn Timer2 und ADC1 fertig initialisiert sind, muss getestet werden, ob das Programm im laufenden Betrieb wie gewünscht in die ADC-Interrupt-Service-Routine springt. Für einen ersten Test wird daher der Debugger von Keil uvision genutzt. Führen Sie folgende Schritte nacheinander aus: Klicken Sie auf F7, um den geschriebenen Code in die Target-Files umzusetzen Klicken Sie auf, um den Debugger zu starten Setzten Sie einen Breakpoint in die ADC-Interrupt-Service-Routine Klicken Sie auf, um den Programmcode vom Debugger in den Kontroller zu laden Klicken Sie auf, um das Programm zu starten Das Programm sollte nun bei dem Breakpoint in der ADC-Interrupt-Service-Routine stoppen. Falls das Programm nicht an dieser Stelle stoppt, muss die Initialisierung von Timer2 und ADC1 sowie die Definition der ADC-Interrupt-Service-Routine auf Fehler untersucht werden. 3.5 Konfiguration von DAC1 Mit dem folgenden Code wurde, entsprechend Kapitel 3 in [1], der DAC1 konfiguriert: device1.setdac(1); device1.setdactrigger(none); device1.dacinit(); Analog zu der Initialisierung des ADC1 wurde DAC1 mit der Funktion setdac(1) ausgewählt. setdactrigger(none) definiert daraufhin, dass der DAC nicht durch einen externen Trigger gesteuert wird. Bei dieser Konfiguration werden Daten ausgegeben, sobald die Ausgabe per Funktionsaufruf gestartet wird und nicht per externem Trigger. Diese Initialisierung wurde schließlich wieder mit der Funktion dacinit() übernommen. Die von [2] bereitgestellten Funktionen setdac(), setdactrigger() und dacinit() konfigurieren im Hintergrund automatisch alle relevanten Elemente (GPIOs, Prescaler, Triggereigenschaften, usw.). Für genauere Informationen zu den verwendeten Funktionen sind in [2] die Funktionsdefinitionen einzusehen. Das Auslesen der digitalisierten Werte des ADC1 und die Ausgabe dieser Werte mit dem DAC1 wurden mit folgendem Code in der ADC-Interrupt-Service-Routine implementiert: convvalue = ADC_GetVonversionValue(ADC1); DAC_SetChannel1Data(DAC_Align_12b_R, convvalue); Der vom ADC1 bereitgestellte digitale Wert wird mit der Funktion ADC_GetConversionValue() erfasst, in der Variablen convvalue zwischengespeichert und dann mit der Funktion DAC_SetChannel1Data() über den DAC1 wieder ausgegeben. Diese beiden Funktionen werden von der STM-Bibliothek, siehe Kapitel 1.1 in [1], bereitgestellt und wurden nicht eigens in [2] definiert. Der Parameter DAC_Align_12b_R definiert, dass eine 12 Bit-Variable mit linksbündiger Datenausrichtung an den DAC1 übergeben wird.

8 Konfiguration von Timer2, ADC1, DAC1 und der Zusatzbeschaltung 3.6 Konfiguration der Zusatzbeschaltung von ADC1 und DAC1 Die Konfiguration der Zusatzbeschaltung wurde, entsprechend Kapitel 8 in [1], mit folgendem Code implementiert: device1.setadcinputpath(1,bypass); device1.setdacoutputpath(1,bypass); Mit der Funktion setadcinputpath() wird der jeweilige ADC-Eingangspfad ausgewählt, in diesem Fall der Pfad 1 und als Bypass konfiguriert. Analog dazu wurde der DAC-Ausgangspfad von DAC1 konfiguriert. Diese von [2] bereitgestellten Funktionen konfigurieren im Hintergrund die Multiplexer auf dem analogen Frontend der Mikro-Controller-Plattform. Für genauere Informationen zu den verwendeten Funktionen sind in [2] die Funktionsdefinitionen einzusehen. Für detaillierte Informationen zu der verwendeten Hardware wird auf Kapitel 8 in [1] verwiesen. 3.7 Test mit Signalgenerator und Oszilloskop Mit der aktuellen Konfiguration wird ein Signal zwischen 0V und 3V vom ADC1 eingelesen, in der ADC-Interrupt-Service-Routine zwischengespeichert und daraufhin vom DAC1 wieder ausgegeben. Das Ausgangssignal deckt dabei ebenfalls einen Spannungsbereich von 0V bis 3V ab. Um diese Konfiguration zu testen, wurden ein Signalgenerator und ein Oszilloskop verwendet. Dabei wurden folgenden Werte am Signalgenerator eingestellt: Frequenz 1kHz Amplitude 100mV Offset 750mV Der Ausgang des Signalgenerators wurde mit einem T-Stücks ausgesplittet und einmal direkt auf das Oszilloskop und einmal auf den Eingang des ADC1 der Mikro-Controller-Plattform gegeben. Des Weiteren wurde der Ausgang DAC1 mit dem Oszilloskop verbunden. Somit konnte das digital bearbeitete Signal mit dem Originalsignal verglichen werden. Da die Implementierung auf der Mikro-Controller-Plattform das Signal lediglich abtastet und wieder ausgibt, muss das Ausgangssignal der diskretisierten Form des Eingangssignals entsprechen. Bei genauer Betrachtung ist ein geringer Zeitverzug des diskretisierten Signals im Vergleich zum Originalsignal zu erkennen. Dieser Zeitverzug ist der Verarbeitungszeit der AD- Wandlung, der internen Speicherzugriffe und der abschließenden DA-Wandlung zu schulden. Falls, wie in Abbildung 2 dargestellt, dieser Test nicht erfolgreich verlaufen ist, muss die Konfiguration von DAC und Zusatzbeschaltung, sowie die Funktionsaufrufe in der ADC-Interrupt- Service-Routine überprüft werden.

Implementierung der digitalen Tiefpass-Filter 9 4 Implementierung der digitalen Tiefpass-Filter In diesem Kapitel wird die Implementierung der digitalen Tiefpass-Filter diskutiert. Dabei wird, wie in Abbildung 3 dargestellt, zuerst auf die Implementierung des rekursiven Tiefpass-Filters und des Moving-Average-Filters in Kapitel 4.1 und 4.2 eingegangen. In Kapitel 4.3 wird dann eine Möglichkeit für das Testen des Filterverhaltens präsentiert. An dieser Stelle ist zu erwähnen, dass lediglich einer der beiden Filter zu einem Zeitpunkt verwendet werden kann, der jeweils andere Filter muss in diesem Moment auskommentiert sein. In Kapitel 5.5 wird dann beschrieben, wie beide Filter verwendet werden können und per USART-Kommunikation der zu verwendende Filter ausgewählt werden kann. Abbildung 3: Implementierung der digitalen Tiefpass-Filter Generell kann die Implementierung eines digitalen Filters mit einer Differenzengleichung und einem Flussdiagramm dargestellt werden. Die Differenzengleichung beschreibt, wie sich der aktuelle Ausgangswert aus gewichteten Werten vorhergegangener Eingangs- und Ausgangswerte zusammensetzt. Das rekursive Tiefpass-Filter und das Moving-Average-Filter werden in Kapitel 4.1 und 4.2 anhand von ihrer Differenzengleichung charakterisiert und diskutiert. Das Flussdiagramm ist generell für Filterimplementierungen gleich und ist in Abbildung 4 dargestellt. Abbildung 4: Flussidagramm einer Filterimplementierung Zu Beginn werden die Variablen, die den aktuellen Eingangswert sowie vorhergegangene Eingangs- und Ausgangswerte speichern, initialisiert. Im zweiten Schritt wird die, für den jeweili-

10 Implementierung der digitalen Tiefpass-Filter gen Filter repräsentative, Differenzengleichung berechnet und somit der aktuelle Ausgangswert bestimmt. In Schritt drei und vier wird eine Speicherverwaltung durchgeführt, bei der die zu Beginn initialisierten Variablen mit den aktuellen Werten beschrieben werden und der aktuelle Ausgangswert ausgegeben wird. Dieser Prozess der Berechnung der Differenzengleichung, der Speicherverwaltung und der Ausgabe der Ausgangsgröße wiederholt sich im laufenden Betrieb zyklisch. Mit welchem Takt diese zyklische Verarbeitung durchgeführt wird, hängt von der Position des zugehörigen Codes ab. In diesem Bespiel findet die Verarbeitung in der ADC- Interrupt-Service-Routine statt und wird also 44100 Mal pro Sekunde ausgeführt. 4.1 Rekursives Tiefpass-Filter Das implementierte rekursive Tiefpass-Filter kann mit Formel 1 beschrieben werden: y k 1 GF u k GF y k 1 Der aktuelle Ausgangswert y[k] wird dabei aus dem aktuellen Eingangswert u[k] und dem vorhergegangenen Ausgangswert y[k-1] berechnet, wobei u[k] und y[k-1] verschieden gewichtet werden können. Die Gewichtung dieser beiden Faktoren wird mit dem Gewichtungsfaktor GF bestimmt, der Werte zwischen 0 und 1 annehmen kann. Wenn GF = 0 gewählt wird, bedeutet dies, dass der aktuellen Eingangswert u[k] mit 1 gewichtet wird und der vorhergegangene Ausgangswert y[k-1] mit 0. y[k] entspricht also u[k], was bedeutet, dass die Zeitkonstante gleich null ist. Wenn GF = 1 gewählt wird, wird u[k] mit 0 gewichtet und y[k-1] mit 1. In diesem Fall hat der aktuelle Eingangswert keinen Einfluss und das Ausgangssignal bleibt für immer auf dem Initialwert, der für gewöhnlich null ist. Die Zeitkonstante ist daher unendlich. Werte zwischen 0 und 1 der Variablen GF definieren also die Zeitkonstante des Filters, welche mit steigendem GF ebenfalls steigt. Die Implementierung, deren generelle Struktur in Abbildung 4 dargestellt ist, wurde mit folgendem Code durchgeführt: // Variablen initialisieren (ADC-Wert lesen) u = ADC_GetVonversionValue(ADC1); // Differenzengleichung berechnen y = (int16_t)((1-gf)*u+gf*yold); // Speicherverwaltung yold = y; // Ausgabe der Ausgangsgröße DAC_SetChannel1Data(DAC_Align_12b_R, y); (1) 4.2 Moving-Average-Filter Das Moving-Average-Filter wurde mit Formel 2 beschrieben: 15 1 y k d u k n 16 n 0 n Der aktuelle Ausgangswert y[k] setzt sich dabei aus dem aktuellen und den vorhergegangenen Eingangswerten u[k-n] zusammen. Da die Summe für einen Wertebereich von n = 0 bis n = 15 berechnet wird, wird der aktuelle Wert (n = 0) und die 15 vorherigen Eingangswerte (n = 1..15) (2)

Implementierung der digitalen Tiefpass-Filter 11 berücksichtigt. Um jeden dieser 16 Werte gleich stark zu gewichten, wird das Ergebnis der Summe schließlich durch 16 geteilt. Im Gegensatz zum rekursiven Tiefpass-Filter wird beim Moving-Average-Filter lediglich der aktuelle und vergangene Eingangswert für die Berechnung der Differenzengleichung berücksichtigt. Die Implementierung, deren generelle Struktur in Abbildung 4 dargestellt ist, wurde mit folgendem Code durchgeführt: // Variablen initialisieren (ADC-Wert lesen) u = ADC_GetVonversionValue(ADC1); // Differenzengleichung berechnen Ue[0]=u; sum=0; for(int i=0;i<m;i++) sum = sum+(int)ue[i]; y = (int16_t)(1/(float)m*sum); // Speicherverwaltung for(int i=m-1;i>0;i--) Ue[i]=Ue[i-1]; // Ausgabe der Ausgangsgröße DAC_SetChannel1Data(DAC_Align_12b_R, y); 4.3 Test der Filter mit Signalgenerator und Oszilloskop Der Test der beiden Tiefpass-Filter ist ähnlich aufgebaut wie der in Kapitel 3.7 beschriebene Test. Der jeweils nicht zu testende Filter muss dazu auskommentiert sein. Im Signalgenerator wird ein Signal, das symmetrisch um 1,5V schwingt und eine Amplitude kleiner gleich 1,5V hat, erzeugt und zusammen mit dem Ausgangssignal der Mikro-Controller-Plattform auf dem Oszilloskop betrachtet und verglichen. Um das Frequenzverhalten des Filters darzustellen, gibt es zwei Möglichkeiten. In beiden Fällen wird im Signalgenerator die Frequenz des erzeugten Signals mit einem Sweep zwischen 1Hz und 20kHz variiert. Im Signalgenerator sind folgende Einstellungen vorzunehmen: Sine: o Amplitude 100mV o Offset 750mV Sweep: o Start 1Hz o Stop 20kHz o Sweep Time 10s Der Ausgang des Signalgenerators wird mit einem T-Stück aufgesplittet und auf den ADC1 Anschluss der Mikro-Controller-Plattform sowie auf das Oszilloskop gegeben. Der Ausgang des DAC1 der Mikro-Controller-Plattform wird ebenfalls mit dem Oszilloskop verbunden, um Eingangs- und Ausgangssignal des Filters miteinander zu vergleichen. Die erste Möglichkeit besteht nun darin, das Zeitverhalten der beiden Signale miteinander zu vergleichen. Dafür werden am Oszilloskop folgende Einstellungen vorgenommen: Channel 1&2: o Time/Division 1s/ -> Es können 10 Sekunden angezeigt werden

12 Implementierung der digitalen Tiefpass-Filter o Voltage/Division 50mV/ o Kopplung AC -> Der Offset von 1,5V wird entfernt Wenn nun Kanal 1 und 2 übereinander gelegt werden, wird dargestellt, wie das Filter das Eingangssignal im Frequenzbereich von 1Hz bis 20kHz verändert. Da die Sweep Time auf 10s eingestellt und auf dem Oszilloskop 1s/Division eingestellt wurde, wird jeweils der komplette Sweep dargestellt. Innerhalb einer Division wird die Frequenz also um (20000-1)/10Hz = 1999,9Hz 2kHz erhöht. Für die Implementierung des rekursiven Tiefpass- Filters und des Moving-Average-Filters ergibt sich das Frequenzverhalten in Abbildung 5. Abbildung 5: Darstellung des Frequenzverhalten im Zeitbereich Auf der linken Seite von Abbildung 5 ist das rekursive Tiefpass-Filter mit einem Gewichtungsfaktor von GF = 0.98 dargestellt. Wie erwartet entspricht das Verhalten dem eines Tiefpasses. Auf der rechten Seite ist das Ausgangssignal des Moving-Average-Filters dargestellt mit einer Länge von M = 16. Das sinx/x-verhalten (Rechteck im Zeitbereich) ist deutlich zu erkennen. Die zweite Möglichkeit besteht darin, mit einer FFT das Spektrum des Ausgangssignals darzustellen. Dafür werden am Oszilloskop folgende Einstellungen vorgenommen: Spanne 20kHz Mitte 9kHz Fenster Rechteck Die Verschiebung um 1kHz (Mitte = 9kHz) wurde durchgeführt, um das Verhalten um eine Frequenz von 0Hz besser beurteilen zu können. Das Ergebnis der FFT für das Ausgangssignal des rekursiven Tiefpasses und des Moving-Average-Filters ist in Abbildung 6 dargestellt. Abbildung 6: Darstellung des Frequenzverhaltens mittels FFT Es ist zu sehen, dass das Ergebnis der FFT (pink) in Abbildung 6 der logarithmischen Darstellung des Ergebnisses des Zeitverhaltens (grün) in Abbildung 5 entspricht.

UART-Kommunikation zwischen Mikro-Controller-Plattform und PC 13 5 UART-Kommunikation zwischen Mikro-Controller-Plattform und PC Auf dem zugrunde liegenden Mikro-Controller STM32F4 ist eine USART-Schnittstelle verfügbar. Im Rahmen der verwendeten Mikro-Controller-Plattform und der verwendeten initdevice Klasse wird diese Schnittstelle als Universal Asynchronous Receive Transmit (UART) verwendet. Das bedeutet, dass lediglich ein Kabel für das Empfangen und ein Kabel für das Versenden zur Verfügung steht, jedoch kein Kabel für die Übertragung des Clock-Singals. Sie ermöglicht die Kommunikation zwischen der Mikro-Controller-Plattform und dem PC. Somit kann zum Beispiel die Filtersteuerung, also die Auswahl des Filters und die Anpassung der Koeffizienten, vom PC durchgeführt werden und umkehrt Abtastwerte an den PC gesendet werden. Der generelle Ablauf der Konfiguration der DAC1-Schnittstelle ist in Abbildung 7 dargestellt und wird in den folgenden Kapiteln im Detail beschrieben. Abbildung 7: Konfiguration und Test der USART1-Schnittstelle 5.1 Konfiguration der USART1-Schnittstelle Die Konfiguration wurde, entsprechend Kapitel 7.2 in [1] mit folgendem Code durchgeführt: device1.setusartchannel(1); device1.setusartdmaconnection(usartdmaoff); device1.usartinit(); device1.setirqchannel(usartinterrupt); device1.nvicinit();

14 UART-Kommunikation zwischen Mikro-Controller-Plattform und PC Die Verwendung der DAC1- Schnittstelle wird mit der Funktion setusartchannel(1) definiert. Mit der Funktion setusartdmaconnection(usartdmaoff) wird daraufhin definiert, dass die Peripherie Direct Memory Access (DMA) nicht verwendet wird. Die DMA wird verwendet, wenn beabsichtigt wird, den Datentransfer zwischen verschiedenen Peripherien untereinander, zwischen einer Peripherie und dem Speicher oder speicherintern zu optimieren. Bei Verwendung der DMA wird der Prozessor erheblich weniger belastet. Da dieses Programm recht kurz ist, wurde diese Optimierung der Laufzeit nicht benötigt und die DMA nicht verwendet. Weitere Informationen zur DMA sind in Kapitel 9 in [1] verfügbar. Mit dem Aufruf der Funktion usartinit() werden schließlich die Einstellungen für die USART-Kommunikation übernommen. Da die USART-Kommunikation mit Interrupts gesteuert wird, muss im NVIC der Kanal für den USART1-Interrupt freigegeben werden. Das wird mit der Funktion setirqchannel(usartinterrupt) bewerkstelligt, woraufhin die Einstellung mit der Funktion nvicinit() übernommen wird. Die von [2] bereitgestellten Funktionen setusartchannel(), setusartdmaconnection(), usartinit(), setirqchannel() und nvicinit() konfigurieren im Hintergrund automatisch alle relevanten Elemente (GPIOs, Prescaler, USART-Einstellungen, usw.). Für genauere Informationen zu den verwendeten Funktionen sind in [2] die Funktionsdefinitionen einzusehen. Die Einstellungen, die mit diesem Code festgelegt wurden, sind in Tabelle 2 in [1] aufgelistet und werden an dieser Stelle kurz wiederholt: Übertragungsrate /Bit pro sek. 57600 Datenbits 8 Paritätsbit keine Stoppbits 2 Flusssteuerung keine Diese Werte werden in Kapitel 5.6 wieder benötigt. Dort wird die Kommunikation mit Hilfe des Terminalprogramms Hyperterminal getestet wird. 5.2 Implementierung der USART1-Interrupt-Service-Routine Die USART-Interrupt-Service-Routine wird aufgerufen, sobald ein UART-Interrupt ausgelöst wird, z.b. im Falle eines neu empfangenen Datenwortes. Abgesehen von den Aufrufen im laufenden Betrieb wird die USART1-Interrupt-Service-Routine einmal zu Beginn, bei der Ausführung des Befehls usartinit(), aufgerufen. Die USART1-Interrupt-Service-Routine wurde, angelehnt an Kapitel 7.2 in [1], mit folgendem Code implementiert: extern "C" void USART1_IRQHandler(void) uint8_t signalfromgui; if(readytosend) ADC_Cmd(ADC1,DISABLE); USART_SEND(char); ADC_Cmd(ADC1,ENABLE); readytosend=0; if(usart_getitstatus(usart1, USART_IT_RXNE)!= RESET) USART_ClearITPendingBit(USART1,USART_IT_RXNE); signalfromgui = (USART_ReceiveData(USART1) & 0x7F);

UART-Kommunikation zwischen Mikro-Controller-Plattform und PC 15 Zu Beginn wird eine 8-Bit Variable definiert, in der im späteren Verlauf der empfangene Wert gespeichert wird. Falls das Programm beabsichtigt, einen Wert via USART zu senden, wird zuvor die Variable readytosend gesetzt und der Code in der if-abfrage ausgeführt. Zu Beginn wird für den Zeitraum, in dem der Sendeprozess stattfindet, der ADC1 mit dem Befehl ADC_Cmd(ADC1,DISABLE) deaktiviert. Das Senden der 8-Bit Daten wird mit der Funktion USART_SEND(char) durchgeführt, woraufhin danach der ADC1 mit dem Befehl ADC_Cmd(ADC1,ENABLE) wieder aktiviert wird. Zum Schluss wird die Variable readytosend zu Null gesetzt, sodass erst wieder wenn das Bit gesetzt wird diese Befehle erneut ausführt. Die zweite if-abfrage testet ob das ReceiveNotEmpty (RXNE) Bit gesetzt ist. Ist das der Fall, wurde ein neuer Wert via USART empfangen und kann ausgelesen werden. Zu Beginn muss das RXNE-Bit zurückgesetzt werden, sodass ein erneutes Setzen dieses Bits erneut einen Interrupt auslöst. Das Zurücksetzten wird mit dem Befehl US- ART_ClearITPendingBit(USART1,USART_IT_RXNE) durchgeführt. Schließlich wird der neu empfangene Wert binär maskiert und in der zu Beginn deklarierte Variablen signalfromgui gespeichert. 5.3 Definition der Funktion USART_SEND() Die Funktion USART_SEND() wurde mit folgendem Code implementiert: void USART_SEND(char byte) USART_SendData(USART1,byte); while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) USART_SEND() sendet pro Aufruf jeweils eine 8-Bit Variable, die übergeben werden kann. Das Senden an sich wird dabei von der Funktion USART_SendData(USART1,byte) durchgeführt. Die darauffolgende while-schleife fragt mit der Funktion US- ART_GetFlagStatus(USART1, USART_FlAG_TC) kontinuierlich ab, welchen Wert das Transmission Complete Flag (USART_FLAG_TC) hat. Dieses Flag kann die Werte SET und RESET annehmen. Solange USART_FLAG_TC nicht gesetzt ist (RESET), verweilt das Programm in der while-schleife. Wird USART_FLAG_TC gesetzt (SET), springt das Programm aus der Schleife und setzt die kommende Programmausführung fort. 5.4 Test der USART-Interrupt-Service-Routine Analog zu der Implementierung der ADC-Interrupt-Service-Routine wird auch an dieser Stelle getestet, ob das Programm wie gewünscht in die USART-Interrupt-Service-Routine springt. Dazu wird ebenfalls der Debugger von Keil uvision verwendet. Führen Sie erneut die folgenden Schritte durch: Klicken Sie auf F7, um den geschriebenen Code in die Target-Files umzusetzen Klicken Sie auf, um den Debugger zu starten Setzten Sie einen Breakpoint in die DAC1-Interrupt-Service-Routine Klicken Sie auf, um den Programmcode vom Debugger in den Kontroller zu laden Klicken Sie auf, um das Programm zu starten

16 UART-Kommunikation zwischen Mikro-Controller-Plattform und PC Das Programm sollte nun bei dem Breakpoint in der DAC1-Interrupt-Service-Routine stoppen. Falls dem nicht so ist, muss die Konfiguration der DAC1-Schnittstelle sowie die Implementierung der DAC1-Interrupt-Service-Routine auf Fehler untersucht werden. 5.5 Implementierung der Filtersteuerung Nachdem getestet wurde, ob das Programm in die USART-Interrupt-Service-Routine springt, kann mit der Implementierung der Filtersteuerung fortgefahren werden. Die Implementierung der Filtersteuerung wurde in den Interrupt-Service-Routinen der USART1-Schnittstelle und des ADC1 durchgeführt. In der USART-Interrupt-Service-Routine werden Steuersignale vom PC empfangen und dazugehörige Steuervariablen gesetzt. Diese Variablen definieren, welcher Filter mit welchen Filtereigenschaften in der ADC-Interrupt-Service-Routine verwendet wird. Der Test der Filter benötigt daher lediglich ein Terminalprogramm, mit welchem USART-Daten vom PC an die Mikro-Controller-Plattform gesendet werden können und wird im Detail in Kapitel 5.6 beschrieben. An dieser Stelle wird auf Kapitel 6 verwiesen, wo der komplette Code aufgeführt ist. Der Einfachheit halber wird in diesem Kapitel lediglich eine Kurzfassung der Filtersteuerung vorgestellt. Um die komplette Funktionsweise mit der MATLAB GUI zu testen, muss der Code, identisch wie er in Kapitel 7 aufgeführt ist, implementiert werden. Zu Beginn des Programms wurden die folgenden Variablen definiert, die die Filtersteuerung übernehmen: volatile bool moving_avr = false; // 'i' (ASCII: 105) volatile bool filter_rec = true; // 'j' (ASCII: 106) volatile float GF = 0.5; volatile int8_t M = 8; // Gewichtungsfaktor GF von 'filter_rec' // Filterlänge M von 'moving_avr' Die Auswahl, welcher Filter aktuell verwendet wird, wurde über die bool-variablen moving_avr und filter_rec definiert. Bei dem Start des Programms ist das rekursive Tiefpass-Filter aktiv (true) und der Moving-Average-Filter inaktiv (false). Die Variablen GF und M bestimmen das jeweilige Übertragungsverhalten des aktuellen Filters. Die Auswertung des empfangenen USART-Signals wurde, wie zuvor erwähnt, in der USART- Interrupt-Service-Routine durchgeführt: if(signalfromgui==105) filter.resetfiltercoefficients(); moving_avr=true; filter_rec=false; else if(signalfromgui==106) filter.resetfiltercoefficients(); filter_rec=true; moving_avr=false; // ASCII 'i' // ASCII 'j' else if((signalfromgui>=0)&&(signalfromgui<=100)) if((filter_rec==true)&&(moving_avr==false)) GF=((float)signalFromGUI/100); else if((filter_rec==false)&&(moving_avr==true)) M=(int8_t)((uint8_t)signalFromGUI-65);

UART-Kommunikation zwischen Mikro-Controller-Plattform und PC 17 Entspricht das via USART empfangene Signal dem ASCII-Wert i wird damit der Moving- Average-Filter mit true ausgewählt, mit j dementsprechend das Tiefpass-Filter. Der jeweils andere Filter wird mit false als inaktiv definiert. Zu Beginn wird in beiden Fällen jedoch erstmal die Funktion resetfiltercoefficients() aufgerufen, mit der die Speicherzellen der Filter in den Ausgangszustand gesetzt werden. Ist das empfangene Signal ungleich dem ASCII-Wert für i oder j und in dem Wertebereich [0, 100], wird das empfangene Signal als eine Veränderung der Filterkoeffizienten ausgewertet. Je nachdem, welcher Filter aktuell aktiv ist, wird das Signal entsprechend ausgewertet. Ist das rekursive Tiefpass-Filter aktiv, wird das empfangene Signal als Gewichtungsfaktor GF interpretiert. Ist wiederum der Moving-Average-Filter aktiv, wird das empfangene Signal als Filterlänge M interpretiert. Das angepasste Filter wird dann, wie bereits erwähnt, in der ADC-Interrupt-Service-Routine verwendet. 5.6 Test der UART-Kommunikation mit Hyperterminal Mit der Erklärung in Kapitel 5.5 kann nun die UART-Kommunikation zwischen dem PC und der Mikro-Controller-Plattform getestet werden. Für diesen Test bietet sich ein Terminalprogramm an. In diesem Projekt wurde dafür Hyperterminal verwendet. Die verwendete Version von Hyperterminal ist unter folgendem Link zu finden: http://www.eit.hs-karlsruhe.de/mesysto/teamorientierte-lehrmethoden/teamorientiertelehrmethoden/student-project-teams/zeitdiskrete-signale-und-systeme.html Führen Sie folgende Schritte durch: Verbinden Sie die USART-Schnittstelle der Mikro-Controller-Plattform mit dem PC Überprüfen Sie welcher COM-Port reserviert wurde o Start -> Systemsteuerung -> Geräten Manager -> Anschlüsse (COM & LPT) -> Silicon Labs CP210x USB to UART Bridge (COMxx) Öffnen Sie Hyperterminal und erstellen Sie eine Verbindung mit den folgenden Parametern: o Connect using: COMxx o Bits pro Sekunde: 57600 o Datenbits 8 o Parität keine o Stoppbits 2 o Flusssteuerung keine

18 UART-Kommunikation zwischen Mikro-Controller-Plattform und PC Abbildung 8: UART-Kommunikation via Hyperterminal Die Verbindung sollte nun erstellt und aktiv sein. Laden Sie das Programm auf den Mikro- Controller. Bei dem Start des Programms ist das rekursive Tiefpass-Filter aktiv. Sie können nun mit i das Moving-Average-Filter aktivieren und mit j dementsprechend wieder das rekursiven-tiefpass-filter. Die Filterkoeffizienten der Filter sind in diesem Moment noch auf dem Standartwerten GF = 0,5 und M = 8. Funktioniert des Wechseln zwischen den Filtern wie erwartet, kann das Verändern der Koeffizienten getestet werden. Ist das rekursive Tiefpass Filter aktiv wird das empfangene Signal als Gewichtungsfaktor GF interpretiert. Dieser Gewichtungsfaktor kann Werte zwischen 0 und 1 in 0.01-Schritten annehmen. Das empfangene Signal für GF kann ASCII-Werte von 0 bis 100 annehmen die dementsprechend durch 100 geteilt werden. Aktivieren Sie das rekursive Tiefpass-Filter mit j und senden Sie ein Z (ASCII: 90); GF wird daraufhin auf 0,9 gesetzt. Damit steigt die Zeitkonstante des Filters an. Mit Space wird GF dementsprechend auf 0,32 gesetzt, wodurch die Zeitkonstante gesenkt wird. Die ersten 32 ASCII-Zeichen sind Steuersignale, können aber trotzdem für den Test verwendet werden. Ist das Moving-Average-Filter aktiv, wird das empfangene Signals als Filterlänge M interpretiert. Die Filterlänge kann Werte zwischen 1 und 16 annehmen. Das empfangene Signal darf ASCII-Werte von B (dez. 66) bis Q (dez. 81) annehmen, da von dem empfangenen Signal der dezimal Wert 65 abgezogen wird. Stellen Sie sicher, dass Sie diesen Wertebereich nicht überschreiten, da in dieser Implementierung keine Abfrage existiert, ob der empfangene Wert zwischen 66 und 81 liegt. 5.7 Test der Filter mit Hilfe der MATLAB GUI In Kapitel 4.3 und 5.6 wird der Funktionstest der Filter an sich, sowie der Test der Filtersteuerung beschrieben. Der in Kapitel 6 angehängte Code enthält jedoch noch weitere Funktionalitäten, die an dieser Stelle kurz beschrieben werden. Zum Schluss wird dann die Steuerung dieser Implementierung mittels MATLAB GUI diskutiert. Wie bereits in Kapitel 1 beschrieben wurde

UART-Kommunikation zwischen Mikro-Controller-Plattform und PC 19 ist die Verwendung der MATLAB GUI nur in Kombination mit der Messkarte BNC-2110 von National Instruments möglich. Der Hauptunterschied zu der bisher beschriebenen Funktionalität ist, dass die vollständige Implementierung eine Messung des Filterverhaltens im Zeitbereich sowie im Frequenzbereich erlaubt. Das Aktivieren der jeweiligen Messung erfolgt via UART-Schnittstelle. Eine Messung im Zeitbereich wird gestartet wenn ein g empfangen wird. In diesem Fall wird die bool- Variable start_zeitbereich auf true gesetzt. Eine Messung im Frequenzbereich wird dementsprechend mit dem Empfang eines h gestartet, woraufhin die bool-variable start_frequenzbereich auf true gesetzt wird. Bei Start des Programms sind beide Variablen auf false. Bei einer Messung im Zeitbereich wird das aktuell empfangene Eingangssignal der Mikro- Controller-Plattform außer Betracht gelassen. Anstelle dessen wird für eine Dauer von 60 bzw. 300 Abtastwerten ein konstanter Wert von 1375 an den Filter übergeben. Dies entspricht einem Sprung von 0V auf 1V. Während der Dauer von 60 bzw. 300 Abtastwerten, wird der Ausgangswert des Filters in einem Array gespeichert. Dieses Array wird daraufhin Byte-weise via USART1 an die MATLAB GUI gesendet, welche die Sprungantwort dann darstellt. Abbildung 9: MATLAB GUI; rekursives Tiefpass-Filter, Messung Zeitbereich Eine Messung im Frequenzbereich wird mit Hilfe der Messkarte BNV-2110 von National Instruments durchgeführt. Dabei wird der Ausgang AO 0 der Messkarte mit ADC1 der Mikro- Controller-Plattform verbunden und der DAC1 der Plattform mit dem Eingang AI 0 der Messkarte. Mit Hilfe der MATLAB GUI wird daraufhin eine Frequenz Sweep erzeugt, der über die Messkarte an die Mirko-Controller-Plattform übergeben wird. Die Ausgangswerte des aktuell verwendeten Filters werden mit Hilfe der Messkarte von MATLAB aufgezeichnet und in der GUI als Amplituden- und Phasengang darstellt.

20 UART-Kommunikation zwischen Mikro-Controller-Plattform und PC Abbildung 10: MATLAB GUI; rekursives Tiefpass-Filter, Messung Frequenzbereich

Abbildungsverzeichnis 21 6 Abbildungsverzeichnis Abbildung 1: Reihenfolge der Implementierung 4 Abbildung 2:Konfiguration von Timer2, ADC1, DAC1 und der Zusatzbeschaltung 5 Abbildung 3: Implementierung der digitalen Tiefpass-Filter 9 Abbildung 4: Flussidagramm einer Filterimplementierung 9 Abbildung 5: Darstellung des Frequenzverhalten im Zeitbereich 12 Abbildung 6: Darstellung des Frequenzverhaltens mittels FFT 12 Abbildung 7: Konfiguration und Test der USART1-Schnittstelle 13 Abbildung 8: UART-Kommunikation via Hyperterminal 18 Abbildung 9: MATLAB GUI; rekursives Tiefpass-Filter, Messung Zeitbereich 19 Abbildung 10: MATLAB GUI; rekursives Tiefpass-Filter, Messung Frequenzbereich 20

22 Anhang 1: Quellcode 7 Anhang 1: Quellcode #include "stm32f4xx.h" #include <stdio.h> #include "stm32f4xx_dac.h" #include "stm32f4xx_adc.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_dma.h" #include "initdevice.h" #include "Filter.h" #include "stm32f4xx_usart.h" #include "inittypes.h" using namespace inittypes; // Wert der Sprungantwort der via USART an die GUI gesendet wird // 'Zeitbereich' char Ua_Out[5]; // Zähler für die Zeitspanne in der 'Sprungantwort'/'Frequenzgang' aufgezeichnet wird volatile uint16_t i_glob1 = 0; // Zähler um 60/300 Werte (NbrOfSamples) im 'Zeitbereich' via USART an die GUI zu senden volatile uint16_t i_glob2 = 0; // Variablen um die Art der Messung zu definieren volatile bool start_zeitbereich = false; // 'g' (ASCII: 103) volatile bool start_frequenzbereich = false; // 'h' (ASCII: 104) volatile bool zeitbereich_fertig = false; // wird auf 'true' gesetzt, wenn 50/300 Werte (NbrOfSamples) konvertiert wurden // wird auf 'false' gesetzt, wenn 50/300 Werte (NbrOfSamples) via USART versendet wurden // Variablen um 'filter_rec' oder 'moving_avr' zu aktivieren volatile bool moving_avr = false; // 'i' (ASCII: 105) volatile bool filter_rec = true; // 'j' (ASCII: 106) // Variablen, die das Verhalten von 'filter_rec' und moving_avr' definieren // Diese Variablen können via USART von der GUI verändert werden volatile float GF = 0.5; // Gewichtungsfaktor GF von 'filter_rec' volatile int8_t M = 8; // Filterlänge M von 'moving_avr' uint16_t NbrOfSamples = 60; // Anzahl der Abtastwerte der Sprungantwort // Wird je nach Wert von GF zwischen 60 und 300 variiert // Variablen für den ADC-Input und DAC-Output static int16_t in=0; uint16_t out; // Puffer in dem 60/300 Werte (NbrOfSamples) der abgetasteten Sprungantwort gespeichert sind // Werte sind als char[5] gespeichert -> 0.000 char Ua_Out_buffer[300][5]; // Variable um den Ausgang auf 1,5V anzuheben int16_t offset = 0; // DAC Flag bool dacflag; // Testobjekt Filter Filter filter; ////////////////////////////////////////////////// // Funktionen für das Versendet von USART-Daten // ////////////////////////////////////////////////// // 1 Byte versenden void USART_SEND(char byte) USART_SendData(USART1,byte); while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) // Loop until the end of transmission // Wait until Transmission Complete (TC) // Versenden eines Puffers von Bytes void USART_SEND_TEXT(char *buffer) while (*buffer) USART_SEND(*buffer); buffer++;

Anhang 1: Quellcode 23 int main() SystemInit(); initdevice device1; ///// Timer 2 ///// device1.settimer(2); device1.setftimer(22050); device1.settimeroutput(trigger); device1.timerinit(); //44kHz ///// ADC ///// device1.setadc(1); // Wenn ADC1 ausgewählt wird, wird automatisch Kanal 13 festgelegt device1.setadctrigger(timer2adc_trgo); device1.adcinit(); device1.setirqchannel(adcinterrupt); device1.nvicinit(); ///// DAC ///// device1.setdac(1); device1.setdactrigger(none); device1.dacinit(); dacflag=false; ///// USART ///// device1.setusartchannel(1); device1.setusartdmaconnection(usartdmaoff); device1.usartinit(); device1.setirqchannel(usartinterrupt); device1.nvicinit(); ///// Parametrisierung der Zusatzbeschaltung ///// device1.setadcinputpath(1,bypass); device1.setdacoutputpath(1,bypass); while(true) return 0; /*-------ADC Interrupt---------*/ extern "C" void ADC_IRQHandler(void) static uint16_t count_uart = 0; ADC_ClearITPendingBit(ADC1, ADC_IT_EOC); //////////////////////////////////// // Messung: Zeitbereich, Tiefpass // //////////////////////////////////// if( start_zeitbereich == true && start_frequenzbereich == false && filter_rec == true && moving_avr == false) in=1375; out=filter.lowpassorder1(in, GF); snprintf(ua_out,6,"%f",(float)out); // Wandelt '(float)out' in einen String um "0.000" for (int i=0; i<5;i++) Ua_Out_buffer[i_glob1][i] = Ua_Out[i]; i_glob1++; if(i_glob1==nbrofsamples) start_zeitbereich=false; zeitbereich_fertig=true; i_glob1=0; else ////////////////////////////////////////// // Messung: Zeitbereich, Moving Average // ////////////////////////////////////////// if( start_zeitbereich == true && start_frequenzbereich == false && filter_rec == false && moving_avr == true) in=1375; out=filter.movingaverage(in, M); snprintf(ua_out,6,"%f",(float)out); // Wandelt '(float)out' in einen String um "0.000" for (int i=0; i<5;i++) Ua_Out_buffer[i_glob1][i] = Ua_Out[i];

24 Anhang 1: Quellcode i_glob1++; if(i_glob1==nbrofsamples) start_zeitbereich=false; zeitbereich_fertig=true; i_glob1=0; else //////////////////////////////////////// // Messung: Frequenzbereich, Tiefpass // //////////////////////////////////////// if( start_zeitbereich == false && start_frequenzbereich == true && filter_rec == true && moving_avr == false) in=adc1->dr; out=filter.lowpassorder1(in, GF); offset=0; DAC_SetChannel1Data(DAC_Align_12b_R, out+offset); else ////////////////////////////////////////////// // Messung: Frequenzbereich, Moving Average // ////////////////////////////////////////////// if( start_zeitbereich == false && start_frequenzbereich == true && filter_rec == false && moving_avr == true) in=adc1->dr; out=filter.movingaverage(in, M); offset=0; DAC_SetChannel1Data(DAC_Align_12b_R, out+offset); else /////////////////////////////////////////////// // Keine Messung: Nur Filterung mit Tiefpass // /////////////////////////////////////////////// if( start_zeitbereich == false && start_frequenzbereich == false && filter_rec == true && moving_avr == false) in=adc1->dr; out=filter.lowpassorder1(in, GF); offset=0; DAC_SetChannel1Data(DAC_Align_12b_R, out+offset); else ///////////////////////////////////////////////////// // Keine Messung: Nur Filterung mit Moving Average // ///////////////////////////////////////////////////// if( start_zeitbereich == false && start_frequenzbereich == false && filter_rec == false && moving_avr == true) in=adc1->dr; out=filter.movingaverage(in, M); offset=0; DAC_SetChannel1Data(DAC_Align_12b_R, out+offset); /*-------USART Interrupt---------*/ extern "C" void USART1_IRQHandler(void) uint8_t signalfromgui; // 'zeitbereich_fertig' -> Es wurden 50/300 Werte (NbrOfSamples) aufgezeichnet // Diese Werte werden via USART an die GUI gesendet // In diesem Zeitraum wird der ADC1 inaktiv geschaltet (DISABLE) if (zeitbereich_fertig) ADC_Cmd(ADC1,DISABLE); if (i_glob2<nbrofsamples) USART_SEND(Ua_Out_buffer[i_glob2][0]); USART_SEND(Ua_Out_buffer[i_glob2][1]); USART_SEND(Ua_Out_buffer[i_glob2][2]); USART_SEND(Ua_Out_buffer[i_glob2][3]); USART_SEND(Ua_Out_buffer[i_glob2][4]); i_glob2++;

Anhang 1: Quellcode 25 // Wenn 50/300 Werte (NbrOfSamples) gesendet wurden wird als Schlusszeichen ':' gesendet // ADC1 wird daraufhin wieder aktiv geschalten (ENBALE) if(i_glob2==nbrofsamples) USART_SEND(':'); ADC_Cmd(ADC1,ENABLE); i_glob2=0; zeitbereich_fertig=false; start_zeitbereich=false; // RXNE == 0 -> RESET -> Es wurden keine Daten empfangen // RXNE!= 0 -> Es wurden Daten empfangen und diese können gelesen werden if(usart_getitstatus(usart1, USART_IT_RXNE)!= RESET) // Pendig Bit 'USART_IT_RXNE' löschen USART_ClearITPendingBit(USART1,USART_IT_RXNE); signalfromgui = (USART_ReceiveData(USART1) & 0x7F); // In der GUI wurde Sprungantwort ausgewählt 'g' if(signalfromgui==103) // 50/300 Werte (NbrOfSamples) aufzeichnen und via USART and die GUI senden filter.resetfiltercoefficients(); start_zeitbereich=true; start_frequenzbereich=false; // In der GUI wurde Frequenzgang ausgewählt 'h' else if(signalfromgui==104) if(start_frequenzbereich==false) start_frequenzbereich=true; else start_frequenzbereich=false; start_zeitbereich=false; filter.resetfiltercoefficients(); // In der GUI wurde im Dropdownmenü 'Moving Average' ausgewählt 'i' else if(signalfromgui==105) filter.resetfiltercoefficients(); moving_avr=true; filter_rec=false; // In der GUI wurde im Dropdownmenü 'Tiefpassfilter' ausgewählt 'j' else if(signalfromgui==106) filter.resetfiltercoefficients(); filter_rec=true; moving_avr=false; // Der Wert für GF oder M wurde in der GUI verändert // Der Datentyp des empfangenen Wertes wird angepasst // Die Anzahl der Abtastwerte der Sprungantwort wird definiert (50/300) else if((signalfromgui>=0)&&(signalfromgui<=100)) if((filter_rec==true)&&(moving_avr==false)) GF=((float)signalFromGUI/100); // 0/100 = 0 // 50/100 = 0.5 // 100/100 = 1 if(gf<=0.9) NbrOfSamples=60; else if((gf>0.9)&&(gf<=1)) NbrOfSamples=300; else if((filter_rec==false)&&(moving_avr==true)) M=(int8_t)((uint8_t)signalFromGUI-65); //(66-65) = 1 //(75-65) = 10 //(81-65) = 16 NbrOfSamples=60;