Mit der zweiten Übung tasten wir uns, im wahrsten Sinne des Wortes, an die eigentliche Aufgabe eines jeden Controllers heran. Dieser soll Zeit seines Lebens fortlaufend Eingaben aus seiner Umgebung nach einer vorgegebenen Logik verarbeiten und entsprechend dieser Verarbeitung Ausgaben erzeugen. Es ist das allseits beliebte EVA-Prinzip, *gähn*. Spaß beiseite! Zum Gähnen ist das nur so lange, wie man mit der EVA nichts Praktisches anfängt *grins*. Es soll ein Taster auf dem XMC4500 Relax Kit ausgewertet und bei Tastendruck eine LED eingeschaltet werden.
Es ist zunächst wieder wichtig, sich mit der konkreten Schaltung zu beschäftigen. Diese entnehmen wir der Produktbeschreibung zum Releax Kit (Schaltplan Seite 15). In der folgenden vereinfachten Darstellung ist das Wesentliche zusammengefasst.
Die gewünschte LED hängt überraschenderweise immer noch an Port 1 Bit 0 und der Taster ist diesmal an Port 1 Bit 15 angeschlossen. Die tatsächliche Tasterlogik wurde hier etwas vereinfacht als Umschalter abgebildet. Es ist also Folgendes zu tun, um die Aufgabe zu erfüllen:
Falls das Tutorial-Projekt nicht mehr offen ist, öffnen Sie dies. Legen Sie bitte ein neues kleines Programm an und laden das Grundgerüst ARM C++ Anwendung. Beachten Sie die Einstellungen für die Zielplattform XMC4500 Relax Kit.
Erstellen Sie die Programmkopfdokumentation. Übersetzen und übertragen Sie das noch leere Programm auf den Controller, um die Verbindung zu testen.
//---------------------------------------------------------------------- // Titel : Beispiel intelligenter Lichtschalter 1 mit SiSy XMC //---------------------------------------------------------------------- // Funktion : ein Taster schaltet eine LED an // Schaltung : LED an Pin1.0, Taster an Pin1.15 //---------------------------------------------------------------------- // Hardware : XMC4500 // Takt : 120 MHz // Sprache : ARM C++ // Datum : heute // Version : 1 // Autor : ich //----------------------------------------------------------------------
Zur Wiederholung hier noch mal die Struktur eines GPIO beim XMC.
Diesmal rücken zusätzlich die Eingabe betreffende Register in den Fokus unserer Betrachtung.
Im IOCR sind das Pin1.0 und Pin 1.15 zu konfigurieren:
Der Taster schaltet gegen Masse. Das heißt, die direkte Eingabe liefert bei gedrücktem Taster eine logische 0, welche in C den Wahrheitswert FALSE repräsentiert. Die unter Umständen nötige Umkehrung der Logik kann in der Software oder eben listigerweise in der Hardware erfolgen. Einen controllerinternen PullUp oder PullDown brauchen wir nicht aktivieren, da dieser auf dem Relax Kit extern, warum auch immer, bereits diskret bestückt ist. Nun ja, warum ist schon klar, die Benutzertaster auf dem Relax Kit werden mit einem PullUp-Widerstand von 10K bereit gegen High gezogen und sind mit einem Kondensator von 100nF hardwareseitig entprellt. Das macht es dem Anfänger etwas leichter. Er braucht den internen PullUp nicht per Software zu aktivieren und was viel schwerer wiegt, er braucht nicht per Software den Taster zu entprellen.
Zuerst wieder der Entwurf in Form von Kommentaren:
//---------------------------------------------------------------------- // Titel : Beispiel intelligenter Lichtschalter 1 mit SiSy XMC //---------------------------------------------------------------------- // Funktion : ein Taster schaltet eine LED an // Schaltung : LED an Pin1.0, Taster an Pin1.15 //---------------------------------------------------------------------- // Hardware : XMC4500 // Takt : 120 MHz // Sprache : ARM C++ // Datum : heute // Version : 1 // Autor : ich //---------------------------------------------------------------------- #include <stddef.h> #include <stdlib.h> #include "hardware.h" #include "xmc_gpio.h" void initApplication() { SysTick_Config(SystemCoreClock/100); // Konfiguriere Pin1.0 als Ausgang // Konfiguriere Pin1.15 als Eingang ohne PullUp } int main(void) { SystemInit(); initApplication(); do{ // WENN Taster an Pin1.15 gedrückt DANN // LED an Pin1.0 einschalten // SONST // LED an Pin1.0 ausschalten } while (true); return 0; } extern "C" void SysTickFunction(void) { // hier nichts tun }
Nachdem wir den Entwurf in Ruhe rekapituliert haben, kann es an die Umsetzung gehen. Die Konfiguration für die LED können wir einfach vom voran gegangenen Beispiel übernehmen.
PORT1->IOCR0 |= (XMC_GPIO_MODE_OUTPUT_PUSH_PULL<<0*8);
Für den Taster sollten wir uns nochmals die Position im IOCR-Registerblock vergegenwärtigen. Die entsprechende Konfiguration muss auf die Position des Pin1.15 in PORT1.IOCR12 gebracht werden. Dazu beauftragen wir den C-Kompiler die gewünschte Konfiguration auf die richtige Position zu schieben.
PORT1->IOCR12 |= (XMC_GPIO_MODE_INPUT_TRISTATE<<3*8);
Für das Einlesen des Tasterzustandes benutzen wir das IN-Register und Maskieren das gewünschte Bit mit einer AND-Verknüpfung.
PORT1->IN & BIT15
Für das EIN- und Ausschalten der LED benutzen wir bewährte Codes:
// LED an Pin1.0 einschalten PORT1->OUT |= BIT0; // LED an Pin1.0 ausschalten PORT1->OUT &= ~BIT0;
oder
// LED an Pin1.0 einschalten SET_BIT(PORT1->OUT,0); // LED an Pin1.0 ausschalten CLR_BIT(PORT1->OUT,0);
Wenn Sie Quelltexte lieber kopieren, können Sie das gern mit dem obigen Entwurf machen, aber die eigentlichen Befehle sollten Sie aus lernpsychologischen Überlegungen tatsächlich selbst und bewusst, demzufolge selbstbewusst, eintippen.
//---------------------------------------------------------------------- // Titel : Beispiel intelligenter Lichtschalter 1 mit SiSy XMC //---------------------------------------------------------------------- // Funktion : ein Taster schaltet eine LED an // Schaltung : LED an Pin1.0, Taster an Pin1.15 //---------------------------------------------------------------------- // Hardware : XMC4500 // Takt : 120 MHz // Sprache : ARM C++ // Datum : heute // Version : 1 // Autor : ich //---------------------------------------------------------------------- #include <stddef.h> #include <stdlib.h> #include "hardware.h" #include "xmc_gpio.h" void initApplication() { // SystemTimer auf 10ms konfigurieren SysTick_Config(SystemCoreClock/100); // weitere Initialisierungen durchführen // Konfiguriere Pin1.0 als Ausgang PORT1->IOCR0 |= (XMC_GPIO_MODE_OUTPUT_PUSH_PULL<<0*8); // Konfiguriere Pin1.15 als Eingang ohne PullUp PORT1->IOCR12 |= (XMC_GPIO_MODE_INPUT_TRISTATE <<3*8); } int main(void) { SystemInit(); initApplication(); do{ // Beachte umgekehrte Logik! // WENN Taster an Pin1.15 gedrückt DANN if ( ! (PORT1->IN & BIT15) ) { // LED an Pin1.0 einschalten PORT1->OUT |= BIT0; } else // SONST { // LED an Pin1.0 ausschalten PORT1->OUT &= ~BIT0; } } while (true); return 0; } extern "C" void SysTick_Handler(void) { // hier nichts tun }
Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers.
Die LED auf dem XMC Relax Kit leuchtet jetzt immer so lange, wie der Taster gedrückt ist.
Und hier diesen Abschnitt dann auch als Videozusammenfassung.
Den Umstand, dass der Taster negative Logik besitzt, also eigentlich ein FALSE liefert, haben wir in der Softwarelösung dadurch gewürdigt, dass wir die Bedingung negiert haben.
if ( !(PORT1->IN & BIT15) )
Diese Arbeit können wir durch entsprechende Konfiguration auch die Hardware erledigen lassen.
PORT1->IOCR12 |= (XMC_GPIO_MODE_INPUT_INVERTED_TRISTATE<<3*8)
Variieren Sie das Beispiel entsprechend.
//---------------------------------------------------------------------- // Titel : Beispiel intelligenter Lichtschalter 1b mit SiSy XMC //---------------------------------------------------------------------- // Funktion : ein Taster schaltet eine LED an // Schaltung : LED an Pin1.0, Taster an Pin1.15 //---------------------------------------------------------------------- // Hardware : XMC4500 // Takt : 120 MHz // Sprache : ARM C++ // Datum : heute // Version : 1 // Autor : ich //---------------------------------------------------------------------- #include <stddef.h> #include <stdlib.h> #include "hardware.h" #include "xmc_gpio.h" void initApplication() { // u.a. nötig für waitMs(..) und waitUs(..) SysTick_Config(SystemCoreClock/100); // Konfiguriere Pin1.0 als Ausgang PORT1->IOCR0 |= (XMC_GPIO_MODE_OUTPUT_PUSH_PULL<<0); // Konfiguriere Pin1.15 als Eingang ohne PullUp PORT1->IOCR12 |= (XMC_GPIO_MODE_INPUT_INVERTED_TRISTATE<<3*8); } int main(void) { SystemInit(); initApplication(); do{ // WENN Taster an Pin1.15 gedrückt DANN // alt: if ( !(PORT1->IN & BIT15) ) if ( PORT1->IN & BIT15 ) { // LED an Pin1.0 einschalten PORT1->OUT |= BIT0; } else // SONST { // LED an Pin1.0 ausschalten PORT1->OUT &= ~BIT0; } } while (true); return 0; } extern "C" void SysTick_Handler(void) { // Application SysTick }
Wir wollen uns den Umstand zu Nutze machen, dass auf dem XMC4500 Zusatzboard die Taster ohne PullUp und Kondensator bestückt sind. Damit können wir den internen PullUp des XMC ausprobieren. Dazu verbinden wir mit einem der Patchkabel den Taster 1 auf dem Zusatzboard mit Pin1.13 des XMC.
Variieren sie die Anwendung wie folgt:
//---------------------------------------------------------------------- // Titel : Beispiel intelligenter Lichtschalter 1c mit SiSy XMC //---------------------------------------------------------------------- // Funktion : ein Taster schaltet eine LED an // Schaltung : LED an Pin1.0, Taster an Pin1.13 //---------------------------------------------------------------------- // Hardware : XMC4500 // Takt : 120 MHz // Sprache : ARM C++ // Datum : heute // Version : 1 // Autor : ich //---------------------------------------------------------------------- #include <stddef.h> #include <stdlib.h> #include "hardware.h" #include "xmc_gpio.h" void initApplication() { // u.a. nötig für waitMs(..) und waitUs(..) SysTick_Config(SystemCoreClock/100); // Konfiguriere Pin1.0 als Ausgang PORT1->IOCR0 |= (XMC_GPIO_MODE_OUTPUT_PUSH_PULL<<0); // Konfiguriere Pin1.13 als Eingang ohne PullUp PORT1->IOCR12 |= (XMC_GPIO_MODE_INPUT_INVERTED_PULL_UP<<1*8); } int main(void) { SystemInit(); initApplication(); do{ // WENN Taster an Pin1.13 gedrückt DANN if ( PORT1->IN & BIT13 ) { // LED an Pin1.0 einschalten PORT1->OUT |= BIT0; } else // SONST { // LED an Pin1.0 ausschalten PORT1->OUT &= ~BIT0; } } while (true); return 0; } extern "C" void SysTick_Handler(void) { // Application SysTick }
Aus der Treiberbibliothek stehen für diese Verarbeitungsaufgabe von digitalen Eingaben unter anderem folgende Funktionen zur Verfügung:
Die entsprechende Lösung sieht dann wie folgt aus:
//--------------------------------------------------------------------------- // Titel : Beispiel intelligenter Lichtschalter 1d mit SiSy XMC (XMC Lib) //--------------------------------------------------------------------------- // Funktion : ein Taster schaltet eine LED an // Schaltung : LED an Pin1.0, Taster an Pin1.13 //---------------------------------------------------------------------- // Hardware : XMC4500 // Takt : 120 MHz // Sprache : ARM C++ // Datum : heute // Version : 1 // Autor : ich //---------------------------------------------------------------------- #include <stddef.h> #include <stdlib.h> #include "hardware.h" #include "xmc_gpio.h" void initApplication() { // u.a. nötig für waitMs(..) und waitUs(..) SysTick_Config(SystemCoreClock/100); // Konfiguriere Pin1.0 als Ausgang // PORT1->IOCR0 |= (XMC_GPIO_MODE_OUTPUT_PUSH_PULL<<0); XMC_GPIO_SetMode(XMC_GPIO_PORT1, 0, XMC_GPIO_MODE_OUTPUT_PUSH_PULL ); // Konfiguriere Pin1.13 als Eingang ohne PullUp // PORT1->IOCR12 |= (XMC_GPIO_MODE_INPUT_INVERTED_PULL_UP<<1*8); XMC_GPIO_SetMode(XMC_GPIO_PORT1, 13, XMC_GPIO_MODE_INPUT_INVERTED_PULL_UP); } int main(void) { SystemInit(); initApplication(); do{ // WENN Taster an Pin1.13 (PORT1->IN & BIT13) gedrückt DANN if ( XMC_GPIO_GetInput(XMC_GPIO_PORT1, 13) ) { // LED an Pin1.0 einschalten (PORT1->OUT |= BIT0;) XMC_GPIO_SetOutputHigh(XMC_GPIO_PORT1, 0); } else // SONST { // LED an Pin1.0 ausschalten (PORT1->OUT &= ~BIT0;) XMC_GPIO_SetOutputLow(XMC_GPIO_PORT1, 0); } } while (true); return 0; } extern "C" void SysTick_Handler(void) { // Application SysTick }
Wohltuend ist es schon nicht mehr mit den Schiebeoperationen die Bits an die richtige Stelle schubsen zu müssen .