Projekt: Mikroprozessortechnik

Ähnliche Dokumente
Zusammenfassung der Assemblerbefehle des 8051

Übungen für die Einführung in die Assemblerprogrammierung mit dem Prozessor c515c

MOP: Befehlsliste für den Mikrocontroller 8051

Zähler- und Zeitgeber-Baugruppen

Befehlssatz der Mikrocontroller der 51er -Familie

Befehlssatz der Mikrocontroller der 51er -Familie

LCD-Display am MVUS (nur einfachste Betriebsweise im Text Display Modus - ausführliche Beschreibung )

Student: Alexander Carls Matrikelnummer: Aufgabe: Beschreibung des euklidischen Algorithmus Datum:

3 Rechnen und Schaltnetze

Praktikum Mikrorechner 8 (Pulsweitenmodulation und Automaten)

1. Keil starten. Sollten Sie keinen leeren Bildschirm haben, löschen Sie einfach die

Speicheraufbau des AT89C5131

D.1 Vorbereitung. Teil D Analog-Digital-Wandler 1

Praktikum Mikrorechner 4 (Bitmanipulation und Spezialregister)

Fingerpulsoximeter. 1. Wie führe ich eine Echtzeitübertragung vom PULOX PO-300 zum PC durch und speichere meine Messdaten auf dem PC?

16-Bit PCA Timer/Counter

Microcontroller Praktikum SS2010 Dipl. Ing. R. Reisch

Rechnergrundlagen SS Vorlesung

Programmierung von ATMEL AVR Mikroprozessoren am Beispiel des ATtiny13. Teil 8: gavrasmw und weitere Beispiele

Aufgabe 2 -Grafische Messwertdarstellung. Labor Mikrocontroller mit NUC130. Prof. Dr.-Ing. F. Kesel Dipl.-Ing. (FH) J.Hampel Dipl.-Ing. (FH) A.

MikroController der 8051-Familie

Technische Informatik für Ingenieure Winter 2005/2006 Übungsblatt Nr. 3

Temperaturmessung mit dem ATmega8

Abbildung 4-9-1: Die Sound-Machine-Tastatur und der Arduino

2

Erste Schritte ACOSAnalyze II

Komponenten eines Mikrocontrollers

4 Assembler für die 8051-Controller-Familie

Anleitung zum Ausführen der vier Grundrechenarten mit dem russischen Abakus ( Stschoty )

Hans-Böckler-Stiftung Ein schneller Einstieg in Bilanzanalyse für Windows

Analog-Digital-Converter

D i g i t a l l a b o r

LCD-Ansteuerung mit MikroForth

= 7 (In Binärdarstellung: = 0111; Unterlauf) = -8 (In Binärdarstellung: = 1000; Überlauf)

Digital-Wandlung. Transferierung von Daten aus der realen (analogen) Welt in die (digitale) Welt des Rechners.

PO-250. Fingerpulsoximeter. 1. Wie führe ich eine Echtzeitübertragung vom PULOX PO-250 zum PC durch und speichere meine Messdaten auf dem PC?

Kapitel 3: Variablen

4-Kanal-Analoglogger für die Regelungstechnik

Benutzerhandbuch. ce - Inspector

Sportprogramm. Stoppuhr. Benutzerhandbuch

Um Werte und deren Verlauf in einer Grafik darzustellen, benutzen wir eine Tabellenkalkulation wie Excel oder das Tabellendokument von Open Office.

$NOMOD51 $INCLUDE (reg515.inc) ; Ein Zeichen auf Tastendruck S1 senden...

Rechnergrundlagen SS Vorlesung

Dateien, die nicht in das Projekt eingebunden sind, werden ohne Syntax highlight dargestellt. MiCoWi und µvision Seite 1 Uwe Wittenfeld

Durch das Borgen steht an der Zehner-Stelle jetzt nur noch eine 1 statt einer 2

Mini-FAQ v1.3 CMS-50E. Fingerpulsoximeter

Inhaltsangabe 3.1 Zahlensysteme und Darstellung natürlicher Zahlen Darstellung ganzer Zahlen

Projektdokumentation: DCF 77 Funkuhr

Kurzanleitung für den MyDrive Client

Mikrocontrollertechnik

Eigenschafte: Konfiguration: Baudrate:

SVG Maut Exact. SVG Wir bewegen Logistik

Reziprok Zähler mit 9-stelliger Anzeigegenauigkeit 10 Hz 1300 MHz

GI Vektoren

11. Die PC-Schnittstelle

PIC16 Programmierung in HITECH-C

B1 Stapelspeicher (stack)

EDT-REFERAT Adressierungsarten

Eclipse Tutorial.doc

V cc. 1 k. 7 mal 150 Ohm

Er ermöglicht die Suche nach allen verfügbaren Informationen, die in diesem Feld eingetragen werden können (z. B. Kontonummer, Artikelname usw.).

Gegenüberstellung von Assembler- und C-Programmierung

Installationshandbuch für das Word Plugin

2017/01/23 15:50 1/5 Bedienung

AVR-Mikrocontroller in BASCOM programmieren, Teil 2

Visual Basic Editor CATIA V5

ELBA-business Anzeige von Belegen/Images in ELBA 5.6.0

Die Benutzung von Stata

Tutoraufgabe 1 (Zweierkomplement): Lösung: Programmierung WS16/17 Lösung - Übung 2

C/C++ Debugging mit CDT unter Eclipse

eoslogistics Anleitung / Systemvoraussetzungen innight.web processing solutions eoscop gmbh Im Kugelfang 38 CH-4102 Binningen

Anleitung um Lieder in 432Hz Kammerton umzuwandeln

Observer. Handbuch. Handbuch Observer. Abbildung: Beispiel Observer. Abbildung: Beispiel Touchinterface

1 Excel Schulung Andreas Todt

Anwendungen der Mikrocontrollertechnik

Anpassen BS-Explorer

Da der Mikrocontroller mit den internen Timern sehr genau Zeiten messen kann, entschieden wir uns für die Zeitmessung.

Teledyne LeCroy - WaveSurfer Arbiträr-Generator

E Mikrocontroller-Programmierung

Der CodeBug. A) Erste Schritte. 1) Einleitung

Leitfaden für Online-Datenrecherche (STAT-TAB)

Operationsmodi des Timers Modus 0 : Ausschalten des Zählers

Easy-One. Controller. Bedienungsanleitung. Ab Version Internet:

Assembler DOS (Beta 1) Copyright 2000 Thomas Peschko. Assembler II - DOS. ASSEMBLER Arbeiten mit Dateien und Daten.

Verarbeiten von Analogwerten

Durch das Borgen steht an der Zehner-Stelle jetzt nur noch eine 1 statt einer 2

Rechnergrundlagen SS Vorlesung

Anleitung für die Installation des USB Netzwerkkabels unter WIN2000 :

(BG Rechte Kremszeile, Version 1.0, Schuljahr 2007/08, remastered von Mag. Dr. Klaus Misof)

LED Skalenbeleuchtung mit einem Arduino

Innovator 11 excellence. Anbindung an Visual Studio. Einführung, Installation und Konfiguration. Connect. Roland Patka.

Kurzanleitung Hama Photokalender v

Steffen Weißer Juni 2003 TG 12/3

Vorbemerkungen. Die Programmieroberfläche des ClassPad

Das Bundesland wechseln: (in der Demoversion nicht möglich) Klicken Sie auf Extras / Optionen Anschließend auf den Reiter Ferienordnung

Transkript:

Berufsakademie Stuttgart - Außenstelle Horb Staatliche Studienakademie University of Cooperative Education Projekt: Mikroprozessortechnik Messung von Blutdruck und Herzfrequenz P r o t o k o l l z u m P r o g r a m m e n t w u r f Autor Dozent Alexander Carls Prof. H. Trück Version Datum Ersteller / Bearbeiter 1.0 23.05.08 Alexander Carls

2 Inhalt 2. Allgemeiner Programmablaufplan...3 3. Programmspeicherplan...4 4. Interner Speicherplan...5 5. Externer Speicherplan...7 6. Grundlegende Überlegungen zur Ermittlung und Berechnung der geforderten Werte...7 6.1 Herzfrequenz...7 6.2 Systole / Diastole...8 7. Division...9 7.1 16 Bit / 16 Bit Divison durch Subtraktion...9 7.2 16 Bit / 8 Bit Division...11 8. Erkennung von Systole und Diastole...12 9. Mittelwertberechnung...16 10. Initialisierungen...17 11. ASCII Ausgabe:...18 11.1 Ausgabe der Herzfrequenz...18 11.2 Ausgabe des Blutdrucks...21 12. Timer2 Interrupt...22 13. Externe Interrupts...24 13.1 Externer Interrupt 3 Herzschlagflankenerkennung...24 13.2 Externer Interrupt 6 Taster für Mittelwertausgabe...26 14. A/D Messung mit 10 Bit Auflösung...29 15. Tests...32 15.1 C-Code für Logic Analyzer...32 16.2 Teststrategie...34 17. Bedienungsanleitung...35 18. Abschluss...39 18.1 Warum kein Unterprogramm für 16 Bit Division und ASCII Ausgabe?...39 18.2 Fazit...40 18.3 Quellenangabe...40

