Lehrmaterial zu den Lehrveranstaltungen ... · mit dem Sensor-Aktor-Modul 11 ... In diesem...

38
Technische Universität Ilmenau Fakultät für Maschinenbau Dr.-Ing. M. Braunschweig Lehrmaterial zu den Lehrveranstaltungen "Mikrorechnertechnik" bzw. "Programmiersprachen" im SS 2016 Zielstellung: Programmieren mit C++ Inhalt Seite Microsoft Visual Studio 2015 Hilfestellung und erste praktische Schritte zur Einarbeitung in das Microsoft Visual Studio 2015 2 Hardwarebeschreibung des Sensor-Aktor Moduls Überblick über die Hardware des im Seminar verwendeten Sensor-Aktor-Moduls 6 Funktionsbibliothek zur Steuerung des Sensor-Aktor- Moduls Beschreibung der Funktionen zur Kommunikation mit dem Sensor-Aktor-Modul 11 Aufgabe 1: C-Dateiarbeit Das Einlesen und Abspeichern von Textdateien und Binärdateien sind immer wiederkehrende Aufgaben für Programmierer. In diesem Versuch sollen die Grundlagen der Dateiarbeit anhand der Bearbeitung einer beispielhaften Messwertdatei vermittelt werden. 13 Aufgabe 2: Tonerzeugung In diesem Praktikum sollen Hardwarekomponenten des PCs, speziell der Zähler-/Zeitgeberschaltkreis (CTC) angesprochen werden. Ziel ist die Erzeugung von Tönen über den PC-Lautsprecher. 14 Aufgabe 3: Peripheriesteuerung mit dem Sensor-Aktor-Modul Der Versuch soll die Aspekte der Hardwareprogrammierung von Peripherie- Baugruppen am Beispiel des Sensor-Aktor- Moduls verdeutlichen. 17 Aufgabe 4: Klassen in C++ und Nutzung des .NET-Frameworks C++ bietet einen objektorientierten Programmieransatz. Unter Verwendung des .NET-Frameworks soll dieser Versuch auf die Verwendung von Klassen und Objekten eingehen. 18 Demoprogramme C++ - Demoprogramme und Syntax-Hinweise 22

Transcript of Lehrmaterial zu den Lehrveranstaltungen ... · mit dem Sensor-Aktor-Modul 11 ... In diesem...

Technische Universität Ilmenau Fakultät für Maschinenbau Dr.-Ing. M. Braunschweig

Lehrmaterial zu den Lehrveranstaltungen "Mikrorechnertechnik" bzw. "Programmiersprachen"

im SS 2016

Zielstellung: Programmieren mit C++

Inhalt Seite

Microsoft Visual Studio 2015 Hilfestellung und erste praktische Schritte zur Einarbeitung in das Microsoft Visual Studio 2015

2

Hardwarebeschreibung des Sensor-Aktor Moduls

Überblick über die Hardware des im Seminar verwendeten Sensor-Aktor-Moduls

6

Funktionsbibliothek zur Steuerung des Sensor-Aktor-Moduls

Beschreibung der Funktionen zur Kommunikation mit dem Sensor-Aktor-Modul

11

Aufgabe 1: C-Dateiarbeit

Das Einlesen und Abspeichern von Textdateien und Binärdateien sind immer wiederkehrende Aufgaben für Programmierer. In diesem Versuch sollen die Grundlagen der Dateiarbeit anhand der Bearbeitung einer beispielhaften Messwertdatei vermittelt werden.

13

Aufgabe 2: Tonerzeugung

In diesem Praktikum sollen Hardwarekomponenten des PCs, speziell der Zähler-/Zeitgeberschaltkreis (CTC) angesprochen werden. Ziel ist die Erzeugung von Tönen über den PC-Lautsprecher.

14

Aufgabe 3: Peripheriesteuerung mit dem Sensor-Aktor-Modul

Der Versuch soll die Aspekte der Hardwareprogrammierung von Peripherie-Baugruppen am Beispiel des Sensor-Aktor-Moduls verdeutlichen.

17

Aufgabe 4: Klassen in C++ und Nutzung des .NET-Frameworks

C++ bietet einen objektorientierten Programmieransatz. Unter Verwendung des .NET-Frameworks soll dieser Versuch auf die Verwendung von Klassen und Objekten eingehen.

18

Demoprogramme C++ - Demoprogramme und Syntax-Hinweise 22

2

C++ Programmentwicklung mit Microsoft Visual Studio 2015 Einführung

Start:

Jedes Programm besteht aus mehreren Dateien, die in einem Projekt zusammengefasst werden. Mehrere Projekte werden in einer Solution abgespeichert. Also muss zuerst ein neues Projekt angelegt werden. Die dazu notwendigen Arbeitsschritte sind: File NewProject Wie abgebildet, ist "Visual C++ - General" und "Empty Project" auszuwählen.

Name: Ein selbst gewählter Projektname, hier z.B. Volumen Location: Bitte hier unbedingt C:\Kopie eintragen. Solution name: Visual Studio schlägt hier automatisch den Projektnamen vor. Das lassen wir so. Weiter: "Ok". Hinweis zu den entstehenden Verzeichnissen: Mit dem Anlegen des Projektes wird in C:\Kopie das Verzeichnis Volumen erzeugt. Dieses Verzeichnis heißt Solutionverzeichnis. Innerhalb des Solutionverzeichnisses liegt ein Verzeichnis, das ebenfalls den Namen Volumen hat. Dies ist das Projektverzeichnis. Ein wichtiges Fenster im Visual Studio ist der Solution Explorer. Im Solution Explorer ist die entstandene Struktur zu erkennen: Es gibt eine Solution, die ein Projekt enthält. Noch sind alle Unterordner im Solution Explorer leer (siehe Abbildung).

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

3

Im nächsten Schritt werden die Quellcodedateien (Source Files) zum Projekt hinzugefügt. Im ersten Beispiel ist das die vorbereitete Beispieldatei VOLUMEN.CPP. Die Datei steht im Verzeichnis "Aushang\VisualC++". Wir kopieren die Datei in das gerade neu entstandene Projektverzeichnis "C:\Kopie\Volumen\Volumen" und addieren die Datei VOLUMEN.CPP zu den Source Files des Projektes (Rechter Mausklick auf Source Files).

Durch Doppelklicken auf die Datei VOLUMEN.CPP im Solution Explorer wird der Editor geöffnet und die Datei angezeigt. Dann kann die Datei VOLUMEN.CPP editiert, kompiliert und gebunden werden. Starten Sie das Programm über Debug Start Without Debugging (Ctrl+F5) oder Debug Start Debugging (F5)!

4

Programmieraufgabe "Rechteck":

1. Ausgabe des Textes "Ich lerne C++" auf dem Bildschirm 2. Erstellen einer Funktion Rechteck(), an die die Seitenlängen als double-Zahlen

übergeben werden und die den Flächeninhalt eines Rechtecks berechnet und zurückgibt 3. Einlesen der Seitenlängen über die Tastatur 4. Aufrufen der Funktion Rechteck() in der Funktion main() 5. Anzeigen des Flächeninhalts auf dem Bildschirm

Im zweiten Beispiel wird ohne Musterdatei gearbeitet. Alles wird neu angelegt. Wir bilden zunächst ein ganz neues Projekt mit dem Namen "Rechteck". Dazu sind die Schritte zum Anlegen des Projektes wie im ersten Beispiel zu verwenden. Neu ist die Eingabe des Quellcodes (des Programms). Ein Programm steht in einer Datei. Also muss eine neue Datei angelegt werden. Der Dialogaufruf zum Öffnen einer neuen Datei erfolgt durch Auswahl des Ordners Source Files im Solution Explorer und Wählen von Add New Item im Kontextmenü (Drücken der rechten Maustaste).

