STM32F10x Standard Peripherals Library

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

Allgemeines

Die STM32F10x Standard Peripherals Library ist eine umfangreiche komfortable C-Bibliothek, die den Zugriff auf alle Funktionen der STM32F10x Familie erlaubt. Dabei ist für die verschiedenen Peripheriekomponenten jeweils ein eigenes Modul verfügbar.

Die Bibliothek kann hier bei ST kostenlos heruntergeladen werden. Dazu auf der ST-Webseite:

  • Oben den Punkt Support wählen
  • Auf der linken Seite "Tools and Software" anklicken
  • Nun links nochmals "Software" auswählen
  • Danach den Unterpunkt "MCU Software" wählen
  • Nun die richtige MCU-Familie, also "STM32 MCUs Software" selektieren
  • Es erscheint eine Tabelle mit vielen Packages für die zahlreichen Demoboards und verschiedene Bibliotheken (USB, Ethernet, etc.)
  • Die STM32F10x Standard Peripherals Library ist hier als "STSW-STM32054" bezeichnet
  • Nach der Auswahl kann diese über den Download-Button in einem *.zip-Archiv heruntergeladen werden

Alternativ ist hier ein Direktlink. In dem Archiv ist die ‎STM32F10x Standard Peripherals Library. Zu jeder Peripherie gibt es diverse Beispiele und eine Beschreibung als CHM Datei "stm32f10x_stdperiph_lib_um.chm".

Bevor Ihr lange sucht, die USB-Schnittstelle ist nicht in der STM32F10x Standard Peripherals Library enthalten. Die hierfür verfügbare Firmware sowie Beispielcode befindet sich in der STM32_USB-FS-Device_Lib

Hinweise

Die notwendigen Informationen, um die Funktionen der Standard Peripherals Library zu verstehen, muss man sich leider aus verschiedenen Quellen zusammensuchen. Daher soll mit diesem Artikel versucht werden, deren Benutzung für die verschiedenen Peripheriekomponenten zu erläutern.

Leider beziehen sich die von ST gelieferten Beispiele sehr auf die von ST verfügbaren Evalboards und der Code wimmelt von #defines, so dass man sich erst mühsam durchhangeln muss um zu verstehen, was da eigentlich passiert. Dies geht zwar durch die gute Verlinkung in der Hilfsdatei ganz gut, erschwert aber den Einstieg unnötig.

In diesem Artikel soll daher die Anwendung bare bones ähnlich den Beispielen in den AVR Datenblättern erfolgen. Wo nötig, werden die zum Verständnis relevanten Ausschnitte des Reference Manual RM0008 in den Artikel kopiert.

(Bevor hier die Copyright Discussion entbrennt: Das Landgericht München hat 1996 festgestellt, dass die Beschreibung von elektronischen Schaltungen nicht dem Urheberrecht unterliegen. Außerdem sollte ST sehr daran gelegen sein mehr Entwickler für Ihre µC zu begeistern.)

Dokumentationen

Um mit der Library zu arbeiten sind folgende Dokumentationen empfehlenswert:

  • RM0008 Reference Manual zum STM32F10xxx Controller
   Beschreibung und Registerdoku der Peripherie (GPIO, Timer ...)
  • PM0056 STM32F10xxx Cortex-M3 programming manual
   Cortex-M3 eigene Peripherie (wichtig zb. NVIC)
  • Datasheet des verwendeten µC Types (zb. STM32F103xC/D/E)
   Pinout des µC und alternative Verwendbarkeit der PINs

Download from [Documents and files for STM32F family]

Die ST Standard Peripheral Lib in CrossWorks

Aufgrund mehrfacher Anfragen, hier ein Archiv, das meine Arbeitsumgebung Datei:CrossWorks StandardLib Setup.zip mit zwei Crossworks Projekten (ARM_LED_TEST und ARM_USB_Test) enthält. Einfach alles in ein Verzeichnis entpacken und schon sollte es Laufen.