3 2. Allgemeiner Programmablaufplan Grafik 1.0: Allgemeiner PAP

4 3. Programmspeicherplan Adresse Kommentar 0000H 0001H Überspringe die Interruptadressbereiche 0002H - 002AH frei 002BH 0043H Timer2 Interruptroutine 0044H 0052H frei 0053H 0059H Externer Interrupt 3 Routine (Teil 1) 0060H 006AH frei 006BH 00CEH Externer Interrupt 6 Routine 00CFH 03FFH frei 0400H 0414H Fortführung der Interrupt 3 Routine, da erster Teil sonst in anderen Interrupt überläuft (Teil 2) 0415H 05FFH frei 0600H 063BH Initialisierung und Warten auf A/D Wandlungsergebnis (Hauptprogramm) 063CH 06FF frei 0700H 072BH Unterprogramm zur Berechnung der Herzfrequenz 072CH 08FFH frei 0900H 0905H Unterprogramm zur Initialisierung des A/D Wandlers 0906H 0FFFH frei 1000H 1048H Unterprogramm zur Durchführung der 10 Bit Analogmessung 1049H 11FFH frei 1200H 1259H Unterprogramm zur Erkennung von Systole bzw. Diastole 125AH 12FFH frei 1300H 1318H Unterprogramm zur Ausgabe der Herzfrequenz als ASCII-Symbole 1319H 13FFH frei 1400H 143DH Unterprogramm zur Ausgabe des Blutdrucks bzw. der Systole / Diastole als ASCII- Symbole Rest frei

5 4. Interner Speicherplan R1 Low Byte der Timerüberläufe in einem Zyklus R2 Zwischenspeicher für High-Byte von 60 Sek der Herzfrequenzberechnung R3 Speichert das Ergebnis für den hochgerechneten Wert der Herzfrequenz R4 Zwischenspeicher zur Überprüfung ob die Anzahl der mitgeloggten Werte > 250 ist / Zwischenspeicher für Low-Byte von 60 Sek der Herzfrequenzberechnung R5 Zwischenspeicher für Akkuinhalt R6 Beinhaltet Wert der in ASCIIAusgabeBlutdruck beim Aufruf ausgegeben werden soll R7 High Byte der Timerüberläufe in einem Zyklus 20H.1 Flag das anzeigt ob erste A/D Messung bereits durchgeführt wurde 21H Zwischenspeicher für High Byte des Analogwertes 22H Zwischenspeicher für Low Byte des 23H Analogwertes Speicher für High Byte des aktuellen Analogwertes 24H Speicher für Low Byte des aktuellen Analogwertes 27H Speichert die Adresse auf, die die ASCIIBlutdruckAusgabe schreiben soll (Indirekte Adressierung) 28H.0 Toggle Bit das anzeigt, ob Mittelwertausgabe aktiv ist oder nicht 28H.3 Flag das anzeigt, ob Systole bzw. Diastole in diesem Zyklus schon gefunden wurde 28H.4 Zwischenspeicher für Carry in Timer2 Interrupt 28H.5 Zwischenspeicher für Carry in externen Interrupt 6 28H.6 Flag zeigt an, ob bereits mehr als 250 Werte mitgeloggt wurden 28H.7 Flag, dass anzeigt, ob Blutdruck noch von Volt in mm Hg umgerechnet werden muss oder nicht 29H.1 Zwischenspeicher für Carry 2BH Zwischenspeicher für Akku in externer Interrupt 6 30H Speicher für High Byte des letzten gemessenen Analogwertes 31H Speicher für Low Byte des letzten gemessenen Analogwertes 32H Zwischenspeicher für Akku in Timer2 Interrupt

6 35H Ausgabe: H 36H Ausgabe: F 37H Ausgabe: : 38H Ausgabe: Höchste Stelle der Herzfrequenz 39H Ausgabe: Mittlere Stelle der Herzfrequenz 3AH Ausgabe: Niederste Stelle der Herzfrequenz 3CH Ausgabe: S 3DH Ausgabe: Y 3EH Ausgabe: : 3FH Ausgabe: Höchste Stelle der Systole 40H Ausgabe: Mittlere Stelle der Systole 41H Ausgabe: Niederste Stelle der Systole 43H Ausgabe: D 44H Ausgabe: I 45H Ausgabe: : 46H Ausgabe: Höchste Stelle der Diastole 47H Ausgabe: Mittlere Stelle der Diastole 48H Ausgabe: Niederste Stelle der Diastole 4AH Ausgabe: B 4BH Ausgabe: D 4CH Ausgabe: : 4DH Ausgabe: Höchste Stelle des Blutdrucks 4EH Ausgabe: Mittlere Stelle des Blutdrucks 4FH Ausgabe: Niederste Stelle des Blutdrucks 50H Pointer (Low Byte) für aktuelle externe Speicheradresse. Wird bei jedem Herzschlag um 1 erhöht und bei 250 zurück gesetzt 51H Pointer (High Byte) für aktuelle externe Speicheradresse. Wird bei jedem Herzschlag um 1 erhöht und bei 250 zurück gesetzt 5CH Zwischenspeicher für Wert in Register R6 6BH Speichert Low-Byte der Addition aller Messergebnisse für Mittelwertberechnung 6CH Speicher High Byte der Addition aller Messergebnisse für Mittelwertberechnung 6EH Speicheradresse von der aus gelesen wird, wenn die ASCIIAusgabeHerzfrequenz aufgerufen wird.

7 5. Externer Speicherplan Adresse Kommentar 0000H 00FFH Frei 0100H 01FAH Beinhaltet die letzten 250 gemessenen Herzfrequenzen zur späteren Mittelwertberechnung 01FBH- 01FFH Frei 0200H 02FAH Beinhaltet die letzten 250 ermittelten Systolen zur späteren Mittelwertberechnung 02FBH 02FFH Frei 0300H 03FAH Beinhaltet die letzten 250 ermittelten Diastolen zur späteren Mittelwertberechnung Frei Frei 6. Grundlegende Überlegungen zur Ermittlung und Berechnung der geforderten Werte 6.1 Herzfrequenz Die Messung der Herzfrequenz erfolgt nach folgendem Schema: 1. Warte Positive Flanke der Herzfrequenz ab 2. Messe Zeit zwischen erster erfasster positiver Flanke und zweiter erfasster positiver Flanke 3. Messe die Zeit mit einer Genauigkeit von 1 ms 4. Rechen hoch welcher Anzahl Schläge pro Minute die gemessene Zeit entspricht 5. Beginne von Neuem Bei der Bestimmung der Herzfrequenz gab es zwei grundlegende Ideen. Zum einen die Messung der Herzschläge über einen bestimmten Zeitraum, z.b. 15 Sekunden und dann Multiplikation der gemessenen Anzahl Herzschläge mit vier. Zum anderen Messung der Zeit von einem Herzschlag zum nächsten und dann Hochrechnung der gemessenen Zeit auf eine Minute. Da es bei der ersten Möglichkeit zwar höchstwahrscheinlich zu genaueren Ergebnissen gekommen wäre, man aber verhältnismäßig lang auf das erste Ergebnis hätte warten müssen, wurde die zweite Methode zur Messung gewählt. Dazu wird mit einem Timer die Zeit zwischen zwei Impulsen auf 1 ms genau gemessen. Das Ergebnis hätte noch genauer gemessen werden können, hätte aber einen bedeutend höheren Aufwand nach sich gezogen, da mehr als zwei Register für das Zählen der Überläufe nötig gewesen wären und die anschließenden Rechnungen somit weiter verkompliziert hätte. Der Wahl der Genauigkeit liegt folgende Berechnung zu Grunde: Maximale Anzahl Herzschläge pro Minute: 250 Minimaler Zeitabstand zwischen zwei Herzschlägen: 60 s / 250 = 240 ms Zeitabstand zwischen zwei Herzschlägen bei 249 Hz: 60 s / 249 = 240, 96 ms Maximale Veränderung der Herzfrequenz in 1 ms: 240,96 240 = ca. 1 Man erkennt deutlich, dass bei dieser Messgenauigkeit, das Ergebnis wenn überhaupt nur leicht verfälscht wird und diese Verfälschung im Vergleich zum Mehraufwand durch eine höhere Genauigkeit hinnehmbar ist. Mit einer Messgenauigkeit von 1 ms kann das Ergebnis