Zu wählen ist als File Typ: C++ File und ein File Name: hier z.B. Rechteck. Die Dateinamenserweiterung (.cpp) wird automatisch angehängt. Ist das Programm fertig eingegeben, wird der Menüpunkt "Build" gewählt, und durch Anwahl des Unterpunktes "Build <Projektname>" das Programm fertig erstellt. Nach einem Compile- und Link-Prozess entsteht das Programm - hier Rechteck.exe. Der Projektname ist also auch der Programmname.

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

5

Aufgabe zur Einarbeitung Tastatureingabe, Bildschirmausgabe, Formelberechnung, Datentypen Für ein Kreissegment mit dem Radius r und dem Winkel α ist der Flächeninhalt A zu berechnen (siehe Skizze). Über die Tastatur sollen eingegeben werden:

Radius des Kreises r in m

Winkel für Kreissegment α in Grad. Die Eingabe soll solange wiederholt werden, solange ein Winkel größer als 180° eingegeben wird. Die Fläche A in m² soll nach folgender Formel (α in rad) berechnet und auf dem Bildschirm angezeigt werden.

𝐴 =𝑟2

2∙ (𝛼 − sin( α))

6

Hardwarebeschreibung des Sensor-Aktor-Moduls

Bild 1: Sensor-Aktor-Modul Oberseite ohne Gehäuse Bild 1 zeigt das im Seminar verwendete Sensor-Aktor-Modul (SAM). Im Bild 2 werden die wichtigsten Baugruppen, die in den Seminaren angesteuert werden, aufgezählt und die zur Verfügung stehenden C-Funktionen genannt.

Bild 2: Baugruppen des Sensor-Aktor-Moduls

ADC DIO (Ports)

I2C

USB

PC

OpenSAM() CloseSAM() WriteValue() ReadValue() ReadData() WriteData()

8 LEDs 8 Schalter

Mikrocontroller XE167 Infineon

Potentiometer

Gleichstrommotor mit Endstufe und Encoder

ADC – Analog/Digital Converter DIO – Digital Input/Output I2C – serieller Bus

Helligkeitssensor

Per

iph

erie

kom

po

nen

ten

Schrittmotor mit Endstufe und Lichtschranke

Lautsprecher und Verstärker

Beschleunigungssensor Barometer

Poti

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

7

Das Sensor-Aktor-Modul arbeitet wahlweise in einer von vier Betriebsarten (siehe Tab. 1). Nach dem Einschalten ist die Betriebsart 0 (Analog) voreingestellt. Zur Nutzung des Gleichstrom-motors z.B. muss auf die Betriebsart 3 umgeschaltet werden. Hinweis: Die Umschaltung dauert ca. 1s, d.h. ihr Programm kann erst fortgesetzt werden, wenn der eingelesene Status (siehe Tab. 1) auch die gewählte Betriebsart zurückliefert. Schalter, LEDs und die Sensoren können unabhängig von der Betriebsart benutzt werden. Display des Sensor-Aktor-Moduls Hinweis: Beachten Sie nach dem Einschalten bitte die Anzeige auf dem Display. Drehen Sie, wenn nötig, am Potentiometer zum Verlassen des Diagnosemodus. Das Display dient zur automatischen Zustandsanzeige. Stromversorgung Die Stromversorgung des Sensor-Aktor-Moduls erfolgt über die USB-Schnittstelle. Die Betriebsspannung Ub ist nicht konstant und hängt vom USB-Anschluß und von der konkreten Belastung durch die Hardware ab. Die aktuelle Betriebsspannung Ub wird auf dem Sensor-Aktor-Modul mit Hilfe einer bekannten Referenzspannung bestimmt und kann abgefragt werden. A/D – Wandlung

Analoge Spannungen werden zur Verarbeitung im Rechner mit Hilfe eines A/D-Wandlers in digitale Größen umgewandelt. Die analogen Spannungen werden in Abhängigkeit von der Bitbreite des Wandlers auf einen bestimmten Wertebereich abgebildet. Im Sensor-Aktor-Modul wird ein 10Bit A/D-Wandler verwendet. Damit beträgt der Wertebereich 0…1023. Der Wert 1023 entspricht der Betriebsspannung am Sensor-Aktor-Modul.

Bild 3: Wertebereich für die 10Bit A/D-Wandlung

Analoge Spannung U

Dig

ital

er A

/D-W

ert

AD

0

1023

Ub

ADx

Ux

8

Gleichstrommotorsteuerung und Encodernutzung am Sensor-Aktor-Modul Die Baugruppe Gleichstrommotorsteuerung des Sensor-Aktor-Moduls soll im Folgenden näher erläutert werden.

Bild 4: Prinzip der Gleichstrommotorsteuerung

Der Mikrocontroller erzeugt mit Hilfe einer Capture-Compare-Einheit ein pulsweiten-moduliertes Signal (PWM) für die Motorendstufe (siehe Bild 4). Die Hardware wurde so konfiguriert, dass die Pulsweite PW in 4096 Stufen eingestellt werden kann, bei Pulsweite PW = 0 liegt die negative Betriebsspannung -Ub am Motor an und bei Pulsweite PW= 4095 liegt die positive Betriebsspannung +Ub am Motor an (siehe Bild 5). Die Periodendauer T beträgt 4095 Zeiteinheiten = ca. 50µs, so dass sich auf Grund der Motorinduktivität ein Stromverlauf im Motor entsprechend der roten Linie im Bild 5 einstellt.

i,u

tTPW

Ub

-Ub

i,u

t

T

PW

Ub

-Ub

Bild 5: Klemmenspannung und Stromverlauf am Motor bei Ansteuerung mit zwei verschiedenen PWM-Signalen, T=4095 Zeiteinheiten Fall a: PW>2048 (>50% von T), Motor dreht sich vorwärts; Fall b: PW<2048 (<50% von T), Motor dreht sich rückwärts

Die Daten zum Setzen der Motorstellgröße über das Kommando DCM_SETVALUE können nach folgendem Diagramm ermittelt werden. Aus der Motorstellgröße berechnet der Mikrocontroller durch Addition von 2048 (Motor steht bei PW=2048) die Pulsweite PW.

µC PWM-Einheit

Counter

Motorendstufe Gleichstrom-motor mit integriertem Encoder

2 um 90⁰ phasenverschobene Impulsfolgen

PWM-Signal A/D-Wandler

A

B . .

Motorspannung

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

9

Bild 6: Motorspannung UM in Abhängigkeit von der Stellgröße für das Kommando DCM_SETVALUE An der Welle des Gleichstrommotors ist ein inkrementaler Impulsgeber - kurz: Encoder - befestigt. Dieser Encoder liefert zwei phasenverschobene Rechteckspannungsfolgen - die Encoderimpulse. Pro Umdrehung enthält jede Rechteckspannungsfolge 16 Rechteckperioden. Die Zähleinheit - der Counter - für die Encoderimpulse realisiert eine Drehrichtungserkennung und eine Vierfachauswertung (Zählen aller Rechteckflanken). Damit werden pro Umdrehung 64 Inkremente richtungsabhängig gezählt und im Counter gespeichert. Kommunikation zwischen dem PC und dem Mikrocontroller auf dem Sensor-Aktor-Modul

Bild 7: Datenfluss für das Beispiel der LED-Steuerung