Einführungsbeispiel Blinking LED

Einführungsbeispiel STM32 LEDBlinken AtollicTrueStudio

Die Idee hinter der STM32 Standard Peripherals Library

So stellt sich ARM und ST-Microelectronics die Library vor.

Stm32 std peripherial library idee.JPG

Clocks - Der Herzschlag unseres Mikrocontrollers

Interner Aufbau eines STM32F103

Unser Mikrocontroller hat viele interne Takte. Diese müssen unbedingt konfiguriert werden. Dazu verwenden wir die RCC (Reset and Clock Control). Dazu gibt es Funktionen in der ST-Library. Welche Takte an welchen Bussen liegen, siehst du im Bild.

Die Controller verfügen über zwei getrennte Datenbusse für die langsameren Teile der Periphierie. Den APB1 und den APB2. Diese sind wiederum über Brücken am Systembus angeschlossen. Das wären in diesem Fall die AHB1 und AHB2. Man muss beachten, dass der APB1 "nur" mit maximal 36MHz getaktet werden darf, der APB2 hingegen mit 72MHz.

Wichtig! Alle unsere Peripherie Teile, die wir verwenden möchten, müssen mit einem Takt versorgt werden, bevor man sie verwenden kann. Bei Nichtbeachten führt dies häufig zu langer Fehlersuche.

Der STM32 wird normalerweise mit einem Quarz von 4-16MHz versorgt. Aus diesem wird dann mittels der internen PLL der eigentliche Takt gebildet (bis 72MHz). Jeder benötigte Takt wird vom Haupttakt abgeleitet. Die Controller verfügen auch über interne RC-Oszillatoren (typischerweise ein 8 MHz RC-Oszillator mit einer Genauigkeit von 1 % sowie einem 40 kHz RC-Oszillator). Zumindest der interne 8 MHz-Oszillator ist für die meisten Anwendungen genau genug. Für z.B. USB oder CAN mit Taktraten > 100 kbit/s ist er aber nicht genau genug. Der interne 40 kHz-Oszillator hingegen ist sehr ungenau (zwischen 30 und 60 kHz).

Hardwaretechnisch sollte darauf geachtet werden, dass bei Verwendung eines externen Quarzes dieser eine Frequenz von 8 MHz besitzt. Die gesamten Defines in der Library beziehen sich darauf. Ansonsten ist eine Anpassung der PLL Multiplikatoren in der Datei "system_stm32f10x.c" nötig.

Taktquelle auswählen

Nach dem Reset wird automatisch immer der interne HSI-Takt genutzt, um einen definierten Zustand zu haben (also der interne 8 MHz RC-Oszillator). Das ist z.B. erforderlich, damit der integrierte Bootloader mit einer bekannten Frequenz versorgt wird (sofern dieser über die Boot-Pins überhaupt gewünscht ist). Zum Glück gibt es ein automatisches Sicherheitsfeature, sodass man die aktuelle Taktquelle des Controllers nicht abschalten kann, da der Controller sonst einfach stehen bleiben würde!

HSI - Highspeed Internal Oscillator

Man kann den internen Oszillator nach dem Reset umkonfigurieren. [Hier fehlt noch etwas]

Zum Ein- und Ausschalten der HSI-Taktquelle verwendet man RCC_HSICmd(). Als Parameter werden entweder ENABLE oder DISABLE erwartet.

RCC_HSICmd(ENABLE); //Aktiviert den internen Highspeed Oszillator.

Takte Resetten

Nach dem Reset befindet sich die gesamte Taktkonfiguration in einem definierten Zustand. Macht man später irgendwelche Änderungen an der Taktkonfiguration kann es sinnvoll sein, vorher alle Takte auf ihre Standardwerte zurückzusetzen. Dies schafft wieder eine definierte zentrale Taktkonfiguration. Man muß sich nicht überlegen, wo man noch was zuvor eingestellt hat. Hat man allerdings schon z.B. irgendwelche Peripheriemodule konfiguriert, muß man natürlich aufpassen, welche Folgen die zentrale Taktänderung hier haben kann! Nach RCC_DeInit() sind alle Takte resettet. Übergeben wird nichts!