8 nur in sehr seltenen Fällen um maximal einen Schlag pro Minute verfälscht werden. Für die Hochrechnung wird anschließend 60000 / die Anzahl der gemessenen Überläufe gerechnet. Dies hat folgenden Grund: 1 Minute = 60 sekunden = 60000 ms 60000 / Anzahl gemessener Überläufe = Herzfrequenz +/ - 1 Schlag 6.2 Systole / Diastole Bei den Überlegungen zur Erfassung der Systole bzw. der Diastole ging es weniger um Messgenauigkeit, da diese von der 10 Bit Auflösung des A/D Wandlers beschränkt ist, als viel mehr um die Frage, wie der Programmablauf auszusehen hat um mögliche Unregelmäßigkeiten im Blutdrucksignal auszufiltern. Um dies zu gewährleisten gab es zwei mögliche Ansätze: 1. Bei der Kontraktion (erkennbar am Highpegel des Herzfrequenzsignals) werden alle Messwerte des A/D Wandlers mitgeschrieben und anschließend (beim Übergang in den Lowpegel des Herzfrequenzsignals) alle Werte miteinander verglichen. Der höchste gefundene Wert würde so der Systole bzw. der niedrigste Wert der Diastole entsprechen 2. Ab Beginn der Kontraktion wird immer der neuste gemessene A/D Wert mit dem zuletzt gemessenen verglichen. Sollte der neue Wert größer sein als der alte, so befindet sich die Blutdruckkurve noch in der Steigung. Sollte er jedoch kleiner sein, so ist klar, dass der zuletzt gemessene Wert der Systole entspricht und nun bis zum nächsten Highpegel aufgehört werden kann, die A/D Messwerte miteinander zu vergleichen (umgekehrtes gilt für die Diastole). Da der Vergleich aller gemessenen A/D Werte einen enormen Verbrauch zeitlicher Ressourcen des Mikrocontrollers bedeuten würde und man zudem nicht die Wandlungszeit, die nach dem Finden der Diastole bzw. Systole nicht mehr benötigt wird, gespart hätte kam in der Umsetzung des Programms die 2. Möglichkeit zum Einsatz. Diese Möglichkeit hat jedoch einen großen Nachteil: Höcker die vor der eigentlichen Systole / Diastole auftreten werden mit diesem Verfahren als Systole bzw. Diastole erkannt und eine Erkennung des eigentlichen Wertes verhindert. Diese Methode konnte deshalb nur aufgrund der Tatsache, dass laut Aufgabenstellung die Erkennung solcher Höcker vor dem eigentlichen Wert nicht gefordert wird, eingesetzt werden.

9 7. Division 7.1 16 Bit / 16 Bit Divison durch Subtraktion Der folgende Abschnitt erläutert die Vorgehensweise zur Durchführung einer 16 Bit Division auf einem 8 Bit Mikroprozessor. Hierzu wurde nicht das durch den Dozenten zur Verfügung gestellte Unterprogramm von Thomas Umbeer verwendet, sondern eine eigene Routine entworfen. Programmcode: ErneuteDivision: CLR C MOV A, R2 SUBB A, R7 MOV R2, A JC EndeDivison MOV A, R4 SUBB A, R1 MOV R4, A INC R3 JNC ErneuteDivision CLR C DJNZ R2, ErneuteDivision EndeDivison:

10 Grafik 1.1: PAP zur 16 Bit / 16 Bit Divison

11 Da es das Ziel dieser 16 Bit Division ist, hochzurechnen wie viele Schläge bei gleichbleibender Herzschlagdauer pro Minute erfasst würden, muss zu Beginn des Programmteils der Wert 60000 in das Register R2 sowie R4 geschrieben werden. Wie bereits in Kapitel 6 hergeleitet, wird der Wert 60000 geladen, da dieser die Zeit von 60 Sekunden bei einer Messgenauigkeit von 1 ms repräsentiert. Im ersten Schritt wird nun das High Byte des gemessenen Zeitwerts, das sich im Register R7 befindet, vom High-Byte der 60000 ms abgezogen und anschließend überprüft, ob das Carry gesetzt ist. Sollte dies der Fall sein so ist klar, dass die gemessene Zeit größer ist als 60 Sekunden (bzw. dem davon noch verbleibenden Wert bei erneuter Subtraktion). Das Register R3 ist dafür zuständig die Anzahl der Subtraktionen mitzuzählen und repräsentiert gleichzeitig nach Beendigung der Subtraktion das Ergebnis der Division. Sollte nun die High-Byte Subtraktion ergeben haben, dass die Hochzählung noch nicht bei 60 Sekunden angekommen ist, so wird noch das Low-Byte der gemessenen Zeit vom Low-Byte von 60 Sekunden bzw. dessen Rest abgezogen. Anschließend wird über JNC abgefragt, ob es durch die Subtraktion zu einem Unterlauf des Akkus kam. Sollte dies der Fall sein, so dient das Carry als Indikator hierfür. Sollte es zu einem Unterlauf gekommen sein, so wird zuerst das Carry für die nächste Subtraktion zurück gesetzt und anschließend der durch den Unterlauf entstandene Übertrag in der Subtraktion durch das dekrementieren des High-Bytes von 60000 durchgeführt. Durch den Befehl DJNZ wird gleichzeitig zum Dekrementieren abgeprüft, ob das High Byte bereits null ist, sollte dies der Fall sein so ist die Division beendet, andernfalls beginnt die Subtraktion durch einen Sprung zum Label ErneuteDivision von vorne. Sollte es nicht zu einem Unterlauf gekommen sein, so wird sofort zum Label ErneuteDivision gesprungen. Berechnung der Worst-Case Laufzeit der Division: Minimale Herzschlagdauer: 60 s / 250 = 240 ms Maximale Anzahl Subtraktionsschritte: 60000 / 240 = 250 Worst-Case Laufzeit einer einzigen Division = 14 µs Worst-Case Gesamtlaufzeit: 14 µs * 250 = 3,5 ms 7.2 16 Bit / 8 Bit Division Dieser Abschnitt ist als kurze Erläuterung der 16 / 8 Bit Division gedacht und zeigt kurz die Unterschiede zur 16 / 16 Bit Division. Programmcode: ErneuteDivision2: SUBB A, 50H INC R7 JNC ErneuteDivision2 CLR C DJNZ 6CH, ErneuteDivision2 DEC R7

12 Dieser Programmcode kommt bei der Berechnung des Mittelwertes zum Einsatz. Hier wird aufgrund der kürzeren Laufzeit (siehe Laufzeitberechnung) auf die 16 / 8 Bit Division zurückgegriffen. Dies wird dadurch möglich, dass bekannt ist, dass der Divisor dieser Division nicht größer als 250 sein kann, und diese Zahl in einem Byte abspeicherbar ist. Bei dieser Division wird folgendermaßen vorgegangen: - Subtrahiere Anzahl der Messwerte vom Low-Byte der addierten Messwerte - Inkrementiere das Divisionsergebnis - Prüfe ob es zu einem Unterlauf bei der Subtraktion kam - Wenn ja, dekrementiere das High-Byte der addierten Messwerte, wenn nein beginne von vorne - Prüfe ob High-Byte der addierte Messwerte = 0, wenn ja ist Division beendet, wenn nein beginne von vorne. Laufzeitberechnung: Worst-Case Laufzeit einer einzigen Division = 7 µs Worst-Case Gesamtlaufzeit: 7 µs * 250 = 1,75 ms 8. Erkennung von Systole und Diastole Dieser Abschnitt beschäftigt sich mit der Umsetzung der im Abschnitt 7 vorgestellten Überlegung zur Erkennung der Systole bzw. Diastole. Programmcode: ORG 1200H GrosserKleinerVergleich: JNB 28H.3, SystoleNichtGefunden CLR C JB I3FR, Diastole MOV A, 21H CJNE A, 23H, HighByteUngleich JMP HighByteGleich HighByteUngleich: JNC SystoleNichtGefunden JMP Gefunden HighByteGleich: MOV A, 22H CJNE A, 24H, LowByteUngleich JMP SystoleNichtGefunden LowByteUngleich: JNC SystoleNichtGefunden JMP Gefunden Diastole: MOV A, 21H CJNE A, 23H, HighByteUngleich2 JMP HighByteGleich2 ; HighByteUngleich2: JNC DiastoleGefunden JMP SystoleNichtGefunden

13 HighByteGleich2: MOV A, 22H CJNE A, 24H, LowByteUngleich2 JMP SystoleNichtGefunden LowByteUngleich2: JNC DiastoleGefunden JMP SystoleNichtGefunden DiastoleGefunden: MOV 30H, 23H MOV 31H, 24H MOV 27H, #046H MOV 51H, #03H JB 28H.0, MittelwertAktiv2 CALL ASCIIAusgabeBlutdruck MittelwertAktiv2: CLR 28H.3 JMP SystoleNichtGefunden Gefunden: MOV 30H, 23H MOV 31H, 24H MOV 27H, #03FH MOV 51H, #02H JB 28H.0, MittelwertAktiv3 CALL ASCIIAusgabeBlutdruck MittelwertAktiv3: CLR 28H.3 SystoleNichtGefunden: RET