Auf dem Sensor-Aktor-Modul befindet sich ein Mikrocontroller (µC), der die externe Hardware (z.B. die LEDs) ansteuert. Zur Ablaufsteuerung und zur Kommunikation mit dem Nutzer dient der PC. Die Kommunikation erfolgt über eine USB-Schnittstelle. Die auf dem Mikrocontrollerboard enthaltene Hardware realisiert die Umwandlung der USB-Signale in ein asynchrones serielles Protokoll (USB to Serial). Die Software für den PC muss ihrerseits die serielle Kommunikation über einen virtuellen COM-Port realisieren. Im Mikrocontroller dient eine Tabelle (ein Feld) von 16-Bit Zahlen (in C++ in Visual Studio dementsprechend short int, entspricht short) als Datenschnittstelle. Sowohl der Mikrocontroller als auch der PC können Daten in diese Tabelle schreiben bzw. auslesen. Die Position in der Tabelle - also der Feldindex - bestimmt dabei die Bedeutung der Daten. Um die Nutzung durch den Programmierer zu erleichtern, wird in der Tabelle 1 (s.u.) der Feldindex durch symbolische Konstanten, nachfolgend als Kommandos bezeichnet, angegeben. Aus dem entsprechenden Kommando ergibt sich die Bedeutung der übertragenen Daten (beachte: Lesen von Daten aus der Mikrocontroller-Tabelle oder Schreiben von Daten in die Mikrocontroller-Tabelle). Anwendungsbeispiel: Sendet der PC z.B. ein neues Bitmuster für die LEDs, so wird dieser Wert in der Mikrocontroller-Tabelle an der Position LED gespeichert und außerdem wird die Mikrocontroller-Software darüber informiert, dass ein neuer Sollwert vorliegt und die Steuerung entsprechend reagieren muss. Statusinformationen und Messwerte (z.B. die Schalterstellungen) werden vom

2047 Stellgröße

-Ub

Ub

UM

0 -2047

PC USB USB to Serial µC LED

10

Mikrocontroller ebenfalls in der Mikrocontroller-Tabelle abgelegt und zyklisch aktualisiert. Der PC kann diese Daten jederzeit abrufen.

Übersicht aller möglichen Kommandos Kommandos für die Funktion WriteValue(…)

Kommando

(command)

Bedeutung Daten

(data)

MODE Betriebsart setzen 0 Analog (Standard)

1 Lautsprecher

2 Schrittmotor

3 Gleichstrommotor

LED LEDs setzen Bitmuster (Bit 0…7)

Bit-Nummer = LED-Nummer

DCM_SETVALUE Stellgröße (Spannung) Motor

setzen

12-Bit PW

-2047 = -Ub (Betriebsspannung)

2047 = Ub

DCM_CLEAR Zähler Encoder löschen 0 = Zähler löschen

SPK_ON Lautsprecher Ein/Aus 1 = Ein, 0 = Aus

SPK_FREQ Tonfrequenz in Hz setzen Wertebereich 20…25000 Hz

STP_MODE Betriebsart des

Schrittmotors

Bit 0,1: Mikroschrittmodus (MSM):

00-Voll, 01-Halb, 10-Viertel,11-Achtel;

Bit 2: 0 = Start/Stop, 1 = Hochlauf;

Bit 3: Richtung: 0 = vorwärts

STEP Einzelschritt ausführen 1: 1 Schritt im Vollschrittmodus

HOME Nulllage Schrittmotor

anfahren

0 = Anfahren der Nulllage (immer rückwärts)

STP_FREQ Schrittfrequenz in Hz

vorgeben

Für Start/Stop-Betrieb, für Hochlaufbetrieb

wird immer auf max. 250 Hz beschleunigt.

Untere Grenze: 20 Hz

STP_STEPS Schrittzahl setzen 1 Umdrehung = 48 Vollschritte

STP_CLEAR Zähler löschen 0 = Absolute/relative Schrittzahl und Anzahl

Umdrehungen löschen

Kommandos für die Funktion ReadValue(…)

Kommando

(command)

Bedeutung Daten

(data)

STATUS Gerätestatus lesen Bit 0,1 enthalten die Betriebsart

VERSION Firmwareversion lesen Bit13..15: Hauptversion, Bit 8..12: Unterversion

Bit0..7: Geräte-ID

SWITCH Schalter lesen Bitmuster (Bit 0…7)

Bit-Nummer = Schalter-Nummer

UB Betriebsspannung lesen in mV

7 6 5 4 3 0 1 2

7 6 5 4 3 0 1 2

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

11

Argumente für die Funktion ReadData(…)

Startindex in der µC-Tabelle

(sourceindex)

Bedeutung Daten

(buffer)

R2_TABLE Startadresse des Verlaufs der

Motordrehzahl (in U/min)

60 Werte (short int) werden

nach der Vorgabe eines neuen

PWM-Wertes für den Gleich-

strommotor gespeichert (10

Werte pro s, neue Messung

wird nur gestartet, wenn

vorherige beendet wurde).

Tabelle 1: Sensor-Aktor-Modul Kommandos

Funktionsbibliothek zur Steuerung des Sensor-Aktor-Moduls

Visual Studio C++ Projekteigenschaften zur Nutzung der Sensor-Aktor-Funktionsbibliothek (LIB und DLL) Für die Kommunikation des PC‘s mit dem Mikrocontroller des Sensor-Aktor-Moduls werden Funktionen bereitgestellt, die die asynchrone serielle Kommunikation realisieren. Die Funktionen wurden zu einer DLL zusammengefasst, die in das aktuelle Projekt eingebunden werden muss.

MES_POTI Spannung am Dreh-

potentiometer lesen

in Inkrementen des 10 Bit A/D-Wandlers

MES_LDR Spannung am

Helligkeitssensor lesen

in Inkrementen des 10 Bit A/D-Wandlers

PRESSURE Luftdruck bezogen auf die

Temperatur im SAM

in hPa

I2C_ACC Beschleunigungen x, y, z siehe Datenblatt MMA8452Q

DCM_VOLTAGEA Brückenspannung A lesen UMA in Inkrementen des 10 Bit A/D-Wandlers

DCM_VOLTAGEB Brückenspannung B lesen UMB in Inkrementen des 10 Bit A/D-Wandlers

UMotor = UMB - UMA

DCM_COUNTER Zähler der Encoderimpulse

lesen

64 Impulse pro Umdrehung

STP_STATUS Schrittmotorstatus lesen Bit 0: 1 = inNulllage, Bit 1: 1 = isRunning,

Bit 2: 0 = no error (Anzahl Umdrehungen),

Bit 3: Pegel der Lichtschranke ( 1 = offen)

STP_RELSTEPS Relative Schrittzahl (SZ) lesen 1 Umdrehung = 48 Vollschritte.

(Wird gelöscht, wenn neue SZ vorgegeben

wird.)

STP_ABSSTEPS Absolute Schrittzahl lesen Wird nach der Fahrt in die Nulllage gelöscht.

STP_TURNS Anzahl Umdrehungen lesen Wird nach der Fahrt in die Nulllage gelöscht.

12

Ein Projekt für Visual Studio 2012, das alle notwendigen Dateien und Einstellungen enthält, liegt auf AUSHANG\VisualC++ und heißt A3_SensorAktorModul. Nutzen Sie dieses vorbereitete Visual Studio Projekt! Bereitgestellte Funktionen zur Kommunikation mit dem Sensor-Aktor-Modul In einer DLL (Funktionsbibliothek) werden für Ihr Programm folgende Funktionen, die für die Ansteuerung des Sensor-Aktor-Moduls notwendig sind, bereitgestellt (command und data siehe Tabelle 1):

1. Verbindung zum Modul herstellen bzw. trennen

int OpenSAM(void);

Nach Programmstart muss die Verbindung einmalig mit OpenSAM(); hergestellt werden. Der Rückgabewert dieser Funktion ist die Gerätenummer. void CloseSAM(void); Am Ende des Programms muss die Verbindung getrennt werden.

2. Einen Wert an das Modul senden int WriteValue(unsigned char command, short data); Beispiel: Schreiben des Wertes 3 für das Kommando MODE = Betriebsart setzen WriteValue(MODE,3);

3. Einen Wert vom Modul lesen int ReadValue(unsigned char command, short* data); Beispiel: Lesen des Status und Speichern des Wertes auf der Variablen status short status; ReadValue(STATUS,&status);