RCC_DeInit(); //Setzt alle Takte auf deren Ursprungsszustand zurück.

HSE - Highspeed External Oscillator (Quarz)

Es kann auch eine externe Taktquelle ausgewählt werden. Um dem Controller dies mitzuteilen, gibt es die Funktion RCC_HSEConfig(). Als Parameter erwartet sie einen der folgenden Werte: RCC_HSE_OFF, RCC_HSE_ON oder RCC_HSE_Bypass.

Die Ersten sind selbsterklärend. Wenn man der Funktion jedoch RCC_HSE_Bypass übergibt, so erwartet der Controller am OSC_IN Pin ein Taktsignal. Dieses darf bis zu 25MHz schnell sein und kann Rechteck, Sinus oder Dreieck Spannung mit einem Duty Cycle von 50% sein.

RCC_HSEConfig(RCC_HSE_ON); //Aktiviert den Externen Highspeed Oszillator (Quarz).

GPIOS - Wie greife ich auf einzelne Pins zur Ein/Ausgabe zu

Grundlagen

Unser Mikrocontroller hat ja einige Beinchen, diese können wir als Eingänge sowie als Ausgänge verwenden. Dazu müssen wir unserem Käfer jedoch erst sagen welcher Pin was machen soll. Wie dies geht wird hier beschrieben.

Der STM32F10x verfügt zur Manipulation der IO-Pins über ein sehr raffiniertes Feature, das es erlaubt Bits für die IO-Pins zu setzen / löschen ohne vorher deren aktuellen Zustand auslesen zu müssen (üblicherweise Read-Modify-Write). Dadurch ist gewährleistet, dass beim Setzen/Löschen von Bits kein Interrupt dies stören kann.

Each of the general-purpose I/O ports has two 32-bit configuration registers (GPIOx_CRL, GPIOx_CRH), two 32-bit data registers (GPIOx_IDR, GPIOx_ODR), a 32-bit set/reset register (GPIOx_BSRR), a 16-bit reset register (GPIOx_BRR) and a 32-bit locking register (GPIOx_LCKR).

Each I/O port bit is freely programmable, however the I/O port registers have to be accessed as 32-bit words (half-word or byte accesses are not allowed). The purpose of the GPIOx_BSRR and GPIOx_BRR registers is to allow atomic read/modify accesses to any of the GPIO registers. This way, there is no risk that an IRQ occurs between the read and the modify access.

Auf die BRR und BSRR register greift man über die entsprechenden GPIO-Port zu.

Hierzu existieren in

\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\stm32f10x.h

folgende Definition:

typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  __IO uint32_t IDR;
  __IO uint32_t ODR;
  __IO uint32_t BSRR;
  __IO uint32_t BRR;
  __IO uint32_t LCKR;
} GPIO_TypeDef;

Pointer auf die entsprechenden GPIO-Ports sind hier ebenfalls definiert:

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE               ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF               ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG               ((GPIO_TypeDef *) GPIOG_BASE)

Welche GPIO-Ports tatsächlich verfügbar sind ist abhängig vom verwendeten Controller!

In stm32f10x_gpio.h sind darüber hinaus Definitionen für alle Pins vorhanden:

#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */
#define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected */
#define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected */
#define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected */
#define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected */
#define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected */
#define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */
#define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */
#define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected */
#define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected */
#define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected */
#define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected */
#define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected */
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */
#define GPIO_Pin_All               ((uint16_t)0xFFFF)  /*!< All pins selected */

Will man also von Hand auf die Bits dieser Register zugreifen, so ist das denkbar einfach:

 GPIOC->BSRR = GPIO_Pin_13;