14 Grafik 1.2: PAP zum Unterprogramm zur Erkennung der Systole / Diastole

15 Vor dem Beginn der eigentlichen Erkennung des Extremwertes wird das Flag 28H.3 abgefragt. Dieses Flag zeigt an, ob in diesem Zyklus bereits die Systole bzw. Diastole gefunden wurde oder nicht. Dazu wird dieses Flag vom Interrupt 3 bei jeder steigenden oder fallenden Flanke des Herzsignals gesetzt und später im obigen Programmteil zurück gesetzt, falls eine Diastole / Systole gefunden wurde. Anschließend wird mit JB das Bit I3FR abgefragt. Dieses Bit ist dafür zuständig dem Interrupt 3 mittzuteilen, ob er bei einer positiven oder negativen Flanke ausgelöst werden soll. Gleichzeitig dient es hier als Indikator dafür, ob nach einer Systole oder nach einer Diastole gesucht werden soll. Die nun folgenden Sprungpunkte verlaufen für Systole und Diastole nahezu gleich, nur eben mit dem Unterschied, dass die abgefragte Richtung der Steigung invertiert ist. Darum soll im folgenden nur der Abschnitt zur Erkennung der Systole erläutert werden: Dazu wird zuerst das High Byte des aktuellen A/D Wandler Ergebnisses aus dem internen Speicher (siehe Speicherplan) geladen und anschließend mit dem über CJNE des zuletzt gemessenen A/D Wandler Ergebnisses verglichen. Um den nun folgenden Teil zu verstehen sind Kenntnisse über die Auswirkungen des CJNE Befehls nötig. Dazu folgende Erläuterung: Ist der Wert der im Akku steht größer als der Vergleichswert der mit CJNE überprüft wird so wird bei der Überprüfung das Carry gesetzt. Ist der Wert kleiner so wird das Carry gelöscht. Dieses Besonderheit macht sich der Programmteil zu nutze. Er vergleicht über CJNE, ob die beiden High Bytes gleich sind, sollte dies der Fall sein so werden anschließend die beiden Low-Bytes miteinander verglichen. Sollte der neue Wert jedoch größer sein, so ist das Carry ein Indikator hierfür und wird darum anschließend mit JNC abgeprüft. Sollte das Carry nicht gesetzt sein so wird der zuvor gemessene Wert als Systole eingetragen, sollte das Carry jedoch gesetzt sein so bedeutet dies, dass der neue gemessene Wert größer ist als der zuvor gemessene Wert und somit, dass in diesem Zyklus keine Systole gefunden wurde. Diese Vorgehensweise gilt Analog für die Überprüfung der Low-Bytes, falls die High-Bytes gleich gewesen sein sollten. Sollte eine Systole gefunden worden sein so wird zum Label Gefunden gesprungen, welches die Ergebnis wegspeichert (siehe Speicherplan) und anschließend das Unterprogramm zur Ausgabe der Werte auf dem Display (bzw. internen Speicher) aufruft.

16 9. Mittelwertberechnung Dieser Abschnitt beschäftigt sich mit der Speicherung der für den Mittelwert benötigten Werte, sowie mit der allgemeinen Idee hinter der Mittelwertberechnung. Programmcode: Herzfrequenzberechnung:. MOV DPH, #01H MOV DPL, 50H MOV A, R3 MOVX @DPTR, A ASCIIAusgabeBlutdruck: MOV DPH, 51H MOV DPL, 50H MOV A, R6 MOVX @DPTR, A Die Abspeicherung der Herzfrequenz erfolgt sofort nach der Berechnung der selbigen (siehe Abschnitt 7). Dazu wird das High Byte des DPTR (DPH) mit dem Wert 1 besetzt. Dies hat den Grund, dass im externen RAM von der Speicheradresse 100H bis 1FAH die Messwerte für die Herzfrequenz abgelegt werden sollen. Zudem ist es durch die Aufteilung des High Bytes in 1,2 und 3 einfacher eine Schleife für die Auswertung der drei Mittelwerte zu schreiben (siehe Interrupt 6 Routine). Das Low Byte des DPTR wird mit der aktuellen Herzschlagzahl, bzw. dem Pointer für den externen RAM geladen. Dieser Pointer wird nach jedem Herzschlag um eins erhöht (siehe Interrupt 3). Nun wird der zu speichernde Messwert der in Register R3 steht in den Akku geschrieben und selbiger dann über MOVX in den externen Speicher geschrieben. Das Prinzip beim Speichern der Systole und Diastole ist gleich, mit dem Unterschied dass hier nicht sofort nach der Erfassung des Analogwertes in den externen Speicher geschrieben wird, sondern erst nachdem erkannt wurde, dass es sich um einen Extremwert handelt und was ganz wichtig ist: Erst nachdem dieser in die Einheit mm Hg umgerechnet wurde. Das heißt das Speichern der Systole und Diastole erfolgt mit den DPH Werten 2 und 3 erst nachdem im Unterprogramm ASCIIAusgabeBlutdruck die Voltzahl in einen Blutdruck gewandelt wurde. Grund hierfür ist der zusätzliche Speicher, der benötigt würde um den 10 Bit breiten Analogwert zu speichern. Die gemessenen Werte werden nun auf die soeben dargestellte Weise einmal pro Herzschlag abgespeichert und alle 250 Herzschläge wird von neuem begonnen. Das heißt, dass im schlimmsten Falle mindestens die Messwerte der letzten Minute verfügbar sind. Der Mittelwert wird nun wie das arithmetische Mittel in der Mathematik berechnen: (Messwerte) / Anzahl Messwerte Das heißt es werden alle Messwerte einer Messreihe (also z.b. Herzfrequenz) aus dem externen RAM geholt und addiert und anschließend durch die Anzahl der geholten Messwerte geteilt.

17 10. Initialisierungen Dieser Abschnitt beschäftigt sich kurz mit den Initialisierungen die zu Beginn des Programmes einmal durchgeführt werden um die einzelnen Mikrocontrollerteile auf ihre Funktion vorzubereiten. Programmcode: SETB IEN1.2 SETB IEN0.5 SETB IEN1.5 SETB EAL SETB T2I0 SETB T2R1 MOV TH2, #00FCH MOV TL2, #0017H MOV 35H, #048H MOV 36H, #046H MOV 37H, #03AH MOV 3CH, #053H MOV 3DH, #059H MOV 3EH, #03AH MOV 43H, #044H MOV 44H, #049H MOV 45H, #03AH MOV 4AH, #042H MOV 4BH, #044H MOV 4CH, #03AH Zu Beginn erfolgt die Freigabe des externen Interrupt 3. Dieser wird durch eine positive oder negative Flanke am Pin 1.0 ausgelöst und dient als Eingang für das Herzfrequenzsignal. Darauf gefolgt wird der Timer2 Interrupt freigegeben, der durch einen Überlauf des Timers ausgelöst wird und innerhalb der Interruptroutine von Hand zurückgesetzt werden muss. Als letzter Interrupt wird der Interrupt 6 freigegeben, der als Eingang für einen Taster dient, der die Aufgabe hat dafür zu sorgen, dass sobald die Taste gedrückt wird, ein Mittelwert der Systole, Diastole sowie der Herzfrequenz ausgegeben wird. Nun wird der Startwert für den Timer2 gesetzt. Dieser wird auf 64535 gesetzt, was einer Überlaufzeit von 1 ms entspricht. Darauf gefolgt wird die Ausgabe der einzelnen Zeichen auf dem Display gestartet. Dazu wird an die entsprechende Stelle im internen Speicher (siehe Speicherplan) der Wert für das auszugebende Zeichen nach ASCII-Codierung (siehe ASCII- Tabelle weiter unten) geschrieben. Nach der kompletten Initialisierung des Displays befindet sich also folgende Zeichenfolge im internen Speicher: HF: SY: DI: BD: Diese Zeichen stehen für die Abkürzungen von Herzfrequenz, Systole, Diastole und Blutdruck.

