Modellgestütztes Software Engineering Versuch 5 Wintersemester 2015 Version 7.0.1, 16. Dezember 2015
Inhalt 1 OOP IN C... 3 1.1 UMSETZUNG IN RAPHSODY (RIC)... 3 2 DIE ENTWICKLUNGSUMGEBUNG... 5 2.1 HARDWARE MCB1700... 5 2.2 EMBEDDED UML MIT DEM REALTIME EXECUTION FRAMEWORK RXF VON WILLERT... 5 2.3 NEUES PROJEKT FÜRS ZIELSYSTEM... 6 a) Projekt anlegen... 6 b) Profil auswählen... 6 c) Benennungen anpassen... 7 d) Stereotype festlegen... 7 e) Header Dateien einbinden... 8 f) Diagramme anlegen... 9 3 KOMPONENTEN DES BOARDS... 10 3.1 ERSTES PROJEKT MIT DEN PORT LEDS... 10 a) LED mit einer HAL-Klasse LED0 ohne weitere Intelligenz ansteuern... 10 b) Generate Make and Run... 12 c) LED mit einer intelligenten Klasse ansteuern... 14 d) Aufgabe LED1:... 14 3.2 TASTERINT0 IM POLLING BETRIEB... 15 3.3 JOYSTICK... 16 a) Aufgabe Joystick:... 16 3.4 POTI... 17 a) Aufgabe Poti... 17 3.5 LCD-TFT DISPLAY-PANEL 240X320... 17 4 AUFGABEN... 18 a) Aufgabe LED1... 18 b) Aufgabe Joystick... 18 c) Aufgabe Poti... 18 d) Ihre Projektidee:... 18 4.2 EVENT DURCH EINE ISR AUSLÖSEN... 19 5 LITERATUR... 20 2
1 OOP in C Im Folgenden werden die Konzepte vorgestellt, die verwendet werden um auch in der strukturierten Programmiersprache C objektorientierte Ansätze umsetzen zu können. Objekte werden als Strukturen (structs) realisiert. Die Methoden werden zu eigenständigen Funktionen, denen bei jedem Aufruf ein Zeiger auf das zu verwendende Objekt übergeben werden muss. 1.1 Umsetzung in Raphsody (RiC) Folgende Klassen werden in C realisiert Realisierung von cklasse Die Struktur erhält den Namen der Klasse: /*## class cklasse */ typedef struct cklasse cklasse; struct cklasse { int iwert; /*## attribute iwert */ }; Die Methoden werden als eigenständige Funktionen angelegt. Es gilt folgende Namensregelung: Klassenname_Methodenname Zusätzlich zu den übergeben Variablen kommt immer noch ein Pointer auf die Struktur der Klasse dazu. void cklasse_setiwert(cklasse* const me, int iein) Auf die Memebervariablen der Klasse muss immer über den übergebenen Zeiger zugegriffen werden. me->iwert=iein; 3
Ausgeführte Methoden: /*## operation GetiWert() */ int cklasse_getiwert(cklasse* const me) { /*#[ operation GetiWert() */ return me->iwert; /*#]*/ } /*## operation SetiWert(int) */ void cklasse_setiwert(cklasse* const me, int iein) { /*#[ operation SetiWert(int) */ me->iwert=iein; /*#]*/ } Instanziierung eines Objektes: /*## classinstance itscklasse */ struct cklasse itscklasse; Bereits beim Aufruf des Konstruktors wird ein Zeiger auf die entsprechende Struktur übergeben. cklasse_init(&(itscklasse)); Beziehungen zwischen Klassen (hier die Aggregation) Die Beziehung wird durch einen Zeiger innerhalb der Klasse (struct) ctest realisiert. typedef struct ctest ctest; struct ctest { RiCReactive ric_reactive; struct cklasse* itscklasse; /*## link itscklasse */ /*#[ ignore */ int rootstate_substate; int rootstate_active; /*#]*/ }; Die konkrete Realisierung erfolgt durch einen Link zwischen zwei Instanzen. Soll auf die Klasse zugegriffen werden, so muss der Zeiger aus der Struktur verwendet werden. cklasse_setiwert(me->itscklasse, 5); 4
2 Die Entwicklungsumgebung 2.1 Hardware MCB1700 Bild: MCB1700 Quelle: www.keil.com Auf dem Board wird ein Cortex M3 Mikrocontroller von NXP (LPC1758) eingesetzt. Zur Vorbereitung sollten Sie den MCB1700 User s Guide[4] durcharbeiten. Folgende Features werden für den Laborbetrieb benötigt: LCD-TFT Display-Panel Port LEDs Joystick Analog Voltage Control for ADC Input (Potentiometer) INT0 Pushbutton 2.2 Embedded UML mit dem Realtime execution Framework RXF von Willert Willert Embedded UML RXF TM verbindet Rhapsody mit der Keil uvision IDE. Es optimiert die Codegenerierung für Ressourcen schonende Verwendung in embedded real-time Umgebungen. Im Dokument UML-Getting Started[5] ist der Installtionsvorgang und das Einrichten eines Projektes beschrieben. Sie sollten dieses Dokument kennen. 5
2.3 Neues Projekt fürs Zielsystem a) Projekt anlegen Legen Sie ein neues Projekt in Rhapsody in C an. Aus dem Verzeichnis \Vorlagen\SDLY\DemoDVD_Rhp_2013-03\Software\WST wird der folgende Ordner ins Projektverzeichnis kopiert. Setup_Rpy_C_OORTX_Keil_ARM_MCB1700_Eval_TD_V6.01 b) Profil auswählen Über den Menüpunkt Add Profile to Model.. können vorbereitet Profile ausgewählt werden. Bild: Auswahl eines Profiles Im Verzeichnis Profile befinden sich entsprechende Dateien. Share/Profiles/WST_RXF_V6/Rpy_C_OORTX_Keil_ARM_MCB1700_Eval_TD_Profile.sbs Bild: Auswahl des Profils Rpy_C_OORTX_Keil_ARM_MCB1700_Eval_TD_Profile.sbs 6
c) Benennungen anpassen Zur besseren Orientierung ist es sinnvoll unter Components die Bezeichnung MCB1700 und unter Configurations die Bezeichnung Debug zu verwenden. d) Stereotype festlegen Bild: Einheitliche Bezeichnung einführen Zwei Stereotype werden benötigt um die Projekte umsetzen zu können. Bild: Stereotype auswählen 7
e) Header Dateien einbinden Es besteht die Möglichkeit fürs Projekt global Header-Dateien vorzugeben. Diese Dateien werden in jedes Modul des Projektes eingebunden. Hier wird die Datei lpc17xx.h benötigt. Bild: Header für Prozessor Neben dem Header für den Prozessor wird fürs das verwendete Board ein Modul fürs Display benötigt. Diese Einstellung sollte aber unter den Konfigurationen verwaltet werden. Bild: Header fürs Display einbinden 8
f) Diagramme anlegen Im Projekt werden zwei OMDs benötigt. Das OMD Overview zum Entwurf und das OMD Runtime zur Realisierung. Bild: OMDs anlegen 9
3 Komponenten des Boards 3.1 Erstes Projekt mit den Port Leds Die Port Leds sind an die folgenden Ports angeschlossen. P1.28 (2^7) P1.29 (2^6) P1.31 (2^5) P2.2 (2^4) P2.3 (2^3) P2.4 (2^2) P2.5 (2^1) P2.6 (2^0) Vor der Verwendung müssen die GPIOs initialisiert werden. Im Folgenden ein Beispiel für LED0. Für Port2 muss das Register LPC_GPIO2 verwendet werden. Ausführliche Informationen unter [7]. Initialiserung (hier für LED0): LPC_GPIO1->FIODIR =(1<<28); //Output LPC_GPIO1->FIOPIN&=~(1<<28); //Off Off: LPC_GPIO1->FIOPIN&=~(1<<28); //Off On: LPC_GPIO1->FIOPIN =(1<<28); //On Toggle: LPC_GPIO1->FIOPIN ^=(1<<28); //On a) LED mit einer HAL-Klasse LED0 ohne weitere Intelligenz ansteuern Bild: Klasse LED0 10
Selbstverständlich könnte diese Klasse auch so erweitert werden, dass bei der Initialisierung der Port und der Pin vorgegeben werden. Zum Testen wird eine seperate Klasse angelegt. In der ein Zustandsautomat das Blinken übernimmt. Bild: Test für LED0 Hier wernden Methoden der Klasse LED verwendet, die Klasse selber verfügt über kein Verhalten. Die Realisierung wird im OMD Runtime vorgenommen. Bild: Realisierung 11
b) Generate Make and Run Wie bisher auch wird mit GMR das Projekt erstellt. Neu ist, daß nun ein Vorlagenprojekt, dass zuvor in den Projektordner kopiert wurde, ausgewählt wird. Zu den schon im Vorlagenprojekt vorhandenen Dateien werden die neuen Projektdateien hinzugefügt. Die Dateien finden sich unter dem folgenden Pfad...Versuch5\Setup_Rpy_C_OORTX_Keil_ARM_MCB1700_Eval_TD_V6.01\WILLERT\Samples\Code\ GettingStarted\GettingStarted.uvproj Bild: Auswahl Vorlagenprojekt In einem letzten Schritt wird das Projekt nun mit Keil uvision 4.74 geöffnet. (Es gibt auch eine Portierung für Keil uvision 5.xx.) Bild: Start der Keil uvision 12
Nun geht alles seinen gewohnten Gang, es liegt ein normales uvision Projekt vor das übersetzt und getestet werden kann. Es können auch Änderungen oder Korrekturen vorgenommen werden, die allerdings von Hand ins UML Design übernommen werden müssen. Bild: Realisierung 13
c) LED mit einer intelligenten Klasse ansteuern Die Klasse enthält nun einen Zustandsautomaten. Die Umschaltung erfolgt über Ivents, die an das Objekt geschickt werden. Die Klasse enthält nur eine Initfunktion und einen Zustandsautomaten. Bild: Klasse LED1 Bild: Zustandautomat LED1 d) Aufgabe LED1: Testen Sie die Funktion von LED1. 14
3.2 TasterINT0 im Polling Betrieb Init: Read: LPC_GPIO2->FIODIR &= ~(1<< 10); //P2.10 Input if((lpc_gpio2->fiopin&(1<<10))==0) return 1; else return 0; Bild: Klasse TatserINT0 Bild: Test des Tasters 15
3.3 Joystick Der Joystick ist über Pull-Down Widerstände an die folgenden Ports angeschlossen. P1.23 up P1.24 right P1.25 down P1.26 left P1.20 press Initialisierung: LPC_GPIO1->FIODIR &= ~((1<<20) (1<<23) (1<<24) (1<<25) (1<<26)); // P1.20, P1.23..26 is input Read Funktion: unsigned int val; val = (LPC_GPIO1->FIOPIN >> 20) & 0x00000079; //JOY_MASK; return(val); a) Aufgabe Joystick: Ordnen Sie die das Anschalten der LEDs den folgenden Joystickfunktionen zu: Up LED3 P2.2 R LED4 P2.3 Down LED5 P2.4 L LED6 P2.5 PUSH LED7 P2.6 16
3.4 Poti Port P0.25 wird als Eingang für den AD-Wandler0 Kanal2 (AD0.2) verwendet. Bei der Initialisierung werden die entsprechenden Einstellungen vorgenommen. Eine Möglichkeit zum Auslesen ist im Folgenden beschrieben. Initialisierung: LPC_PINCON->PINSEL1 &= ~(3<<18); /* P0.25 is GPIO */ LPC_PINCON->PINSEL1 = (1<<18); /* P0.25 is AD0.2 */ LPC_SC->PCONP = (1<<12); /* Enable power to ADC block */ LPC_ADC->ADCR = (1<< 2) /* select AD0.2 pin */ (4<< 8) /* ADC clock is 25MHz/5 */ (1<<21); /* enable ADC */ Read Funktion: int adwert; LPC_ADC->ADCR &= ~(7<<24); LPC_ADC->ADCR = (1<<24); //stop conversion // start conversion while (!(LPC_ADC->ADGDR & (1UL<<31))); adwert = LPC_ADC->ADGDR; LPC_ADC->ADCR &= ~(7<<24); return((adwert >> 4) & 0xFFF); // Wait for Conversion end // stop conversion // read converted value a) Aufgabe Poti Geben Sie den Poti-Wert als Zahlenwert und als Bargraph auf dem Display aus. In welchem Wertebereich arbeitet das Potentiometer? Der Funktion Bargraph wird zuerst die Koordinate für die Linke obere Ecke übergeben, dann folgt Breite, Höhe und die Angabe für den ausgefüllten Anteil in Promille. Mit dem Potentiometer wird die Geschwindigkeit des Lauflichts verändert. 3.5 LCD-TFT Display-Panel 240x320 Es steht ein Bibliothek zur Verfügung, vor der ersten Benutzung des Displays muss dieses initialisiert werden. Wird das der Speicher nicht gelöscht so entsteht ein buntes Hintergrundbild. GLCD_Init(); GLCD_Clear(White); Die verfügbaren Funktionen und die vordefinierten Farbwerte finden Sie in der Headerdatei glcd.h z.b. void GLCD_DisplayChar (unsigned int ln, unsigned int col, unsigned char c); void GLCD_DisplayString (unsigned int ln, unsigned int col, unsigned char *s); void GLCD_Bargraph (unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int val); //val 0-1000 17
4 Aufgaben a) Aufgabe LED1 b) Aufgabe Joystick c) Aufgabe Poti d) Ihre Projektidee: 18
4.2 Event durch eine ISR auslösen Der Button INT0 kann einen externen Interrupt auslösen, er ist an P2.10 angeschlossen. In einer eigenen Klasse, von der ein Objekt angelegt wird, kann in der Init() Funktion die entsprechenden Einstellungen vorgenommen werden. //EXTINT INI LPC_PINCON->PINSEL4 = 0x00100000; // set P2.10 as EINT0 and P2.0~7 GPIO output */ LPC_GPIOINT->IO2IntEnF = 0x200; // Port2.10 is falling edge. */ LPC_SC->EXTMODE = 0x00000001; // EINT0_EDGE; // INT0 edge trigger LPC_SC->EXTPOLAR = 0; // INT0 is falling edge by default NVIC_EnableIRQ(EINT0_IRQn); Jeder Interrupt löst eine ISR aus so auch hier. Die ISR muss innerhalb einer Header Datei ins Projekt eingebunden werden, hier Ext_INT_P2_10.h #include "LPC17xx.h" #include "default.h" #include "tester.h" //Klasse in der ein Event erzeugt werden soll void EINT0_IRQHandler (void) { LPC_SC->EXTINT = 0x00000001; Tester_sendEv_Taster(evZiel); } Vorgehensweise: DefaultComponent-> Add New File->Name.h Name.h ->Feature Menue -> Elements-> ICON New Text Elements-> Hier Source Code einfügen In der ISR kann auf die gesamte Hardware des Controllers zugegriffen werden. Wie aber kann ein Event ausgelöst werden. Es wird ein Globaler Zeiger auf eine Klasse benötigt, in der ein Event ausgelöst wird (hier evtaster). Packages->Default->Add New Variable Typ void und wichtig Reference (Zeiger) aktivieren In der Init() Funktion der Klasse, in der der Event ausgelöst werden soll, muss die globale Variable initialisiert werden. evziel=me; Anlegen eines Events und Erstellen einer Funktion, die einen Event auslöst. Diese Funktion kann in der ISR aufgerufen werden. /*## operation sendev_taster() */ void Tester_sendEv_Taster(Tester* const me) { /*#[ operation sendev_taster() */ RiCGEN(me, evtaster()); /*#]*/ } 19
5 Literatur Nachfolgend findet sich eine Zusammenstellung weiterführender Informationen, die mit dem Inhalt dieses Laborversuchs in Zusammenhang stehen. [1] Rupp, Queins, Zengler; UML 2 Glasklar; Hanser [2] http://www.ibm.com/developerworks/rational/products/rhapsody/ [3] UML 2.0 Das umfassende Handbuch, Christoph Kecher, Galileo Computing [4] http://www.keil.com/support/man/docs/mcb1700/mcb1700_intro.htm [5] http://www.willert.de/uml-getting-started-3/ [6] http://www.willert.de/assets/download/uml-getting-started-rhp-v9.0-en.pdf [7] http://www.nxp.com/products/microcontrollers/cortex_m3/lpc1700/lpc1758fbd80.html Board: http://www.keil.com/mcb1700/ Schaltplan: http://www.keil.com/mcb1700/mcb1700-schematics.pdf Datasheet LPC1758 http://www.nxp.com/documents/data_sheet/lpc1759_58_56_54_52_51.pdf User Manual LPC1758 http://www.nxp.com/documents/user_manual/um10360.pdf 20