Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
hallo_c [2019/02/04 14:10]
127.0.0.1 Externe Bearbeitung
hallo_c [2019/07/25 15:45] (aktuell)
huwi [Videozusammenfassung]
Zeile 1: Zeile 1:
 ====== Hallo ARM C ====== ====== Hallo ARM C ======
-Die erste Übung in jedem Programmierkurs ist das berühmte „Hallo Welt“. Damit wird versucht, dem Lernenden ein motivierendes **„AHA-Erlebnis“** zu vermitteln. OK mal sehen, ob wir das auch hin bekommen. Bei der Programmierung von eingebetteten Systemen besteht oft das Problem, dass kein Bildschirm oder Display zur Textausgabe angeschlossen ist. Dann stehen für das "sich bemerkbar machen"​ dem System nur LEDs zur Verfügung. Also leuchten und blinken eingebettete Systeme somit ihre Botschaft in die Welt. 
  
 +Die erste Übung in jedem Programmierkurs ist das berühmte „Hallo Welt“. Damit wird versucht, dem Lernenden ein motivierendes **„AHA-Erlebnis“** zu vermitteln. OK mal sehen, ob wir das auch hin bekommen. Bei der Programmierung von eingebetteten Systemen besteht oft das Problem, dass kein Bildschirm oder Display zur Textausgabe angeschlossen ist. Dann stehen für das "sich bemerkbar machen"​ dem System nur LEDs zur Verfügung. Also leuchten und blinken eingebettete Systeme somit ihre Botschaft in die Welt.
 ===== Die Aufgabe ===== ===== Die Aufgabe =====
 +
 Die erste Übung soll das typische LED einschalten sein. Dazu nutzen wir die blaue LED auf dem STM32F4 Discovery Board. Die blaue LED ist bereits fest mit dem Pin //PD15// verbunden. Die erste Übung soll das typische LED einschalten sein. Dazu nutzen wir die blaue LED auf dem STM32F4 Discovery Board. Die blaue LED ist bereits fest mit dem Pin //PD15// verbunden.
  