18 Die Initialisierung wird daraufhin von einem Unterprogrammaufruf der für die Initialisierung des A/D Wandlers zuständig ist, gefolgt. Programmcode: AnalogmessungInitialisieren: ANL ADCON, #11110000b SETB ADCON.0 MOV DAPR, #0 RET Innerhalb der A/D Wandler Initialisierung wird zuerst das untere Nibble des ADDCON Registers auf null gesetzt um anschließend das Bit 0 des selben Registers zu setzen. Dies bewirkt, dass die Analogmessung auf dem Pin AIN1 durchgeführt wird. Anschließend wird durch das Rücksetzen des DAPR Registers die Analogmessung gestartet. 11. ASCII Ausgabe: Die Ausgabe der ermittelten Messwerte erfolgt in zwei Unterprogrammen (siehe Programmspeicherplan). Zwei deshalb, weil bei der Ausgabe der A/D Werte zuvor im selben Unterprogramm noch eine Umrechnung von Volt in mm Hg stattfindet um so dem Blutdruckmessenden eine Ausgabe zu ermöglichen mit der er etwas anfangen kann. 11.1 Ausgabe der Herzfrequenz Programmcode: ORG 1300H ASCIIAusgabeHerzfrequenz: MOV B, #100D MOV A, 6EH DIV AB ADD A,#30H MOV 38H, A MOV A, B MOV B,#10D DIV AB ADD A, #30H MOV 39H, A MOV A, B ADD A, #30H MOV 3AH, A RET

19 Grafik 1.3: Ausgaberoutine Zu Beginn des Unterprogramms wird eine Division vorbereitet in dem das Register B mit dem Wert 100 geladen wird. Dies hat folgenden Grund: Die anzuzeigenden Zahl hat maximal 3 Stellen (max. = 250). Am einfachsten lassen sich die drei Stellen mit Hilfe von Modulo herausfiltern. Um die höchstwertige Stelle zu bekommen, muss dazu lediglich die zu splittende Zahl durch 100 geteilt werden und der Rest wiederrum durch 10 geteilt werden um im dadurch erhaltenen Ergebnis die 2. Höchstwertige Stelle und im Rest des Ergebnisses die niederwertigste Stelle zu erhalten. Zur weiteren Vorbereitung der Division wird nun der Wert der aktuellen Herzfrequenz in den Akku gelegt und wie oben bereits beschrieben mit DIV AB eine Division durch 100 durchgeführt. Zu dem dadurch erhaltenen Ergebnis muss im nächsten Schritt der Wert 30H zuaddiert werden. Dies wird aufgrund der Tatsache durchgeführt, dass laut ASCII-Tabelle (siehe Bild) die alphanumerischen Zeichen erst ab dem Wert 30H beginnen und es so ohne diese Addition zur Ausgabe von wirren Zeichen kommen würde. Nachdem dieser Schritt durchgeführt wurde, wird das Ergebnis der höchstwertigen Stelle auf dem Display oder in meinem Falle im internen Speicher (siehe Programmspeicherplan) ausgegeben. Anschließend wird der Rest der Divison, der im Register B liegt, in den Akku geschrieben und nun eine Divison durch zehn durchgeführt. Die beiden so erhaltenen noch verbleibenden Stellen, werden abermals zu 30 H dazuaddiert und im internen Speicher ausgegeben.

20 Beispielrechnung: Blutdruck = 250 250 / 100 = 2 Rest 50 50 / 10 = 5 Rest 0 Farbig markiert die einzelnen Stellen Grafik 1.4: ASCII-Tabelle

21 11.2 Ausgabe des Blutdrucks Da die Ermittlung der einzelnen, auszugebenden Stellen des Blutdrucks gleich abläuft, wie die Ausgabe der Herzfrequenz (siehe 12.1), beschränkt sich dieser Abschnitt auf die Umrechnung von Volt in mm Hg. Einzige Ausnahme bei der Umrechnung ist die, dass die auszugebenden Werte indirekt über das Register R0 ausgegeben werden, da eine Unterscheidung der Ausgabeposition von Systole und Diastole vor dem Unterprogrammaufruf erfolgt. Programmcode: JB 28H.7, Herzfrequenz Neustart: INC R6 CLR C SUBB A,#04D JNC Neustart CLR C MOV B, A MOV A, 30H SUBB A, #1 MOV 30H, A MOV A, B JNC Neustart DEC R6 Herzfrequenz: Dieser Programmteil führt nach einer Überprüfung, ob es sich bei dieser Ausgabeanfrage um eine Herzfrequenzausgabe handeltm (wenn ja wird der folgende Teil übersprungen) eine Division einer 10 Bit Zahl durch 4 durch. Dies hat folgenden Hintergrund: Bei einer maximalen Amplitude von 5 Volt entsprechen ca. 0,02 einem mm Hg. (5.0 V / 250). Ebenso entspricht ein Schritt des A/D Wandler einer Voltzahl von 0,0048. Teilt man nun die die 0,02 mm Hg durch die Voltzahl pro Schritt erhält man 4,1667. Das bedeute, dass ca. alle 4,1667 Schritte des A/D Wandler der Blutdruck um 1 mm Hg fallen bzw. steigen muss. Da sich mit dieser Kommazahl in dem von uns verwendeten Prozessor nur sehr schwer rechnen lässt ist es einfacher folgende Annahme zu treffen: 4,88 V = 250 mm Hg und 0,00 V = 0 mm Hg. Dadurch wird gewährleistet, dass genau alle 4 A/D Wandler Schritte 1 mm Hg bedeutet und somit die Umrechnung von Volt in mm Hg deutlich erleichtert. Der oben gezeigte Programmteil übernimmt genau diese Aufgabe. Dazu wird vom Low-Byte des 10 Bit Wandlerergebnisses vier subtrahiert und gleichzeitig das Register R6 um eins erhöht. Nun wird geprüft ob es bei dieser Division einen Über- bzw. Unterlauf gab. Ist dies der Fall (wird durch JNC erkannt) so wird das High Byte um eins dekrementiert. Ist dies nicht der Fall so wird der gesamte Programmteilablauf erneut gestartet. Dieser Vorgang wird solange wiederholt bis High Byte und Low Byte null sind. Anschließend steht im Register R6 das Ergebnis der Subtraktion

22 Beispiel: Eingangsvoltzahl = 0,01952 V = 000000100 als A/D Wandlerergebnis 4 4 = 0. Es wurde einmal subtrahiert, das Ergebnis entspricht also einem Blutdruck von 1 mm Hg 12. Timer2 Interrupt Dieser Abschnitt beschäftigt sich mit der Messung der Herzschlagzeit. Programmcode: ORG 002BH CLR 28H.4 MOV 32H, A MOV 28H.4, C MOV TH2, #00FCH MOV TL2, #0017H CLR C INC R1 CJNE R1, #0, KeinUbert INC R7 KeinUbert: CLR TF2 MOV C, 28H.4 MOV A, 32H RETI

23 Grafik 1.5: PAP zur Ermittlung der Herzschlagzeit Diese Interruptroutine wird bei einem Überlauf des Timer2 aufgerufen. Darin wird der Startwert für den nächsten Timer2-Zyklus erneut gesetzt und das Überlaufzählregister R1 inkrementiert. Sollte dieses seinerseits übergelaufen sein, so wird dies über die CJNE Abfrage erkannt und in diesem Falle das Register R7 inkrementiert. Die Register R1 und R7 speichern das High- bzw. Low- Byte der Timerüberläufe ab. Da der Timer2-Interrupt softwaremäßig zurückgesetzt werden muss, wird am Ende der Interruptroutine das TF2 Flag gelöscht, welches für den Prozessor als Indikator für einen Interrupt dient. Wie bei allen Interruptroutine wird auch bei dieser Routine der derzeit im Akku, sowie im Carry befindliche Wert zwischengespeichert und am Ende des Interrupts wieder zurückgeschrieben, um dafür zu sorgen, dass keine Rechnungen im restlichen Programm beeinflusst werden.

24 13. Externe Interrupts Dieser Abschnitt beschäftigt sich mit den beiden externen Interrupts an Pin 1.0 und Pin 1.3, die für den Start der Ausgabe des Mittelwertes, sowie für die Erkennung der Herzschlagflanken zuständig sind. 13.1 Externer Interrupt 3 Herzschlagflankenerkennung Programmcode: ORG 0053H SETB 28H.3 MOV 5CH, R6 JMP Interrupt3Fortsetzung ORG 400H Interrupt3Fortsetzung: JNB P1.0, NegativeFlanke JB 28H.0, MittelwertAktiv5 INC 50H MittelwertAktiv5: CALL Frequenzberechnung MOV R1,#0H MOV R7,#0H MOV R4, 50H CJNE R4, #250, NegativeFlanke MOV 50H, #0 SETB 28H.6 NegativeFlanke: CPL I3FR MOV R6, 5CH ; RETI