4. Schreiben und Lesen von Datenfeldern

int WriteData(unsigned char destinationindex, unsigned char count, unsigned char* buffer); // count in Byte, max. 126

int ReadData(unsigned char sourceindex, unsigned char count, unsigned char* buffer); // count in Byte, max. 126

Beispiel: Lesen der Drehzahlmesswertetabelle short drehzahl[60]; ReadData(R2_TABLE,120,(unsigned char *)drehzahl);

Wenn der Rückgabewert einer der genannten Funktionen negativ ist, ist ein Fehler aufgetreten.

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

13

Aufgabe 1: C-Dateiarbeit Ziel des Programms sind das Lesen und Schreiben von Textdateien und das Lesen und Schreiben von Binärdateien. Vorgegeben ist die Textdatei "Durchmesser.txt". Sie liegt auf "Aushang\VisualC++\Text_und_Binaerdateien". Sie speichert eine Menge von Durchmesser - Messwerten einschließlich Zusatzinformationen. Jede Zeile enthält das Datum, eine Nummer und den Messwert in mm. Der Dateiaufbau entspricht folgendem Muster: 17.09.2014 315 20.032 17.09.2014 316 19.997 18.09.2014 317 20.018 ……. Aufgaben: 1. Anzeige des Inhalts der Textdatei auf dem Bildschirm. Die Formatierung der Datei soll erhalten

bleiben.

2. Einlesen der Textdatei und Auswertung der Messwerte a. Erzeugen Sie eine neue Textdatei "Ausschuss.txt".

In dieser Datei sollen alle Zeilen von "Durchmesser.txt" gespeichert werden, deren Messwerte außerhalb einer Toleranz von ±0.05 mm um den Nennwert 20.0 mm liegen. Zeigen Sie die Anzahl der Zeilen mit Ausschuss an.

b. Erzeugen Sie eine neue Binärdatei "Messwerte.bin". In dieser Datei sollen nur die Messwerte abgespeichert werden, die in der vorgegebenen Toleranz liegen.

3. Ermitteln Sie den arithmetischen Mittelwert der Messwerte aus der Datei "Messwerte.bin"

und zeigen Sie diesen auf dem Bildschirm an.

14

Aufgabe 2: Tonerzeugung

Mit Hilfe des Zeitgeberschaltkreises 8253 und des Lautsprechers des PCs sollen Töne (Hardware siehe unten) erzeugt werden.

Aufgabe:

Erzeugen Sie eine einfache Melodie (8 -12 Töne), wobei die Notenfrequenzen (Tonhöhe) und die Notenlängen in Feldern abgespeichert werden sollen (Hinweise zu Feldern siehe Lehrmaterial). Für die Notendauer ist die Funktion Sleep() zu benutzen siehe C++-Hilfe.

Hardwarebeschreibung In jedem PC befindet sich ein CTC-Schaltkreis 8253. CTC heißt Counter-Timer-Circuit also Zähler-Zeitgeber-Schaltkreis. An den Clock Eingängen dreier, voneinander unabhängiger, Kanäle ist ein konstantes Rechtecksignal mit der Frequenz f0 angeschlossen. An den Ausgängen OUT kann eine (kleinere) Frequenz f entnommen werden. Diese ergibt sich aus der Division der Eingangsfrequenz f0 durch die programmierbare Zeitgeberkonstante n. n ist eine 16-Bit Zahl vom Datentyp unsigned short int. Für die Tonerzeugung steht der Kanal 2 zur Verfügung.

Clock0 Gate0 Clock1 Gate1 Clock 2 Gate2

Kanal0 Kanal1 Kanal2

Adresse 0X40 Adresse 0X41 Adresse 0X42

OUT0 OUT1 OUT2

Eingangsfrequenz (Quarz)

f0= 1193180 Hz

zum Interrupt-

Controller zum DMA-

Controller

Paralleler E/A-Baustein

8255 (Baustein wird vom Betriebs-

system konfiguriert)

PortB:Adresse 0X61

PortB Bit0

PortB Bit1

Ausgangsfrequenz

f= 1193180 Hz /n

AND Lautsprecher

Zeitgeberschaltkreis 8253

OUT2= 1193180 Hz / n

n-Zeitgeberzeitkonstante

Co

ntr

olr

egis

ter

Ad

ress

e 0

x43

1 heißt Ton freigeschaltet

T0=1/f0

Tn=1/f

Schwingquarzfrequenz

f0 = 1,19318 106 Hz

Frequenz f des Ausgangssignals

in Betriebsart 3 bei n=4.

Am Eingang Gate muß

Highpegel anliegen.

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

15

Beispielfrequenzen für ausgewählte Töne Beispiele für Notendauern

Ton Frequenz in Hz Note Dauer in ms

c 262 ganze Note 2560

d 294 halbe Note 1280

e 330 viertel Note 640

f 349 achtel Note 320

g 392 sechzehntel Note 160

a 440 zweiunddreißigstel Note 80

h 494 vierundsechzigstel Note 40

c² 523

Programmierung des CTC-Schaltkreises 8253

Zur Erzeugung der gewünschten Ausgangsfrequenz f muss der Schaltkreis programmiert werden. Dies erfolgt durch Ausgabe eines Bytes an das Control-Register des Schaltkreises. Das Control-Register hat die Adresse 0X43. Die einzelnen Bits dieses Bytes ergeben sich aus folgender Tabelle.

0 0 0 = Betriebsart 0

0 0 1 = Betriebsart 1

0 1 0 = Betriebsart 2

0 1 1 = Betriebsart 3

1 0 0 = Betriebsart 4

0 = Binär

1 = BCD

0 0 = Inhalt Counterregister -> Latchregister

0 1 = Nur MSB lesen/schreiben

1 0 = Nur LSB lesen/schreiben

1 1 = Erst LSB, dann MSB lesen/schreiben

0 0 = Kanal 0 programmieren

0 1 = Kanal 1 programmieren

1 0 = Kanal 2 programmieren

Controlregister ( Portadresse 0X43 )

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

Zur Erzeugung einer Frequenz f mit dem Tastverhältnis 1:1 wird der Kanal 2 in Betriebsart 3, Binär betrieben. Der Teilerfaktor n ist eine 16 Bit-Zahl. Es müssen also zwei 8 Bit-Werte, erst LSB ( least significant byte ), dann MSB ( most significant byte ) auf die Portadresse 0X42 geschrieben werden.

16

Hardwarezugriff unter Windows 7 64 Bit

Der Zugriff auf Hardwareressourcen ist unter Windows nur über entsprechende Treiber möglich.

Für den Zugriff auf die Ports des Zeitgeberschaltkreises wird für diesen Versuch der Treiber mit den zugehörigen Bibliotheken WinRing0 benutzt. WinRing0 ermöglicht den Hardwarezugriff unter Windows mit Hilfe der Funktionen WriteIoPortByte() und ReadIoPortByte().

Für die Nutzung des Treibers im Rechnerlabor MB (Treiber wurde installiert und automatisch gestartet.) wird das Projekt A2_Tonerzeugung unter Aushang\VisualC++ bereitgestellt. Kopieren Sie den Ordner A2_Tonerzeugung nach C:\Kopie und öffnen Sie die Solution.

Beispielcode #include <stdio.h> #include <windows.h> #include "OlsApi.h" // Deklaration der Funktionen void main(void) { InitializeOls(); int retval = 0;

retval = GetDllStatus(); printf("\nRueckgabewert: %d\n",retval); // 0 heißt o.k. //.... WriteIoPortByte(0x43,0xB6); // Ausgabe des Steuerworts an den Port 43H unsigned char b = 0;

b = ReadIoPortByte(0x61);// Lesen von Port 61H //....

DeinitializeOls(); }

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

17

Aufgabe 3: Peripheriesteuerung mit einem Sensor-Aktor-Modul