setzt das Bit für Pin 13 im Port C.

 GPIOC->BRR = GPIO_Pin_13;

oder

 GPIOC->BSRR = GPIO_Pin_13 << 16;

löscht dieses Bit wieder. Mit

 GPIOC->BSRR = (0x00F0 << 16) | ((data << 4) & 0x00F0);

kann man die Pins 4..7 auf einen beliebigen Wert setzen, ohne die übrigen Pins zu beeinflussen. Die oberen 16 Bits des geschriebenen Wertes definieren die betroffenen Pins, die unteren 16 Bits den Wert. In der Standard Peripheral Library ist keine Funktion enthalten, die diese Fähigkeit des Ports unterstützt.

Die äquivalente Operation über das ODR ist nicht atomar und somit in Verbindung mit Interrupts problematisch.


Die Standard Peripheral Library stellt für dies Zugriffe allerdings auch komfortablere und vor allem sprechendere Funktionen zur verfügen, die weiter unten erklärt werden.

Initialisierung

WICHTIG: Bevor man Pins eines GPIO-Ports benutzen kann, muss man die Clock des entsprechenden Ports mit der Funktion RCC_APB2PeriphClockCmd aktivieren , da diese nach einem Reset immer ausgeschaltet ist. Dies ist ein sehr beliebter Fehler beim Arbeiten mit Ports. Mehr dazu bei Clocks

Bevor man einen Pin benutzen kann, muss dieser Initialisiert werden.

Die Funktion GPIO_Init() ermöglicht es einen oder mehere Pins auf einmal zu konfigurieren. Hierzu muss eine struct ausgefüllt und GPIO_Init übergeben werden:

typedef struct
{
  u16 GPIO_Pin;
  GPIOSpeed_TypeDef GPIO_Speed;
  GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;


Definieren müssen wir dieses zuvor jedoch auch. Dies geschieht mit

GPIO_InitTypeDef GPIO_InitStructure;


Danach können wir bequem auf die einzelnen Einträge aus der Struct zugreifen. Der nachfolgende Code zeigt eine Beispielkonfiguration.

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;


GPIO_Speed definiert die maximale Änderungsrate des Pins. Das ist aber keine harte Grenze, sondern verändert die Charakteristik des Pintreibers. Eine niedrigere Grenzfrequenz reduziert die Flankensteilheit und damit Leitungsreflexionen. Mögliche Werte für GPIO_Speed

Wert ' Bedeutung
GPIO_Speed_2MHz 2MHz / 125ns
GPIO_Speed_10MHz 10MHz / 25ns
GPIO_Speed_50MHz 30-50MHz / 5-12ns


GPIO_Mode konfiguriert den Port oder den Port Pin. Mögliche Werte für GPIO_Mode

Wert Beschreibung
GPIO_Mode_Out_PP Der Pin wird als Ausgang im Push Pull Modus konfiguriert. Dies bedeutet, der Ausgang kann sowohl positive als auch negative Ströme liefern
GPIO_Mode_Out_OD Der Pin wird als Ausgang im Open Drain Modus konfiguriert.
GPIO_Mode_IN_FLOATING Der Pin wird als Eingang im Floating modus konfiguriert. Dies bedeutet, das der Pin kein Niveau hat. Er "schwebt"
GPIO_Mode_AIN Der Pin wird als analoger Eingang konfiguriert
GPIO_Mode_IPD Der Pin wird als Eingang konfiguriert mit internem Pull Down Widerstand
GPIO_Mode_IPU Der Pin wird als Eingang konfiguriert mit internem Pull Up Widerstand
GPIO_Mode_AF_OD Der Pin wird mit Alternativer Funktion (SPI, I2C..) konfiguriert im Open Drain Modus
GPIO_Mode_AF_PP Der Pin wird mit Alternativer Funktion (SPI, I2C..) konfiguriert im Push Pull Modus


GPIO_Pin definiert den Pin welcher konfiguriert werden soll.

Um den zu konfigurierenden Pin anzugeben, genügt es GPIO_Pin_X zu schreiben. Wobei "X" durch die entsprechende Pinnummer zu ersetzen ist.
Es können auch mehrere Pins gleichzeitig konfiguriert werden. Dazu wird einfach logische ODER verknüfung verwendet ( | ) Möchte man den gesamten Port konfigurieren, so genügt es wenn man GPIO_Pin_All angibt.

Hier ein Beispiel mit mehreren Pins

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_7


GPIO_Init()

Nachdem wir nun alle relevanten Parameter gesetzt haben, müssen wir den Port nur noch mit GPIO_Init() initialisieren.

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

GPIOx ist der Pointer auf den den zu initialisierenden Port. Wobei x einfach mit dem entsprechenden Buchstaben zu ersetzen ist.

GPIO_InitStruct ist der Pointer auf die soeben von uns ausgefüllte struct.

Ein Beispiel für GPIOA

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // Clock des Ports einschalten

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_7

GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_Init() arbeitet Pinweise anhand der Konfiguration von GPIO_InitStructure.GPIO_Pin d.h. an einem Port können den Pins wie folgt verschiedene Funktionen zugeordnet werden.

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // Nur der eine Pin
GPIO_Init(GPIOA, &GPIO_InitStructure); //erst PA1 Out PP

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // Nur der zweite Pin
GPIO_Init(GPIOA, &GPIO_InitStructure); //jetzt PA0 In Pull Up

Etwas auf den Port ausgeben

Um etwas an einem GPIO auszugeben, gibt es drei Möglichkeiten (Funktionen). Entweder man schreibt den gesamten Port oder nur ein einzelnes Bit. Die STMs bieten eine Bitbanding-Funktion, die in ARM Bitbanding genauer erklärt ist.


Funktion 1

Die erste Funktion lautet GPIO_SetBits() und GPIO_ResetBits() Erster Parameter ist der GPIO Port, der zweite ist der Pin oder eine Kombination daraus. Kombinationen sind wieder logisch zu verknüpfen mit ODER ( | )


GPIO_SetBits(GPIOA,GPIO_Pin_1 | GPIO_Pin_5); //Setzt die Bits 1 und 5 am GPIOA auf high

GPIO_ResetBits(GPIOA,GPIO_Pin_2 | GPIO_Pin_9); //Setzt die Bits 2 und 9 am GPIOA auf low

In neueren Versionen der Lib existiert auch eine Funktion GPIO_ToggleBits. Die ist allerdings Stand 2013 nicht atomar implementiert. Das kann im Zusammenspiel mit Interrupts zu sporadischen Überraschungen führen.

Funktion 2

Die zweite Funktion lautet GPIO_WriteBit() Diese Funktion kann sowohl einen oder mehrere Pins setzen als auch löschen. Erster Parameter ist der GPIO Port, der zweite ist der Pin oder eine Kombination daraus, und der dritte sagt aus, ob gesetzt oder gelöscht wird! Kombinationen sind auch hier logisch zu verknüpfen mit ODER ( | ).


GPIO_WriteBit(GPIOA, GPIO_Pin_1 | GPIO_Pin_5, Bit_SET); //Setzt die Bits 1 und 5 am GPIOA auf high

GPIO_WriteBit(GPIOA, GPIO_Pin_2 | GPIO_Pin_9, Bit_RESET); //Setzt die Bits 2 und 9 am GPIOA auf low

Funktion 3

Die dritte und somit letzte Funktion lautet GPIO_Write(). Diese Funktion beschreibt den gesamten Port! Erster Parameter ist der GPIO Port, der zweite ist der an dem Port auszugebende Wert. Wichtig! Hier wird der ganze Port mit einem 16 bit Wert beschrieben. Viel leserlicher als mit magic numbers im Hex-Format zu arbeiten, sind natürlich auch hier die defines: GPIO_Pin_1 | GPIO_Pin_5

GPIO_Write(GPIOA,0x0011); //Setzt die Bits 1 und 5 am GPIOA auf high
GPIO_Write(GPIOA, GPIO_Pin_1 | GPIO_Pin_5); // Geht natürlich auch und ist verständlicher                

GPIO_ResetBits(GPIOA,0x0102); //Setzt die Bits 2 und 9 am GPIOA auf low

Pin Sperren

Der STM32 bietet die Möglichkeit, einen Pin zu sperren. Ist ein Pin gesperrt, so kann dessen Zustand (High / Low) bis zu einem Reset nicht mehr geändert werden! Wie wir es nun gewohnt sind, hat ST dafür eine eigene Funktion geschrieben. Diese lautet GPIO_PinLockConfig(). Erster Parameter ist der Port, der zweite sind die Pins, welche man sperren möchte. Diese kann man wieder mit der ODER Verknüpfung kombinieren.


GPIO_PinLockConfig(GPIOA,GPIO_Pin_1 | GPIO_Pin_5); //Sperrt die Pins bis zu einem Reset

Eingänge einlesen

Um Daten in den STM32 einzulesen, gibt es wieder ein paar ST Funktionen. Diese möchten wir hier vorstellen. Die dafür verwendbaren Funktionen sind: GPIO_ReadInputDataBit() sowie GPIO_ReadInputData(). Erster Parameter ist der Port, der zweite sind die Pins, die man einlesen möchte. Bei GPIO_ReadInputData() wird jedoch nur der Port übergeben, da diese Funktion den gesamten Port zurück liefert! Hier wird der tatsächliche logische Pegel am Pin eingelesen!

uint8_t ucStatus = 0;

ucStatus = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5); //Speichert den Zustand von Pin5 am GPIOA in die 8-bit-Variable ucStatus 
                                                    //(uint8_t ist die kleinstmögliche, eigenständige Variable für dieses eine Bit)