25 Grafik 1.6: PAP zur Herzschlagflankenerkennung Diese Interruptroutine erkennt sowohl steigende als auch fallende Flanken am Pin 1.0. Dazu wird das Bit I3FR mit jedem Interrupt invertiert. Dieses Bit zeigt an, ob der Interrupt 3 auf eine fallende oder steigende Flanke reagieren soll. Durch die ständige Invertierung des Signals wird gewährleistet, dass beide Flanken erkannt werden. Dies hat zum Zweck, dass das Systolen / Diastolen Erkennungsflag 28H.3 bei jedem Wechsel von Kontraktion in Füllen und umgekehrt wieder gesetzt wird, denn wie im Abschnitt 8 beschrieben wird dieses Bit immer dann zurück gesetzt wenn in einem Kontraktions- bzw. Füllzyklus bereits die Systole oder Diastole erkannt wurde, um so Prozessorleistung zu sparen. Würde dieses Bit nicht bei jeder Flanke gesetzt so würde nur ein einziges Mal eine Diastole bzw. eine Systole erkannt werden. Außerdem wird innerhalb dieser Interruptroutine die Speicheradresse 50H inkrementiert, die anzeigt wie viele Herzschläge bereits gemessen wurden und somit gleichzeitig als Kontrolle dafür dient, an welche Stelle die aktuellen Werte momentan in den externen Speicher geschrieben werden. (siehe hierzu auch Mittelwertberechnung). Anschließend wird das Unterprogramm Frequenzberechnung aufgerufen, dass wie in Abschnitt 7 beschrieben für die Berechnung der Herzfrequenz zuständig ist. Das letztendliche Löschen der Register R1 und R7 bewirkt, dass die gemessen Dauer des letzten Herzschlages zurückgesetzt wird und die Anzahl der Überläufe (siehe Timer2 Interrupt) von

26 neuem gemessen wird. Der Sprung innerhalb der Interruptroutine wird benötigt um dafür zu sorgen, dass der bei 53H beginnende Programmcode nicht in die an der Speicherstelle 6BH beginnende Interruptroutine überläuft und somit ein unkontrolliertes Verhalten des Programms bewirkt wird. 13.2 Externer Interrupt 6 Taster für Mittelwertausgabe ORG 006BH CPL 28H.0 CLR 28H.5 MOV 28H.5, C MOV 2BH, A MOV DPH, #03H DEC 50H NaechsterMittelwert: MOV R7, #0 MOV 6BH, #0 MOV 6CH, #0 MOV DPL, #00F9H JB 28H.6, StarteMittelwertBerechnung MOV DPL, 50H MOVX A, @DPTR ADD A, 6BH JNC NichtUbergeloffen INC 6CH NichtUbergeloffen: MOV 6BH, A DJNZ DPL, StarteMittelwertBerechnung MOV A, 6BH // 16 Bit Divison // MOV A, DPH CJNE A, #03H, Next MOV 27H, #046H MOV A, R7 MOV R6, A SETB 28H.7 CALL ASCIIAusgabeBlutdruck CLR 28H.7 Next: CJNE A, #02H, Next2 MOV 27H, #03FH MOV A, R7 MOV R6, A SETB 28H.7 CALL ASCIIAusgabeBlutdruck CLR 28H.7

27 Next2: Next3: RETI CJNE A, #01H, Next3 MOV 6EH, R7 CALL ASCIIAusgabeHerzfrequenz DJNZ DPH, NaechsterMittelwert MOV C, 28H.5 MOV A, 2BH Grafik 1.7: PAP zur Mittelwertberechnung

28 Diese Interruptroutine ist dafür zuständig zu erkennen, wenn ein Benutzer einen Mittelwert angezeigt haben möchte, diesen zu berechnen und anschließend auszugeben. Die Interruptroutine läuft nach folgendem Schema ab: 1. Speichere Akku und Carry zwischen 2. Addiere alle Messwerte der Herzfrequenz die im externen RAM stehen zusammen 3. Teile Ergebnis der Addition durch die Anzahl der Messwerte 4. Erkenne, dass es sich bei den Messwerten um die Herzfrequenzmesswerte gehandelt hat und gebe das Ergebnis der Division auf dem Display aus 5. Wiederhole die Schritte 2-4 für Systole und Diastole 6. Toggle das Flag, dass anzeigt ob Mittelwert ausgegeben wird oder nicht Da es sich bei Schritt drei um eine schon bereits beschriebene 16 / 8 Bit Division handelt soll hierauf in diesem Abschnitt nicht erneut eingegangen werden. Schritt 2 erfolgt in dem zunächst die Register 6BH und 6CH gelöscht werden. Diese enthalten nachher das Highbzw. Lowbyte der Addition der Messergebnisse. Danach wird abgeprüft ob bereits 250 Messwerte im externen Speicher stehen, sollte dies nicht der Fall sein so wird der aktuelle Speicherpointer (Speicherregister 50H) verwendet. Andernfalls wird standardmäßig der Wert 250 genommen. Nun wird damit begonnen das DPH Register mit 1 (Herzfrequenzmesswerte),2 (Systolenmesswerte) oder 3 (Diastolenmesswerte) zu laden. Anschließend wird die ermittelte Pointerstelle in das DPL Register geschrieben. Nun wird der erste Wert mit MOVX aus dem externen RAM zu 6BH addiert. Es wird nun überprüft ob das Carry Flag gesetzt ist, sollte dies der Fall sein so wird 6CH inkrementiert, da das Low-Byte übergeloffen ist. Nun wird das DPL Register dekrementiert und die gesamte Prozedur wiederholt, bis alle Werte aus dem externen RAM abgeholt wurden. Anschließend folgt die bereits beschriebene 16 Bit Division, sodass sich nun im Register R7 der Mittelwert der Herzfrequenz (oder Systole, bzw. Diastole) befindet. Zuletzt wird mit drei CJNE Befehlen das DPH Register abgeprüft, ob es sich bei der Mittelwertberechnung um eine Herzfrequenz, Systole oder Diastole gehandelt hat. Je nachdem um was es sich handelt wird nun die Ausgabe des errechneten Wertes durch einen Unterprogrammaufruf gestartet. Mit dem Toggeln des Flags, dass angibt ob momentan der Mittelwert ausgegeben wird oder nicht, wird zum einen die Ausgabe der aktuellen Werte gestoppt und zum anderen das Inkrementieren, des externen Speicherpointers. Durch dieses Toggeln wird erreicht, dass eine Mittelwertausgabe beim ersten Tastendruck gestartet wird und mit einem erneuten Tastendruck beendet werden kann.

29 14. A/D Messung mit 10 Bit Auflösung Dieser Abschnitt beschäftigt sich mit dem Programmablauf der nötig ist um aus der Standardmäßigen 8 Bit Analogmessung des 80535 eine Analogmessung mit einer Auflösung von 10 Bit zu machen Programmcode: ORG 1000H ADWandlung: JB 20H.1, Messung2 CLR C ANL ADDAT, #11110000b MOV A, ADDAT SWAP A ORL A, ADDAT ADD A,#01000000b JNC NoOverflow MOV A, #00CH NoOverflow: MOV DAPR, A SETB 20H.1 JMP Ende Messung2: CLR C MOV 21H, #0 MOV A, DAPR ANL A, #00001111b SWAP A RLC A MOV 21H.1, C RLC A MOV 21H.0, C CLR C ADD A, ADDAT JNC KeinUbertrag INC 21H KeinUbertrag: MOV 22H, A CLR 20H.1 CALL GrosserKleinerVergleich MOV 23H, 21H MOV 24H, 22H MOV 30H, 23H MOV 31H, 24H MOV 27H, #04DH MOV 51H, #00H JB 28H.0, MittelwertAktiv4 CALL ASCIIAusgabeBlutdruck MOV DAPR, #0H Ende: JMP Warte

30 Grafik 1.8: PAP zur 10 Bit Analogmessung