Aufgaben 1. Prüfen Sie, ob die Funktion OpenSam() eine gültige Gerätenummer aus dem Bereich 1…25

liefert. Wenn ja, zeigen Sie diese an, wenn nein, beenden Sie das Programm mit einer Fehlermeldung.

2. Setzen Sie die Betriebsart "Gleichstrommotor" und warten Sie anschließend, bis die entsprechenden Bits im Gerätestatus die Betriebsart "Gleichstrommotor" anzeigen.

3. Ermitteln Sie die Betriebsspannung Ub des Sensor-Aktor-Moduls und zeigen Sie diese an.

4. Programmieren Sie eine Schleife zur Vorgabe der Motorspannung.

Der Nutzer soll eine Motorspannung in Volt ( Maximalwert ist die Betriebsspannung Ub, Minimalwert ist -Ub ! ) über die Tastatur eingeben. Die Schleife soll beendet werden, wenn der Eingabewert außerhalb des Bereiches -Ub…Ub liegt. Jeder gültige Spannungswert soll am Gleichstrommotor des Sensor-Aktor-Moduls eingestellt werden.

5. Fügen Sie in die Schleife das Messen der Drehzahl und der Motorspannung ein. Ermitteln Sie die sich bei einer vorgegebenen Spannung einstellende Motordrehzahl mit Hilfe des Zählerstandes der Encoderimpulse. Zeigen Sie die Motordrehzahl in U/min auf dem Bildschirm an. Ermitteln Sie aus den beiden Brückenspannungen die tatsächliche Motorspannung. Zeigen Sie die Motorspannung in Volt auf dem Bildschirm an.

18

Aufgabe 4: Klassen in C++ und Nutzung des .NET Frameworks

Aufgabe: Erstellen Sie ein Programm zur Berechnung von Dreiecken, das folgende Teilaufgaben realisiert: 1. Einlesen der Seitenlängen (in mm) über die Tastatur

2. Prüfen, ob die eingegebenen Seitenlängen ein gültiges Dreieck ergeben

3. Wiederholung der Eingabe, solange die Seiten kein Dreieck ergeben

4. Prüfen, ob das Dreieck rechtwinklig ist und Anzeigen des Ergebnisses

5. Berechnen und Anzeigen des Flächeninhalts des Dreiecks

Zur Lösung der Aufgabe ist ein Programmgerüst, das Projekt P4_Klassen, vorgegeben. Dieses können Sie von AUSHANG\VISUALC++ kopieren.

Das Projekt P4_Klassen enthält die 3 Dateien

Triangle.h – Klassendeklaration

Triangle.cpp – Klassenimplementation

Start.cpp – Hauptprogramm

Wenn Sie das Projekt neu erstellen wollen, müssen Sie folgende Hinweise beachten:

Erstellen Sie ein leeres C++ Projekt

Schalten Sie ProjectPropertiesConfiguration PropertiesGeneralCommon Language Runtime support ein (/CLR)

Kopieren Sie die vorgegebenen Dateien in das Projektverzeichnis und fügen Sie diese zu Ihrem Projekt hinzu (Alternativ: Add Class zum Erzeugen einer neuen Klasse).

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

19

Triangle.h – Klassendeklaration

#pragma once ref class Triangle { private: double sideA; double sideB; double sideC; // auf diese Variable wird immer die größte Seite geladen double area; void CalculateArea(); public: Triangle(void); ~Triangle(void); bool SetValues(double sA, double sB, double sC); bool IsOrthogonal(); property double Area { double get() { CalculateArea(); return area; } /* set-Zweig hier nicht erforderlich void set(double value) { area=value; } */ } };

20

Triangle.cpp – Klassenimplementation

using namespace System; #include "Triangle.h" //Konstruktor Triangle::Triangle(void) { // Initialisieren der privaten Felder (Membervariablen) mit 1.0 // und Berechnung des Flächeninhalts } //Destruktor Triangle::~Triangle(void) { } bool Triangle::SetValues(double sA, double sB, double sC) { // die Werte sortieren, so dass der größte Wert in sC steht