uint16_t uiPort = 0;

uiPort = GPIO_ReadInputData(GPIOA); //Speichert den Zustand von GPIOA in die 16-bit-Variable uiPort

Ausgänge einlesen

Man hat ja häufig das Problem, dass man gerne nachsehen möchte, was man denn gerade am Ausgang ausgibt. Dazu kann man den Ausgang wie ein Eingang einlesen. Die dafür verwendbaren Funktionen sind: GPIO_ReadOutputDataBit() sowie GPIO_ReadOutputData(). Erster Parameter ist der Port, der zweite sind die Pins, welche man auslesen möchte. Bei GPIO_ReadOutputData() wird jedoch nur der Port übergeben, da diese Funktion den gesamten Port zurück liefert!Hier wird nicht der tatsächliche logische Pegel am Pin eingelesen, sondern was im Ausgangsregister eingestellt wurde (also eigentlich anliegen sollte)! Diese beiden Werte können sich auf Grund externer Einflüsse aber unterscheiden!!!

uint8_t ucStatus = 0;

ucStatus = GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5); //Speichert den Zustand von Pin5 am GPIOA in die 8-bit-Variable ucStatus 
                                                     //(uint8_t ist die kleinstmögliche, eigenständige Variable für dieses eine Bit)
uint16_t uiPort = 0;

uiPort = GPIO_ReadOutputData(GPIOA); //Speichert den Zustand von GPIOA in die 16-bit-Variable uiPort

Deinitialisieren von Ports

Es gibt auch die Möglichkeit, den Port zu deinitialisieren. Dann wird er mit seinen Standardwerten konfiguriert. Die Funktion dazu lautet GPIO_DeInit(). Erster und einziger Parameter ist der Port, den man deinitialisieren möchte.

GPIO_DeInit(GPIOA); //Setzt den GPIOA auf seine Standardwerte zurück

Weblinks, Foren, Communities