31 Die A/D Wandlung mit einer Auflösung von 10 Bit gliedert sich in zwei Messvorgänge; einen groben und einen genauen Messvorgang. Als Indikator um welchen Messvorgang es sich gerade handelt dient das Flag 20H.1. Sollte dieses Bit gesetzt sein so wird mit JB zum Programmteil der für die zweite Messung zuständig ist gesprungen. Das Ergebnis der ersten Messung (die Vorbereitung der selbigen erfolgt wie in der Analogmessungsinitialisierung beschrieben siehe hierzu auch Abschnitt 11) wird folgendermaßen ausgewertet und weiterverwendet: 1. Lösche Low-Nibble der ersten Messung (ANL ) 2. Schreibe Messergebnis in den Akku (MOV ) 3. Vertausche oberes und unteres Nibble der Messung (SWAP ) 4. Verknüpfe oberes Nibble der 1. Messung mit dem Akku Ergebnis ist, dass im unteren Nibble des Akkus nun jeweils das obere Nibble des 1. Messergebnisses steht 5. Addiere 4 zum oberen Nibble des Akkus hinzu und überprüfe das Ergebnis auf Überläufe, wenn es einen Überlauf gab, dann setze das obere Nibble auf 1111 6. Beginne zweite Messung Diese Vorgehensweise hat folgenden Zweck. Während der ersten Messung wurde ein Messbereich von 0.0 5.0 V erfasst und somit eine maximale Genauigkeit von ca. 20 mv ermöglicht. In dem man nun das grobe Ergebnis dieser ersten Messung nimmt (grob daher, weil das untere Nibble gelöscht wird) und dieses Wert als Referenzspannung für die zweite Messung verwendet erhält man eine 4 mal höhere Auflösung. Um dies zu gewährleisten muss zudem noch der obere maximale Messwert angegeben werden, was durch das hinzuzählen von 4 zum oberen Nibble geschieht, was einer um 1,25 V höheren Spannung als der Referenzspannung entspricht. Der Messbereich der zweiten Messung beträgt also nun GND + 1,25 Ist die zweite Messung beendet so beginnt die Auswertung bzw. Umrechnung des gemachten Ergebnisses in einen 10 Bit Wert. Dazu wird folgendermaßen vorgegangen: 1. Erfassen der Referenzspannung der 2. Messung in dem das obere Nibble des DAPR Registers gelöscht wird. 2. Schreibe das Ergebnis in den Akku und tausche die Nibble 3. Schiebe den Akku zweimal durch das Carry in ein zweites Register nach links 4. Addiere das Ergebnis der 2. Messung zum Akku hinzu und überprüfe auf Überläufe. Wenn es einen Überlauf gab, so addiere 1 zum zweiten Register hinzu. 5. Schreibe 10 Bit Ergebnis weg und beginne erneut mit der 1. Messung Diesem Programmablauf liegt folgende Überlegung zu Grunde. Die erste Messung sorgte dafür dass der Messbereich beispielsweise von 0.0 5.0 V auf 3.0 4.25 V eingeschränkt wurde. Die zweite Messung gibt nun die Differenz von der Referenzspannung (3.0 V) zum eigentlichen Ergebnis an. Also muss zur Referenzspannung, das Ergebnis der 2. Messung hinzuaddiert werden um das neue Ergebnis zu erhalten. Hierzu muss jedoch zuerst durch die Programmschritte 1-3 die Referenzspannung in den obersten Teil des 10 Bit Messergebnisses geschoben werden, sodass anschließend die Addition des neuen Ergebnisses folgen kann. Um das so gemachte Ergebnis sofort auszuwerten wird im Anschluss an die zweite Messung das Unterprogramm zur Erkennung der Systole bzw. Diastole sowie das Unterprogramm zur Ausgabe des aktuellen Blutdrucks aufgerufen.