// Prüfen, ob die eingegebenen Seiten ein Dreieck ergeben // wenn die Seiten ein Dreieck ergeben, die übergebenen Werte auf die // privaten Membervariablen setzen

} bool Triangle::IsOrthogonal() { // Prüfen, ob das Dreieck rechtwinklig ist } void Triangle::CalculateArea() { // Berechnen des Flächeninhalts // Flächeninhalt für beliebiges Dreieck: // A=sqrt(s*(s-a)*(s-b)*(s-c)) mit s=(a+b+c)/2 }

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

21

Start.cpp – Hauptprogramm // Datei: Start.cpp // Versuch 4: Klassen in C++ // C++ Console Projekt mit .NET // C++ .NET - muss in den Projekteigenschaften eingeschaltet werden // --> Common language runtime support einschalten! siehe Anleitung

using namespace System; #include "Triangle.h" void main(void) { String^ message="Programm zur Berechnung von Dreiecken"; Console::WriteLine(message); // Ein Objekt der Klasse Triangle anlegen // Seitenlängen über Tastatur eingeben mit Hilfe der Funktion // Console::ReadLine() // So lange wiederholen, bis die eingegebenen Seitenlängen ein // gültiges Dreieck ergeben // Prüfen, ob das Dreieck rechtwinklig ist und Anzeigen des Ergebnisses // Berechnen und Anzeigen des Flächeninhalts des Dreiecks Console::ReadKey(); // Warten auf Tastendruck }

22

Lehrmaterial Datentypen und Konstanten in C++

Typname Byte- anzahl

Kommentar Konstante (Beispiele)

Ganzzahlige Typen = integrale Typen

char / signed char

1 8-Bit mit Vorzeichen -128 bis +127

'A', '\n' '\x1B' = Escape

unsigned char 1 8-Bit ohne Vorzeichen 0 bis 255

0xFF (hexadezimal)

short int 2 16-Bit mit Vorzeichen -32.768 bis 32.767

2345

unsigned short int

2 16-Bit ohne Vorzeichen 0 bis 65.535

2345U 2345u

int / signed int

4 32-Bit mit Vorzeichen -2.147.483.648 bis 2.147.483.647

2345

unsigned int 4 32-Bit ohne Vorzeichen 0 bis 4.294.967.295

2345U 2345u

long int / signed long int

4 32-Bit mit Vorzeichen ( in C# 8 Byte ! ) -2.147.483.648 bis 2.147.483.647

2345L 2345l

unsigned long int 4 32-Bit ohne Vorzeichen 0 bis 4.294.967.295

2345UL 2345ul

long long / signed long long

8 64-Bit mit Vorzeichen ( 19 Stellen ) - 9.223.372.036.854.775.808 bis +9.223.372.036.854.775.807

unsigned long long

8 64-Bit ohne Vorzeichen ( 19 Stellen ) 0 bis 18.446.744.073.709.551.615

Gleitkommatypen

float 4 ±1.5 × 10-45 bis ±3.4 × 1038 7 Stellen

2.34F 2.34f

double 8 ±5.0 × 10-324 bis ±1.7 × 10308 15 Stellen

2.34 12E-2, 1.67e5

Unicodezeichen

wchar_t 2 Ein 16-Bit Zeichen aus der Unicodetabelle, 0 - 65535

L'A', L'\n'

Wahrheitswerte

bool 1 Schlüsselworte: true, false

true

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

23

Funktionen zur Anzeige auf dem Bildschirm - printf() und zur Tastatureingabe - scanf() Einlesen formatierter Daten von der Tastatur und formatierte Anzeige auf dem Bildschirm #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> void main() { int i; double x; char text[80]; printf("Geben Sie eine int-Zahl ein: "); scanf("%d", &i); printf("Geben Sie eine double-Zahl ein: "); scanf("%lf", &x); printf("Geben Sie eine Zeichenkette ein: "); scanf("%s", text); printf("Inhalt der Daten: %d %lf %s\n", i, x, text); }

Nutzung von _kbhit() und _getch() sowie der Taste Esc (Escape)

#include <conio.h> #include <stdio.h> void main() {

bool ende = false; // Taste Esc setzt ende auf true int taste = 0;

do { // Hier kommt das gesamte Programm printf("Ich rechne noch …\n"); if(_kbhit() != 0) // Test auf Tastendruck { // Ja, es wurde eine Taste gedrückt taste =_getch(); // Taste lesen if(taste == 0x1B) // War es die Esc-Taste? ende = true;// Ja, dann Ende der while-Schleife } } while(ende == false); }

24

Felder und Strukturen

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <conio.h> #include <string.h> void main() { char anzeigetext[80]; // Ein Feld für 80 Zeichen = Zeichenkette strcpy(anzeigetext,"Anzeige der Quadratzahlen von 0 bis 19\n"); int quadratzahlen[20]; // Ein Feld für 20 int-Zahlen for(int i=0; i<20; ++i) // Index läuft von 0 bis 19 quadratzahlen[i]=i*i; // Füllen des Feldes printf("%s",anzeigetext); for(int i=0; i<20; ++i) printf("%d x %d = %d\n",i,i,quadratzahlen[i]); _getch(); }

Anzeige: Anzeige der Quadratzahlen von 0 bis 19 0 x 0 = 0 1 x 1 = 1 2 x 2 = 4 …

#include <stdio.h> #include <conio.h> #include <string.h> struct student // Strukturdeklaration { int matrikelNr; double bafoeg; }; void main() { student meier; //Definition der Struktur meier vom Typ student meier.matrikelNr = 12345; // Zugriff auf eine Komponente der Struktur meier.bafoeg = 512.50; printf("Der Student mit der Matrikelnummer %d erhaelt %.2lf Euro Bafoeg.\n", meier.matrikelNr,meier.bafoeg); _getch(); }

Anzeige: Der Student mit der Matrikelnummer 12345 erhaelt 512.00 Euro Bafoeg.

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

25

Funktionen zur Dateiarbeit Formatiertes Schreiben und Lesen einer Datei im Textmodus (vergleiche: printf() und scanf() ) #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main() { FILE *stream1, *stream2; int i, zeilenzahl=0; double x; char name[80]; if((stream1=fopen("test.txt", "rt" )) == NULL) { printf("Datei konnte nicht geoeffnet werden!\n"); return(-1); } while(fscanf(stream1,"%d%lf%s", &i, &x, name) != EOF) ++zeilenzahl; printf("%d Zeilen wurden gelesen.\n", zeilenzahl); rewind(stream1); //Filepointer wieder an den Anfang der Datei setzen fscanf(stream1,"%d%lf%s", &i, &x, name); fclose(stream1); if((stream2=fopen("erstezeile.txt", "wt" )) == NULL) { printf("Datei konnte nicht erzeugt werden!\n"); return(-2); } fprintf(stream2,"%s: %lf\n", name, x); fclose(stream2); return(0); }

Aufbau der Datei "test.txt":

1 27.5 Temperatur … 27 1026 Druck

Aufbau der Datei "erstezeile.txt": Temperatur: 27.500000

26

Schreiben und Lesen im Binärmodus Demo 1: Ein Feld von 10 int-Zahlen schreiben und lesen und anzeigen #define _CRT_SECURE_NO_WARNINGS #include < stdio.h > #include <conio.h> void main () { FILE *fp; int testout[10], testin[10], i; for ( i = 0 ; i < 10 ; ++i ) testout[i] = 276 + i ; // Feld füllen (Demo Werte) fp = fopen ( "C:\\Kopie\\test.bin", "wb" ); // Datei im Binärmodus

// hier wird als Demo das ganze Feld // (10 int-Zahlen = 40 Byte) auf einmal geschrieben

fwrite ( testout, sizeof (testout), 1, fp ); fclose ( fp ); fp = fopen ( "C:\\Kopie\\test.bin", "rb" ); for (i=0; i<10; ++i) // hier wird als Demo jede int-Zahl = 4 Byte einzeln gelesen fread (&testin[i], sizeof (int), 1, fp ); fclose ( fp ); // Anzeigen for ( i = 0 ; i < 10 ; ++i ) printf ( "%d %d %d \n", i, testout[i], testin[i]); _getch(); }

Demo 2: Schreiben und Lesen eines Feldes aus Strukturen #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> struct messwert { int nr; char zeit[12]; double wert; }; void main() { struct messwert feld[5]={ {1,"12:27",3.45}, {2,"13:35",1.78}, {3,"10:56",5.96}, {4,"9:17",11.73}, {5,"14:27",-3.01}}; FILE * fp; fp=fopen("messwerte.bin","wb"); fwrite(feld, sizeof(feld), 1, fp); // ganzes Feld schreiben fclose(fp); //nur die erste Struktur einlesen fp=fopen("messwerte.bin", "rb"); struct messwert zeile; fread(&zeile, sizeof(zeile), 1, fp); printf("Erster Messwert: %lf\n", zeile.wert); fclose(fp); }

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

27

Ablaufsteuerung do-while-Schleife Syntax: do { < Anweisungen > } while ( < Bedingungstest > ) ; int k ; k = 12 ; do { printf( " k = % d \n " , k ); k = k-1; } while( k > 8 );

while-Schleife Syntax: while ( < Bedingungstest > ) { < Anweisungen > }

int k = 12; while( k > 8 ) { printf( "k = %d \n", k ); k = k-1; }

for-Schleife Syntax: for ( < Initialisierung > ; < Bedingungstest > ; < Modifizierung > ) { < Anweisungen > } for( int k = 12 ; k > 8 ; --k) { printf("k = %d \n", k );

}

28

if-Anweisung Syntax: if ( < Bedingungstest > ) { < Anweisungen > }

if - else Syntax: if ( < Bedingungstest > ) { /* Test liefert wahr */ < Anweisungen 1 > } else { /* Test liefert falsch */ < Anweisungen 2 > } taste = _getch( ); if( taste == 'p' ) printf("Ein kleines p !"); else printf("Kein kleines p !");

switch-Anweisung Syntax: switch ( < ganzzahliger Ausdruck > ) { case < ganzzahliger Ausdruck >:< Anweisungen > break; default : < Anweisungen > break; } #include <stdio.h> #include <conio.h> void main() { int taste; printf("Bitte Taste betaetigen "); taste = _getch(); switch( taste ) { case 'p' : printf("Taste p\n"); break ; case '\r': printf("Enter Taste! \n"); break ; default : printf("Ende !"); break ; } _getch(); }

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

29

Die Anweisung break ist in folgenden Fällen anwendbar - mit break kann man eine (nicht zwei) Schleife verlassen - wirkt bei switch, while, do - while und for - wirkt nicht auf if oder else #include <stdio.h> #include <conio.h> void main() { int taste; int flag = 1; printf("Druecken Sie eine Taste ( Ende mit der Tabulatortaste! )\n"); while(flag == 1) { taste = _getch(); if( taste == '\t' ) { printf("Das war die Tabulatortaste!\n\a"); break; } } }

Die Anweisung continue - mit continue kann man einen Schleifendurchlauf abbrechen - man springt zum Anfang (zur Modifizierung) der Schleife zurück

#include <stdio.h> void main() { int i; for ( i = 0 ; i < 10 ; ++i ) { if ( i > 3 ) continue ; printf( " i = %d \n ", i ); } printf(" i = %d \n ", i ); printf(" ok ! "); }

30

Arithmetische Operatoren * Multiplikation x = 5 * y / Division x = x/y % Modulo (Rest der ganzzahligen Division) x = 19 % 3 (Ergebnis: x = 1 ) + Addition - Subtraktion Vergleichsoperatoren < kleiner als < = kleiner gleich > größer als > = größer gleich = = Test auf Gleichheit ( Verwechselungsgefahr mit dem Zuweisungsoperator = ) ! = Test auf Ungleichheit Inkrement- und Dekrementoperatoren ++ bedeutet Inkrementieren des Operanden um eine Einheit, - - bedeutet Dekrementieren des Operanden um eine Einheit aber: Die Stellung der Operatoren ist zu beachten: - Präfixinkrementierung int x, y; x = 3; y = ++x ; // x = x + 1, y = x // also x = 4, y = 4

- Postfixinkrementierung int x, y; x = 3 y = x++ ; // y = x, x = x + 1 // also y = 3, x = 4

Bitweise Operatoren & UND ( Bits löschen, Bits ausblenden, Bits maskieren ) | ODER ( Bits setzen, Bits einblenden ) ^ exklusives ODER << Linksschieben >> Rechtsschieben ~ Einerkomplement

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016

31

unsigned char x=0x33; // binär: x = 0011 0011 unsigned char y=0x0F; // y = 0000 1111 unsigned char z; z = x & y ; // 0011 0011 // & 0000 1111 // z = 0000 0011 = 0x03 Bit 4-7 auf 0 setzen z = x | y ; // 0011 0011 // | 0000 1111 // z = 0011 1111 = 0x3F Bit 0-3 auf 1 setzen z = x ^ y ; // 0011 0011 // ^ 0000 1111 // z = 0011 1100 = 0x3C einzelne Bits negieren unsigned char w = 0xB4; // binär: w = 1011 0100 w = ~w; // w = 0100 1011 alle Bits negieren w = w >> 2; // w = 0001 0010 um 2 Bit nach rechts schieben

Beispiel: Die Funktion liefert die Anzahl der Einsen in einem Byte. int AnzahlEins ( unsigned char wert ) { int anzahl=0; for ( int i = 0; i < 8; ++i ) { if ( (wert & 0X80) != 0 ) ++anzahl; wert = 2 * wert; } return anzahl; }

Logische Operatoren && logisches UND || logisches ODER ! logische Negation Beispiel: Test, ob eine Zahl z der Code eines ASCII-Buchstabens ist

int busta(int z) { if( z >= 'a' && z <= 'z' || z >= 'A' && z <= 'Z' ) return (1) ; else return (0) ; }

32

Adressoperatoren

& liefert die Speicheradresse eines Operanden

* - beeinflusst den Speicherinhalt, der unter einer Speicheradresse zu finden ist - beeinflusst also den Wert unter Benutzung der Adresse eines Operanden

sizeof – Operator Der sizeof – Operator liefert die Anzahl der in seinem Operanden enthaltenen Bytes. x = sizeof (int); // x = 4 bei 32/64-Bit-Windows char text [] = "C++"; x = sizeof (text); // x = 4 da 3 ASCII-Zeichen und das Endekennzeichen '\0'

new und delete - Operatoren zur dynamischen Anforderung von Speicher Beispiel: Speicher für eine double Zahl anfordern, nutzen und freigeben

double * px; px = new double; *px = 6.285; delete px;

Beispiel: Speicher für 10000 Byte anfordern, nutzen und freigeben

char * pc; pc = new char [10000]; strcpy( pc, "Neuer Speicher!"); printf("%s\n", pc); delete [] pc;

33

weitere Bibliotheksfunktionen (Beachte: einige Funktionen benötigen #define _CRT_SECURE_NO_WARNINGS)

Mathematische Funktionen, benötigte Headerdatei: #include <math.h> #define _USE_MATH_DEFINES vor #include <math.h> ermöglicht die Benutzung der Konstanten M_PI für π

Beschreibung Funktion Beispiel

Betrag einer int-Zahl int abs(int x); int value1 = abs(-3); //value1 = 3

Betrag einer double-Zahl double fabs(double x); double value2 = fabs(-3.1); //value2 = 3.1

Aufrunden double ceil(double x); value2 = ceil(3.4); //value2 = 4.0

Ganzzahliger Anteil einer double-Zahl (Abrunden)

double floor(double x); value2 = floor(3.6); //value2 = 3.0

Rest einer Division double fmod(double x, double y); value2 = fmod(4.1,2.0); //value2 = 0.1

Kosinus

Par

amet

er in

Bo

gen

maß

double cos(double x); value2 = cos(0.0); //value2 = 1.0

Sinus double sin(double x); value2 = sin(0.0); //value2 = 0.0

Tangens double tan(double x); value2 = tan(0.0); //value2 = 0.0

Arkuskosinus double acos(double x); value2 = acos(1.0); //value2 = 0.0

Arkussinus double asin(double x); value2 = asin(0.0); //value2 = 0.0

Arkustangens double atan(double x); value2 = atan(1.0); //value2 = 0.7853.. -->45°

Arkustangens mit Berücksichtigung des Quadranten

double atan2(double x, double y); value2 = atan2(-1.0,1.0); //value2 = -0.7853.. -->-45° value2 = atan2(1.0,0.0); //value2 = 1.570.. -->180°

natürliche Exponentialfunktion, e-Funktion 𝑒𝑥

double exp(double x); value2 = exp(1.0); //value2 = 2.718281..

natürlicher Logarithmus, 𝑙𝑜𝑔𝑒𝑥

double log(double x); value2 = log(2.718281); //value2 = 1.0

dekadischer Logarithmus, 𝑙𝑜𝑔10𝑥

double log10(double x); value2 = log10(1000.0); //value2 = 3.0

Potenzfunktion, 𝑥𝑦 double pow(double x, double y); value2 = pow(2.0,3.0); //value2 = 8.0 value2 = pow(27.0,1.0/3.0); //3. Wurzel aus 27: value2 = 3.0

Quadratwurzel double sqrt(double x); value2 = sqrt(16.0); //value2 = 4.0

34

Zeichenketten-Funktionen, benötigte Header-Datei: #include <string.h>

Beschreibung Funktion Beispiel

Anlegen einer Variable zum Speichern von Zeichenketten

- char str[80]; //Zeichenkette mit bis zu 79 Zeichen (+ Stringendekennzeichen)

Zeichenkette in eine andere kopieren

char *strcpy(char *ziel, const char *quelle); strcpy(str, "Hallo "); //str = "Hallo ", evtl. vorhandener //Inhalt wird überschrieben

Zeichenkette an eine andere anhängen

char *strcat(char *ziel, const char *quelle); strcat(str, "Welt!"); //str = "Hallo Welt!"

Zeichenketten vergleichen int strcmp(const char *str1, const char *str2);

int result = strcmp("Affe","Affe"); //result = 0 result = strcmp("Affe","affe"); //result = -1 result = strcmp("Affe","Zebra"); //result = -1 result = strcmp("Zebra","Affe"); //result = 1

Prüfen, ob ein Zeichen in einer Zeichenkette vorhanden ist

char *strchr(const char *str, int c); char *pos = strchr(str,'x'); //pos = NULL, da kein 'x' vorh. pos = strchr(str,'e'); //pos != NULL, "Adresse" von 'e' int index = pos – str; //Index von 'e' innerhalb von str ermitteln

Prüfen, ob Zeichenkette in einer anderen enthalten ist

char *strstr(char *str1, const char *str2); pos = strstr(str,"Affe"); //Bedeutung von pos: siehe strchr()

Länge einer Zeichenkette ermitteln

int strlen(const char *str); int len = strlen(str); //len = 11 (Länge ohne Stringendekennz.)

Sonstige Funktionen, benötigte Header-Dateien: für a: #include <windows.h> für b-e: #include <stdlib.h>

Beschreibung Funktion Beispiel

a Wartezeit, Programm anhalten

void Sleep(DWORD milliSeconds); Sleep(500); //wartet 500ms

b Zufallsgenerator initialisieren

void srand(unsigned int seed); srand(20); //Zufallszahlengenerator wird auf "pseudo"- zufälligen Startwert gesetzt

c Zufallszahl erzeugen int rand(void); int zuf = rand(); //zuf = Zufallszahl zwischen 0 und 32767 zuf = rand() % 100; //zuf = Zufallsz. zw. 0 und 99

d Zeichenkette in double-Zahl konvertieren

double atof(char *str); double wert = atof("3.141"); //wert = 3.141

e Zeichenkette in int-Zahl konvertieren

int atoi(char *str); int wert2 = atoi("128"); //wert2 = 128

35

Funktionen zur Dateiarbeit, benötigte Headerdatei: #include <stdio.h>

Für alle Dateien

Beschreibung Funktion Beispiel

Eine Datei öffnen FILE * fopen(const char * DateiName, const char * Modus);

FILE * fp = fopen("Messwerte.bin","rb"); //binär lesen FILE * fp2 = fopen("Messwerte.bin","wb"); //binär schreiben FILE * fp3 = fopen("Messwerte.txt","rt"); //Textdatei lesen FILE * fp4 = fopen("Messwerte.txt","wt"); //Textd. Schreiben // fopen liefert NULL, wenn Datei nicht geöffnet werden kann

Eine Datei schließen int fclose(FILE *DateiZeiger); fclose(fp);

Dateizeiger an Dateianfang setzen

void rewind(FILE *DateiZeiger); rewind(fp);

Dateizeiger an beliebige Stelle setzen

int fseek(FILE *DateiZeiger, long offsetInByte, int origin);

fseek(fp, 24L, SEEK_SET); //Dateizeiger auf Byte 24 (vom //Dateianfang aus) setzen fseek(fp, -8L, SEEK_CUR); //Dateizeiger 8 Byte zurücksetzen

Nur für Binärdateien

In eine Binärdatei schreiben size_t fwrite(const void *daten, size_t GroeßeInByte, size_t Anzahl, FILE *DateiZeiger); Rückgabewert = Anzahl geschriebener Elemente size_t = unsigned int

double messwert = 12.3; double alleWerte[5] = { 2.4, 3.5, 7.2, 8.1, 9.9};

//Eine Double-Zahl schreiben fwrite(&messwert, sizeof(double), 1, fp2);

//Ein ganzes Feld aus Double-Zahlen auf einmal schreiben fwrite(alleWerte, sizeof(alleWerte), 1, fp2);

Aus einer Binärdatei lesen size_t fread(const void *daten, size_t GroeßeInByte, size_t Anzahl, FILE *DateiZeiger); Rückgabewert = Anzahl gelesener Elemente. Rückg.w. = 0: kein Wert gelesen, z.B. am Dateiende.

//Eine Double-Zahl lesen fread(&alleWerte[0], sizeof(double), 1, fp);

//Ein ganzes Feld aus Double-Zahlen auf einmal lesen fread(alleWerte, sizeof(alleWerte), 1, fp);

//Solange eine Double-Zahl gelesen werden konnte, ... while (fread(&messwert, sizeof(double), 1, fp) > 0) ...

36

Nur für Textdateien

In eine Textdatei schreiben int fprintf(FILE *DateiZeiger, const char *format);

int i = 1; fprintf(fp4,"%d. Messwert:\t%lf\n", i, 23.67);

Aus einer Textdatei lesen int fscanf(FILE *DateiZeiger, const char *format);

//Eine Zeile mit obigem Aufbau lesen unsigned char text[20]; double wert; fscanf(fp3,"%d. %s %lf", &i, text, &wert); //Ein Zeichen aus Textdatei lesen, solange Dateiende //noch nicht erreicht ist unsigned char zeichen; while( fscanf(fp3, "%c", &zeichen) != EOF) ...

Funktionen für Bildschirmausgaben und Tastaturnutzung, benötigte Headerdateien: #include <stdio.h> #include <conio.h>

Bildschirmausgaben

Beschreibung Funktion Beispiel

Formatierte Ausgabe auf dem Bildschirm

int printf(const char *text [, argumente]);

int tag = 15; printf("Heute ist Mittwoch, der %d.%d.%d\n", tag, 10, 2014);

wichtige Escape-Sequenzen und Platzhalter \n neue Zeile %d Integer-Zahl \t Tabulator %lf Double-Zahl \b „Backspace“ %s Zeichenkette \r Cursor Zeilenanfang %c einzelnes (ASCII)-Zeichen

Ein Zeichen ausgeben int putch(int zeichen); putch(0x34); //Gibt die Ziffer 4 aus putch('a'); //Gibt ein kleines a aus

Tastaturnutzung

Formatiertes einlesen über die Tastatur (Eingaben müssen mit <Enter> abgeschlossen werden)

int scanf(const char *text [, argumente]);

double eingabe1, eingabe2; scanf("%lf", &eingabe1); scanf("%lf %lf", &eingabe1, &eingabe2);

Ein Zeichen lesen (wartet auf Drücken einer Taste!)

int _getch(void); int taste = _getch(); //ASCII-Zeichen steht in taste if(_getch() == 'a') ... else ... // Wenn 'a' gedrückt, ...

Prüfen, ob überhaupt eine Taste gedrückt wurde

int _kbhit(void); if(_kbhit() != 0) taste = _getch(); //_getch() nur aufrufen, wenn Taste gedr.

TU Ilmenau, Fakultät für Maschinenbau 22.03.2016 Univ.-Prof. Dr.-Ing. habil. M. Weiß

37

C++ - Klassendemo Schritt 1: Klassendeklaration using namespace System;

ref class CDate // die Klasse heisst also CDate { private: // drei private- Membervariablen vom Typ int int tag; int monat; int jahr; public: CDate(); // Konstruktor ~CDate(); // Destruktor void SetWerte( int t, int m, int j ); //eine Methode der Klasse String^ GetString(); // noch eine Methode

property int Jahr // eine property für jahr { int get() { return jahr; } void set(int value) { jahr=value; } } };

Schritt 2: Methodendefinition // Konstruktor, Aufgabe: Initialisierung aller Membervariablen (Felder) CDate::CDate() { tag=1; monat=1; jahr=2015; } // Destruktor, hat in diesem Beispiel keine Aufgabe CDate:: ~CDate() { }

38

// Eine Methode (Funktion) zum Setzen der privaten Variablen void CDate::SetWerte( int t, int m, int j ) { tag=t; monat=m; jahr=j; } // Eine Methode zum Erstellen eines Datumsstrings String^ CDate::GetString() { String^ dateString; dateString=tag + "." + monat + "." + jahr; return dateString; }

Schritt 3: Klassennutzung void main() { // Ein Objekt der Klasse CDate wird angelegt // Das Objekt heisst datum // Der Konstruktor wird automatisch abgearbeitet CDate datum; // Methodenaufruf durch Nutzung des Punktoperators String^ anzeige=datum.GetString(); // Aufruf einer statischen Methode der Klasse Console mit :: Operator Console::WriteLine(anzeige); // Änderung aller Werte und Anzeigen auf dem Bildschirm datum.SetWerte( 15, 5, 2016); Console::WriteLine(datum.GetString()); // Einlesen von der Tastatur mit Hilfe von .NET Klassen int jahreingabe; String^ input; Console::WriteLine("Bitte geben Sie das Jahr ein:"); input= Console::ReadLine(); jahreingabe=Convert::ToInt32(input); // Setzen des Jahres über die Property datum.Jahr=jahreingabe; // Anzeigen der geänderten Werte Console::WriteLine(datum.Jahr); Console::WriteLine("Neues Datum: {0}",datum.GetString()); Console::ReadKey(); //Warten auf Tastendruck } // Der Destruktor wird automatisch abgearbeitet