->>>​{{:​d15anschalten.jpg?​700|}}+>​{{:​d15anschalten.jpg?​700|d15anschalten.jpg}}
  
 Aus dem [[http://​www.st.com/​internet/​com/​TECHNICAL_RESOURCES/​TECHNICAL_LITERATURE/​DATASHEET/​DM00037051.pdf|Datenblatt des STM32F4xx]] ( schauen Sie auf [[http://​www.mystm32.de/​lib/​exe/​detail.php?​id=systemtickc&​cache=cache&​media=blockbildstm32f4.jpg|Seite 18]]) können wir entnehmen, das dieser über drei AHB verfügt. Für uns ist erst mal nur der AHB1 interessant. An AHB2 und AHB3 hängen spezielle Geräte, wie die Kameraschnittstelle oder ein externer Speicher. Über AHB1 erreichen wir die GPIO Ports und die zwei Peripheriebusse APB1 und APB2. Die digitalen Eingabe- und Ausgabeleitungen hängen direkt an AHB1 und sind zu 9 Ports (A bis I) mit jeweils 16 Leitungen (Bit 0 bis 15) zusammengefasst. Digitale Ein- und Ausgabe sind die primären Funktionen der Pins und im Pin-Out entsprechend als Pin-Namen gekennzeichnet. Aus dem [[http://​www.st.com/​internet/​com/​TECHNICAL_RESOURCES/​TECHNICAL_LITERATURE/​DATASHEET/​DM00037051.pdf|Datenblatt des STM32F4xx]] ( schauen Sie auf [[http://​www.mystm32.de/​lib/​exe/​detail.php?​id=systemtickc&​cache=cache&​media=blockbildstm32f4.jpg|Seite 18]]) können wir entnehmen, das dieser über drei AHB verfügt. Für uns ist erst mal nur der AHB1 interessant. An AHB2 und AHB3 hängen spezielle Geräte, wie die Kameraschnittstelle oder ein externer Speicher. Über AHB1 erreichen wir die GPIO Ports und die zwei Peripheriebusse APB1 und APB2. Die digitalen Eingabe- und Ausgabeleitungen hängen direkt an AHB1 und sind zu 9 Ports (A bis I) mit jeweils 16 Leitungen (Bit 0 bis 15) zusammengefasst. Digitale Ein- und Ausgabe sind die primären Funktionen der Pins und im Pin-Out entsprechend als Pin-Namen gekennzeichnet.
  
 Die Aufgabe besteht also darin: Die Aufgabe besteht also darin:
 +
   - über den AHB1 Bus den GPIO Port D zu aktivieren, indem dieser mit einem Taktsignal versorgt wird   - über den AHB1 Bus den GPIO Port D zu aktivieren, indem dieser mit einem Taktsignal versorgt wird
   - das Bit 15 des GPIOD als Ausgang zu konfigurieren   - das Bit 15 des GPIOD als Ausgang zu konfigurieren
Zeile 15: Zeile 17:
  
 ===== Vorbereitung ===== ===== Vorbereitung =====
-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 STM32F4-Discovery. 
  
->>>​{{:​halloarm1.jpg?​700|}}+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 STM32F4-Discovery. 
 + 
 +>​{{:​halloarm1.jpg?​700|halloarm1.jpg}}
  
 Erstellen Sie die Programmkopfdokumentation. Übersetzen und übertragen Sie das noch leere Programm auf den Controller, um die Verbindung zu testen. Erstellen Sie die Programmkopfdokumentation. Übersetzen und übertragen Sie das noch leere Programm auf den Controller, um die Verbindung zu testen.
  
->>><code c>+> 
 + 
 +<code c>
 //​---------------------------------------------------------------------- //​----------------------------------------------------------------------
 // Titel     : Beispiel Hallo Welt mit SiSy ARM // Titel     : Beispiel Hallo Welt mit SiSy ARM
Zeile 40: Zeile 45:
 Als Erstes diskutieren wir kurz die nötigen Lösungsschritte. Wie bereits ausgeführt,​ sind nach dem RESET alle Peripheriegeräte ausgeschaltet. Demzufolge muss der I/O-Port, an dem die LED angeschlossen ist, erst mal eingeschaltet werden. Jetzt schauen wir uns das Blockbild zum STM32F4 [[http://​www.st.com/​internet/​com/​TECHNICAL_RESOURCES/​TECHNICAL_LITERATURE/​DATASHEET/​DM00037051.pdf|zum Beispiel im Datenblatt Seite 18]] oder [[http://​www.mystm32.de/​lib/​exe/​detail.php?​id=hardware&​cache=cache&​media=stm32sysml.jpg|dieses vereinfachte Blockbild]] an. Man erkennt, dass der RCC-Unit (Reset & Clock Control ) mitgeteilt werden muss, dass GPIOD über den AHB1 mit Takt zu versorgen ist. Dazu benutzen wir die Funktion //​RCC_AHB1PeriphClockCmd//​ aus den STM32F4-Peripherie-Treibern. Die Hilfe zu der Funktion können wir uns über den //Editor, rechte Maustaste, Hilfe STM32// anschauen. ​ Als Erstes diskutieren wir kurz die nötigen Lösungsschritte. Wie bereits ausgeführt,​ sind nach dem RESET alle Peripheriegeräte ausgeschaltet. Demzufolge muss der I/O-Port, an dem die LED angeschlossen ist, erst mal eingeschaltet werden. Jetzt schauen wir uns das Blockbild zum STM32F4 [[http://​www.st.com/​internet/​com/​TECHNICAL_RESOURCES/​TECHNICAL_LITERATURE/​DATASHEET/​DM00037051.pdf|zum Beispiel im Datenblatt Seite 18]] oder [[http://​www.mystm32.de/​lib/​exe/​detail.php?​id=hardware&​cache=cache&​media=stm32sysml.jpg|dieses vereinfachte Blockbild]] an. Man erkennt, dass der RCC-Unit (Reset & Clock Control ) mitgeteilt werden muss, dass GPIOD über den AHB1 mit Takt zu versorgen ist. Dazu benutzen wir die Funktion //​RCC_AHB1PeriphClockCmd//​ aus den STM32F4-Peripherie-Treibern. Die Hilfe zu der Funktion können wir uns über den //Editor, rechte Maustaste, Hilfe STM32// anschauen. ​
  
->>>{{:hilferccahb1gpiod.jpg?​600|}}+>​{{hilferccahb1gpiod.jpg?​600|}} ​
  
 Die Funktion //​RCC_AHB1PeriphClockCmd//​ benötigt zwei Parameter. Parameter eins bestimmt das Gerät und Parameter zwei den neuen Status des Gerätetaktes. Daraus ergibt sich folgende Befehlszeile:​ Die Funktion //​RCC_AHB1PeriphClockCmd//​ benötigt zwei Parameter. Parameter eins bestimmt das Gerät und Parameter zwei den neuen Status des Gerätetaktes. Daraus ergibt sich folgende Befehlszeile:​
  
->>><​code>​+><​code>​
 /* GPIOD Takt einschalten ​ */ /* GPIOD Takt einschalten ​ */
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,​ ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,​ ENABLE);
Zeile 59: Zeile 64:
 Der Takt für Port D ist bereits aktiviert. Demzufolge ist als Nächstes die Initialisierungsstruktur anzulegen und mit Standardwerten zu füllen. Strukturen und Funktionen finden sich in der Hilfe im Abschnitt des jeweiligen Gerätes. Der entsprechende Quellcode für den GPIO Port D sieht wie folgt aus: Der Takt für Port D ist bereits aktiviert. Demzufolge ist als Nächstes die Initialisierungsstruktur anzulegen und mit Standardwerten zu füllen. Strukturen und Funktionen finden sich in der Hilfe im Abschnitt des jeweiligen Gerätes. Der entsprechende Quellcode für den GPIO Port D sieht wie folgt aus:
  
->>><​code>​+><​code>​
 GPIO_InitTypeDef ​ GPIO_InitStructure;​ GPIO_InitTypeDef ​ GPIO_InitStructure;​
 GPIO_StructInit (&​GPIO_InitStructure);​ GPIO_StructInit (&​GPIO_InitStructure);​
Zeile 66: Zeile 71:
 Nun müssen die anwendungsspezifischen Einstellungen angegeben werden. Das erfolgt durch Zuweisung der entsprechenden Werte zu den einzelnen Elementen der Initialisierungsstruktur. Die möglichen Strukturelemente und Werte sind wiederum der Hilfe entnehmbar. Nun müssen die anwendungsspezifischen Einstellungen angegeben werden. Das erfolgt durch Zuweisung der entsprechenden Werte zu den einzelnen Elementen der Initialisierungsstruktur. Die möglichen Strukturelemente und Werte sind wiederum der Hilfe entnehmbar.
  
->>>​<​html><​iframe width="​640" height="​480" src="​https://​www.youtube.com/​embed/​3aezM5AWbGQ"​ frameborder="​0"​ allowfullscreen></​iframe></​html>​+<​html><​iframe width="​800" height="​600" src="​https://​www.youtube.com/​embed/​3aezM5AWbGQ"​ frameborder="​0"​ allowfullscreen></​iframe></​html>​
  
 Bei den Werten für die Strukturelemente handelt es sich um Aufzählungen bzw. Bitdefinitionen,​ welche als selbsterklärende Bezeichner deklariert wurden. Bei den Werten für die Strukturelemente handelt es sich um Aufzählungen bzw. Bitdefinitionen,​ welche als selbsterklärende Bezeichner deklariert wurden.
Zeile 101: Zeile 106:
 Für unsere LED ergibt sich, dass diese an Pin15 angeschlossen ist, dieser als Ausgang betrieben werden soll und keine PullUp oder PullDown benötigt werden. Der mögliche Quellcode sieht wie folgt aus: Für unsere LED ergibt sich, dass diese an Pin15 angeschlossen ist, dieser als Ausgang betrieben werden soll und keine PullUp oder PullDown benötigt werden. Der mögliche Quellcode sieht wie folgt aus:
  
->>><​code>​+><​code>​
 GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_15;​ GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_15;​
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;​ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;​
Zeile 111: Zeile 116:
 Damit sind alle relevanten Einstellungen in der Initialisierungsstruktur vorbereitet. Jetzt kann die eigentliche Initialisierung erfolgen. Das geschieht mit der Funktion //​GPIO_Init//​. Diese efordert die Angabe des GPIO-Port und der vorbereiteten Initialisierungsstruktur. Damit sind alle relevanten Einstellungen in der Initialisierungsstruktur vorbereitet. Jetzt kann die eigentliche Initialisierung erfolgen. Das geschieht mit der Funktion //​GPIO_Init//​. Diese efordert die Angabe des GPIO-Port und der vorbereiteten Initialisierungsstruktur.
  
->>><​code>​+><​code>​
 GPIO_Init(GPIOD,​ &​GPIO_InitStructure);​ GPIO_Init(GPIOD,​ &​GPIO_InitStructure);​
 </​code>​ </​code>​
Zeile 117: Zeile 122:
 Für das An- oder Ausschalten von GPIO-Pins stehen die Funktionen //​GPIO_SetBit//​ und //​GPIO_ResetBit//​ zur Verfügung. Diese Funktionen erwarten den Port und die Pins, welche zu schalten sind. Für das An- oder Ausschalten von GPIO-Pins stehen die Funktionen //​GPIO_SetBit//​ und //​GPIO_ResetBit//​ zur Verfügung. Diese Funktionen erwarten den Port und die Pins, welche zu schalten sind.
  
->>><​code>​+><​code>​
 GPIO_SetBits(GPIOD,​GPIO_Pin_15);​ GPIO_SetBits(GPIOD,​GPIO_Pin_15);​
 </​code>​ </​code>​
Zeile 126: Zeile 131:
 Gewöhnen wir uns gleich daran einigermaßen systematisch vorzugehen. Bevor wir die Befehle in unseren Code wild hineinhacken,​ schreiben wir erst die Kommentare, was wir an dieser oder jener Stelle im Code tun wollen. ​ Gewöhnen wir uns gleich daran einigermaßen systematisch vorzugehen. Bevor wir die Befehle in unseren Code wild hineinhacken,​ schreiben wir erst die Kommentare, was wir an dieser oder jener Stelle im Code tun wollen. ​
  
->>><​code c>+><​code c>
 //​---------------------------------------------------------------------- //​----------------------------------------------------------------------
 // Titel     : Beispiel Hallo Welt mit SiSy STM32 // Titel     : Beispiel Hallo Welt mit SiSy STM32
Zeile 178: Zeile 183:
 Nutzen Sie die Codevervollständigung des Editors. Die in den Treibern systematisch festgelegten Bezeichner folgen einem einfach einzuprägenden Muster: Nutzen Sie die Codevervollständigung des Editors. Die in den Treibern systematisch festgelegten Bezeichner folgen einem einfach einzuprägenden Muster:
  
->>><​code>​+><​code>​
 Gerät_TeilKomponente_Was Gerät_TeilKomponente_Was
 </​code>​ </​code>​
Zeile 184: Zeile 189:
 Der Bezeichner beschreibt einen Pfad vom Allgemeinen (dem Gerät) zum Speziellen (z.B. einer konkreten Funktion oder einem Bit). Zum Beispiel finden Sie alle Funktionen zur //Reset and Clock Control Unit// unter *RCC_* . Der Bezeichner beschreibt einen Pfad vom Allgemeinen (dem Gerät) zum Speziellen (z.B. einer konkreten Funktion oder einem Bit). Zum Beispiel finden Sie alle Funktionen zur //Reset and Clock Control Unit// unter *RCC_* .
  
->>>{{:rcc_cs.jpg?400|}}+>​{{rcc_cs.jpg?​600|}}
  
 Nach drei zusammenhängenden Buchstaben springt die Codevervollständigung an und listet alle Bezeichner fortlaufend gefiltert nach dem Stand der Eingabe. Wählen sie jetzt die Taste //CUD (Cursor/​Pfeil nach unten)//, können Sie in der Liste rollen und per //Enter// einen Eintrag auswählen. Schauen Sie sich dieses kurze Video an. Nach drei zusammenhängenden Buchstaben springt die Codevervollständigung an und listet alle Bezeichner fortlaufend gefiltert nach dem Stand der Eingabe. Wählen sie jetzt die Taste //CUD (Cursor/​Pfeil nach unten)//, können Sie in der Liste rollen und per //Enter// einen Eintrag auswählen. Schauen Sie sich dieses kurze Video an.
  
->>><​html><​iframe width="​640" height="​361" src="​https://​www.youtube.com/​embed/​GN4libWhHDk"​ frameborder="​0"​ allowfullscreen></​iframe></​html>​+><​html><​iframe width="​800" height="​455" src="​https://​www.youtube.com/​embed/​GN4libWhHDk"​ frameborder="​0"​ allowfullscreen></​iframe></​html>​
  
 Also dann, viel Erfolg bei den ersten //​richtigen//​ Programmierschritten. Also dann, viel Erfolg bei den ersten //​richtigen//​ Programmierschritten.
  
->>><​code c>+><​code c>
 //​---------------------------------------------------------------------- //​----------------------------------------------------------------------
 // Titel     : Beispiel Hallo Welt mit SiSy STM32 // Titel     : Beispiel Hallo Welt mit SiSy STM32
Zeile 245: Zeile 250:
  
 </​code>​ </​code>​
 +
  
 ===== Test ===== ===== Test =====
-Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers. ​+ 
 +Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers. 
   - Kompilieren   - Kompilieren
   - Linken   - Linken
   - Brennen   - Brennen
  
->>>​{{:​blaueled.jpg?​500|}}+>​{{:​blaueled.jpg?​500}}
  
-Gratulation! Sie haben Ihre erste Ausgabe realisiert. Die blaue LED auf dem STM32F4 Discovery leuchtet jetzt. ​+Gratulation! Sie haben Ihre erste Ausgabe realisiert. Die blaue LED auf dem STM32F4 Discovery leuchtet jetzt.
  
 ====== Videozusammenfassung ====== ====== Videozusammenfassung ======
 +
 Fassen wir nochmal kurz zusammen, was es sich einzuprägen gilt: Fassen wir nochmal kurz zusammen, was es sich einzuprägen gilt:
  
 **Initialisierungssequenz für Geräte:** **Initialisierungssequenz für Geräte:**
 +
   - Takt einschalten,​ RCC_xxxClockCmd   - Takt einschalten,​ RCC_xxxClockCmd
   - Initialisierungsstruktur anlegen, xxx_InitTypDef initStruct   - Initialisierungsstruktur anlegen, xxx_InitTypDef initStruct
Zeile 266: Zeile 276:
   - Gerät initialisieren,​ xxx_Init(xxx,​ &​initStructure)   - Gerät initialisieren,​ xxx_Init(xxx,​ &​initStructure)
  
-**Initialisierungsstruktur für Digitalports:​** //​GPIO_InitTypeDef initStruct;//​ +**Initialisierungsstruktur für Digitalports:​** ​ //​GPIO_InitTypeDef initStruct;//​ 
-  * initStruct.GPIO_Pin =  GPIO_Pin_0..15;​+ 
 +  * initStruct.GPIO_Pin = GPIO_Pin_0..15;​
   * initStruct.GPIO_Mode = GPIO_Mode_OUT|IN|AF;​   * initStruct.GPIO_Mode = GPIO_Mode_OUT|IN|AF;​
   * initStruct.GPIO_OType = GPIO_OType_PP|OD;​   * initStruct.GPIO_OType = GPIO_OType_PP|OD;​
Zeile 274: Zeile 285:
  
 **wichtige Funktionen für Digitalports:​** **wichtige Funktionen für Digitalports:​**
 +
   * RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOx,​ ENABLE|DISABLE);​   * RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOx,​ ENABLE|DISABLE);​
   * GPIO_StructInit (&​initStruct);​   * GPIO_StructInit (&​initStruct);​
Zeile 280: Zeile 292:
   * GPIO_ResetBits(GPIOD,​GPIO_Pin_x);​   * GPIO_ResetBits(GPIOD,​GPIO_Pin_x);​
  
 +Und hier diesen Abschnitt wiederum als Videozusammenfassung.
 +
 +><​html><​iframe width="​640"​ height="​400"​ src="​https://​www.youtube.com/​embed/​7pQQIVPg06I"​ frameborder="​0"​ allowfullscreen></​iframe></​html> ​
 +
 +====== Nächstes Thema ====== ​
 +
 +  * [[:​einfache_ein-_und_ausgaben_mit_dem_arm|Einfache Ein- und Ausgaben mit dem ARM]] 
  
  
-Und hier diesen Abschnitt wiederum als Videozusammenfassung. 
  
->>><​html><​iframe width="​640"​ height="​400"​ src="​https://​www.youtube.com/​embed/​7pQQIVPg06I"​ frameborder="​0"​ allowfullscreen></​iframe></​html>​ 
  
-====== Nächstes Thema ====== 
-  * [[Einfache Ein- und Ausgaben mit dem ARM]]