32 15. Tests 15.1 C-Code für Logic Analyzer Dieser Abschnitt soll die Funktion des C-Programms zur Simulation eines Analogsignals am Pin AIN1 erläutern. Sinn und Zweck dieser Simulation ist die Nachbildung eines Blutdrucksignals wie es an einer echten Hardware eingehen könnte und somit gleichzeitig die Überprüfung der ordnungsgemäßen Funktion des Programms. Der hier vorgestellte C- Code befindet sich in der Datei Analog.ini und muss vor dem Test durch eine Einstellung des Debugmodus eingebunden werden. (siehe Bedienungsanleitung) Programmcode: signal void bob3(float limit) { float volts; // peak-to-peak voltage float frequency; // output frequency in Hz float offset; // voltage offset float YVerschiebung; float duration; // duration in Seconds float val; float val2; long i, end; float Ubersteuerung; volts = 0.9; offset = 1.0; YVerschiebung = 1.0; frequency = 0.5; duration = 1000; Ubersteuerung = YVerschiebung + ((volts + offset) / 2); printf ("Sine Wave Signal on AD Channel 0.\n"); end = (duration * 100000); for (i = 0 ; i < end; i++) { val = sin (2 * frequency * (((float) STATES) / CLOCK) * 2 * 3.1415926); val = (val * volts) + offset + YVerschiebung; val2 = sin ((frequency * (((float) STATES) / CLOCK) * 2 * 3.1415926)+1.1); val2 = (val2 * volts) + offset + YVerschiebung; AIN1 = (2*val2) - val + YVerschiebung; AIN2 = val2; if (AIN1 > Ubersteuerung) { P1.0 = 1; } else { P1.0 = 0; } } } swatch (0.00001); // in 10 usec steps

33 Vor Beginn der eigentlichen Routine werden einige Variablen initialisiert. Die Variablen haben folgende Zuständigkeiten: volts = obere Hälfte der Amplitude des Signals, bei einem Sinussignal von 0.0 3.0 V müsste diese Variable auf 1.5 Volt gesetzt werden frequency = Die zu simulierende Herzfrequenz in Herz. Eine eingestellter Wert von 0.5 entspricht demnach einer Herzfrequenz von 30 Schlägen pro Minute offset = Hälfte der unteren Hälfte der Amplitude des Analogsignals, bei einem Sinussignal von 0.0 3.0 V müsste diese Variable auf 0.75 V gesetzt werden YVerschiebung = Zweite Hälfte der unteren Hälfte der Amplitude des Analogsignals, bei einem Sinussigal von 0.0 3.0 V müsste diese Variable auf 0.75 V gesetzt werden duration = Dauer über die das Programm wiederholt werden sollt. Ein Wert von 10000 entspricht demnach einer Dauer von 100 Sekunden. Ubersteuerung = Dieser Wert berechnet die Nulllinie des Analogsignals und dient als Indikator dafür wann ein Herzschlagsignal generiert werden soll. Die Berechnung eines Sinussignals für die Variable val richtet sich nach den Vorgaben der Keilhomepage. (http://www.keil.com/support/man/docs/uv3/uv3_sm_ai_sinewave.htm) Dabei wird alle 10 µs ein neuer Sinus-Wert berechnet und an AIN1 ausgegeben. Dafür werden die in den oben genannten Variablen gespeicherten Werte für Frequenz und Amplitude verwendet. Anschließend wird ein zweites, leicht verschobenes Sinussignal in der Variable val2 hinzuaddiert und so eine unregelmäßig an der fallenden Seite des Sinussignals generiert. Abhängig davon welcher Wert in der Variable Ubersteuerung gespeichert ist, wird bei Überschreiten dieses Wertes eine 1 an Pin 1.0 generiert, während beim Unterschreiten dieses Wertes eine 0 generiert wird. Das so generierte Rechtecksignal entspricht der zu simulierenden Herzfrequenz.

34 Grafik 1.9: Ausschnitt aus Logic Analyzer mit Sinusfunktion 16.2 Teststrategie In diesem Abschnitt sollen kurz die einzelnen Tests die zur Überprüfung der Korrektheit des Programms durchgeführt werden können erläutert werden: Überprüfung der Herzfrequenz: Hierzu wird im C-Code zur Simulation eines Sinussignals die Frequenz verändert. Dabei entspricht eine Frequenz von 0.5 Hz einer Herzfrequenz von 30 Schlägen / Minute und eine Frequenz von 4,1 Hz einer Herzfrequenz von 250 Schlägen / Minute Überprüfung der Systole und Diastole: Hierzu wird im C-Code zur Simulation eines Sinussignals der Offset, sowie die Y- Verschiebung und die Voltzahl verändert. So kann z.b. durch Einstellen der Voltzahl auf 2.44, sowie des Offsets auf 2.44 erreicht werden, dass der Wert der Systole bei 250 und der Wert der Diastole bei 0 liegt. Überprüfung der Mittelwertausgabe: Zur Überprüfung der Mittelwertausgabe wird der Pin 1.3 ein erstes Mal getoggelt. Nun müsste, der Wert für die Systole, sowie die Diastole gleich bleiben, da bei einer Sinuskurve die Messwerte immer gleich sind. Der Wert für die Herzfrequenz muss jedoch variieren, da hier in der Messwertaufzeichnung falsche Ergebnisse, die durch die ersten beiden Messzyklen entstehen mit eingestreut sind.

35 Überprüfung ob Höcker ignoriert werden: Dazu muss die zweite Funktion der bereitgestellten C-Codes geladen werden. Wird in dieser zweiten Funktion, der selbe Wert für Frequency, Volts und Offset eingesteltl, so dürfte in der Ausgabe des Programms keine Veränderung zur ersten Funktion ersichtlich sein. 17. Bedienungsanleitung Dieser Abschnitt soll kurz die Einstellung der Simulationsumgebung, sowie das Vorgehen für das Ablesen der Messergebnisse mit Hilfe eines FAQ erläutern. Es sei jedoch explizit erwähnt, dass dieses Beschreibung sich nicht mit dem grundlegenden Umgang mit dem Entwicklungssystem uvision der Firma Keil beschäftigt. Es ist also dringend zu empfehlen mit diesem Programm etwas vertraut zu sein. Wie lade ich das Projekt? Über den Button Project in der Menüleiste von Keil und dann durch Drücken des Buttons Open Project und der anschließenden Auswahl des Projekts von der bereitgestellten CD. Welche Einstellungen muss ich vor der Ausführung des Projektes machen? Über den Button Project in der Menüleiste und anschließend durch Betätigen des Buttons Options for Target gelangen Sie in ein Menü in dem Sie oben auf den Reiter Debug klicken müssen. Hier aktivieren Sie bitte folgende Checkboxen: Use Simulator, Limit Speed to Real Time, Load Application at Startup und Run to main. Zudem wählen Sie bitte über den Button mit den drei Punkten auf der linken Seite das auf der CD bereitgestellte File Analog.ini aus und bestätigen ihre Einstellungen mit Ok

36 Wie kann ich die Simulation der Herzfrequenz, sowie der Diastole und Systole beeinflussen? Hierzu müssen Sie den Debug Modus starten. Drücken Sie hierzu bitte auf den Button Debug und anschließend auf den Button Start / Stop Debug Session. Öffnen Sie nun erneut das Menü Debug und wählen nun den letzten Menüeintrag Function Editor. Hier müsste sich nun der Programmcode der Datei analog.ini befinden, sollte dies nicht der Fall sein, so können Sie diesen Programmcode laden indem Sie den Button Open verwenden und dann die Datei auf der zur Verfügung gestellten CD auswählen. Nun sehen Sie den Programmcode der Analogfunktion und können mit den bereits in Kapitel 15 vorgestellten Variablen die Eigenschaften der Funktion verändern. Haben Sie ihre Einstellungen vorgenommen, so müssen Sie diese Einstellungen mit dem Button Compile kompilieren und anschließend mit dem Button Save speichern. Lassen Sie sich nicht von der Fehlermeldung Function is currently in use verunsichern, diese führt auf einen Fehler in der Version 3.23 von uvision zurück und hat keine weiteren Auswirkungen auf die Simulation. Nachdem Sie den Function Editor verlassen haben können Sie nun wie gewohnt über Debug Start das Programm ablaufen lassen

37 Wie kann ich die Simulation des Analogsignals anzeigen? Der Verlauf des derzeitigen Analogsignals kann über den Logic Analyzer angezeigt werden. Dieser kann im Menü View über den Button Logic Analyzer gewählt werden. Bevor hier jedoch ein Signal angezeigt werden kann, muss dem Logic Analyzer zuerst mitgeteilt werden, welches Signal angezeigt werden soll. Diese Einstellung kann über einen Klick auf den Button Setup durchgeführt werden. Im nun geöffneten Menü kann über den Button New (Insert in der oberen Rechten Ecke ein neues Signal hinzugefügt werden. Hier kann z.b. P1.0 oder AIN1. eingetippt werden. Nach anschließender Bestätigung mit dem Button Close kann nun das Programm gestartet werden. Daraufhin müsste im Logic Analyzer der aktuelle Signalverlauf der angegebenen Eingänge angezeigt werden.

38 Wie kann ich die aktuellen Messergebnisse anschauen? Hierzu muss zuerst das sogenannte Memory Window geöffnet werden. Dies funktioniert über das Menü View und anschließend über den Button Memory Window. Im unteren Teil der Entwicklungsumgebung müsste sich nun ein Fenster mit einem Eingabefeld zur Adresseingabe geöffnet haben. In dieses Feld muss nun folgendes eingetippt werden: I:30H. I steht hierbei für den internen Speicher und 30 H für die Speicherstelle. Klicken Sie nun mit der rechten Maustaste in das Fenster darunter und aktivieren Sie dort den Menüpunkt ASCII. Wenn Sie nun das Programm starten, wird in diesem Fenster der aktuelle Wert in ASCII-Darstellung angezeigt. (siehe hierfür z.b. Kapitel Initialisierungen). Wie kann ich den Taster zur Ausgabe des Mittelwertes bedienen? Hierzu müssen Sie den Pin 1.3 toggeln. Dies können Sie tun in dem Sie im Menü Peripherals und dann über I/O Ports gefolgt von Port 1 das Menü zur Simulierung von Ports öffnen. Nun können Sie während das Programm läuft durch Anklicken der Checkbox für Pin 1.3 selbigen toggeln und somit die Ausgabe des Mittelwertes auslösen.

39 18. Abschluss 18.1 Warum kein Unterprogramm für 16 Bit Division und ASCII Ausgabe? Die Antwort dieser Frage mag auf den ersten Blick nicht sofort einleuchtend sein, jedoch hat hierbei das Verhältnis von Nutzen zu Aufwand eine sehr große Rolle gespielt. Doch vor der eigentlichen Beantwortung der Frage ein kurzes Fallbeispiel für die ASCII Ausgabe: Annahme: Es existiert ein Unterprogramm für die Ausgabe im ASCII Format beliebiger, dreistelliger Zahlen Dieses Programm müsste um die Allgemeinheit zu garantieren ungefähr so aussehen: - Lade auszugebenden Wert aus Register XY - Schreibe XY in Akku - Teile Akku durch 100 - Gebe Ergebnis aus - Teile Ergebnis durch 10 - Gebe Akku aus - Gebe Register B aus Fallbeispiel: Das oben beschriebene Unterprogramm wurde gerade aufgerufen um den so eben ermittelten Wert der Systole auszugeben und befindet sich an der Stelle Gebe Ergebnis aus. Zuvor wurde der auszugebende Wert 1 errechnet. Nun wird der Interrupt 3 ausgelöst und bekanntermaßen dadurch die aktuelle Herzfrequenz ermittelt und ausgegeben. Es wird nun also wieder das oben beschriebene Unterprogramm geladen und durchgeführt. Am Ende dieses Aufrufs befindet sich im Akku die Zahl 2. Nun wird die Interruptroutine beendet und die Ausgabe der Systole wird fortgesetzt. Statt der zuvor errechneten 1 wird aber nun eine 2 ausgegeben, da diese sich derzeit im Akku befindet. Fazit: Das Ergebnis wird verfälscht. Die Logische Konsequenz hieraus wäre die Werte im Akku, sowie im Carry und B Register zwischen zu speichern. Doch man stelle sich nun vor, es würde im Interrupt 3 noch ein weiterer Interrupt aufgerufen. Man stelle sich zum Beispiel den Aufruf der Interrupt 6 Routine vor. Es käme zu nur sehr schwer handhabbaren Verzerrungen der Ergebnisse in den einzelnen Registern, die jedes Mal bei einem Aufruf unter Umständen sogar mehrere Ebenen tief zwischen gespeichert werden müssten. Dies würde einen Mehraufwand und eine höhere Prozessorleistung bedeuten, die kaum in Relation zum Gewinn durch ein so kurzes eigenständiges Unterprogramm stehen würde. Aus diesem Grund wurde für die 16 / 16 Bit Division, sowie für die Ausgabe der ASCII keine strikte Anwendung eines einzelnen Unterprogramms durchgeführt, sondern vielmehr für die 16 Bit Division folgendermaßen vorgegangen: - Behandle 16 / 8 Bit Division als eigenständiges Problem und damit als eigenen Programmteil - Die zum Einsatz kommende 16 / 16 Bit Division kommt in der Herzfrequenzberechnung vor - Die 16 / 8 Bit Division kommt in der Mittelwertberechnung zu Einsatz

40 Bei der ASCII Ausgabe wird folgendermaßen vorgegangen: - Unterscheide zwischen Extremwert- und Herzfrequenzausgabe, da die Herzfrequenz durch einen Interrupt zu jedem beliebigen Zeitpunkt ausgelöst werden kann - Rufe die Extremwerteausgabe einzeln als Unterprogramm für die Ausgabe der Systole bzw. Diastole auf 18.2 Fazit Ziel dieser Projektarbeit war der Entwurf und die Implementierung eines Assemblerprogramms zur Messung des Blutdrucks, sowie der Herzfrequenz und die Möglichkeit zur Ausgabe eines Mittelwertes. Diese geforderten Ergebnisse wurden erreicht und in dieser Ausarbeitung, sowie im Code selber dokumentiert. Zusätzlich hierzu wurde noch die Ausgabe des aktuellen Blutdruckwertes mit eingebaut, sowie eine Variable C- Funktion zur Simulation eines Sinussignals und eines modifizierten Sinussignals mit Höcker geschrieben. Das Projekt hätte hinsichtlich der Laufzeit, sowie der Speicherplatzverteilung weiter optimiert werden können. Dies hätte aber wie bereits in der Dokumentation erwähnt eine erhebliche Steigerung des Arbeitsaufwandes für den Programmentwurf bedeutet, der gleichzeitig nicht zur Relation des Nutzens gestanden hätte, da dieses Projekt nicht kommerziell vermarktet werden soll. Abschließend gilt also zu sagen: Das Projekt konnte erfolgreich implementiert werden. 18.3 Quellenangabe - Datenblatt des Mikrocontrollers: http://pdf1.alldatasheet.com/datasheet-pdf/view/128898/amd/80535.html - Erklärung der Vorgehensweise zur Durchführung einer A/D Wandlung mit 10 Bit Auflösung: http://www.goblack.de/desy/mc8051chip/datenblatt/adwandl/index.html - Skript zur Vorlesung Mikroprozessortechnik bei Herrn Prof. H. Trück